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

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