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

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