You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

romprefix.S 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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 DELAYED_INT when NO_DELAYED_INT is not defined.
  9. * This allows positive tests instead of tests that contain
  10. * double negatives, and become confusing.
  11. */
  12. #ifndef NO_DELAYED_INT
  13. #define DELAYED_INT
  14. #endif
  15. /* We need some unique magic ID, if we defer startup thru the INT18H or INT19H
  16. * handler. This way, we can check if we have already been installed.
  17. */
  18. #ifndef MAGIC
  19. #define MAGIC 0xE44C
  20. #endif
  21. /* Hook into INT18H or INT19H handler */
  22. #ifdef BOOT_INT18H
  23. #define BOOT_INT 0x18
  24. #else
  25. #define BOOT_INT 0x19
  26. #endif
  27. #define BOOT_INT_VEC BOOT_INT*4
  28. #define SCRATCHVEC 0x300
  29. /* Prefix exit codes. We store these on the stack so that we will
  30. * know how to return control to the BIOS when Etherboot exits.
  31. */
  32. #define EXIT_VIA_LRET 0x0
  33. #define EXIT_VIA_INT_18 0x1
  34. #define EXIT_VIA_BOOT_INT 0x2
  35. .text
  36. .code16
  37. .arch i386
  38. .org 0
  39. .section ".prefix", "ax", @progbits
  40. _prefix:
  41. .word 0xAA55 /* BIOS extension signature */
  42. size: .byte 0 /* number of 512 byte blocks */
  43. /* = number of 256 word blocks */
  44. /* filled in by makerom program */
  45. jmp over /* skip over checksum */
  46. .byte 0 /* checksum */
  47. jmp legacyentry /* alternate entry point +6 */
  48. /* used by mknbi-rom */
  49. #ifdef PCI_PNP_HEADER
  50. mfgstr:
  51. .asciz "Etherboot"
  52. #ifdef PXE_EXPORT
  53. .org 0x16
  54. .word UNDIROMID - _prefix
  55. #endif /* PXE_EXPORT */
  56. .org 0x18
  57. .word PCI - _prefix
  58. .word PnP - _prefix
  59. PCI:
  60. .ascii "PCIR"
  61. .word 0x0000 /* vendor ID, filled in by makerom */
  62. .word 0x0000 /* device ID, filled in by makerom */
  63. .word 0x0000 /* pointer to vital product data */
  64. .word 0x0018 /* PCI data structure length */
  65. .byte 0x00 /* PCI data structure revision */
  66. .byte 0x02 /* Device Base Type code */
  67. .byte 0x00 /* Device Sub-Type code */
  68. .byte 0x00 /* Device Interface Type code */
  69. .word 0x0000 /* Image length same as offset 02h */
  70. .word 0x0001 /* revision level of code/data */
  71. .byte 0x00 /* code type */
  72. .byte 0x80 /* indicator (last PCI data structure) */
  73. .word 0x0000 /* reserved */
  74. PnP:
  75. .ascii "$PnP"
  76. .byte 0x01 /* structure revision */
  77. .byte 0x02 /* length (in 16 byte increments) */
  78. .word 0x0000 /* offset of next header */
  79. .byte 0x00 /* Reserved */
  80. .byte 0x00 /* checksum filled by makerom */
  81. .long 0x00000000 /* Device identifier */
  82. .word mfgstr - _prefix
  83. .word 0x0 /* pointer to product name */
  84. /* filled by makerom */
  85. .byte 0x02 /* Device Base Type code */
  86. .byte 0x00 /* Device Sub-Type code */
  87. .byte 0x00 /* Device Interface Type code */
  88. .byte 0x14 /* device indicator */
  89. .word 0x0000 /* boot connection vector */
  90. .word 0x0000 /* disconnect vector */
  91. .word pnpentry - _prefix
  92. .word 0x0000 /* reserved */
  93. .word 0x0000 /* static resource information vector */
  94. #ifdef PXE_EXPORT
  95. UNDIROMID:
  96. .ascii "UNDI"
  97. .byte UNDIROMID_end - UNDIROMID /* length of structure */
  98. .byte 0 /* Checksum */
  99. .byte 0 /* Structure revision */
  100. .byte 0,1,2 /* PXE version 2.1.0 */
  101. .word UNDILoader - _prefix /* Offset to loader routine */
  102. .word _real_mode_stack_size /* Stack segment size */
  103. .word _real_mode_stack_size /* Data segment size */
  104. .word _pxe_stack_size /* Code segment size */
  105. .ascii "PCIR"
  106. /* The code segment contains our pxe_stack_t plus the PXE and
  107. * RM callback interfaces. We don't actually use a data
  108. * segment, but we put a nonzero value here to avoid confusing
  109. * things. 16k of stack space should be enough.
  110. *
  111. * When we claim our own memory, we fill out the data segment
  112. * with the address and size of the real-mode stack, so that
  113. * NBPs will free that area of memory for us. When the UNDI
  114. * loader is used to initialise us, we will never need a
  115. * real-mode stack because we will only ever be called via the
  116. * PXE API, hence our stack is already in base memory.
  117. */
  118. .equ UNDICodeSize, _pxe_stack_size
  119. .equ UNDIDataSize, _real_mode_stack_size
  120. .equ UNDIStackSize, _real_mode_stack_size
  121. UNDIROMID_end:
  122. #endif /* PXE_EXPORT */
  123. #endif /* PCI_PNP_HEADER */
  124. /*
  125. * Explicitly specify DI is wrt ES to avoid problems with some BIOSes
  126. * Discovered by Eric Biederman
  127. * In addition, some BIOSes don't point DI to the string $PnP so
  128. * we need another #define to take care of that.
  129. */
  130. over:
  131. #ifdef DEBUG_ROMPREFIX
  132. call print_bcv
  133. #endif
  134. /* Omit this test for ISA cards anyway */
  135. #ifdef PCI_PNP_HEADER
  136. /* Accept old name too for backward compatibility */
  137. #if !defined(BBS_BUT_NOT_PNP_COMPLIANT) && !defined(PNP_BUT_NOT_BBS_COMPLIANT)
  138. cmpw $'$'+'P'*256,%es:0(%di)
  139. jne notpnp
  140. cmpw $'n'+'P'*256,%es:2(%di)
  141. jne notpnp
  142. #endif /* BBS_BUT_NOT_PNP_COMPLIANT */
  143. movw $0x20,%ax
  144. lret
  145. #endif /* PCI_PNP_HEADER */
  146. notpnp:
  147. #ifdef DEBUG_ROMPREFIX
  148. call print_notpnp
  149. #endif
  150. #ifdef DELAYED_INT
  151. pushw %ax
  152. pushw %ds
  153. xorw %ax,%ax
  154. movw %ax,%ds /* access first 64kB segment */
  155. movw SCRATCHVEC+4, %ax /* check if already installed */
  156. cmpw $MAGIC, %ax /* check magic word */
  157. jz installed
  158. movw BOOT_INT_VEC, %ax /* hook into INT18H or INT19H */
  159. movw %ax, SCRATCHVEC
  160. movw BOOT_INT_VEC+2, %ax
  161. movw %ax, SCRATCHVEC+2
  162. movw $start_int - _prefix, %ax
  163. movw %ax, BOOT_INT_VEC
  164. movw %cs,%ax
  165. movw %ax, BOOT_INT_VEC+2
  166. movw $MAGIC, %ax /* set magic word */
  167. movw %ax, SCRATCHVEC+4
  168. #ifdef DEBUG_ROMPREFIX
  169. call print_installed
  170. #endif
  171. installed:
  172. popw %ds
  173. popw %ax
  174. movw $0x20,%ax
  175. lret
  176. start_int: /* clobber magic id, so that we will */
  177. #ifdef DEBUG_ROMPREFIX
  178. call print_start_int
  179. #endif
  180. xorw %ax,%ax /* not inadvertendly end up in an */
  181. movw %ax,%ds /* endless loop */
  182. movw %ax, SCRATCHVEC+4
  183. movw SCRATCHVEC+2, %ax /* restore original INT19h handler */
  184. movw %ax, BOOT_INT_VEC+2
  185. movw SCRATCHVEC, %ax
  186. movw %ax, BOOT_INT_VEC
  187. pushl %eax /* padding */
  188. pushw $EXIT_VIA_BOOT_INT
  189. jmp invoke
  190. #endif /* DELAYED_INT */
  191. legacyentry:
  192. #ifdef DEBUG_ROMPREFIX
  193. call print_legacyentry
  194. #endif
  195. pushw $EXIT_VIA_LRET
  196. jmp invoke
  197. #ifdef PCI_PNP_HEADER
  198. pnpentry:
  199. #ifdef DEBUG_ROMPREFIX
  200. call print_bev
  201. #endif
  202. pushl %eax /* padding */
  203. pushw $EXIT_VIA_INT_18
  204. jmp invoke
  205. #endif /* PCI_PNP_HEADER */
  206. invoke:
  207. /* Store ROM segment and size on stack */
  208. pushw %ax
  209. pushw %ds
  210. pushw %cs
  211. movzbw %cs:(size-_prefix), %ax
  212. shlw $9, %ax /* 512-byte blocks */
  213. pushw %ax
  214. /* Relocate to free base memory, switch stacks */
  215. pushw $12 /* Preserve exit code & far ret addr */
  216. call prelocate
  217. /* We are now running in RAM */
  218. popw %ax /* padding */
  219. movw %cs, %ax
  220. movw %ax, %ds
  221. popw %ds:(_prefix_rom+2) /* ROM size */
  222. popw %ds:(_prefix_rom+0) /* ROM segment */
  223. popw %ds /* Original %ds */
  224. popw %ax /* Original %ax */
  225. pushw %ax /* 4-byte alignment */
  226. pushl $8 /* Preserve exit code & far ret addr */
  227. pushw $0 /* Set null return address */
  228. jmp _start
  229. .section ".text16", "ax", @progbits
  230. prefix_exit:
  231. popw %ax /* padding */
  232. popw %ax /* %ax = exit code */
  233. cmpw $EXIT_VIA_LRET, %ax
  234. jne 1f
  235. /* Exit via LRET */
  236. lret
  237. 1: addw $4, %sp /* Strip padding */
  238. cmpw $EXIT_VIA_BOOT_INT, %ax
  239. jne 2f
  240. /* Exit via int BOOT_INT */
  241. int $BOOT_INT /* Try original vector */
  242. 2: /* Exit via int $0x18 */
  243. int $0x18 /* As per BIOS Boot Spec, next dev */
  244. prefix_exit_end:
  245. .previous
  246. /* UNDI loader needs to be rewritten to use new mechanism */
  247. #if 0
  248. #ifdef PXE_EXPORT
  249. #define PXENV_UNDI_LOADER 0x104d
  250. .section ".prefix"
  251. UNDILoader:
  252. /* Loader API is different to the usual PXE API; there is no
  253. * opcode on the stack. We arrange the stack to look like a
  254. * normal PXE API call; this makes the Etherboot internals
  255. * cleaner and avoids adding an extra API type just for the
  256. * PXE loader.
  257. */
  258. pushw %bx
  259. movw %sp, %ax /* Store original %ss:sp */
  260. pushw %ss
  261. pushw %ax
  262. pushl %eax /* Space for loader structure ptr */
  263. pushw %bp
  264. movw %sp, %bp
  265. movw 16(%bp), %ax /* Copy loader structure ptr */
  266. movw %ax, 2(%bp)
  267. movw 18(%bp), %ax
  268. movw %ax, 4(%bp)
  269. popw %bp
  270. pushw $PXENV_UNDI_LOADER /* PXE 'opcode' */
  271. pushl %eax /* dummy return address */
  272. /* Stack now looks like a normal PXE API call */
  273. /* Store ROM segment and size on stack */
  274. pushw %ax
  275. pushw %cs
  276. movzbw %cs:(size-_prefix), %ax
  277. shlw $9, %ax /* 512-byte blocks */
  278. pushw %ax
  279. /* Unpack Etherboot into temporarily claimed base memory */
  280. pushw $20 /* Dummy ret, PXE params, orig ss:sp */
  281. call prelocate
  282. popw %ax /* discard */
  283. popw %cs:(_prefix_rom+2) /* ROM size */
  284. popw %cs:(_prefix_rom+0) /* ROM segment */
  285. popw %ax /* Original %ax */
  286. /* Inhibit automatic deallocation of base memory */
  287. movl $0, %cs:_prefix_image_basemem
  288. /* Make PXE API call to Etherboot */
  289. pushl $0x201 /* PXE API version */
  290. /* Need to USE_INTERNAL_STACK, since we will call relocate() */
  291. pushl $(EB_OPCODE_PXE|EB_USE_INTERNAL_STACK) /* PXE API call type */
  292. call _entry
  293. addw $18, %sp /* discard */
  294. popw %bx /* Restore original %ss:sp */
  295. popw %ss
  296. movw %bx, %sp
  297. popw %bx
  298. call deprelocate
  299. lret $2 /* Skip our PXE 'opcode' */
  300. #endif /* PXE_EXPORT */
  301. #endif /* 0 */
  302. #ifdef DEBUG_ROMPREFIX
  303. .section ".prefix"
  304. print_bcv:
  305. pushw %si
  306. movw $1f-_prefix, %si
  307. call print_message
  308. popw %si
  309. ret
  310. 1: .asciz "ROM detected\r\n"
  311. print_bev:
  312. pushw %si
  313. movw $1f-_prefix, %si
  314. call print_message
  315. popw %si
  316. ret
  317. 1: .asciz "booting\r\n"
  318. print_notpnp:
  319. pushw %si
  320. movw $1f-_prefix, %si
  321. call print_message
  322. popw %si
  323. ret
  324. 1: .asciz ": Non-PnP BIOS detected!\r\n"
  325. print_legacyentry:
  326. pushw %si
  327. movw $1f-_prefix, %si
  328. call print_message
  329. popw %si
  330. ret
  331. 1: .asciz "ROM using legacy boot mechanism\r\n"
  332. print_installed:
  333. pushw %si
  334. movw $1f-_prefix, %si
  335. call print_message
  336. popw %si
  337. ret
  338. 1: .ascii "hooked boot via INT"
  339. #ifdef BOOT_INT18H
  340. .asciz "18\r\n"
  341. #else
  342. .asciz "19\r\n"
  343. #endif
  344. print_start_int:
  345. pushw %si
  346. movw $1f-_prefix, %si
  347. call print_message
  348. popw %si
  349. ret
  350. 1: .asciz "booting via hooked interrupt\r\n"
  351. print_message:
  352. pushaw
  353. pushw %ds
  354. pushw %cs
  355. popw %ds
  356. pushw %si
  357. movw $1f-_prefix, %si
  358. call print_string
  359. popw %si
  360. call print_string
  361. popw %ds
  362. popaw
  363. ret
  364. 1: .asciz "Etherboot "
  365. print_string:
  366. 1: lodsb
  367. testb %al,%al
  368. je 2f
  369. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  370. movb $0x0e, %ah /* write char, tty mode */
  371. int $0x10
  372. jmp 1b
  373. 2: ret
  374. #endif