2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
21 .section ".text16", "ax", @progbits
22 .section ".data16", "aw", @progbits
23 .section ".text16.data", "aw", @progbits
26 #define SMAP 0x534d4150
28 /****************************************************************************
30 * Allowed memory windows
32 * There are two ways to view this list. The first is as a list of
33 * (non-overlapping) allowed memory regions, sorted by increasing
34 * address. The second is as a list of (non-overlapping) hidden
35 * memory regions, again sorted by increasing address. The second
36 * view is offset by half an entry from the first: think about this
37 * for a moment and it should make sense.
39 * xxx_memory_window is used to indicate an "allowed region"
40 * structure, hidden_xxx_memory is used to indicate a "hidden region"
41 * structure. Each structure is 16 bytes in length.
43 ****************************************************************************
48 .globl hidemem_umalloc
51 base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */
53 hidemem_base: .long 0x000a0000, 0x00000000 /* Changes at runtime */
54 ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */
56 hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */
57 .long 0xffffffff, 0xffffffff /* Changes at runtime */
59 hidemem_text: .long 0xffffffff, 0xffffffff /* Changes at runtime */
60 .long 0xffffffff, 0xffffffff /* Changes at runtime */
62 .long 0xffffffff, 0xffffffff /* End of memory */
65 /****************************************************************************
66 * Truncate region to memory window
69 * %edx:%eax Start of region
70 * %ecx:%ebx Length of region
73 * %edx:%eax Start of windowed region
74 * %ecx:%ebx Length of windowed region
75 ****************************************************************************
79 /* Convert (start,len) to (start, end) */
82 /* Truncate to window start */
89 2: /* Truncate to window end */
96 2: /* Convert (start, end) back to (start, len) */
99 /* If length is <0, set length to 0 */
104 .size window_region, . - window_region
106 /****************************************************************************
107 * Patch "memory above 1MB" figure
110 * %ax Memory above 1MB, in 1kB blocks
112 * %ax Modified memory above 1M in 1kB blocks
113 ****************************************************************************
118 /* Convert to (start,len) format and call truncate */
124 movw $ext_memory_window, %si
126 /* Convert back to "memory above 1MB" format and return via %ax */
134 .size patch_1m, . - patch_1m
136 /****************************************************************************
137 * Patch "memory above 16MB" figure
140 * %bx Memory above 16MB, in 64kB blocks
142 * %bx Modified memory above 16M in 64kB blocks
143 ****************************************************************************
148 /* Convert to (start,len) format and call truncate */
152 movl $0x1000000, %eax
153 movw $ext_memory_window, %si
155 /* Convert back to "memory above 16MB" format and return via %bx */
163 .size patch_16m, . - patch_16m
165 /****************************************************************************
166 * Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
169 * %ax Memory between 1MB and 16MB, in 1kB blocks
170 * %bx Memory above 16MB, in 64kB blocks
172 * %ax Modified memory between 1MB and 16MB, in 1kB blocks
173 * %bx Modified memory above 16MB, in 64kB blocks
174 ****************************************************************************
180 /* If 1M region is no longer full-length, kill off the 16M region */
181 cmpw $( 15 * 1024 ), %ax
185 .size patch_1m_16m, . - patch_1m_16m
187 /****************************************************************************
188 * Get underlying e820 memory region to underlying_e820 buffer
195 * Wraps the underlying INT 15,e820 call so that the continuation
196 * value (%ebx) is a 16-bit simple sequence counter (with the high 16
197 * bits ignored), and termination is always via CF=1 rather than
200 ****************************************************************************
205 /* If the requested region is in the cache, return it */
206 cmpw %bx, underlying_e820_index
210 movw $underlying_e820_cache, %si
220 /* If the requested region is earlier than the cached region,
221 * invalidate the cache.
223 cmpw %bx, underlying_e820_index
225 movw $0xffff, underlying_e820_index
227 /* If the cache is invalid, reset the underlying %ebx */
228 cmpw $0xffff, underlying_e820_index
230 andl $0, underlying_e820_ebx
232 /* If the cache is valid but the continuation value is zero,
233 * this means that the previous underlying call returned with
234 * %ebx=0. Return with CF=1 in this case.
236 cmpw $0xffff, underlying_e820_index
238 cmpl $0, underlying_e820_ebx
243 /* Get the next region into the cache */
252 movw $underlying_e820_cache, %di
254 movl underlying_e820_ebx, %ebx
257 lcall *%cs:int15_vector
260 /* Check for error return from underlying e820 call */
261 jc 1f /* CF set: error */
263 je 2f /* 'SMAP' missing: error */
264 1: /* An error occurred: return values returned by underlying e820 call */
265 stc /* Force CF set if SMAP was missing */
266 addr32 leal 16(%esp), %esp /* avoid changing other flags */
268 2: /* No error occurred */
269 movl %ebx, underlying_e820_ebx
274 /* Mark cache as containing this result */
275 incw underlying_e820_index
277 /* Loop until found */
278 jmp get_underlying_e820
279 .size get_underlying_e820, . - get_underlying_e820
282 underlying_e820_index:
283 .word 0xffff /* Initialise to an invalid value */
284 .size underlying_e820_index, . - underlying_e820_index
289 .size underlying_e820_ebx, . - underlying_e820_ebx
292 underlying_e820_cache:
294 .size underlying_e820_cache, . - underlying_e820_cache
296 /****************************************************************************
297 * Get windowed e820 region, without empty region stripping
304 * Wraps the underlying INT 15,e820 call so that each underlying
305 * region is returned N times, windowed to fit within N visible-memory
306 * windows. Termination is always via CF=1.
308 ****************************************************************************
313 /* Preserve registers */
317 /* Split %ebx into %si:%bx, store original %bx in %bp */
322 /* %si == 0 => start of memory_windows list */
325 movw $memory_windows, %si
327 /* Get (cached) underlying e820 region to buffer */
328 call get_underlying_e820
329 jc 99f /* Abort on error */
331 /* Preserve registers */
333 /* start => %edx:%eax, len => %ecx:%ebx */
334 movl %es:0(%di), %eax
335 movl %es:4(%di), %edx
336 movl %es:8(%di), %ebx
337 movl %es:12(%di), %ecx
338 /* Truncate region to current window */
340 1: /* Store modified values in e820 map entry */
341 movl %eax, %es:0(%di)
342 movl %edx, %es:4(%di)
343 movl %ebx, %es:8(%di)
344 movl %ecx, %es:12(%di)
345 /* Restore registers */
348 /* Derive continuation value for next call */
350 cmpw $memory_windows_end, %si
352 /* End of memory windows: reset %si and allow %bx to continue */
355 1: /* More memory windows to go: restore original %bx */
357 2: /* Construct %ebx from %si:%bx */
364 99: /* Restore registers and return */
368 .size get_windowed_e820, . - get_windowed_e820
370 /****************************************************************************
371 * Get windowed e820 region, with empty region stripping
378 * Wraps the underlying INT 15,e820 call so that each underlying
379 * region is returned up to N times, windowed to fit within N
380 * visible-memory windows. Empty windows are never returned.
381 * Termination is always via CF=1.
383 ****************************************************************************
388 /* Record entry parameters */
393 /* Get next windowed region */
394 call get_windowed_e820
395 jc 99f /* abort on error */
397 /* If region is non-empty, finish here */
403 /* Region was empty: restore entry parameters and go to next region */
407 jmp get_nonempty_e820
411 99: /* Return values from underlying call */
412 addr32 leal 12(%esp), %esp /* avoid changing flags */
414 .size get_nonempty_e820, . - get_nonempty_e820
416 /****************************************************************************
417 * Get mangled e820 region, with empty region stripping
424 * Wraps the underlying INT 15,e820 call so that underlying regions
425 * are windowed to the allowed memory regions. Empty regions are
426 * stripped from the map. Termination is always via %ebx=0.
428 ****************************************************************************
433 /* Get a nonempty region */
434 call get_nonempty_e820
435 jc 99f /* Abort on error */
437 /* Peek ahead to see if there are any further nonempty regions */
446 call get_nonempty_e820
447 addr32 leal 20(%esp), %esp /* avoid changing flags */
449 jnc 99f /* There are further nonempty regions */
451 /* No futher nonempty regions: zero %ebx and clear CF */
456 .size get_mangled_e820, . - get_mangled_e820
458 /****************************************************************************
459 * INT 15,e820 handler
460 ****************************************************************************
467 call get_mangled_e820
470 .size int15_e820, . - int15_e820
472 /****************************************************************************
473 * INT 15,e801 handler
474 ****************************************************************************
478 /* Call previous handler */
480 lcall *%cs:int15_vector
493 /* Restore flags returned by previous handler and return */
496 .size int15_e801, . - int15_e801
498 /****************************************************************************
500 ****************************************************************************
504 /* Call previous handler */
506 lcall *%cs:int15_vector
514 /* Restore flags returned by previous handler and return */
517 .size int15_88, . - int15_88
519 /****************************************************************************
521 ****************************************************************************
526 /* See if we want to intercept this call */
543 ljmp *%cs:int15_vector
544 .size int15, . - int15
546 .section ".text16.data"
550 .size int15_vector, . - int15_vector