mirror of
https://github.com/ipxe/ipxe
synced 2025-12-29 02:52:36 +03:00
[bios] Add bin-x86_64-pcbios build platform
Move most arch/i386 files to arch/x86, and adjust the contents of the Makefiles and the include/bits/*.h headers to reflect the new locations. This patch makes no substantive code changes, as can be seen using a rename-aware diff (e.g. "git show -M5"). This patch does not make the pcbios platform functional for x86_64; it merely allows it to compile without errors. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
589
src/arch/x86/interface/pcbios/e820mangler.S
Normal file
589
src/arch/x86/interface/pcbios/e820mangler.S
Normal file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.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
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
Reference in New Issue
Block a user