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.

e820mangler.S 15KB

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