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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #undef CODE16
  2. #if defined(PCBIOS)
  3. #define CODE16
  4. #endif
  5. #ifdef CODE16
  6. #define BOCHSBP xchgw %bx,%bx
  7. .text
  8. .arch i386
  9. .section ".text16", "ax", @progbits
  10. .code16
  11. /****************************************************************************
  12. * Memory map mangling code
  13. ****************************************************************************
  14. */
  15. .globl e820mangler
  16. e820mangler:
  17. /* Macro to calculate offset of labels within code segment in
  18. * installed copy of code.
  19. */
  20. #define INSTALLED(x) ( (x) - e820mangler )
  21. /****************************************************************************
  22. * Intercept INT 15 memory calls and remove the hidden memory ranges
  23. * from the resulting memory map.
  24. ****************************************************************************
  25. */
  26. .globl _intercept_int15
  27. _intercept_int15:
  28. /* Preserve registers */
  29. pushw %bp
  30. /* Store %ax for future reference */
  31. pushw %ax
  32. /* Make INT-style call to old INT15 routine */
  33. pushfw
  34. lcall %cs:*INSTALLED(_intercepted_int15)
  35. /* Preserve flags returned by original E820 routine */
  36. pushfw
  37. /* Check for valid INT15 routine */
  38. jc intercept_int15_exit
  39. /* Check for a routine we want to intercept */
  40. movw %sp, %bp
  41. cmpw $0xe820, 2(%bp)
  42. je intercept_e820
  43. cmpw $0xe801, 2(%bp)
  44. je intercept_e801
  45. cmpb $0x88, 3(%bp)
  46. je intercept_88
  47. intercept_int15_exit:
  48. /* Restore registers and return */
  49. popfw
  50. popw %bp /* discard original %ax */
  51. popw %bp
  52. lret $2 /* 'iret' - flags already loaded */
  53. .globl _intercepted_int15
  54. _intercepted_int15: .word 0,0
  55. /****************************************************************************
  56. * Exclude an address range from a potentially overlapping address range
  57. *
  58. * Note: this *can* be called even if the range doesn't overlap; it
  59. * will simply return the range unaltered. It copes with all the
  60. * possible cases of overlap, including total overlap (which will
  61. * modify the range to length zero). If the to-be-excluded range is
  62. * in the middle of the target range, then the larger remaining
  63. * portion will be returned. If %di is nonzero on entry then the
  64. * range will only be truncated from the high end, i.e. the base
  65. * address will never be altered. All this in less than 30
  66. * instructions. :)
  67. *
  68. * Parameters:
  69. * %eax Base address of memory range
  70. * %ecx Length of memory range
  71. * %ebx Base address of memory range to exclude
  72. * %edx Length of memory range to exclude
  73. * %di 0 => truncate either end, 1 => truncate high end only
  74. * Returns:
  75. * %eax Updated base address of range
  76. * %ecx Updated length of range
  77. * %ebx,%edx Undefined
  78. * All other registers (including %di) preserved
  79. *
  80. * Note: "ja" is used rather than "jg" because we are comparing
  81. * unsigned ints
  82. ****************************************************************************
  83. */
  84. #ifdef TEST_EXCLUDE_ALGORITHM
  85. .code32
  86. #endif /* TEST_EXCLUDE_ALGORITHM */
  87. exclude_memory_range:
  88. /* Convert (start,length) to (start,end) */
  89. addl %eax, %ecx
  90. addl %ebx, %edx
  91. /* Calculate "prefix" length */
  92. subl %eax, %ebx /* %ebx = "prefix" length */
  93. ja 1f
  94. xorl %ebx, %ebx /* Truncate to zero if negative */
  95. 1: /* %di == 0 => truncate either end
  96. * %di != 0 => truncate only high end
  97. */
  98. testw %di, %di
  99. je use_either
  100. cmpl %eax, %edx
  101. jbe 99f /* excl. range is below target range */
  102. use_prefix: /* Use prefix, discard suffix */
  103. addl %eax, %ebx /* %ebx = candidate end address */
  104. cmpl %ecx, %ebx /* %ecx = min ( %ebx, %ecx ) */
  105. ja 1f
  106. movl %ebx, %ecx
  107. 1: jmp 99f
  108. use_either:
  109. /* Calculate "suffix" length */
  110. subl %ecx, %edx /* %edx = -( "suffix" length ) */
  111. jb 1f
  112. xorl %edx, %edx /* Truncate to zero if negative */
  113. 1: negl %edx /* %edx = "suffix" length */
  114. /* Use whichever is longest of "prefix" and "suffix" */
  115. cmpl %ebx, %edx
  116. jbe use_prefix
  117. use_suffix: /* Use suffix, discard prefix */
  118. negl %edx
  119. addl %ecx, %edx /* %edx = candidate start address */
  120. cmpl %eax, %edx /* %eax = max ( %eax, %edx ) */
  121. jb 1f
  122. movl %edx, %eax
  123. 1:
  124. 99: subl %eax, %ecx /* Convert back to (start,length) */
  125. ret
  126. #ifdef TEST_EXCLUDE_ALGORITHM
  127. .globl __test_exclude
  128. __test_exclude:
  129. pushl %ebx
  130. pushl %edi
  131. movl 12(%esp), %eax
  132. movl 16(%esp), %ecx
  133. movl 20(%esp), %ebx
  134. movl 24(%esp), %edx
  135. movl 28(%esp), %edi
  136. call exclude_memory_range
  137. shll $16, %eax
  138. orl %ecx, %eax
  139. popl %edi
  140. popl %ebx
  141. ret
  142. .code16
  143. #endif /* TEST_EXCLUDE_ALGORITHM */
  144. /****************************************************************************
  145. * Exclude Etherboot-reserved address ranges from a potentially
  146. * overlapping address range
  147. *
  148. * Parameters:
  149. * %eax Base address of memory range
  150. * %ecx Length of memory range
  151. * %di 0 => truncate either end, 1 => truncate high end only
  152. * Returns:
  153. * %eax Updated base address of range
  154. * %ecx Updated length of range
  155. * All other registers (including %di) preserved
  156. ****************************************************************************
  157. */
  158. exclude_hidden_memory_ranges:
  159. pushw %si
  160. pushl %ebx
  161. pushl %edx
  162. movw $INSTALLED(_hide_memory), %si
  163. 2: movl %cs:0(%si), %ebx
  164. movl %cs:4(%si), %edx
  165. call exclude_memory_range
  166. addw $8, %si
  167. cmpw $INSTALLED(_hide_memory_end), %si
  168. jl 2b
  169. popl %edx
  170. popl %ebx
  171. popw %si
  172. ret
  173. .globl _hide_memory
  174. _hide_memory:
  175. .long 0,0 /* Etherboot text (base,length) */
  176. .long 0,0 /* Heap (base,length) */
  177. _hide_memory_end:
  178. /****************************************************************************
  179. * Intercept INT 15,E820 calls and remove the hidden memory ranges
  180. * from the resulting memory map.
  181. ****************************************************************************
  182. */
  183. #define SMAP ( 0x534d4150 )
  184. intercept_e820:
  185. /* Check for valid E820 routine */
  186. cmpl $SMAP, %eax
  187. jne intercept_int15_exit
  188. /* If base address isn't in the low 4GB, return unaltered
  189. * (since we never claim memory above 4GB). WARNING: we cheat
  190. * by assuming that no E820 region will straddle the 4GB
  191. * boundary: if this is not a valid assumption then things
  192. * will probably break.
  193. */
  194. cmpl $0, %es:4(%di)
  195. jne intercept_int15_exit
  196. /* Preserve registers */
  197. pushl %eax
  198. pushl %ecx
  199. /* Update returned memory range */
  200. movl %es:0(%di), %eax /* Base */
  201. movl %es:8(%di), %ecx /* Length */
  202. pushw %di
  203. xorw %di, %di /* "truncate either end" flag */
  204. call exclude_hidden_memory_ranges
  205. popw %di
  206. movl %eax, %es:0(%di) /* Store updated base */
  207. movl %ecx, %es:8(%di) /* Store updated length */
  208. /* Restore registers and return */
  209. popl %ecx
  210. popl %eax
  211. jmp intercept_int15_exit
  212. /****************************************************************************
  213. * Intercept INT 15,E801 calls and remove the hidden memory ranges
  214. * from the resulting memory map.
  215. ****************************************************************************
  216. */
  217. intercept_e801:
  218. /* Adjust return values */
  219. call e801_adjust
  220. xchgw %ax, %cx
  221. xchgw %bx, %dx
  222. call e801_adjust
  223. xchgw %ax, %cx
  224. xchgw %bx, %dx
  225. jmp intercept_int15_exit
  226. /* %ax = #KB from 1MB+, %bx = #64KB from 16MB+
  227. * Return with modified values in %ax, %bx. Preserver other regs.
  228. */
  229. e801_adjust:
  230. pushw %di
  231. pushl %ecx
  232. pushl %eax
  233. movw $1, %di /* "truncate only high end" flag */
  234. /* Truncate #64KB from 16MB+ as appropriate */
  235. movw %bx, %cx /* (no need to zero high word) */
  236. shll $16, %ecx /* %ecx = length in bytes */
  237. movl $(1<<24), %eax /* 16MB start address */
  238. call exclude_hidden_memory_ranges
  239. shrl $16, %ecx /* %cx = updated length in 64KB */
  240. movw %cx, %bx /* Return in %bx */
  241. /* Truncate #KB from 1MB+ as appropriate */
  242. popw %cx /* Orig. %ax (high word already 0) */
  243. shll $10, %ecx /* %ecx = length in bytes */
  244. shrl $4, %eax /* 1MB start address */
  245. call exclude_hidden_memory_ranges
  246. shrl $10, %ecx /* %cx = updated length in KB */
  247. pushw %cx /* Will be picked up in %eax */
  248. popl %eax
  249. popl %ecx
  250. popw %di
  251. ret
  252. /****************************************************************************
  253. * Intercept INT 15,88 calls and remove the hidden memory ranges
  254. * from the resulting memory map.
  255. ****************************************************************************
  256. */
  257. intercept_88:
  258. pushw %bx /* E801 adjust, ignore %bx */
  259. call e801_adjust
  260. popw %bx
  261. jmp intercept_int15_exit
  262. .globl e820mangler_end
  263. e820mangler_end:
  264. .globl _e820mangler_size
  265. .equ _e820mangler_size, e820mangler_end - e820mangler
  266. .globl e820mangler_size
  267. e820mangler_size:
  268. .word _e820mangler_size
  269. #else
  270. .globl _e820mangler_size
  271. .equ _e820mangler_size, 0
  272. #endif /* CODE16 */