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.

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