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.

libprefix.S 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /*
  2. * Copyright (C) 2006 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., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. *
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER )
  20. .arch i386
  21. /**
  22. * High memory temporary load address
  23. *
  24. * Temporary buffer into which to copy (or decompress) our runtime
  25. * image, prior to calling get_memmap() and relocate(). We don't
  26. * actually leave anything here once install() has returned.
  27. *
  28. * We use the start of an even megabyte so that we don't have to worry
  29. * about the current state of the A20 line.
  30. *
  31. * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
  32. * combinations are known to place data required by other UNDI ROMs
  33. * loader around the 2MB mark.
  34. */
  35. .globl HIGHMEM_LOADPOINT
  36. .equ HIGHMEM_LOADPOINT, ( 4 << 20 )
  37. /* Image compression enabled */
  38. #define COMPRESS 1
  39. /*****************************************************************************
  40. * Utility function: print character (with LF -> LF,CR translation)
  41. *
  42. * Parameters:
  43. * %al : character to print
  44. * %ds:di : output buffer (or %di=0 to print to console)
  45. * Returns:
  46. * %ds:di : next character in output buffer (if applicable)
  47. *****************************************************************************
  48. */
  49. .section ".prefix.lib", "awx", @progbits
  50. .code16
  51. .globl print_character
  52. print_character:
  53. /* Preserve registers */
  54. pushw %ax
  55. pushw %bx
  56. pushw %bp
  57. /* If %di is non-zero, write character to buffer and exit */
  58. testw %di, %di
  59. jz 1f
  60. movb %al, %ds:(%di)
  61. incw %di
  62. jmp 3f
  63. 1: /* Print character */
  64. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  65. movb $0x0e, %ah /* write char, tty mode */
  66. cmpb $0x0a, %al /* '\n'? */
  67. jne 2f
  68. int $0x10
  69. movb $0x0d, %al
  70. 2: int $0x10
  71. /* Restore registers and return */
  72. 3: popw %bp
  73. popw %bx
  74. popw %ax
  75. ret
  76. .size print_character, . - print_character
  77. /*****************************************************************************
  78. * Utility function: print a NUL-terminated string
  79. *
  80. * Parameters:
  81. * %ds:si : string to print
  82. * %ds:di : output buffer (or %di=0 to print to console)
  83. * Returns:
  84. * %ds:si : character after terminating NUL
  85. * %ds:di : next character in output buffer (if applicable)
  86. *****************************************************************************
  87. */
  88. .section ".prefix.lib", "awx", @progbits
  89. .code16
  90. .globl print_message
  91. print_message:
  92. /* Preserve registers */
  93. pushw %ax
  94. /* Print string */
  95. 1: lodsb
  96. testb %al, %al
  97. je 2f
  98. call print_character
  99. jmp 1b
  100. 2: /* Restore registers and return */
  101. popw %ax
  102. ret
  103. .size print_message, . - print_message
  104. /*****************************************************************************
  105. * Utility functions: print hex digit/byte/word/dword
  106. *
  107. * Parameters:
  108. * %al (low nibble) : digit to print
  109. * %al : byte to print
  110. * %ax : word to print
  111. * %eax : dword to print
  112. * %ds:di : output buffer (or %di=0 to print to console)
  113. * Returns:
  114. * %ds:di : next character in output buffer (if applicable)
  115. *****************************************************************************
  116. */
  117. .section ".prefix.lib", "awx", @progbits
  118. .code16
  119. .globl print_hex_dword
  120. print_hex_dword:
  121. rorl $16, %eax
  122. call print_hex_word
  123. rorl $16, %eax
  124. /* Fall through */
  125. .size print_hex_dword, . - print_hex_dword
  126. .globl print_hex_word
  127. print_hex_word:
  128. xchgb %al, %ah
  129. call print_hex_byte
  130. xchgb %al, %ah
  131. /* Fall through */
  132. .size print_hex_word, . - print_hex_word
  133. .globl print_hex_byte
  134. print_hex_byte:
  135. rorb $4, %al
  136. call print_hex_nibble
  137. rorb $4, %al
  138. /* Fall through */
  139. .size print_hex_byte, . - print_hex_byte
  140. .globl print_hex_nibble
  141. print_hex_nibble:
  142. /* Preserve registers */
  143. pushw %ax
  144. /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
  145. andb $0x0f, %al
  146. cmpb $10, %al
  147. sbbb $0x69, %al
  148. das
  149. call print_character
  150. /* Restore registers and return */
  151. popw %ax
  152. ret
  153. .size print_hex_nibble, . - print_hex_nibble
  154. /*****************************************************************************
  155. * Utility function: print PCI bus:dev.fn
  156. *
  157. * Parameters:
  158. * %ax : PCI bus:dev.fn to print
  159. * %ds:di : output buffer (or %di=0 to print to console)
  160. * Returns:
  161. * %ds:di : next character in output buffer (if applicable)
  162. *****************************************************************************
  163. */
  164. .section ".prefix.lib", "awx", @progbits
  165. .code16
  166. .globl print_pci_busdevfn
  167. print_pci_busdevfn:
  168. /* Preserve registers */
  169. pushw %ax
  170. /* Print bus */
  171. xchgb %al, %ah
  172. call print_hex_byte
  173. /* Print ":" */
  174. movb $( ':' ), %al
  175. call print_character
  176. /* Print device */
  177. movb %ah, %al
  178. shrb $3, %al
  179. call print_hex_byte
  180. /* Print "." */
  181. movb $( '.' ), %al
  182. call print_character
  183. /* Print function */
  184. movb %ah, %al
  185. andb $0x07, %al
  186. call print_hex_nibble
  187. /* Restore registers and return */
  188. popw %ax
  189. ret
  190. .size print_pci_busdevfn, . - print_pci_busdevfn
  191. /*****************************************************************************
  192. * Utility function: clear current line
  193. *
  194. * Parameters:
  195. * %ds:di : output buffer (or %di=0 to print to console)
  196. * Returns:
  197. * %ds:di : next character in output buffer (if applicable)
  198. *****************************************************************************
  199. */
  200. .section ".prefix.lib", "awx", @progbits
  201. .code16
  202. .globl print_kill_line
  203. print_kill_line:
  204. /* Preserve registers */
  205. pushw %ax
  206. pushw %cx
  207. /* Print CR */
  208. movb $( '\r' ), %al
  209. call print_character
  210. /* Print 79 spaces */
  211. movb $( ' ' ), %al
  212. movw $79, %cx
  213. 1: call print_character
  214. loop 1b
  215. /* Print CR */
  216. movb $( '\r' ), %al
  217. call print_character
  218. /* Restore registers and return */
  219. popw %cx
  220. popw %ax
  221. ret
  222. .size print_kill_line, . - print_kill_line
  223. /****************************************************************************
  224. * copy_bytes
  225. *
  226. * Copy bytes
  227. *
  228. * Parameters:
  229. * %ds:esi : source address
  230. * %es:edi : destination address
  231. * %ecx : length
  232. * Returns:
  233. * %ds:esi : next source address
  234. * %es:edi : next destination address
  235. * Corrupts:
  236. * None
  237. ****************************************************************************
  238. */
  239. #if ! COMPRESS
  240. .section ".prefix.lib", "awx", @progbits
  241. .code16
  242. copy_bytes:
  243. pushl %ecx
  244. rep addr32 movsb
  245. popl %ecx
  246. ret
  247. .size copy_bytes, . - copy_bytes
  248. #endif /* COMPRESS */
  249. /****************************************************************************
  250. * install_block
  251. *
  252. * Install block to specified address
  253. *
  254. * Parameters:
  255. * %esi : source physical address (must be a multiple of 16)
  256. * %edi : destination physical address (must be a multiple of 16)
  257. * %ecx : length of (decompressed) data
  258. * %edx : total length of block (including any uninitialised data portion)
  259. * Returns:
  260. * %esi : next source physical address (will be a multiple of 16)
  261. * %edi : next destination physical address (will be a multiple of 16)
  262. * Corrupts:
  263. * none
  264. ****************************************************************************
  265. */
  266. .section ".prefix.lib", "awx", @progbits
  267. .code16
  268. install_block:
  269. /* Preserve registers */
  270. pushw %ds
  271. pushw %es
  272. pushl %ecx
  273. /* Convert %esi and %edi to %ds:esi and %es:edi */
  274. shrl $4, %esi
  275. movw %si, %ds
  276. xorw %si, %si
  277. shll $4, %esi
  278. shrl $4, %edi
  279. movw %di, %es
  280. xorw %di, %di
  281. shll $4, %edi
  282. #if COMPRESS
  283. /* Decompress source to destination */
  284. call decompress16
  285. #else
  286. /* Copy source to destination */
  287. call copy_bytes
  288. #endif
  289. /* Zero .bss portion */
  290. negl %ecx
  291. addl %edx, %ecx
  292. pushw %ax
  293. xorw %ax, %ax
  294. rep addr32 stosb
  295. popw %ax
  296. /* Round up %esi and %edi to start of next blocks */
  297. addl $0xf, %esi
  298. andl $~0xf, %esi
  299. addl $0xf, %edi
  300. andl $~0xf, %edi
  301. /* Convert %ds:esi and %es:edi back to physical addresses */
  302. xorl %ecx, %ecx
  303. movw %ds, %cx
  304. shll $4, %ecx
  305. addl %ecx, %esi
  306. xorl %ecx, %ecx
  307. movw %es, %cx
  308. shll $4, %ecx
  309. addl %ecx, %edi
  310. /* Restore registers and return */
  311. popl %ecx
  312. popw %es
  313. popw %ds
  314. ret
  315. .size install_block, . - install_block
  316. /****************************************************************************
  317. * alloc_basemem
  318. *
  319. * Allocate space for .text16 and .data16 from top of base memory.
  320. * Memory is allocated using the BIOS free base memory counter at
  321. * 0x40:13.
  322. *
  323. * Parameters:
  324. * none
  325. * Returns:
  326. * %ax : .text16 segment address
  327. * %bx : .data16 segment address
  328. * Corrupts:
  329. * none
  330. ****************************************************************************
  331. */
  332. .section ".prefix.lib", "awx", @progbits
  333. .code16
  334. .globl alloc_basemem
  335. alloc_basemem:
  336. /* Preserve registers */
  337. pushw %fs
  338. /* FBMS => %ax as segment address */
  339. pushw $0x40
  340. popw %fs
  341. movw %fs:0x13, %ax
  342. shlw $6, %ax
  343. /* Calculate .data16 segment address */
  344. subw $_data16_memsz_pgh, %ax
  345. pushw %ax
  346. /* Calculate .text16 segment address */
  347. subw $_text16_memsz_pgh, %ax
  348. pushw %ax
  349. /* Update FBMS */
  350. shrw $6, %ax
  351. movw %ax, %fs:0x13
  352. /* Retrieve .text16 and .data16 segment addresses */
  353. popw %ax
  354. popw %bx
  355. /* Restore registers and return */
  356. popw %fs
  357. ret
  358. .size alloc_basemem, . - alloc_basemem
  359. /****************************************************************************
  360. * free_basemem
  361. *
  362. * Free space allocated with alloc_basemem.
  363. *
  364. * Parameters:
  365. * %ax : .text16 segment address
  366. * %bx : .data16 segment address
  367. * Returns:
  368. * %ax : 0 if successfully freed
  369. * Corrupts:
  370. * none
  371. ****************************************************************************
  372. */
  373. .section ".text16", "ax", @progbits
  374. .code16
  375. .globl free_basemem
  376. free_basemem:
  377. /* Preserve registers */
  378. pushw %fs
  379. /* Check FBMS counter */
  380. pushw %ax
  381. shrw $6, %ax
  382. pushw $0x40
  383. popw %fs
  384. cmpw %ax, %fs:0x13
  385. popw %ax
  386. jne 1f
  387. /* Check hooked interrupt count */
  388. cmpw $0, %cs:hooked_bios_interrupts
  389. jne 1f
  390. /* OK to free memory */
  391. addw $_text16_memsz_pgh, %ax
  392. addw $_data16_memsz_pgh, %ax
  393. shrw $6, %ax
  394. movw %ax, %fs:0x13
  395. xorw %ax, %ax
  396. 1: /* Restore registers and return */
  397. popw %fs
  398. ret
  399. .size free_basemem, . - free_basemem
  400. .section ".text16.data", "aw", @progbits
  401. .globl hooked_bios_interrupts
  402. hooked_bios_interrupts:
  403. .word 0
  404. .size hooked_bios_interrupts, . - hooked_bios_interrupts
  405. /****************************************************************************
  406. * install
  407. *
  408. * Install all text and data segments.
  409. *
  410. * Parameters:
  411. * none
  412. * Returns:
  413. * %ax : .text16 segment address
  414. * %bx : .data16 segment address
  415. * Corrupts:
  416. * none
  417. ****************************************************************************
  418. */
  419. .section ".prefix.lib", "awx", @progbits
  420. .code16
  421. .globl install
  422. install:
  423. /* Preserve registers */
  424. pushl %esi
  425. pushl %edi
  426. /* Allocate space for .text16 and .data16 */
  427. call alloc_basemem
  428. /* Image source = %cs:0000 */
  429. xorl %esi, %esi
  430. /* Image destination = HIGHMEM_LOADPOINT */
  431. movl $HIGHMEM_LOADPOINT, %edi
  432. /* Install text and data segments */
  433. call install_prealloc
  434. /* Restore registers and return */
  435. popl %edi
  436. popl %esi
  437. ret
  438. .size install, . - install
  439. /****************************************************************************
  440. * install_prealloc
  441. *
  442. * Install all text and data segments.
  443. *
  444. * Parameters:
  445. * %ax : .text16 segment address
  446. * %bx : .data16 segment address
  447. * %esi : Image source physical address (or zero for %cs:0000)
  448. * %edi : Decompression temporary area physical address
  449. * Corrupts:
  450. * none
  451. ****************************************************************************
  452. */
  453. .section ".prefix.lib", "awx", @progbits
  454. .code16
  455. .globl install_prealloc
  456. install_prealloc:
  457. /* Save registers */
  458. pushal
  459. pushw %ds
  460. pushw %es
  461. /* Sanity: clear the direction flag asap */
  462. cld
  463. /* Copy decompression temporary area physical address to %ebp */
  464. movl %edi, %ebp
  465. /* Install .text16.early */
  466. pushl %esi
  467. xorl %esi, %esi
  468. movw %cs, %si
  469. shll $4, %esi
  470. addl $_text16_early_lma, %esi
  471. movzwl %ax, %edi
  472. shll $4, %edi
  473. movl $_text16_early_filesz, %ecx
  474. movl $_text16_early_memsz, %edx
  475. call install_block /* .text16.early */
  476. popl %esi
  477. /* Open up access to payload */
  478. #ifndef KEEP_IT_REAL
  479. /* Flatten real mode */
  480. pushw %cs
  481. pushw $1f
  482. pushw %ax
  483. pushw $flatten_real_mode
  484. lret
  485. 1:
  486. #endif
  487. /* Calculate physical address of payload (i.e. first source) */
  488. testl %esi, %esi
  489. jnz 1f
  490. movw %cs, %si
  491. shll $4, %esi
  492. 1: addl %cs:payload_lma, %esi
  493. /* Install .text16.late and .data16 */
  494. movl $_text16_late_filesz, %ecx
  495. movl $_text16_late_memsz, %edx
  496. call install_block /* .text16.late */
  497. movzwl %bx, %edi
  498. shll $4, %edi
  499. movl $_data16_filesz, %ecx
  500. movl $_data16_memsz, %edx
  501. call install_block /* .data16 */
  502. /* Set up %ds for access to .data16 */
  503. movw %bx, %ds
  504. #ifdef KEEP_IT_REAL
  505. /* Initialise libkir */
  506. movw %ax, (init_libkir_vector+2)
  507. lcall *init_libkir_vector
  508. #else
  509. /* Install .text and .data to temporary area in high memory,
  510. * prior to reading the E820 memory map and relocating
  511. * properly.
  512. */
  513. movl %ebp, %edi
  514. movl $_textdata_filesz, %ecx
  515. movl $_textdata_memsz, %edx
  516. call install_block
  517. /* Initialise librm at current location */
  518. movw %ax, (init_librm_vector+2)
  519. movl %ebp, %edi
  520. lcall *init_librm_vector
  521. /* Call relocate() to determine target address for relocation.
  522. * relocate() will return with %esi, %edi and %ecx set up
  523. * ready for the copy to the new location.
  524. */
  525. movw %ax, (prot_call_vector+2)
  526. pushl $relocate
  527. lcall *prot_call_vector
  528. popl %edx /* discard */
  529. /* Copy code to new location */
  530. xorw %ax, %ax
  531. movw %ax, %es
  532. movl %ebp, %edi
  533. es rep addr32 movsb
  534. /* Initialise librm at new location */
  535. movl %ebp, %edi
  536. lcall *init_librm_vector
  537. #endif
  538. /* Restore registers */
  539. popw %es
  540. popw %ds
  541. popal
  542. ret
  543. .size install_prealloc, . - install_prealloc
  544. /* Vectors for far calls to .text16 functions. Must be in
  545. * .data16, since .prefix may not be writable.
  546. */
  547. .section ".data16", "aw", @progbits
  548. #ifdef KEEP_IT_REAL
  549. init_libkir_vector:
  550. .word init_libkir
  551. .word 0
  552. .size init_libkir_vector, . - init_libkir_vector
  553. #else
  554. init_librm_vector:
  555. .word init_librm
  556. .word 0
  557. .size init_librm_vector, . - init_librm_vector
  558. prot_call_vector:
  559. .word prot_call
  560. .word 0
  561. .size prot_call_vector, . - prot_call_vector
  562. #endif
  563. /* Payload address */
  564. .section ".prefix.lib", "awx", @progbits
  565. payload_lma:
  566. .long 0
  567. .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
  568. .ascii "ADHL"
  569. .long payload_lma
  570. .long 1
  571. .long 0
  572. .previous
  573. /****************************************************************************
  574. * uninstall
  575. *
  576. * Uninstall all text and data segments.
  577. *
  578. * Parameters:
  579. * %ax : .text16 segment address
  580. * %bx : .data16 segment address
  581. * Returns:
  582. * none
  583. * Corrupts:
  584. * none
  585. ****************************************************************************
  586. */
  587. .section ".text16", "ax", @progbits
  588. .code16
  589. .globl uninstall
  590. uninstall:
  591. call free_basemem
  592. ret
  593. .size uninstall, . - uninstall
  594. /* File split information for the compressor */
  595. #if COMPRESS
  596. #define PACK_OR_COPY "PACK"
  597. #else
  598. #define PACK_OR_COPY "COPY"
  599. #endif
  600. .section ".zinfo", "a", @progbits
  601. .ascii "COPY"
  602. .long _prefix_lma
  603. .long _prefix_filesz
  604. .long _max_align
  605. .ascii PACK_OR_COPY
  606. .long _text16_early_lma
  607. .long _text16_early_filesz
  608. .long _max_align
  609. .ascii "PAYL"
  610. .long 0
  611. .long 0
  612. .long _max_align
  613. .ascii PACK_OR_COPY
  614. .long _text16_late_lma
  615. .long _text16_late_filesz
  616. .long _max_align
  617. .ascii PACK_OR_COPY
  618. .long _data16_lma
  619. .long _data16_filesz
  620. .long _max_align
  621. .ascii PACK_OR_COPY
  622. .long _textdata_lma
  623. .long _textdata_filesz
  624. .long _max_align