summaryrefslogtreecommitdiff
path: root/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/arch/i386/firmware/pcbios/e820mangler.S')
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/e820mangler.S596
1 files changed, 0 insertions, 596 deletions
diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
deleted file mode 100644
index 99ca519b..00000000
--- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER )
-
- .text
- .arch i386
- .code16
-
-#define SMAP 0x534d4150
-
-/* Most documentation refers to the E820 buffer as being 20 bytes, and
- * the API makes it perfectly legitimate to pass only a 20-byte buffer
- * and expect to get valid data. However, some morons at ACPI decided
- * to extend the data structure by adding an extra "extended
- * attributes" field and by including critical information within this
- * field, such as whether or not the region is enabled. A caller who
- * passes in only a 20-byte buffer therefore risks getting very, very
- * misleading information.
- *
- * I have personally witnessed an HP BIOS that returns a value of
- * 0x0009 in the extended attributes field. If we don't pass this
- * value through to the caller, 32-bit WinPE will die, usually with a
- * PAGE_FAULT_IN_NONPAGED_AREA blue screen of death.
- *
- * Allow a ridiculously large maximum value (64 bytes) for the E820
- * buffer as a guard against insufficiently creative idiots in the
- * future.
- */
-#define E820MAXSIZE 64
-
-/****************************************************************************
- *
- * Allowed memory windows
- *
- * There are two ways to view this list. The first is as a list of
- * (non-overlapping) allowed memory regions, sorted by increasing
- * address. The second is as a list of (non-overlapping) hidden
- * memory regions, again sorted by increasing address. The second
- * view is offset by half an entry from the first: think about this
- * for a moment and it should make sense.
- *
- * xxx_memory_window is used to indicate an "allowed region"
- * structure, hidden_xxx_memory is used to indicate a "hidden region"
- * structure. Each structure is 16 bytes in length.
- *
- ****************************************************************************
- */
- .section ".data16", "aw", @progbits
- .align 16
- .globl hidemem_base
- .globl hidemem_umalloc
- .globl hidemem_textdata
-memory_windows:
-base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */
-
-hidemem_base: .long 0x000a0000, 0x00000000 /* Changes at runtime */
-ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */
-
-hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */
- .long 0xffffffff, 0xffffffff /* Changes at runtime */
-
-hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */
- .long 0xffffffff, 0xffffffff /* Changes at runtime */
-
- .long 0xffffffff, 0xffffffff /* End of memory */
-memory_windows_end:
-
-/****************************************************************************
- * Truncate region to memory window
- *
- * Parameters:
- * %edx:%eax Start of region
- * %ecx:%ebx Length of region
- * %si Memory window
- * Returns:
- * %edx:%eax Start of windowed region
- * %ecx:%ebx Length of windowed region
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-window_region:
- /* Convert (start,len) to (start, end) */
- addl %eax, %ebx
- adcl %edx, %ecx
- /* Truncate to window start */
- cmpl 4(%si), %edx
- jne 1f
- cmpl 0(%si), %eax
-1: jae 2f
- movl 4(%si), %edx
- movl 0(%si), %eax
-2: /* Truncate to window end */
- cmpl 12(%si), %ecx
- jne 1f
- cmpl 8(%si), %ebx
-1: jbe 2f
- movl 12(%si), %ecx
- movl 8(%si), %ebx
-2: /* Convert (start, end) back to (start, len) */
- subl %eax, %ebx
- sbbl %edx, %ecx
- /* If length is <0, set length to 0 */
- jae 1f
- xorl %ebx, %ebx
- xorl %ecx, %ecx
- ret
- .size window_region, . - window_region
-
-/****************************************************************************
- * Patch "memory above 1MB" figure
- *
- * Parameters:
- * %ax Memory above 1MB, in 1kB blocks
- * Returns:
- * %ax Modified memory above 1M in 1kB blocks
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-patch_1m:
- pushal
- /* Convert to (start,len) format and call truncate */
- xorl %ecx, %ecx
- movzwl %ax, %ebx
- shll $10, %ebx
- xorl %edx, %edx
- movl $0x100000, %eax
- movw $ext_memory_window, %si
- call window_region
- /* Convert back to "memory above 1MB" format and return via %ax */
- pushfw
- shrl $10, %ebx
- popfw
- movw %sp, %bp
- movw %bx, 28(%bp)
- popal
- ret
- .size patch_1m, . - patch_1m
-
-/****************************************************************************
- * Patch "memory above 16MB" figure
- *
- * Parameters:
- * %bx Memory above 16MB, in 64kB blocks
- * Returns:
- * %bx Modified memory above 16M in 64kB blocks
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-patch_16m:
- pushal
- /* Convert to (start,len) format and call truncate */
- xorl %ecx, %ecx
- shll $16, %ebx
- xorl %edx, %edx
- movl $0x1000000, %eax
- movw $ext_memory_window, %si
- call window_region
- /* Convert back to "memory above 16MB" format and return via %bx */
- pushfw
- shrl $16, %ebx
- popfw
- movw %sp, %bp
- movw %bx, 16(%bp)
- popal
- ret
- .size patch_16m, . - patch_16m
-
-/****************************************************************************
- * Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
- *
- * Parameters:
- * %ax Memory between 1MB and 16MB, in 1kB blocks
- * %bx Memory above 16MB, in 64kB blocks
- * Returns:
- * %ax Modified memory between 1MB and 16MB, in 1kB blocks
- * %bx Modified memory above 16MB, in 64kB blocks
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-patch_1m_16m:
- call patch_1m
- call patch_16m
- /* If 1M region is no longer full-length, kill off the 16M region */
- cmpw $( 15 * 1024 ), %ax
- je 1f
- xorw %bx, %bx
-1: ret
- .size patch_1m_16m, . - patch_1m_16m
-
-/****************************************************************************
- * Get underlying e820 memory region to underlying_e820 buffer
- *
- * Parameters:
- * As for INT 15,e820
- * Returns:
- * As for INT 15,e820
- *
- * Wraps the underlying INT 15,e820 call so that the continuation
- * value (%ebx) is a 16-bit simple sequence counter (with the high 16
- * bits ignored), and termination is always via CF=1 rather than
- * %ebx=0.
- *
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-get_underlying_e820:
-
- /* If the requested region is in the cache, return it */
- cmpw %bx, underlying_e820_index
- jne 2f
- pushw %di
- pushw %si
- movw $underlying_e820_cache, %si
- cmpl underlying_e820_cache_size, %ecx
- jbe 1f
- movl underlying_e820_cache_size, %ecx
-1: pushl %ecx
- rep movsb
- popl %ecx
- popw %si
- popw %di
- incw %bx
- movl %edx, %eax
- clc
- ret
-2:
- /* If the requested region is earlier than the cached region,
- * invalidate the cache.
- */
- cmpw %bx, underlying_e820_index
- jbe 1f
- movw $0xffff, underlying_e820_index
-1:
- /* If the cache is invalid, reset the underlying %ebx */
- cmpw $0xffff, underlying_e820_index
- jne 1f
- andl $0, underlying_e820_ebx
-1:
- /* If the cache is valid but the continuation value is zero,
- * this means that the previous underlying call returned with
- * %ebx=0. Return with CF=1 in this case.
- */
- cmpw $0xffff, underlying_e820_index
- je 1f
- cmpl $0, underlying_e820_ebx
- jne 1f
- stc
- ret
-1:
- /* Get the next region into the cache */
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- pushl %esi /* Some implementations corrupt %esi, so we */
- pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */
- pushl %ebp
- pushw %es
- pushw %ds
- popw %es
- movw $underlying_e820_cache, %di
- cmpl $E820MAXSIZE, %ecx
- jbe 1f
- movl $E820MAXSIZE, %ecx
-1: movl underlying_e820_ebx, %ebx
- stc
- pushfw
- lcall *%cs:int15_vector
- popw %es
- popl %ebp
- popl %edi
- popl %esi
- /* Check for error return from underlying e820 call */
- jc 2f /* CF set: error */
- cmpl $SMAP, %eax
- je 3f /* 'SMAP' missing: error */
-2: /* An error occurred: return values returned by underlying e820 call */
- stc /* Force CF set if SMAP was missing */
- addr32 leal 16(%esp), %esp /* avoid changing other flags */
- ret
-3: /* No error occurred */
- movl %ebx, underlying_e820_ebx
- movl %ecx, underlying_e820_cache_size
- popl %edx
- popl %ecx
- popl %ebx
- popl %eax
- /* Mark cache as containing this result */
- incw underlying_e820_index
-
- /* Loop until found */
- jmp get_underlying_e820
- .size get_underlying_e820, . - get_underlying_e820
-
- .section ".data16", "aw", @progbits
-underlying_e820_index:
- .word 0xffff /* Initialise to an invalid value */
- .size underlying_e820_index, . - underlying_e820_index
-
- .section ".bss16", "aw", @nobits
-underlying_e820_ebx:
- .long 0
- .size underlying_e820_ebx, . - underlying_e820_ebx
-
- .section ".bss16", "aw", @nobits
-underlying_e820_cache:
- .space E820MAXSIZE
- .size underlying_e820_cache, . - underlying_e820_cache
-
- .section ".bss16", "aw", @nobits
-underlying_e820_cache_size:
- .long 0
- .size underlying_e820_cache_size, . - underlying_e820_cache_size
-
-/****************************************************************************
- * Get windowed e820 region, without empty region stripping
- *
- * Parameters:
- * As for INT 15,e820
- * Returns:
- * As for INT 15,e820
- *
- * Wraps the underlying INT 15,e820 call so that each underlying
- * region is returned N times, windowed to fit within N visible-memory
- * windows. Termination is always via CF=1.
- *
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-get_windowed_e820:
-
- /* Preserve registers */
- pushl %esi
- pushw %bp
-
- /* Split %ebx into %si:%bx, store original %bx in %bp */
- pushl %ebx
- popw %bp
- popw %si
-
- /* %si == 0 => start of memory_windows list */
- testw %si, %si
- jne 1f
- movw $memory_windows, %si
-1:
- /* Get (cached) underlying e820 region to buffer */
- call get_underlying_e820
- jc 99f /* Abort on error */
-
- /* Preserve registers */
- pushal
- /* start => %edx:%eax, len => %ecx:%ebx */
- movl %es:0(%di), %eax
- movl %es:4(%di), %edx
- movl %es:8(%di), %ebx
- movl %es:12(%di), %ecx
- /* Truncate region to current window */
- call window_region
-1: /* Store modified values in e820 map entry */
- movl %eax, %es:0(%di)
- movl %edx, %es:4(%di)
- movl %ebx, %es:8(%di)
- movl %ecx, %es:12(%di)
- /* Restore registers */
- popal
-
- /* Derive continuation value for next call */
- addw $16, %si
- cmpw $memory_windows_end, %si
- jne 1f
- /* End of memory windows: reset %si and allow %bx to continue */
- xorw %si, %si
- jmp 2f
-1: /* More memory windows to go: restore original %bx */
- movw %bp, %bx
-2: /* Construct %ebx from %si:%bx */
- pushw %si
- pushw %bx
- popl %ebx
-
-98: /* Clear CF */
- clc
-99: /* Restore registers and return */
- popw %bp
- popl %esi
- ret
- .size get_windowed_e820, . - get_windowed_e820
-
-/****************************************************************************
- * Get windowed e820 region, with empty region stripping
- *
- * Parameters:
- * As for INT 15,e820
- * Returns:
- * As for INT 15,e820
- *
- * Wraps the underlying INT 15,e820 call so that each underlying
- * region is returned up to N times, windowed to fit within N
- * visible-memory windows. Empty windows are never returned.
- * Termination is always via CF=1.
- *
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-get_nonempty_e820:
-
- /* Record entry parameters */
- pushl %eax
- pushl %ecx
- pushl %edx
-
- /* Get next windowed region */
- call get_windowed_e820
- jc 99f /* abort on error */
-
- /* If region is non-empty, finish here */
- cmpl $0, %es:8(%di)
- jne 98f
- cmpl $0, %es:12(%di)
- jne 98f
-
- /* Region was empty: restore entry parameters and go to next region */
- popl %edx
- popl %ecx
- popl %eax
- jmp get_nonempty_e820
-
-98: /* Clear CF */
- clc
-99: /* Return values from underlying call */
- addr32 leal 12(%esp), %esp /* avoid changing flags */
- ret
- .size get_nonempty_e820, . - get_nonempty_e820
-
-/****************************************************************************
- * Get mangled e820 region, with empty region stripping
- *
- * Parameters:
- * As for INT 15,e820
- * Returns:
- * As for INT 15,e820
- *
- * Wraps the underlying INT 15,e820 call so that underlying regions
- * are windowed to the allowed memory regions. Empty regions are
- * stripped from the map. Termination is always via %ebx=0.
- *
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-get_mangled_e820:
-
- /* Get a nonempty region */
- call get_nonempty_e820
- jc 99f /* Abort on error */
-
- /* Peek ahead to see if there are any further nonempty regions */
- pushal
- pushw %es
- movw %sp, %bp
- subw %cx, %sp
- movl $0xe820, %eax
- movl $SMAP, %edx
- pushw %ss
- popw %es
- movw %sp, %di
- call get_nonempty_e820
- movw %bp, %sp
- popw %es
- popal
- jnc 99f /* There are further nonempty regions */
-
- /* No futher nonempty regions: zero %ebx and clear CF */
- xorl %ebx, %ebx
-
-99: /* Return */
- ret
- .size get_mangled_e820, . - get_mangled_e820
-
-/****************************************************************************
- * Set/clear CF on the stack as appropriate, assumes stack is as it should
- * be immediately before IRET
- ****************************************************************************
- */
-patch_cf:
- pushw %bp
- movw %sp, %bp
- setc 8(%bp) /* Set/reset CF; clears PF, AF, ZF, SF */
- popw %bp
- ret
-
-/****************************************************************************
- * INT 15,e820 handler
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-int15_e820:
- pushw %ds
- pushw %cs:rm_ds
- popw %ds
- call get_mangled_e820
- popw %ds
- call patch_cf
- iret
- .size int15_e820, . - int15_e820
-
-/****************************************************************************
- * INT 15,e801 handler
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-int15_e801:
- /* Call previous handler */
- pushfw
- lcall *%cs:int15_vector
- call patch_cf
- /* Edit result */
- pushw %ds
- pushw %cs:rm_ds
- popw %ds
- call patch_1m_16m
- xchgw %ax, %cx
- xchgw %bx, %dx
- call patch_1m_16m
- xchgw %ax, %cx
- xchgw %bx, %dx
- popw %ds
- iret
- .size int15_e801, . - int15_e801
-
-/****************************************************************************
- * INT 15,88 handler
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
-int15_88:
- /* Call previous handler */
- pushfw
- lcall *%cs:int15_vector
- call patch_cf
- /* Edit result */
- pushw %ds
- pushw %cs:rm_ds
- popw %ds
- call patch_1m
- popw %ds
- iret
- .size int15_88, . - int15_88
-
-/****************************************************************************
- * INT 15 handler
- ****************************************************************************
- */
- .section ".text16", "ax", @progbits
- .globl int15
-int15:
- /* See if we want to intercept this call */
- pushfw
- cmpw $0xe820, %ax
- jne 1f
- cmpl $SMAP, %edx
- jne 1f
- popfw
- jmp int15_e820
-1: cmpw $0xe801, %ax
- jne 2f
- popfw
- jmp int15_e801
-2: cmpb $0x88, %ah
- jne 3f
- popfw
- jmp int15_88
-3: popfw
- ljmp *%cs:int15_vector
- .size int15, . - int15
-
- .section ".text16.data", "aw", @progbits
- .globl int15_vector
-int15_vector:
- .long 0
- .size int15_vector, . - int15_vector