Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

e820mangler.S 15KB

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