Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

e820mangler.S 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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. FILE_LICENCE ( GPL2_OR_LATER )
  19. .text
  20. .arch i386
  21. .code16
  22. #define SMAP 0x534d4150
  23. /* Most documentation refers to the E820 buffer as being 20 bytes, and
  24. * the API makes it perfectly legitimate to pass only a 20-byte buffer
  25. * and expect to get valid data. However, some morons at ACPI decided
  26. * to extend the data structure by adding an extra "extended
  27. * attributes" field and by including critical information within this
  28. * field, such as whether or not the region is enabled. A caller who
  29. * passes in only a 20-byte buffer therefore risks getting very, very
  30. * misleading information.
  31. *
  32. * I have personally witnessed an HP BIOS that returns a value of
  33. * 0x0009 in the extended attributes field. If we don't pass this
  34. * value through to the caller, 32-bit WinPE will die, usually with a
  35. * PAGE_FAULT_IN_NONPAGED_AREA blue screen of death.
  36. *
  37. * Allow a ridiculously large maximum value (64 bytes) for the E820
  38. * buffer as a guard against insufficiently creative idiots in the
  39. * future.
  40. */
  41. #define E820MAXSIZE 64
  42. /****************************************************************************
  43. *
  44. * Allowed memory windows
  45. *
  46. * There are two ways to view this list. The first is as a list of
  47. * (non-overlapping) allowed memory regions, sorted by increasing
  48. * address. The second is as a list of (non-overlapping) hidden
  49. * memory regions, again sorted by increasing address. The second
  50. * view is offset by half an entry from the first: think about this
  51. * for a moment and it should make sense.
  52. *
  53. * xxx_memory_window is used to indicate an "allowed region"
  54. * structure, hidden_xxx_memory is used to indicate a "hidden region"
  55. * structure. Each structure is 16 bytes in length.
  56. *
  57. ****************************************************************************
  58. */
  59. .section ".data16", "aw", @progbits
  60. .align 16
  61. .globl hidemem_base
  62. .globl hidemem_umalloc
  63. .globl hidemem_textdata
  64. memory_windows:
  65. base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */
  66. hidemem_base: .long 0x000a0000, 0x00000000 /* Changes at runtime */
  67. ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */
  68. hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */
  69. .long 0xffffffff, 0xffffffff /* Changes at runtime */
  70. hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */
  71. .long 0xffffffff, 0xffffffff /* Changes at runtime */
  72. .long 0xffffffff, 0xffffffff /* End of memory */
  73. memory_windows_end:
  74. /****************************************************************************
  75. * Truncate region to memory window
  76. *
  77. * Parameters:
  78. * %edx:%eax Start of region
  79. * %ecx:%ebx Length of region
  80. * %si Memory window
  81. * Returns:
  82. * %edx:%eax Start of windowed region
  83. * %ecx:%ebx Length of windowed region
  84. ****************************************************************************
  85. */
  86. .section ".text16", "ax", @progbits
  87. window_region:
  88. /* Convert (start,len) to (start, end) */
  89. addl %eax, %ebx
  90. adcl %edx, %ecx
  91. /* Truncate to window start */
  92. cmpl 4(%si), %edx
  93. jne 1f
  94. cmpl 0(%si), %eax
  95. 1: jae 2f
  96. movl 4(%si), %edx
  97. movl 0(%si), %eax
  98. 2: /* Truncate to window end */
  99. cmpl 12(%si), %ecx
  100. jne 1f
  101. cmpl 8(%si), %ebx
  102. 1: jbe 2f
  103. movl 12(%si), %ecx
  104. movl 8(%si), %ebx
  105. 2: /* Convert (start, end) back to (start, len) */
  106. subl %eax, %ebx
  107. sbbl %edx, %ecx
  108. /* If length is <0, set length to 0 */
  109. jae 1f
  110. xorl %ebx, %ebx
  111. xorl %ecx, %ecx
  112. ret
  113. .size window_region, . - window_region
  114. /****************************************************************************
  115. * Patch "memory above 1MB" figure
  116. *
  117. * Parameters:
  118. * %ax Memory above 1MB, in 1kB blocks
  119. * Returns:
  120. * %ax Modified memory above 1M in 1kB blocks
  121. ****************************************************************************
  122. */
  123. .section ".text16", "ax", @progbits
  124. patch_1m:
  125. pushal
  126. /* Convert to (start,len) format and call truncate */
  127. xorl %ecx, %ecx
  128. movzwl %ax, %ebx
  129. shll $10, %ebx
  130. xorl %edx, %edx
  131. movl $0x100000, %eax
  132. movw $ext_memory_window, %si
  133. call window_region
  134. /* Convert back to "memory above 1MB" format and return via %ax */
  135. pushfw
  136. shrl $10, %ebx
  137. popfw
  138. movw %sp, %bp
  139. movw %bx, 28(%bp)
  140. popal
  141. ret
  142. .size patch_1m, . - patch_1m
  143. /****************************************************************************
  144. * Patch "memory above 16MB" figure
  145. *
  146. * Parameters:
  147. * %bx Memory above 16MB, in 64kB blocks
  148. * Returns:
  149. * %bx Modified memory above 16M in 64kB blocks
  150. ****************************************************************************
  151. */
  152. .section ".text16", "ax", @progbits
  153. patch_16m:
  154. pushal
  155. /* Convert to (start,len) format and call truncate */
  156. xorl %ecx, %ecx
  157. shll $16, %ebx
  158. xorl %edx, %edx
  159. movl $0x1000000, %eax
  160. movw $ext_memory_window, %si
  161. call window_region
  162. /* Convert back to "memory above 16MB" format and return via %bx */
  163. pushfw
  164. shrl $16, %ebx
  165. popfw
  166. movw %sp, %bp
  167. movw %bx, 16(%bp)
  168. popal
  169. ret
  170. .size patch_16m, . - patch_16m
  171. /****************************************************************************
  172. * Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
  173. *
  174. * Parameters:
  175. * %ax Memory between 1MB and 16MB, in 1kB blocks
  176. * %bx Memory above 16MB, in 64kB blocks
  177. * Returns:
  178. * %ax Modified memory between 1MB and 16MB, in 1kB blocks
  179. * %bx Modified memory above 16MB, in 64kB blocks
  180. ****************************************************************************
  181. */
  182. .section ".text16", "ax", @progbits
  183. patch_1m_16m:
  184. call patch_1m
  185. call patch_16m
  186. /* If 1M region is no longer full-length, kill off the 16M region */
  187. cmpw $( 15 * 1024 ), %ax
  188. je 1f
  189. xorw %bx, %bx
  190. 1: ret
  191. .size patch_1m_16m, . - patch_1m_16m
  192. /****************************************************************************
  193. * Get underlying e820 memory region to underlying_e820 buffer
  194. *
  195. * Parameters:
  196. * As for INT 15,e820
  197. * Returns:
  198. * As for INT 15,e820
  199. *
  200. * Wraps the underlying INT 15,e820 call so that the continuation
  201. * value (%ebx) is a 16-bit simple sequence counter (with the high 16
  202. * bits ignored), and termination is always via CF=1 rather than
  203. * %ebx=0.
  204. *
  205. ****************************************************************************
  206. */
  207. .section ".text16", "ax", @progbits
  208. get_underlying_e820:
  209. /* If the requested region is in the cache, return it */
  210. cmpw %bx, underlying_e820_index
  211. jne 2f
  212. pushw %di
  213. pushw %si
  214. movw $underlying_e820_cache, %si
  215. cmpl underlying_e820_cache_size, %ecx
  216. jbe 1f
  217. movl underlying_e820_cache_size, %ecx
  218. 1: pushl %ecx
  219. rep movsb
  220. popl %ecx
  221. popw %si
  222. popw %di
  223. incw %bx
  224. movl %edx, %eax
  225. clc
  226. ret
  227. 2:
  228. /* If the requested region is earlier than the cached region,
  229. * invalidate the cache.
  230. */
  231. cmpw %bx, underlying_e820_index
  232. jbe 1f
  233. movw $0xffff, underlying_e820_index
  234. 1:
  235. /* If the cache is invalid, reset the underlying %ebx */
  236. cmpw $0xffff, underlying_e820_index
  237. jne 1f
  238. andl $0, underlying_e820_ebx
  239. 1:
  240. /* If the cache is valid but the continuation value is zero,
  241. * this means that the previous underlying call returned with
  242. * %ebx=0. Return with CF=1 in this case.
  243. */
  244. cmpw $0xffff, underlying_e820_index
  245. je 1f
  246. cmpl $0, underlying_e820_ebx
  247. jne 1f
  248. stc
  249. ret
  250. 1:
  251. /* Get the next region into the cache */
  252. pushl %eax
  253. pushl %ebx
  254. pushl %ecx
  255. pushl %edx
  256. pushl %esi /* Some implementations corrupt %esi, so we */
  257. pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */
  258. pushl %ebp
  259. pushw %es
  260. pushw %ds
  261. popw %es
  262. movw $underlying_e820_cache, %di
  263. cmpl $E820MAXSIZE, %ecx
  264. jbe 1f
  265. movl $E820MAXSIZE, %ecx
  266. 1: movl underlying_e820_ebx, %ebx
  267. stc
  268. pushfw
  269. lcall *%cs:int15_vector
  270. popw %es
  271. popl %ebp
  272. popl %edi
  273. popl %esi
  274. /* Check for error return from underlying e820 call */
  275. jc 2f /* CF set: error */
  276. cmpl $SMAP, %eax
  277. je 3f /* 'SMAP' missing: error */
  278. 2: /* An error occurred: return values returned by underlying e820 call */
  279. stc /* Force CF set if SMAP was missing */
  280. addr32 leal 16(%esp), %esp /* avoid changing other flags */
  281. ret
  282. 3: /* No error occurred */
  283. movl %ebx, underlying_e820_ebx
  284. movl %ecx, underlying_e820_cache_size
  285. popl %edx
  286. popl %ecx
  287. popl %ebx
  288. popl %eax
  289. /* Mark cache as containing this result */
  290. incw underlying_e820_index
  291. /* Loop until found */
  292. jmp get_underlying_e820
  293. .size get_underlying_e820, . - get_underlying_e820
  294. .section ".data16", "aw", @progbits
  295. underlying_e820_index:
  296. .word 0xffff /* Initialise to an invalid value */
  297. .size underlying_e820_index, . - underlying_e820_index
  298. .section ".bss16", "aw", @nobits
  299. underlying_e820_ebx:
  300. .long 0
  301. .size underlying_e820_ebx, . - underlying_e820_ebx
  302. .section ".bss16", "aw", @nobits
  303. underlying_e820_cache:
  304. .space E820MAXSIZE
  305. .size underlying_e820_cache, . - underlying_e820_cache
  306. .section ".bss16", "aw", @nobits
  307. underlying_e820_cache_size:
  308. .long 0
  309. .size underlying_e820_cache_size, . - underlying_e820_cache_size
  310. /****************************************************************************
  311. * Get windowed e820 region, without empty region stripping
  312. *
  313. * Parameters:
  314. * As for INT 15,e820
  315. * Returns:
  316. * As for INT 15,e820
  317. *
  318. * Wraps the underlying INT 15,e820 call so that each underlying
  319. * region is returned N times, windowed to fit within N visible-memory
  320. * windows. Termination is always via CF=1.
  321. *
  322. ****************************************************************************
  323. */
  324. .section ".text16", "ax", @progbits
  325. get_windowed_e820:
  326. /* Preserve registers */
  327. pushl %esi
  328. pushw %bp
  329. /* Split %ebx into %si:%bx, store original %bx in %bp */
  330. pushl %ebx
  331. popw %bp
  332. popw %si
  333. /* %si == 0 => start of memory_windows list */
  334. testw %si, %si
  335. jne 1f
  336. movw $memory_windows, %si
  337. 1:
  338. /* Get (cached) underlying e820 region to buffer */
  339. call get_underlying_e820
  340. jc 99f /* Abort on error */
  341. /* Preserve registers */
  342. pushal
  343. /* start => %edx:%eax, len => %ecx:%ebx */
  344. movl %es:0(%di), %eax
  345. movl %es:4(%di), %edx
  346. movl %es:8(%di), %ebx
  347. movl %es:12(%di), %ecx
  348. /* Truncate region to current window */
  349. call window_region
  350. 1: /* Store modified values in e820 map entry */
  351. movl %eax, %es:0(%di)
  352. movl %edx, %es:4(%di)
  353. movl %ebx, %es:8(%di)
  354. movl %ecx, %es:12(%di)
  355. /* Restore registers */
  356. popal
  357. /* Derive continuation value for next call */
  358. addw $16, %si
  359. cmpw $memory_windows_end, %si
  360. jne 1f
  361. /* End of memory windows: reset %si and allow %bx to continue */
  362. xorw %si, %si
  363. jmp 2f
  364. 1: /* More memory windows to go: restore original %bx */
  365. movw %bp, %bx
  366. 2: /* Construct %ebx from %si:%bx */
  367. pushw %si
  368. pushw %bx
  369. popl %ebx
  370. 98: /* Clear CF */
  371. clc
  372. 99: /* Restore registers and return */
  373. popw %bp
  374. popl %esi
  375. ret
  376. .size get_windowed_e820, . - get_windowed_e820
  377. /****************************************************************************
  378. * Get windowed e820 region, with empty region stripping
  379. *
  380. * Parameters:
  381. * As for INT 15,e820
  382. * Returns:
  383. * As for INT 15,e820
  384. *
  385. * Wraps the underlying INT 15,e820 call so that each underlying
  386. * region is returned up to N times, windowed to fit within N
  387. * visible-memory windows. Empty windows are never returned.
  388. * Termination is always via CF=1.
  389. *
  390. ****************************************************************************
  391. */
  392. .section ".text16", "ax", @progbits
  393. get_nonempty_e820:
  394. /* Record entry parameters */
  395. pushl %eax
  396. pushl %ecx
  397. pushl %edx
  398. /* Get next windowed region */
  399. call get_windowed_e820
  400. jc 99f /* abort on error */
  401. /* If region is non-empty, finish here */
  402. cmpl $0, %es:8(%di)
  403. jne 98f
  404. cmpl $0, %es:12(%di)
  405. jne 98f
  406. /* Region was empty: restore entry parameters and go to next region */
  407. popl %edx
  408. popl %ecx
  409. popl %eax
  410. jmp get_nonempty_e820
  411. 98: /* Clear CF */
  412. clc
  413. 99: /* Return values from underlying call */
  414. addr32 leal 12(%esp), %esp /* avoid changing flags */
  415. ret
  416. .size get_nonempty_e820, . - get_nonempty_e820
  417. /****************************************************************************
  418. * Get mangled e820 region, with empty region stripping
  419. *
  420. * Parameters:
  421. * As for INT 15,e820
  422. * Returns:
  423. * As for INT 15,e820
  424. *
  425. * Wraps the underlying INT 15,e820 call so that underlying regions
  426. * are windowed to the allowed memory regions. Empty regions are
  427. * stripped from the map. Termination is always via %ebx=0.
  428. *
  429. ****************************************************************************
  430. */
  431. .section ".text16", "ax", @progbits
  432. get_mangled_e820:
  433. /* Get a nonempty region */
  434. call get_nonempty_e820
  435. jc 99f /* Abort on error */
  436. /* Peek ahead to see if there are any further nonempty regions */
  437. pushal
  438. pushw %es
  439. movw %sp, %bp
  440. subw %cx, %sp
  441. movl $0xe820, %eax
  442. movl $SMAP, %edx
  443. pushw %ss
  444. popw %es
  445. movw %sp, %di
  446. call get_nonempty_e820
  447. movw %bp, %sp
  448. popw %es
  449. popal
  450. jnc 99f /* There are further nonempty regions */
  451. /* No futher nonempty regions: zero %ebx and clear CF */
  452. xorl %ebx, %ebx
  453. 99: /* Return */
  454. ret
  455. .size get_mangled_e820, . - get_mangled_e820
  456. /****************************************************************************
  457. * Set/clear CF on the stack as appropriate, assumes stack is as it should
  458. * be immediately before IRET
  459. ****************************************************************************
  460. */
  461. patch_cf:
  462. pushw %bp
  463. movw %sp, %bp
  464. setc 8(%bp) /* Set/reset CF; clears PF, AF, ZF, SF */
  465. popw %bp
  466. ret
  467. /****************************************************************************
  468. * INT 15,e820 handler
  469. ****************************************************************************
  470. */
  471. .section ".text16", "ax", @progbits
  472. int15_e820:
  473. pushw %ds
  474. pushw %cs:rm_ds
  475. popw %ds
  476. call get_mangled_e820
  477. popw %ds
  478. call patch_cf
  479. iret
  480. .size int15_e820, . - int15_e820
  481. /****************************************************************************
  482. * INT 15,e801 handler
  483. ****************************************************************************
  484. */
  485. .section ".text16", "ax", @progbits
  486. int15_e801:
  487. /* Call previous handler */
  488. pushfw
  489. lcall *%cs:int15_vector
  490. call patch_cf
  491. /* Edit result */
  492. pushw %ds
  493. pushw %cs:rm_ds
  494. popw %ds
  495. call patch_1m_16m
  496. xchgw %ax, %cx
  497. xchgw %bx, %dx
  498. call patch_1m_16m
  499. xchgw %ax, %cx
  500. xchgw %bx, %dx
  501. popw %ds
  502. iret
  503. .size int15_e801, . - int15_e801
  504. /****************************************************************************
  505. * INT 15,88 handler
  506. ****************************************************************************
  507. */
  508. .section ".text16", "ax", @progbits
  509. int15_88:
  510. /* Call previous handler */
  511. pushfw
  512. lcall *%cs:int15_vector
  513. call patch_cf
  514. /* Edit result */
  515. pushw %ds
  516. pushw %cs:rm_ds
  517. popw %ds
  518. call patch_1m
  519. popw %ds
  520. iret
  521. .size int15_88, . - int15_88
  522. /****************************************************************************
  523. * INT 15 handler
  524. ****************************************************************************
  525. */
  526. .section ".text16", "ax", @progbits
  527. .globl int15
  528. int15:
  529. /* See if we want to intercept this call */
  530. pushfw
  531. cmpw $0xe820, %ax
  532. jne 1f
  533. cmpl $SMAP, %edx
  534. jne 1f
  535. popfw
  536. jmp int15_e820
  537. 1: cmpw $0xe801, %ax
  538. jne 2f
  539. popfw
  540. jmp int15_e801
  541. 2: cmpb $0x88, %ah
  542. jne 3f
  543. popfw
  544. jmp int15_88
  545. 3: popfw
  546. ljmp *%cs:int15_vector
  547. .size int15, . - int15
  548. .section ".text16.data", "aw", @progbits
  549. .globl int15_vector
  550. int15_vector:
  551. .long 0
  552. .size int15_vector, . - int15_vector