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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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. /**
  20. * High memory temporary load address
  21. *
  22. * Temporary buffer into which to copy (or decompress) our runtime
  23. * image, prior to calling get_memmap() and relocate(). We don't
  24. * actually leave anything here once install() has returned.
  25. *
  26. * We use the start of an even megabyte so that we don't have to worry
  27. * about the current state of the A20 line.
  28. *
  29. * We use 4MB rather than 2MB because there is at least one commercial
  30. * PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores
  31. * data required by the UNDI ROM loader (yes, the ROM loader; that's
  32. * the component which should be impossible to damage short of
  33. * screwing with the MMU) around the 2MB mark. Sadly, this is not a
  34. * joke.
  35. *
  36. */
  37. #define HIGHMEM_LOADPOINT ( 4 << 20 )
  38. /* Image compression enabled */
  39. #define COMPRESS 1
  40. #define CR0_PE 1
  41. .arch i386
  42. .section ".prefix.lib", "awx", @progbits
  43. .section ".data16", "aw", @progbits
  44. /****************************************************************************
  45. * install_block (real-mode near call)
  46. *
  47. * Install block to specified address
  48. *
  49. * Parameters:
  50. * %esi : start offset within loaded image (must be a multiple of 16)
  51. * %es:edi : destination address
  52. * %ecx : length of (decompressed) data
  53. * %edx : total length of block (including any uninitialised data portion)
  54. * Returns:
  55. * %esi : end offset within image (rounded up to next multiple of 16)
  56. * Corrupts:
  57. * %edi, %ecx, %edx
  58. ****************************************************************************
  59. */
  60. .section ".prefix.lib"
  61. .code16
  62. install_block:
  63. /* Preserve registers */
  64. pushw %ds
  65. pushl %eax
  66. pushl %ebx
  67. movl %esi, %ebx
  68. /* Starting segment => %ds */
  69. movw %cs, %ax
  70. shrl $4, %esi
  71. addw %si, %ax
  72. movw %ax, %ds
  73. xorl %esi, %esi
  74. /* Calculate start and length of uninitialised data portion */
  75. addr32 leal (%edi,%ecx), %eax
  76. subl %ecx, %edx
  77. /* Do the copy */
  78. cld
  79. #if COMPRESS
  80. call decompress16
  81. #else
  82. rep addr32 movsb
  83. #endif
  84. /* Zero remaining space */
  85. movl %eax, %edi
  86. movl %edx, %ecx
  87. xorb %al, %al
  88. rep addr32 stosb
  89. /* Adjust %esi */
  90. addl %ebx, %esi
  91. addl $0xf, %esi
  92. andl $~0xf, %esi
  93. /* Restore registers */
  94. popl %ebx
  95. popl %eax
  96. popw %ds
  97. ret
  98. .size install_block, . - install_block
  99. /****************************************************************************
  100. * alloc_basemem (real-mode near call)
  101. *
  102. * Allocate space for .text16 and .data16 from top of base memory.
  103. * Memory is allocated using the BIOS free base memory counter at
  104. * 0x40:13.
  105. *
  106. * Parameters:
  107. * none
  108. * Returns:
  109. * %ax : .text16 segment address
  110. * %bx : .data16 segment address
  111. * Corrupts:
  112. * none
  113. ****************************************************************************
  114. */
  115. .section ".prefix.lib"
  116. .code16
  117. alloc_basemem:
  118. /* FBMS => %ax as segment address */
  119. movw $0x40, %ax
  120. movw %ax, %fs
  121. movw %fs:0x13, %ax
  122. shlw $6, %ax
  123. /* .data16 segment address */
  124. subw $_data16_size_pgh, %ax
  125. pushw %ax
  126. /* .text16 segment address */
  127. subw $_text16_size_pgh, %ax
  128. pushw %ax
  129. /* Update FBMS */
  130. shrw $6, %ax
  131. movw %ax, %fs:0x13
  132. /* Return */
  133. popw %ax
  134. popw %bx
  135. ret
  136. .size alloc_basemem, . - alloc_basemem
  137. /****************************************************************************
  138. * install_basemem (real-mode near call)
  139. *
  140. * Install .text16 and .data16 into base memory
  141. *
  142. * Parameters:
  143. * %ax : .text16 segment address
  144. * %bx : .data16 segment address
  145. * %esi : start offset within loaded image (must be a multiple of 16)
  146. * Returns:
  147. * %esi : end offset within image (rounded up to next multiple of 16)
  148. * Corrupts:
  149. * none
  150. ****************************************************************************
  151. */
  152. .section ".prefix.lib"
  153. .code16
  154. install_basemem:
  155. /* Preserve registers */
  156. pushw %es
  157. pushl %edi
  158. pushl %ecx
  159. pushl %edx
  160. /* Install .text16 */
  161. movw %ax, %es
  162. xorl %edi, %edi
  163. movl $_text16_size, %ecx
  164. movl %ecx, %edx
  165. call install_block
  166. /* Install .data16 */
  167. movw %bx, %es
  168. xorl %edi, %edi
  169. movl $_data16_progbits_size, %ecx
  170. movl $_data16_size, %edx
  171. call install_block
  172. /* Restore registers */
  173. popl %edx
  174. popl %ecx
  175. popl %edi
  176. popw %es
  177. ret
  178. .size install_basemem, . - install_basemem
  179. /****************************************************************************
  180. * install_highmem (flat real-mode near call)
  181. *
  182. * Install .text and .data into high memory
  183. *
  184. * Parameters:
  185. * %esi : start offset within loaded image (must be a multiple of 16)
  186. * %es:edi : address in high memory
  187. * Returns:
  188. * %esi : end offset within image (rounded up to next multiple of 16)
  189. * Corrupts:
  190. * none
  191. ****************************************************************************
  192. */
  193. #ifndef KEEP_IT_REAL
  194. .section ".prefix.lib"
  195. .code16
  196. install_highmem:
  197. /* Preserve registers */
  198. pushl %edi
  199. pushl %ecx
  200. pushl %edx
  201. /* Install .text and .data to specified address */
  202. movl $_textdata_progbits_size, %ecx
  203. movl $_textdata_size, %edx
  204. call install_block
  205. /* Restore registers and interrupt status */
  206. popl %edx
  207. popl %ecx
  208. popl %edi
  209. ret
  210. .size install_highmem, . - install_highmem
  211. #endif /* KEEP_IT_REAL */
  212. /****************************************************************************
  213. * GDT for flat real mode
  214. *
  215. * We only ever use this GDT to set segment limits; the bases are
  216. * unused. Also, we only change data segments, so we don't need to
  217. * worry about the code or stack segments. This makes everything much
  218. * simpler.
  219. ****************************************************************************
  220. */
  221. #ifndef KEEP_IT_REAL
  222. .section ".prefix.lib"
  223. .align 16
  224. gdt:
  225. gdt_limit: .word gdt_length - 1
  226. gdt_base: .long 0
  227. .word 0 /* padding */
  228. flat_ds: /* Flat real mode data segment */
  229. .equ FLAT_DS, flat_ds - gdt
  230. .word 0xffff, 0
  231. .byte 0, 0x93, 0xcf, 0
  232. real_ds: /* Normal real mode data segment */
  233. .equ REAL_DS, real_ds - gdt
  234. .word 0xffff, 0
  235. .byte 0, 0x93, 0x00, 0
  236. gdt_end:
  237. .equ gdt_length, gdt_end - gdt
  238. .size gdt, . - gdt
  239. #endif /* KEEP_IT_REAL */
  240. /****************************************************************************
  241. * set_real_mode_limits (real-mode near call)
  242. *
  243. * Sets limits on the data segments %ds and %es.
  244. *
  245. * Parameters:
  246. * %dx : segment type (FLAT_DS for 4GB or REAL_DS for 64kB)
  247. ****************************************************************************
  248. */
  249. #ifndef KEEP_IT_REAL
  250. .section ".prefix.lib"
  251. .code16
  252. set_real_mode_limits:
  253. /* Preserve real-mode segment values and temporary registers */
  254. pushw %es
  255. pushw %ds
  256. pushw %bp
  257. pushl %eax
  258. /* Set GDT base and load GDT */
  259. xorl %eax, %eax
  260. movw %cs, %ax
  261. shll $4, %eax
  262. addl $gdt, %eax
  263. pushl %eax
  264. pushw %cs:gdt_limit
  265. movw %sp, %bp
  266. lgdt (%bp)
  267. addw $6, %sp
  268. /* Switch to protected mode */
  269. movl %cr0, %eax
  270. orb $CR0_PE, %al
  271. movl %eax, %cr0
  272. /* Set flat segment limits */
  273. movw %dx, %ds
  274. movw %dx, %es
  275. /* Switch back to real mode */
  276. movl %cr0, %eax
  277. andb $0!CR0_PE, %al
  278. movl %eax, %cr0
  279. /* Restore real-mode segment values and temporary registers */
  280. popl %eax
  281. popw %bp
  282. popw %ds
  283. popw %es
  284. ret
  285. .size set_real_mode_limits, . - set_real_mode_limits
  286. #endif /* KEEP_IT_REAL */
  287. /****************************************************************************
  288. * install (real-mode near call)
  289. * install_prealloc (real-mode near call)
  290. *
  291. * Install all text and data segments.
  292. *
  293. * Parameters:
  294. * %ax : .text16 segment address (install_prealloc only)
  295. * %bx : .data16 segment address (install_prealloc only)
  296. * Returns:
  297. * %ax : .text16 segment address
  298. * %bx : .data16 segment address
  299. * %edi : .text physical address (if applicable)
  300. * Corrupts:
  301. * none
  302. ****************************************************************************
  303. */
  304. .section ".prefix.lib"
  305. .code16
  306. .globl install
  307. install:
  308. /* Allocate space for .text16 and .data16 */
  309. call alloc_basemem
  310. .size install, . - install
  311. .globl install_prealloc
  312. install_prealloc:
  313. /* Save registers */
  314. pushl %esi
  315. pushw %dx
  316. /* Install .text16 and .data16 */
  317. movl $_payload_offset, %esi
  318. call install_basemem
  319. #ifdef KEEP_IT_REAL
  320. /* Preserve %ds, call init_libkir, restore registers */
  321. pushw %ds
  322. movw %bx, %ds
  323. movw %ax, (init_libkir_vector+2)
  324. lcall *init_libkir_vector
  325. popw %ds
  326. #else
  327. /* Preserve registers and interrupt status, and disable interrupts */
  328. pushfw
  329. pushw %ds
  330. pushw %es
  331. pushl %ecx
  332. cli
  333. /* Load up %ds and %es, and set up vectors for far calls to .text16 */
  334. movw %bx, %ds
  335. xorw %cx, %cx
  336. movw %cx, %es
  337. movw %ax, (init_librm_vector+2)
  338. movw %ax, (prot_call_vector+2)
  339. /* Install .text and .data to temporary area in high memory,
  340. * prior to reading the E820 memory map and relocating
  341. * properly.
  342. */
  343. movw $FLAT_DS, %dx
  344. call set_real_mode_limits
  345. movl $HIGHMEM_LOADPOINT, %edi
  346. call install_highmem
  347. /* Set up initial protected-mode GDT, call relocate().
  348. * relocate() will return with %esi, %edi and %ecx set up
  349. * ready for the copy to the new location.
  350. */
  351. lcall *init_librm_vector
  352. pushl $relocate
  353. lcall *prot_call_vector
  354. addw $4, %sp
  355. /* Move code to new location, set up new protected-mode GDT */
  356. movw $FLAT_DS, %dx
  357. call set_real_mode_limits
  358. pushl %edi
  359. es rep addr32 movsb
  360. popl %edi
  361. lcall *init_librm_vector
  362. /* Restore real-mode segment limits */
  363. movw $REAL_DS, %dx
  364. call set_real_mode_limits
  365. /* Restore registers and interrupt status */
  366. popl %ecx
  367. popw %es
  368. popw %ds
  369. popfw
  370. #endif
  371. popw %dx
  372. popl %esi
  373. ret
  374. .size install_prealloc, . - install_prealloc
  375. /* Vectors for far calls to .text16 functions */
  376. .section ".data16"
  377. #ifdef KEEP_IT_REAL
  378. init_libkir_vector:
  379. .word init_libkir
  380. .word 0
  381. .size init_libkir_vector, . - init_libkir_vector
  382. #else
  383. init_librm_vector:
  384. .word init_librm
  385. .word 0
  386. .size init_librm_vector, . - init_librm_vector
  387. prot_call_vector:
  388. .word prot_call
  389. .word 0
  390. .size prot_call_vector, . - prot_call_vector
  391. #endif
  392. /* File split information for the compressor */
  393. #if COMPRESS
  394. .section ".zinfo", "a"
  395. .ascii "COPY"
  396. .long _prefix_load_offset
  397. .long _prefix_progbits_size
  398. .long _max_align
  399. .ascii "PACK"
  400. .long _text16_load_offset
  401. .long _text16_progbits_size
  402. .long _max_align
  403. .ascii "PACK"
  404. .long _data16_load_offset
  405. .long _data16_progbits_size
  406. .long _max_align
  407. .ascii "PACK"
  408. .long _textdata_load_offset
  409. .long _textdata_progbits_size
  410. .long _max_align
  411. #else /* COMPRESS */
  412. .section ".zinfo", "a"
  413. .ascii "COPY"
  414. .long _prefix_load_offset
  415. .long _load_size
  416. .long _max_align
  417. #endif /* COMPRESS */