boot_x86.asm 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. ;
  2. ; src/boot_x86.asm
  3. ; https://codeberg.org/bzt/easyboot
  4. ;
  5. ; Copyright (C) 2023 bzt
  6. ;
  7. ; This program is free software; you can redistribute it and/or modify
  8. ; it under the terms of the GNU General Public License as published by
  9. ; the Free Software Foundation; either version 3 of the License, or
  10. ; (at your option) any later version.
  11. ;
  12. ; This program is distributed in the hope that it will be useful,
  13. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ; GNU General Public License for more details.
  16. ;
  17. ; You should have received a copy of the GNU General Public License
  18. ; along with this program; if not, write to the Free Software
  19. ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. ;
  21. ; @brief Legacy mode Protective Master Boot Record for Easyboot, written with
  22. ; flatassembler: https://flatassembler.net It's job is to load loader_x86.efi,
  23. ; extract its sections, set up long mode and pass control to it
  24. ;
  25. ; Memory layout on handover:
  26. ; 0h - 400h IVT (must be preserved)
  27. ; 400h - 4FFh BDA (must be preserved)
  28. ; 4FFh - 500h BIOS boot drive code
  29. ; 500h - 510h BIOS LBA packet
  30. ; 510h - 550h GDT
  31. ; 550h - 1000h stack (2k+)
  32. ; 1000h - 8000h paging tables
  33. ; 8000h - 60000h loader_x86.efi's sections
  34. ; 9A000h - A0000h EBDA (must be preserved)
  35. easyboot_addr equ 08000h
  36. ORG 07C00h
  37. USE16
  38. ;*********************************************************************
  39. ;* code *
  40. ;*********************************************************************
  41. jmp short @f ; mandatory jump (magic)
  42. nop
  43. db "Easyboot", 0, 0, 0
  44. ;---- set up environment ----
  45. @@: cli
  46. cld
  47. mov al, 0FFh ; disable PIC
  48. out 021h, al
  49. out 0A1h, al
  50. in al, 70h ; disable NMI
  51. or al, 80h
  52. out 70h, al
  53. xor ax, ax
  54. mov ss, ax
  55. mov ds, ax
  56. mov es, ax
  57. mov sp, easyboot_addr
  58. ;---- read in loader_x86.efi ----
  59. mov bx, 500h
  60. mov di, bx
  61. mov byte [di - 1], dl
  62. mov si, loader_lba
  63. xor ah, ah
  64. mov al, 16 ; size
  65. stosw
  66. mov al, 120 ; count
  67. stosw
  68. xor ax, ax ; addr0, load to 60000h
  69. stosw
  70. mov ah, 60h ; addr1
  71. stosw
  72. movsw ; sect0
  73. movsw ; sect1
  74. xor ax, ax
  75. stosw ; sect2
  76. stosw ; sect3
  77. mov si, GDT_value
  78. mov cx, word[si]
  79. repnz movsb
  80. mov ah, 42h
  81. mov si, bx
  82. push si
  83. int 13h
  84. pop si
  85. add byte [si + 7], 15
  86. add dword [si + 8], 120
  87. mov ah, 42h
  88. int 13h
  89. ;---- enable protmode ----
  90. mov ax, 2401h ; enable A20
  91. int 15h
  92. lgdt [510h]
  93. mov eax, cr0
  94. or al, 1
  95. mov cr0, eax
  96. jmp 16:@f
  97. USE32
  98. @@: mov ax, 24
  99. mov ds, ax
  100. mov es, ax
  101. ; look for long mode supported flag
  102. xor edx, edx
  103. mov eax, 80000001h
  104. cpuid
  105. bt edx, 29
  106. jnc .die
  107. ;---- enable longmode ----
  108. xor eax, eax
  109. mov ah, 010h
  110. mov cr3, eax
  111. ; we only map 2M here, loader will finish up the rest overwriting us in the process
  112. mov edx, eax ; PML4
  113. mov ebx, eax
  114. xor eax, eax
  115. mov dword [ebx], 02003h ; pointer to 2M PDPE
  116. mov dword [ebx + 4], eax
  117. add ebx, edx ; 2M PDPE
  118. mov dword [ebx], 03003h
  119. mov dword [ebx + 4], eax
  120. add ebx, edx ; 2M PDE
  121. mov dword [ebx], 00083h
  122. mov dword [ebx + 4], eax
  123. mov al, 0E0h ; set PAE, MCE, PGE; clear everything else
  124. mov cr4, eax
  125. mov ecx, 0C0000080h ; EFER MSR
  126. rdmsr
  127. bts eax, 8 ; enable long mode page tables
  128. wrmsr
  129. mov eax, cr0
  130. xor cl, cl
  131. or eax, ecx
  132. btc eax, 16 ; clear WP
  133. mov cr0, eax ; enable paging with cache disabled (set PE, CD)
  134. lgdt [510h] ; read 80 bit address (16+64)
  135. jmp 32:@f
  136. USE64
  137. @@: xor rax, rax ; load long mode segments
  138. mov al, 40
  139. mov ds, ax
  140. mov es, ax
  141. mov ss, ax
  142. mov ax, easyboot_addr
  143. ;---- parse loader_x86.efi (PE / COFF format) ----
  144. mov ebx, 60000h ; load buffer address
  145. cmp word [ebx], 5A4Dh ; check MZ
  146. jne .die
  147. mov r8d, ebx
  148. add ebx, dword [ebx + 0x3c] ; get COFF header
  149. cmp word [ebx], 4550h ; check PE
  150. jne .die
  151. mov dl, byte [ebx + 6] ; number of sections
  152. mov r9d, dword [ebx + 0x28] ; entry point
  153. mov ebp, dword [ebx + 0x2c] ; code base
  154. add r9d, eax
  155. sub r9d, ebp
  156. add bx, word [ebx + 0x14] ; add header size
  157. add bx, 24 ; ebx now points to section table
  158. @@: mov edi, dword [ebx + 12] ; copy sections from PE into VA
  159. add edi, eax
  160. sub edi, ebp ; dest: virtual address + reloc offset - code base
  161. mov ecx, dword [ebx + 16] ; size of raw data
  162. mov esi, dword [ebx + 20]
  163. add esi, r8d ; source: pointer to raw data + load offset
  164. repnz movsb
  165. add ebx, 40 ; go to next section
  166. dec dl
  167. jnz @b
  168. xor rsp, rsp
  169. mov sp, 1000h ; set stack
  170. xor rcx, rcx ; image handle
  171. xor rdx, rdx ; system table pointer
  172. jmp r9 ; jump to relocated entry point
  173. ;---- die function ----
  174. ; written in a way that it's decodeable as prot mode as well as long mode instructions
  175. .die: mov esi, .err
  176. mov edi, 0B8000h
  177. mov ah, 04fh
  178. @@: lodsb
  179. or al, al
  180. jz @f
  181. stosw
  182. jmp @b
  183. @@: hlt
  184. ;*********************************************************************
  185. ;* data area *
  186. ;*********************************************************************
  187. .err: db "PMBR-ERR", 0
  188. GDT_value: dw GDT_value.end-GDT_value ; value / null descriptor
  189. dd 510h
  190. dw 0
  191. dd 0000FFFFh,00009800h ; 8 - legacy real cs
  192. dd 0000FFFFh,00CF9A00h ; 16 - prot mode cs
  193. dd 0000FFFFh,008F9200h ; 24 - prot mode ds
  194. dd 0000FFFFh,00AF9A00h ; 32 - long mode cs
  195. dd 0000FFFFh,00CF9200h ; 40 - long mode ds
  196. .end: db 01B0h-($-$$) dup 0
  197. loader_lba: dd 0h ; the image generator sets this
  198. ;---- space for legacy partitioning table ----
  199. db 01FEh-($-$$) dup 0
  200. db 55h, 0AAh ; mandatory magic bytes