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 17KB

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