romprefix.S 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /* At entry, the processor is in 16 bit real mode and the code is being
  2. * executed from an address it was not linked to. Code must be pic and
  3. * 32 bit sensitive until things are fixed up.
  4. *
  5. * Also be very careful as the stack is at the rear end of the interrupt
  6. * table so using a noticeable amount of stack space is a no-no.
  7. */
  8. #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
  9. #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
  10. #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
  11. #define PNP_GET_BBS_VERSION 0x60
  12. .text
  13. .code16
  14. .arch i386
  15. .section ".prefix", "ax", @progbits
  16. .org 0x00
  17. romheader:
  18. .word 0xAA55 /* BIOS extension signature */
  19. romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */
  20. jmp init /* Initialisation vector */
  21. checksum:
  22. .byte 0
  23. .org 0x16
  24. .word undiheader
  25. .org 0x18
  26. .word pciheader
  27. .org 0x1a
  28. .word pnpheader
  29. .size romheader, . - romheader
  30. .section ".zinfo.fixup", "a" /* Compressor fixup information */
  31. .ascii "SUBB"
  32. .long romheader_size
  33. .long 512
  34. .long 0
  35. .previous
  36. pciheader:
  37. .ascii "PCIR" /* Signature */
  38. .word pci_vendor_id /* Vendor ID */
  39. .word pci_device_id /* Device ID */
  40. .word 0x0000 /* pointer to vital product data */
  41. .word pciheader_len /* PCI data structure length */
  42. .byte 0x00 /* PCI data structure revision */
  43. .byte 0x02 /* Device Base Type code */
  44. .byte 0x00 /* Device Sub-Type code */
  45. .byte 0x00 /* Device Interface Type code */
  46. pciheader_size: .word _load_size_sect /* Image length same as offset 02h */
  47. .word 0x0001 /* revision level of code/data */
  48. .byte 0x00 /* code type */
  49. .byte 0x80 /* Flags (last PCI data structure) */
  50. .word 0x0000 /* reserved */
  51. .equ pciheader_len, . - pciheader
  52. .size pciheader, . - pciheader
  53. .section ".zinfo.fixup", "a" /* Compressor fixup information */
  54. .ascii "SUBW"
  55. .long pciheader_size
  56. .long 512
  57. .long 0
  58. .previous
  59. pnpheader:
  60. .ascii "$PnP" /* Signature */
  61. .byte 0x01 /* Structure revision */
  62. .byte ( pnpheader_len / 16 ) /* Length (in 16 byte increments) */
  63. .word 0x0000 /* Offset of next header */
  64. .byte 0x00 /* Reserved */
  65. .byte 0x00 /* Checksum */
  66. .long 0x00000000 /* Device identifier */
  67. .word mfgstr /* Manufacturer string */
  68. .word prodstr /* Product name */
  69. .byte 0x02 /* Device base type code */
  70. .byte 0x00 /* Device sub-type code */
  71. .byte 0x00 /* Device interface type code */
  72. .byte 0x54 /* Device indicator */
  73. .word 0x0000 /* Boot connection vector */
  74. .word 0x0000 /* Disconnect vector */
  75. .word bev_entry /* Boot execution vector */
  76. .word 0x0000 /* Reserved */
  77. .word 0x0000 /* Static resource information vector*/
  78. .equ pnpheader_len, . - pnpheader
  79. .size pnpheader, . - pnpheader
  80. mfgstr:
  81. .asciz "http://etherboot.org"
  82. .size mfgstr, . - mfgstr
  83. prodstr:
  84. .asciz "gPXE"
  85. .size prodstr, . - prodstr
  86. undiheader:
  87. .ascii "UNDI" /* Signature */
  88. .byte undiheader_len /* Length of structure */
  89. .byte 0 /* Checksum */
  90. .byte 0 /* Structure revision */
  91. .byte 0,1,2 /* PXE version: 2.1.0 */
  92. .word undiloader /* Offset to loader routine */
  93. .word _data16_size /* Stack segment size */
  94. .word _data16_size /* Data segment size */
  95. .word _text16_size /* Code segment size */
  96. .equ undiheader_len, . - undiheader
  97. .size undiheader, . - undiheader
  98. /* Initialisation (called once during POST)
  99. *
  100. * Determine whether or not this is a PnP system via a signature
  101. * check. If it is PnP, return to the PnP BIOS indicating that we are
  102. * a boot-capable device; the BIOS will call our boot execution vector
  103. * if it wants to boot us. If it is not PnP, hook INT 19.
  104. */
  105. init:
  106. /* Preserve registers, clear direction flag, set %ds=%cs */
  107. pushaw
  108. pushw %ds
  109. pushw %es
  110. cld
  111. pushw %cs
  112. popw %ds
  113. /* Print message as early as possible */
  114. movw $init_message, %si
  115. call print_message
  116. /* Check for PnP BIOS */
  117. testw $0x0f, %di /* PnP signature must be aligned - bochs */
  118. jnz hook_int19 /* uses unalignment to indicate 'fake' PnP. */
  119. cmpl $PNP_SIGNATURE, %es:0(%di)
  120. jne hook_int19
  121. /* Is PnP: print PnP message */
  122. movw $init_message_pnp, %si
  123. call print_message
  124. xchgw %bx, %bx
  125. /* Check for BBS */
  126. pushw %es:0x1b(%di) /* Real-mode data segment */
  127. pushw %ds /* &(bbs_version) */
  128. pushw $bbs_version
  129. pushw $PNP_GET_BBS_VERSION
  130. lcall *%es:0xd(%di)
  131. addw $8, %sp
  132. testw %ax, %ax
  133. jne hook_int19
  134. movw $init_message_bbs, %si
  135. call print_message
  136. jmp hook_bbs
  137. /* Not BBS-compliant - must hook INT 19 */
  138. hook_int19:
  139. movw $init_message_int19, %si
  140. call print_message
  141. xorw %ax, %ax
  142. movw %ax, %es
  143. pushw %cs
  144. pushw $int19_entry
  145. popl %es:( 0x19 * 4 )
  146. hook_bbs:
  147. /* Check for PMM */
  148. movw $( 0xe000 - 1 ), %di
  149. pmm_scan:
  150. incw %di
  151. jz no_pmm
  152. movw %di, %es
  153. cmpl $PMM_SIGNATURE, %es:0
  154. jne pmm_scan
  155. xorw %bx, %bx
  156. xorw %si, %si
  157. movzbw %es:5, %cx
  158. 1: es lodsb
  159. addb %al, %bl
  160. loop 1b
  161. jnz pmm_scan
  162. /* PMM found: print PMM message */
  163. movw $init_message_pmm, %si
  164. call print_message
  165. /* Try to allocate 2MB block via PMM */
  166. pushw $0x0006 /* Aligned, extended memory */
  167. pushl $0xffffffff /* No handle */
  168. pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */
  169. pushw $0x0000 /* pmmAllocate */
  170. lcall *%es:7
  171. addw $12, %sp
  172. testw %dx, %dx /* %ax==0 even on success, since align=2MB */
  173. jnz gotpmm
  174. movw $init_message_pmm_failed, %si
  175. call print_message
  176. jmp no_pmm
  177. gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */
  178. pushal /* PMM presence implies 1kB stack */
  179. movw %ax, %es /* %ax=0 already - see above */
  180. pushw %dx
  181. pushw %ax
  182. popl %edi
  183. movl %edi, image_source
  184. xorl %esi, %esi
  185. movzbl romheader_size, %ecx
  186. shll $9, %ecx
  187. addr32 rep movsb /* PMM presence implies flat real mode */
  188. movl %edi, decompress_to
  189. /* Shrink ROM and update checksum */
  190. xorw %bx, %bx
  191. xorw %si, %si
  192. movw $_prefix_size_sect, %cx
  193. movb %cl, romheader_size
  194. shlw $9, %cx
  195. 1: lodsb
  196. addb %al, %bl
  197. loop 1b
  198. subb %bl, checksum
  199. popal
  200. no_pmm:
  201. /* Print CRLF to terminate messages */
  202. movw $'\n', %ax
  203. call print_character
  204. /* Restore registers */
  205. popw %es
  206. popw %ds
  207. popaw
  208. /* Indicate boot capability to PnP BIOS, if present */
  209. movw $0x20, %ax
  210. lret
  211. .size init, . - init
  212. init_message:
  213. .asciz "gPXE (http://etherboot.org) -"
  214. .size init_message, . - init_message
  215. init_message_pnp:
  216. .asciz " PnP"
  217. .size init_message_pnp, . - init_message_pnp
  218. init_message_bbs:
  219. .asciz " BBS"
  220. .size init_message_bbs, . - init_message_bbs
  221. init_message_pmm:
  222. .asciz " PMM"
  223. .size init_message_pmm, . - init_message_pmm
  224. init_message_pmm_failed:
  225. .asciz "(failed)"
  226. .size init_message_pmm_failed, . - init_message_pmm_failed
  227. init_message_int19:
  228. .asciz " INT19"
  229. .size init_message_int19, . - init_message_int19
  230. /* ROM image location
  231. *
  232. * May be either within option ROM space, or within PMM-allocated block.
  233. */
  234. image_source:
  235. .long 0
  236. .size image_source, . - image_source
  237. /* Temporary decompression area
  238. *
  239. * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
  240. */
  241. decompress_to:
  242. .long HIGHMEM_LOADPOINT
  243. .size decompress_to, . - decompress_to
  244. /* BBS version
  245. *
  246. * Filled in by BBS BIOS. We ignore the value.
  247. */
  248. bbs_version:
  249. .word 0
  250. /* Boot Execution Vector entry point
  251. *
  252. * Called by the PnP BIOS when it wants to boot us.
  253. */
  254. bev_entry:
  255. pushw %cs
  256. call exec
  257. lret
  258. .size bev_entry, . - bev_entry
  259. /* INT19 entry point
  260. *
  261. * Called via the hooked INT 19 if we detected a non-PnP BIOS.
  262. */
  263. int19_entry:
  264. pushw %cs
  265. call exec
  266. /* No real way to return from INT19 */
  267. int $0x18
  268. .size int19_entry, . - int19_entry
  269. /* Execute as a boot device
  270. *
  271. */
  272. exec: /* Set %ds = %cs */
  273. pushw %cs
  274. popw %ds
  275. /* Print message as soon as possible */
  276. movw $exec_message, %si
  277. call print_message
  278. /* Store magic word on BIOS stack and remember BIOS %ss:sp */
  279. pushl $STACK_MAGIC
  280. movw %ss, %dx
  281. movw %sp, %bp
  282. /* Obtain a reasonably-sized temporary stack */
  283. xorw %ax, %ax
  284. movw %ax, %ss
  285. movw $0x7c00, %sp
  286. /* Install gPXE */
  287. movl image_source, %esi
  288. movl decompress_to, %edi
  289. call alloc_basemem
  290. call install_prealloc
  291. /* Set up real-mode stack */
  292. movw %bx, %ss
  293. movw $_estack16, %sp
  294. /* Jump to .text16 segment */
  295. pushw %ax
  296. pushw $1f
  297. lret
  298. .section ".text16", "awx", @progbits
  299. 1: /* Call main() */
  300. pushl $main
  301. pushw %cs
  302. call prot_call
  303. /* No need to clean up stack; we are about to reload %ss:sp */
  304. /* Restore BIOS stack */
  305. movw %dx, %ss
  306. movw %bp, %sp
  307. /* Check magic word on BIOS stack */
  308. popl %eax
  309. cmpl $STACK_MAGIC, %eax
  310. jne 1f
  311. /* BIOS stack OK: return to caller */
  312. lret
  313. 1: /* BIOS stack corrupt: use INT 18 */
  314. int $0x18
  315. .previous
  316. exec_message:
  317. .asciz "gPXE starting boot\n"
  318. .size exec_message, . - exec_message
  319. /* UNDI loader
  320. *
  321. * Called by an external program to load our PXE stack.
  322. */
  323. undiloader:
  324. /* Save registers */
  325. pushl %esi
  326. pushl %edi
  327. pushw %es
  328. pushw %bx
  329. /* UNDI loader parameter structure address into %es:%di */
  330. movw %sp, %bx
  331. movw %ss:12(%bx), %di
  332. movw %ss:14(%bx), %es
  333. /* Install to specified real-mode addresses */
  334. pushw %di
  335. movw %es:12(%di), %bx
  336. movw %es:14(%di), %ax
  337. movl %cs:image_source, %esi
  338. movl %cs:decompress_to, %edi
  339. call install_prealloc
  340. popw %di
  341. /* Call UNDI loader C code */
  342. pushl $pxe_loader_call
  343. pushw %cs
  344. pushw $1f
  345. pushw %ax
  346. pushw $prot_call
  347. lret
  348. 1: popw %bx /* discard */
  349. popw %bx /* discard */
  350. /* Restore registers and return */
  351. popw %bx
  352. popw %es
  353. popl %edi
  354. popl %esi
  355. lret
  356. .size undiloader, . - undiloader