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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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. * pm_call (real-mode near call)
  43. *
  44. * Call routine in 16-bit protected mode for access to extended memory
  45. *
  46. * Parameters:
  47. * %ax : address of routine to call in 16-bit protected mode
  48. * Returns:
  49. * none
  50. * Corrupts:
  51. * %ax
  52. *
  53. * The specified routine is called in 16-bit protected mode, with:
  54. *
  55. * %cs : 16-bit code segment with base matching real-mode %cs
  56. * %ss : 16-bit data segment with base matching real-mode %ss
  57. * %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit
  58. *
  59. ****************************************************************************
  60. */
  61. #ifndef KEEP_IT_REAL
  62. /* GDT for protected-mode calls */
  63. .section ".data16"
  64. .align 16
  65. gdt:
  66. gdt_limit: .word gdt_length - 1
  67. gdt_base: .long 0
  68. .word 0 /* padding */
  69. pm_cs: /* 16-bit protected-mode code segment */
  70. .equ PM_CS, pm_cs - gdt
  71. .word 0xffff, 0
  72. .byte 0, 0x9b, 0x00, 0
  73. pm_ss: /* 16-bit protected-mode stack segment */
  74. .equ PM_SS, pm_ss - gdt
  75. .word 0xffff, 0
  76. .byte 0, 0x93, 0x00, 0
  77. pm_ds: /* 32-bit protected-mode flat data segment */
  78. .equ PM_DS, pm_ds - gdt
  79. .word 0xffff, 0
  80. .byte 0, 0x93, 0xcf, 0
  81. gdt_end:
  82. .equ gdt_length, . - gdt
  83. .size gdt, . - gdt
  84. .section ".data16"
  85. .align 16
  86. pm_saved_gdt:
  87. .long 0, 0
  88. .size pm_saved_gdt, . - pm_saved_gdt
  89. .section ".prefix.lib"
  90. .code16
  91. pm_call:
  92. /* Preserve registers, flags, GDT, and RM return point */
  93. pushfl
  94. sgdt pm_saved_gdt
  95. pushw %gs
  96. pushw %fs
  97. pushw %es
  98. pushw %ds
  99. pushw %ss
  100. pushw %cs
  101. pushw $99f
  102. /* Set up GDT bases */
  103. pushl %eax
  104. pushw %bx
  105. xorl %eax, %eax
  106. movw %ds, %ax
  107. shll $4, %eax
  108. addl $gdt, %eax
  109. movl %eax, gdt_base
  110. movw %cs, %ax
  111. movw $pm_cs, %bx
  112. call set_seg_base
  113. movw %ss, %ax
  114. movw $pm_ss, %bx
  115. call set_seg_base
  116. popw %bx
  117. popl %eax
  118. /* Switch CPU to protected mode and load up segment registers */
  119. pushl %eax
  120. cli
  121. lgdt gdt
  122. movl %cr0, %eax
  123. orb $CR0_PE, %al
  124. movl %eax, %cr0
  125. ljmp $PM_CS, $1f
  126. 1: movw $PM_SS, %ax
  127. movw %ax, %ss
  128. movw $PM_DS, %ax
  129. movw %ax, %ds
  130. movw %ax, %es
  131. movw %ax, %fs
  132. movw %ax, %gs
  133. popl %eax
  134. /* Call PM routine */
  135. call *%ax
  136. /* Set real-mode segment limits on %ds, %es, %fs and %gs */
  137. movw %ss, %ax
  138. movw %ax, %ds
  139. movw %ax, %es
  140. movw %ax, %fs
  141. movw %ax, %gs
  142. /* Return CPU to real mode */
  143. movl %cr0, %eax
  144. andb $0!CR0_PE, %al
  145. movl %eax, %cr0
  146. /* Restore registers and flags */
  147. lret /* will ljmp to 99f */
  148. 99: popw %ss
  149. popw %ds
  150. popw %es
  151. popw %fs
  152. popw %gs
  153. lgdt pm_saved_gdt
  154. popfl
  155. ret
  156. .size pm_call, . - pm_call
  157. set_seg_base:
  158. rolw $4, %ax
  159. movw %ax, 2(%bx)
  160. andw $0xfff0, 2(%bx)
  161. movb %al, 4(%bx)
  162. andb $0x0f, 4(%bx)
  163. ret
  164. .size set_seg_base, . - set_seg_base
  165. #endif /* KEEP_IT_REAL */
  166. /****************************************************************************
  167. * copy_bytes (real-mode or 16-bit protected-mode near call)
  168. *
  169. * Copy bytes
  170. *
  171. * Parameters:
  172. * %ds:esi : source address
  173. * %es:edi : destination address
  174. * %ecx : length
  175. * Returns:
  176. * %ds:esi : next source address
  177. * %ds:esi : next destination address
  178. * Corrupts:
  179. * None
  180. ****************************************************************************
  181. */
  182. .section ".prefix.lib"
  183. .code16
  184. copy_bytes:
  185. pushl %ecx
  186. rep addr32 movsb
  187. popl %ecx
  188. ret
  189. .size copy_bytes, . - copy_bytes
  190. /****************************************************************************
  191. * install_block (real-mode or 16-bit protected-mode near call)
  192. *
  193. * Install block to specified address
  194. *
  195. * Parameters:
  196. * %ds:esi : source address (must be a multiple of 16)
  197. * %es:edi : destination address
  198. * %ecx : length of (decompressed) data
  199. * %edx : total length of block (including any uninitialised data portion)
  200. * Returns:
  201. * %ds:esi : next source address (will be a multiple of 16)
  202. * Corrupts:
  203. * %ecx, %edx
  204. ****************************************************************************
  205. */
  206. .section ".prefix.lib"
  207. .code16
  208. install_block:
  209. /* Preserve registers */
  210. pushl %edi
  211. #if COMPRESS
  212. /* Decompress source to destination */
  213. call decompress16
  214. #else
  215. /* Copy source to destination */
  216. call copy_bytes
  217. #endif
  218. /* Zero .bss portion */
  219. negl %ecx
  220. addl %edx, %ecx
  221. pushw %ax
  222. xorw %ax, %ax
  223. rep addr32 stosb
  224. popw %ax
  225. /* Round up %esi to start of next source block */
  226. addl $0xf, %esi
  227. andl $~0xf, %esi
  228. /* Restore registers and return */
  229. popl %edi
  230. ret
  231. .size install_block, . - install_block
  232. /****************************************************************************
  233. * alloc_basemem (real-mode near call)
  234. *
  235. * Allocate space for .text16 and .data16 from top of base memory.
  236. * Memory is allocated using the BIOS free base memory counter at
  237. * 0x40:13.
  238. *
  239. * Parameters:
  240. * none
  241. * Returns:
  242. * %ax : .text16 segment address
  243. * %bx : .data16 segment address
  244. * Corrupts:
  245. * none
  246. ****************************************************************************
  247. */
  248. .section ".prefix.lib"
  249. .code16
  250. .globl alloc_basemem
  251. alloc_basemem:
  252. /* FBMS => %ax as segment address */
  253. movw $0x40, %ax
  254. movw %ax, %fs
  255. movw %fs:0x13, %ax
  256. shlw $6, %ax
  257. /* .data16 segment address */
  258. subw $_data16_size_pgh, %ax
  259. pushw %ax
  260. /* .text16 segment address */
  261. subw $_text16_size_pgh, %ax
  262. pushw %ax
  263. /* Update FBMS */
  264. shrw $6, %ax
  265. movw %ax, %fs:0x13
  266. /* Return */
  267. popw %ax
  268. popw %bx
  269. ret
  270. .size alloc_basemem, . - alloc_basemem
  271. /****************************************************************************
  272. * install_basemem (real-mode near call)
  273. *
  274. * Install source block into base memory
  275. *
  276. * Parameters:
  277. * %esi : source physical address (must be a multiple of 16)
  278. * %es : destination segment address
  279. * %cx : length of (decompressed) data
  280. * %dx : total length of block (including any uninitialised data portion)
  281. * Returns:
  282. * %esi : next source physical address (will be a multiple of 16)
  283. * Corrupts:
  284. * %ecx, %edx
  285. ****************************************************************************
  286. */
  287. .section ".prefix.lib"
  288. .code16
  289. install_basemem:
  290. /* Preserve registers */
  291. pushl %edi
  292. pushw %ds
  293. /* Preserve original %esi */
  294. pushl %esi
  295. /* Install to specified address */
  296. shrl $4, %esi
  297. movw %si, %ds
  298. xorw %si, %si
  299. xorl %edi, %edi
  300. movzwl %cx, %ecx
  301. movzwl %dx, %edx
  302. call install_block
  303. /* Fix up %esi for return */
  304. popl %ecx
  305. addl %ecx, %esi
  306. /* Restore registers */
  307. popw %ds
  308. popl %edi
  309. ret
  310. .size install_basemem, . - install_basemem
  311. /****************************************************************************
  312. * install_highmem (real-mode near call)
  313. *
  314. * Install source block into high memory
  315. *
  316. * Parameters:
  317. * %esi : source physical address (must be a multiple of 16)
  318. * %edi : destination physical address
  319. * %ecx : length of (decompressed) data
  320. * %edx : total length of block (including any uninitialised data portion)
  321. * Returns:
  322. * %esi : next source physical address (will be a multiple of 16)
  323. * Corrupts:
  324. * %ecx, %edx
  325. ****************************************************************************
  326. */
  327. #ifndef KEEP_IT_REAL
  328. .section ".prefix.lib"
  329. .code16
  330. install_highmem:
  331. /* Preserve registers */
  332. pushw %ax
  333. /* Install to specified address */
  334. movw $install_block, %ax
  335. call pm_call
  336. /* Restore registers */
  337. popw %ax
  338. ret
  339. .size install_highmem, . - install_highmem
  340. #endif /* KEEP_IT_REAL */
  341. /****************************************************************************
  342. * install (real-mode near call)
  343. *
  344. * Install all text and data segments.
  345. *
  346. * Parameters:
  347. * none
  348. * Returns:
  349. * %ax : .text16 segment address
  350. * %bx : .data16 segment address
  351. * Corrupts:
  352. * none
  353. ****************************************************************************
  354. */
  355. .section ".prefix.lib"
  356. .code16
  357. .globl install
  358. install:
  359. /* Preserve registers */
  360. pushl %esi
  361. pushl %edi
  362. /* Allocate space for .text16 and .data16 */
  363. call alloc_basemem
  364. /* Image source = %cs:0000 */
  365. xorl %esi, %esi
  366. /* Image destination = HIGHMEM_LOADPOINT */
  367. movl $HIGHMEM_LOADPOINT, %edi
  368. /* Install text and data segments */
  369. call install_prealloc
  370. /* Restore registers and return */
  371. popl %edi
  372. popl %esi
  373. ret
  374. .size install, . - install
  375. /****************************************************************************
  376. * install_prealloc (real-mode near call)
  377. *
  378. * Install all text and data segments.
  379. *
  380. * Parameters:
  381. * %ax : .text16 segment address
  382. * %bx : .data16 segment address
  383. * %esi : Image source physical address (or zero for %cs:0000)
  384. * %edi : Decompression temporary area physical address
  385. * Corrupts:
  386. * none
  387. ****************************************************************************
  388. */
  389. .section ".prefix.lib"
  390. .code16
  391. .globl install_prealloc
  392. install_prealloc:
  393. /* Save registers */
  394. pushal
  395. pushw %ds
  396. pushw %es
  397. /* Sanity: clear the direction flag asap */
  398. cld
  399. /* Calculate physical address of payload (i.e. first source) */
  400. testl %esi, %esi
  401. jnz 1f
  402. movw %cs, %si
  403. shll $4, %esi
  404. 1: addl $_payload_offset, %esi
  405. /* Install .text16 */
  406. movw %ax, %es
  407. movw $_text16_size, %cx
  408. movw %cx, %dx
  409. call install_basemem
  410. /* Install .data16 */
  411. movw %bx, %es
  412. movw $_data16_progbits_size, %cx
  413. movw $_data16_size, %dx
  414. call install_basemem
  415. /* Set up %ds for access to .data16 */
  416. movw %bx, %ds
  417. #ifdef KEEP_IT_REAL
  418. /* Initialise libkir */
  419. movw %ax, (init_libkir_vector+2)
  420. lcall *init_libkir_vector
  421. #else
  422. /* Install .text and .data to temporary area in high memory,
  423. * prior to reading the E820 memory map and relocating
  424. * properly.
  425. */
  426. movl $_textdata_progbits_size, %ecx
  427. movl $_textdata_size, %edx
  428. pushl %edi
  429. call install_highmem
  430. popl %edi
  431. /* Initialise librm at current location */
  432. movw %ax, (init_librm_vector+2)
  433. lcall *init_librm_vector
  434. /* Call relocate() to determine target address for relocation.
  435. * relocate() will return with %esi, %edi and %ecx set up
  436. * ready for the copy to the new location.
  437. */
  438. movw %ax, (prot_call_vector+2)
  439. pushl $relocate
  440. lcall *prot_call_vector
  441. popl %edx /* discard */
  442. /* Copy code to new location */
  443. pushl %edi
  444. pushw %ax
  445. movw $copy_bytes, %ax
  446. call pm_call
  447. popw %ax
  448. popl %edi
  449. /* Initialise librm at new location */
  450. lcall *init_librm_vector
  451. #endif
  452. /* Restore registers */
  453. popw %es
  454. popw %ds
  455. popal
  456. ret
  457. .size install_prealloc, . - install_prealloc
  458. /* Vectors for far calls to .text16 functions */
  459. .section ".data16"
  460. #ifdef KEEP_IT_REAL
  461. init_libkir_vector:
  462. .word init_libkir
  463. .word 0
  464. .size init_libkir_vector, . - init_libkir_vector
  465. #else
  466. init_librm_vector:
  467. .word init_librm
  468. .word 0
  469. .size init_librm_vector, . - init_librm_vector
  470. prot_call_vector:
  471. .word prot_call
  472. .word 0
  473. .size prot_call_vector, . - prot_call_vector
  474. #endif
  475. /* File split information for the compressor */
  476. #if COMPRESS
  477. .section ".zinfo", "a"
  478. .ascii "COPY"
  479. .long _prefix_load_offset
  480. .long _prefix_progbits_size
  481. .long _max_align
  482. .ascii "PACK"
  483. .long _text16_load_offset
  484. .long _text16_progbits_size
  485. .long _max_align
  486. .ascii "PACK"
  487. .long _data16_load_offset
  488. .long _data16_progbits_size
  489. .long _max_align
  490. .ascii "PACK"
  491. .long _textdata_load_offset
  492. .long _textdata_progbits_size
  493. .long _max_align
  494. #else /* COMPRESS */
  495. .section ".zinfo", "a"
  496. .ascii "COPY"
  497. .long _prefix_load_offset
  498. .long _load_size
  499. .long _max_align
  500. #endif /* COMPRESS */