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.

mromprefix.S 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. *
  23. */
  24. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
  25. #define PCIBIOS_READ_CONFIG_WORD 0xb109
  26. #define PCIBIOS_READ_CONFIG_DWORD 0xb10a
  27. #define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
  28. #define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
  29. #define PCI_COMMAND 0x04
  30. #define PCI_COMMAND_MEM 0x02
  31. #define PCI_BAR_0 0x10
  32. #define PCI_BAR_5 0x24
  33. #define PCI_BAR_EXPROM 0x30
  34. #define PCIR_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) )
  35. #define ROMPREFIX_EXCLUDE_PAYLOAD 1
  36. #define ROMPREFIX_MORE_IMAGES 1
  37. #define _pcirom_start _mrom_start
  38. #include "pciromprefix.S"
  39. .text
  40. .arch i386
  41. .code16
  42. /* Obtain access to payload by exposing the expansion ROM BAR at the
  43. * address currently used by a suitably large memory BAR on the same
  44. * device. The memory BAR is temporarily disabled. Using a memory
  45. * BAR on the same device means that we don't have to worry about the
  46. * configuration of any intermediate PCI bridges.
  47. *
  48. * Parameters:
  49. * %ds:0000 : Prefix
  50. * %esi : Buffer for copy of image source (or zero if no buffer available)
  51. * %ecx : Expected offset within buffer of first payload block
  52. * Returns:
  53. * %esi : Valid image source address (buffered or unbuffered)
  54. * %ecx : Actual offset within buffer of first payload block
  55. * CF set on error
  56. */
  57. .section ".text16.early", "awx", @progbits
  58. .globl open_payload
  59. open_payload:
  60. /* Preserve registers */
  61. pushl %eax
  62. pushw %bx
  63. pushl %edx
  64. pushl %edi
  65. pushw %bp
  66. pushw %es
  67. pushw %ds
  68. /* Retrieve bus:dev.fn from .prefix */
  69. movw init_pci_busdevfn, %bx
  70. /* Set up %ds for access to .text16.early */
  71. pushw %cs
  72. popw %ds
  73. /* Set up %es for access to flat address space */
  74. xorw %ax, %ax
  75. movw %ax, %es
  76. /* Store bus:dev.fn to .text16.early */
  77. movw %bx, payload_pci_busdevfn
  78. /* Get expansion ROM BAR current value */
  79. movw $PCI_BAR_EXPROM, %di
  80. call pci_read_bar
  81. movl %eax, rom_bar_orig_value
  82. /* Get expansion ROM BAR size */
  83. call pci_size_mem_bar_low
  84. movl %ecx, rom_bar_size
  85. /* Find a suitable memory BAR to use */
  86. movw $PCI_BAR_0, %di /* %di is PCI BAR register */
  87. xorw %bp, %bp /* %bp is increment */
  88. find_mem_bar:
  89. /* Move to next BAR */
  90. addw %bp, %di
  91. cmpw $PCI_BAR_5, %di
  92. jle 1f
  93. stc
  94. movl $0xbabababa, %esi /* Report "No suitable BAR" */
  95. movl rom_bar_size, %ecx
  96. jmp 99f
  97. 1: movw $4, %bp
  98. /* Get BAR current value */
  99. call pci_read_bar
  100. /* Skip non-existent BARs */
  101. notl %eax
  102. testl %eax, %eax
  103. notl %eax
  104. jz find_mem_bar
  105. /* Skip I/O BARs */
  106. testb $0x01, %al
  107. jnz find_mem_bar
  108. /* Set increment to 8 for 64-bit BARs */
  109. testb $0x04, %al
  110. jz 1f
  111. movw $8, %bp
  112. 1:
  113. /* Skip 64-bit BARs with high dword set; we couldn't use this
  114. * address for the (32-bit) expansion ROM BAR anyway
  115. */
  116. testl %edx, %edx
  117. jnz find_mem_bar
  118. /* Get low dword of BAR size */
  119. call pci_size_mem_bar_low
  120. /* Skip BARs smaller than the expansion ROM BAR */
  121. cmpl %ecx, rom_bar_size
  122. ja find_mem_bar
  123. /* We have a memory BAR with a 32-bit address that is large
  124. * enough to use. Store BAR number and original value.
  125. */
  126. movw %di, stolen_bar_register
  127. movl %eax, stolen_bar_orig_value
  128. /* Remove flags from BAR address */
  129. xorb %al, %al
  130. /* Write zero to our stolen BAR. This doesn't technically
  131. * disable it, but it's a pretty safe bet that the PCI bridge
  132. * won't pass through accesses to this region anyway. Note
  133. * that the high dword (if any) must already be zero.
  134. */
  135. xorl %ecx, %ecx
  136. call pci_write_config_dword
  137. /* Enable expansion ROM BAR at stolen BAR's address */
  138. movl %eax, %ecx
  139. orb $0x1, %cl
  140. movw $PCI_BAR_EXPROM, %di
  141. call pci_write_config_dword
  142. /* Locate our ROM image */
  143. 1: movl $0xaa55, %ecx /* 55aa signature */
  144. addr32 es cmpw %cx, (%eax)
  145. jne 2f
  146. movl $PCIR_SIGNATURE, %ecx /* PCIR signature */
  147. addr32 es movzwl 0x18(%eax), %edx
  148. addr32 es cmpl %ecx, (%eax,%edx)
  149. jne 2f
  150. addr32 es cmpl $_build_id, build_id(%eax) /* iPXE build ID */
  151. je 3f
  152. movl $0x80, %ecx /* Last image */
  153. addr32 es testb %cl, 0x15(%eax,%edx)
  154. jnz 2f
  155. addr32 es movzwl 0x10(%eax,%edx), %ecx /* PCIR image length */
  156. shll $9, %ecx
  157. addl %ecx, %eax
  158. jmp 1b
  159. 2: /* Failure */
  160. stc
  161. movl %eax, %esi /* Report failure address */
  162. jmp 99f
  163. 3:
  164. /* Copy payload to buffer, or set buffer address to BAR address */
  165. testl %esi, %esi
  166. jz 1f
  167. /* We have a buffer; copy payload to it. Since .mrom is
  168. * designed specifically for real hardware, we assume that
  169. * flat real mode is working properly. (In the unlikely event
  170. * that this code is run inside a hypervisor that doesn't
  171. * properly support flat real mode, it will die horribly.)
  172. */
  173. pushl %esi
  174. movl %esi, %edi
  175. movl %eax, %esi
  176. addr32 es movzbl 2(%esi), %ecx
  177. shll $7, %ecx
  178. addr32 es movzwl mpciheader_image_length(%esi,%ecx,4), %edx
  179. shll $7, %edx
  180. addl %edx, %ecx
  181. addr32 es rep movsl
  182. popl %esi
  183. jmp 2f
  184. 1: /* We have no buffer; set %esi to the BAR address */
  185. movl %eax, %esi
  186. 2:
  187. /* Locate first payload block (after the dummy ROM header) */
  188. addr32 es movzbl 2(%esi), %ecx
  189. shll $9, %ecx
  190. addl $_pprefix_skip, %ecx
  191. clc
  192. /* Restore registers and return */
  193. 99: popw %ds
  194. popw %es
  195. popw %bp
  196. popl %edi
  197. popl %edx
  198. popw %bx
  199. popl %eax
  200. lret
  201. .size open_payload, . - open_payload
  202. .section ".text16.early.data", "aw", @progbits
  203. payload_pci_busdevfn:
  204. .word 0
  205. .size payload_pci_busdevfn, . - payload_pci_busdevfn
  206. .section ".text16.early.data", "aw", @progbits
  207. rom_bar_orig_value:
  208. .long 0
  209. .size rom_bar_orig_value, . - rom_bar_orig_value
  210. .section ".text16.early.data", "aw", @progbits
  211. rom_bar_size:
  212. .long 0
  213. .size rom_bar_size, . - rom_bar_size
  214. .section ".text16.early.data", "aw", @progbits
  215. stolen_bar_register:
  216. .word 0
  217. .size stolen_bar_register, . - stolen_bar_register
  218. .section ".text16.early.data", "aw", @progbits
  219. stolen_bar_orig_value:
  220. .long 0
  221. .size stolen_bar_orig_value, . - stolen_bar_orig_value
  222. /* Restore original BAR values
  223. *
  224. * Parameters:
  225. * none
  226. * Returns:
  227. * none
  228. */
  229. .section ".text16.early", "awx", @progbits
  230. .globl close_payload
  231. close_payload:
  232. /* Preserve registers */
  233. pushw %bx
  234. pushw %di
  235. pushl %ecx
  236. pushw %ds
  237. /* Set up %ds for access to .text16.early */
  238. pushw %cs
  239. popw %ds
  240. /* Retrieve stored bus:dev.fn */
  241. movw payload_pci_busdevfn, %bx
  242. /* Restore expansion ROM BAR original value */
  243. movw $PCI_BAR_EXPROM, %di
  244. movl rom_bar_orig_value, %ecx
  245. call pci_write_config_dword
  246. /* Restore stolen BAR original value */
  247. movw stolen_bar_register, %di
  248. movl stolen_bar_orig_value, %ecx
  249. call pci_write_config_dword
  250. /* Restore registers and return */
  251. popw %ds
  252. popl %ecx
  253. popw %di
  254. popw %bx
  255. lret
  256. .size close_payload, . - close_payload
  257. /* Get PCI BAR value
  258. *
  259. * Parameters:
  260. * %bx : PCI bus:dev.fn
  261. * %di : PCI BAR register number
  262. * Returns:
  263. * %edx:%eax : PCI BAR value
  264. */
  265. .section ".text16.early", "awx", @progbits
  266. pci_read_bar:
  267. /* Preserve registers */
  268. pushl %ecx
  269. pushw %di
  270. /* Read low dword value */
  271. call pci_read_config_dword
  272. movl %ecx, %eax
  273. /* Read high dword value, if applicable */
  274. xorl %edx, %edx
  275. andb $0x07, %cl
  276. cmpb $0x04, %cl
  277. jne 1f
  278. addw $4, %di
  279. call pci_read_config_dword
  280. movl %ecx, %edx
  281. 1:
  282. /* Restore registers and return */
  283. popw %di
  284. popl %ecx
  285. ret
  286. .size pci_read_bar, . - pci_read_bar
  287. /* Get low dword of PCI memory BAR size
  288. *
  289. * Parameters:
  290. * %bx : PCI bus:dev.fn
  291. * %di : PCI BAR register number
  292. * %eax : Low dword of current PCI BAR value
  293. * Returns:
  294. * %ecx : PCI BAR size
  295. */
  296. .section ".text16.early", "awx", @progbits
  297. pci_size_mem_bar_low:
  298. /* Preserve registers */
  299. pushw %dx
  300. /* Disable memory accesses */
  301. xorw %dx, %dx
  302. call pci_set_mem_access
  303. /* Write all ones to BAR */
  304. xorl %ecx, %ecx
  305. decl %ecx
  306. call pci_write_config_dword
  307. /* Read back BAR */
  308. call pci_read_config_dword
  309. /* Calculate size */
  310. notl %ecx
  311. orb $0x0f, %cl
  312. incl %ecx
  313. /* Restore original value */
  314. pushl %ecx
  315. movl %eax, %ecx
  316. call pci_write_config_dword
  317. popl %ecx
  318. /* Enable memory accesses */
  319. movw $PCI_COMMAND_MEM, %dx
  320. call pci_set_mem_access
  321. /* Restore registers and return */
  322. popw %dx
  323. ret
  324. .size pci_size_mem_bar_low, . - pci_size_mem_bar_low
  325. /* Read PCI config dword
  326. *
  327. * Parameters:
  328. * %bx : PCI bus:dev.fn
  329. * %di : PCI register number
  330. * Returns:
  331. * %ecx : Dword value
  332. */
  333. .section ".text16.early", "awx", @progbits
  334. pci_read_config_dword:
  335. /* Preserve registers */
  336. pushl %eax
  337. pushl %ebx
  338. pushl %edx
  339. /* Issue INT 0x1a,b10a */
  340. movw $PCIBIOS_READ_CONFIG_DWORD, %ax
  341. int $0x1a
  342. /* Restore registers and return */
  343. popl %edx
  344. popl %ebx
  345. popl %eax
  346. ret
  347. .size pci_read_config_dword, . - pci_read_config_dword
  348. /* Write PCI config dword
  349. *
  350. * Parameters:
  351. * %bx : PCI bus:dev.fn
  352. * %di : PCI register number
  353. * %ecx : PCI BAR value
  354. * Returns:
  355. * none
  356. */
  357. .section ".text16.early", "awx", @progbits
  358. pci_write_config_dword:
  359. /* Preserve registers */
  360. pushal
  361. /* Issue INT 0x1a,b10d */
  362. movw $PCIBIOS_WRITE_CONFIG_DWORD, %ax
  363. int $0x1a
  364. /* Restore registers and return */
  365. popal
  366. ret
  367. .size pci_write_config_dword, . - pci_write_config_dword
  368. /* Enable/disable memory access response in PCI command word
  369. *
  370. * Parameters:
  371. * %bx : PCI bus:dev.fn
  372. * %dx : PCI_COMMAND_MEM, or zero
  373. * Returns:
  374. * none
  375. */
  376. .section ".text16.early", "awx", @progbits
  377. pci_set_mem_access:
  378. /* Preserve registers */
  379. pushal
  380. /* Read current value of command register */
  381. pushw %bx
  382. pushw %dx
  383. movw $PCI_COMMAND, %di
  384. movw $PCIBIOS_READ_CONFIG_WORD, %ax
  385. int $0x1a
  386. popw %dx
  387. popw %bx
  388. /* Set memory access enable as appropriate */
  389. andw $~PCI_COMMAND_MEM, %cx
  390. orw %dx, %cx
  391. /* Write new value of command register */
  392. movw $PCIBIOS_WRITE_CONFIG_WORD, %ax
  393. int $0x1a
  394. /* Restore registers and return */
  395. popal
  396. ret
  397. .size pci_set_mem_access, . - pci_set_mem_access
  398. /* Update image source address for UNDI loader
  399. *
  400. * Parameters:
  401. * %esi : Image source address
  402. * Returns:
  403. * %esi : Image source address
  404. */
  405. .section ".prefix", "ax", @progbits
  406. .globl undiloader_source
  407. undiloader_source:
  408. /* Always use expansion ROM BAR directly when installing via
  409. * the UNDI loader entry point, since the PMM-allocated block
  410. * may collide with whatever is calling the UNDI loader entry
  411. * point.
  412. */
  413. xorl %esi, %esi
  414. ret
  415. /* Payload prefix
  416. *
  417. * We include a dummy ROM header to cover the "hidden" portion of the
  418. * overall ROM image.
  419. */
  420. .globl _payload_align
  421. .equ _payload_align, 512
  422. .section ".pprefix", "ax", @progbits
  423. .org 0x00
  424. mromheader:
  425. .word 0xaa55 /* BIOS extension signature */
  426. .byte 0x01 /* Dummy size (BIOS bug workaround) */
  427. .org 0x18
  428. .word mpciheader
  429. .org 0x1a
  430. .word 0
  431. .size mromheader, . - mromheader
  432. .align 4
  433. mpciheader:
  434. .ascii "PCIR" /* Signature */
  435. .word pci_vendor_id /* Vendor identification */
  436. .word pci_device_id /* Device identification */
  437. .word 0x0000 /* Device list pointer */
  438. .word mpciheader_len /* PCI data structure length */
  439. .byte 0x03 /* PCI data structure revision */
  440. .byte 0x00, 0x00, 0x02 /* Class code */
  441. mpciheader_image_length:
  442. .word 0 /* Image length */
  443. .word 0x0001 /* Revision level */
  444. .byte 0xff /* Code type */
  445. .byte 0x80 /* Last image indicator */
  446. mpciheader_runtime_length:
  447. .word 0 /* Maximum run-time image length */
  448. .word 0x0000 /* Configuration utility code header */
  449. .word 0x0000 /* DMTF CLP entry point */
  450. .equ mpciheader_len, . - mpciheader
  451. .size mpciheader, . - mpciheader
  452. .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
  453. .ascii "APPW"
  454. .long mpciheader_image_length
  455. .long 512
  456. .long 0
  457. .ascii "APPW"
  458. .long mpciheader_runtime_length
  459. .long 512
  460. .long 0
  461. .previous
  462. /* Fix up additional image source size
  463. *
  464. */
  465. .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
  466. .ascii "ADPW"
  467. .long extra_size
  468. .long 512
  469. .long 0
  470. .previous