diff options
Diffstat (limited to 'qemu/roms/ipxe/src/arch/i386/transitions')
-rw-r--r-- | qemu/roms/ipxe/src/arch/i386/transitions/liba20.S | 313 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/arch/i386/transitions/libkir.S | 256 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/arch/i386/transitions/libpm.S | 0 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/arch/i386/transitions/librm.S | 671 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c | 158 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c | 122 |
6 files changed, 0 insertions, 1520 deletions
diff --git a/qemu/roms/ipxe/src/arch/i386/transitions/liba20.S b/qemu/roms/ipxe/src/arch/i386/transitions/liba20.S deleted file mode 100644 index 6c1e1f62f..000000000 --- a/qemu/roms/ipxe/src/arch/i386/transitions/liba20.S +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2010 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 ) - - .arch i386 - -/**************************************************************************** - * test_a20_short, test_a20_long - * - * Check to see if A20 line is enabled - * - * Parameters: - * none - * Returns: - * CF set if A20 line is not enabled - * Corrupts: - * none - **************************************************************************** - */ -#define TEST_A20_SHORT_MAX_RETRIES 0x20 -#define TEST_A20_LONG_MAX_RETRIES 0x200000 - .section ".text16.early", "awx", @progbits - .code16 -test_a20_short: - pushl %ecx - movl $TEST_A20_SHORT_MAX_RETRIES, %ecx - jmp 1f - .size test_a20_short, . - test_a20_short -test_a20_long: - pushl %ecx - movl $TEST_A20_LONG_MAX_RETRIES, %ecx -1: pushw %ax - pushw %ds - pushw %es - - /* Set up segment registers for access across the 1MB boundary */ - xorw %ax, %ax - movw %ax, %ds - decw %ax - movw %ax, %es - -2: /* Modify and check test pattern; succeed if we see a difference */ - pushfw - cli - xchgw %ds:0, %cx - movw %es:0x10, %ax - xchgw %ds:0, %cx - popfw - cmpw %ax, %cx - clc - jnz 99f - - /* Delay and retry */ - outb %al, $0x80 - addr32 loop 2b - stc - -99: /* Restore registers and return */ - popw %es - popw %ds - popw %ax - popl %ecx - ret - .size test_a20_long, . - test_a20_long - -/**************************************************************************** - * enable_a20_bios - * - * Try enabling A20 line via BIOS - * - * Parameters: - * none - * Returns: - * CF set if A20 line is not enabled - * Corrupts: - * none - **************************************************************************** - */ - .section ".text16.early", "awx", @progbits - .code16 -enable_a20_bios: - - /* Preserve registers. Be very paranoid, since some BIOSes - * are reported to clobber %ebx - */ - pushal - - /* Attempt INT 15,2401 */ - movw $0x2401, %ax - int $0x15 - jc 99f - - /* Check that success was really successful */ - call test_a20_short - -99: /* Restore registers and return */ - popal - ret - .size enable_a20_bios, . - enable_a20_bios - -/**************************************************************************** - * enable_a20_kbc - * - * Try enabling A20 line via keyboard controller - * - * Parameters: - * none - * Returns: - * CF set if A20 line is not enabled - * Corrupts: - * none - **************************************************************************** - */ -#define KC_RDWR 0x60 -#define KC_RDWR_SET_A20 0xdf -#define KC_CMD 0x64 -#define KC_CMD_WOUT 0xd1 -#define KC_CMD_NULL 0xff -#define KC_STATUS 0x64 -#define KC_STATUS_OBUF_FULL 0x01 -#define KC_STATUS_IBUF_FULL 0x02 -#define KC_MAX_RETRIES 100000 - .section ".text16.early", "awx", @progbits - .code16 -enable_a20_kbc: - /* Preserve registers */ - pushw %ax - - /* Try keyboard controller */ - call empty_kbc - movb $KC_CMD_WOUT, %al - outb %al, $KC_CMD - call empty_kbc - movb $KC_RDWR_SET_A20, %al - outb %al, $KC_RDWR - call empty_kbc - movb $KC_CMD_NULL, %al - outb %al, $KC_CMD - call empty_kbc - - /* Check to see if it worked */ - call test_a20_long - - /* Restore registers and return */ - popw %ax - ret - .size enable_a20_kbc, . - enable_a20_kbc - - .section ".text16.early", "awx", @progbits - .code16 -empty_kbc: - /* Preserve registers */ - pushl %ecx - pushw %ax - - /* Wait for KBC to become empty */ - movl $KC_MAX_RETRIES, %ecx -1: outb %al, $0x80 - inb $KC_STATUS, %al - testb $( KC_STATUS_OBUF_FULL | KC_STATUS_IBUF_FULL ), %al - jz 99f - testb $KC_STATUS_OBUF_FULL, %al - jz 2f - outb %al, $0x80 - inb $KC_RDWR, %al -2: addr32 loop 1b - -99: /* Restore registers and return */ - popw %ax - popl %ecx - ret - .size empty_kbc, . - empty_kbc - -/**************************************************************************** - * enable_a20_fast - * - * Try enabling A20 line via "Fast Gate A20" - * - * Parameters: - * none - * Returns: - * CF set if A20 line is not enabled - * Corrupts: - * none - **************************************************************************** - */ -#define SCP_A 0x92 - .section ".text16.early", "awx", @progbits - .code16 -enable_a20_fast: - /* Preserve registers */ - pushw %ax - - /* Try "Fast Gate A20" */ - inb $SCP_A, %al - orb $0x02, %al - andb $~0x01, %al - outb %al, $SCP_A - - /* Check to see if it worked */ - call test_a20_long - - /* Restore registers and return */ - popw %ax - ret - .size enable_a20_fast, . - enable_a20_fast - -/**************************************************************************** - * enable_a20 - * - * Try enabling A20 line via any available method - * - * Parameters: - * none - * Returns: - * CF set if A20 line is not enabled - * Corrupts: - * none - **************************************************************************** - */ -#define ENABLE_A20_RETRIES 255 - .section ".text16.early", "awx", @progbits - .code16 - .globl enable_a20 -enable_a20: - /* Preserve registers */ - pushl %ecx - pushw %ax - - /* Check to see if A20 is already enabled */ - call test_a20_short - jnc 99f - - /* Use known working method, if we have one */ - movw %cs:enable_a20_method, %ax - testw %ax, %ax - jz 1f - call *%ax - jmp 99f -1: - /* Try all methods in turn until one works */ - movl $ENABLE_A20_RETRIES, %ecx -2: movw $enable_a20_bios, %ax - movw %ax, %cs:enable_a20_method - call *%ax - jnc 99f - movw $enable_a20_kbc, %ax - movw %ax, %cs:enable_a20_method - call *%ax - jnc 99f - movw $enable_a20_fast, %ax - movw %ax, %cs:enable_a20_method - call *%ax - jnc 99f - addr32 loop 2b - /* Failure; exit with carry set */ - movw $0, %cs:enable_a20_method - stc - -99: /* Restore registers and return */ - popw %ax - popl %ecx - ret - - .section ".text16.early.data", "aw", @progbits - .align 2 -enable_a20_method: - .word 0 - .size enable_a20_method, . - enable_a20_method - -/**************************************************************************** - * access_highmem (real mode far call) - * - * Open up access to high memory with A20 enabled - * - * Parameters: - * none - * Returns: - * CF set if high memory could not be accessed - * Corrupts: - * none - **************************************************************************** - */ - .section ".text16.early", "awx", @progbits - .code16 - .globl access_highmem -access_highmem: - /* Enable A20 line */ - call enable_a20 - lret - .size access_highmem, . - access_highmem diff --git a/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S b/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S deleted file mode 100644 index fa9459d52..000000000 --- a/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S +++ /dev/null @@ -1,256 +0,0 @@ -/* - * libkir: a transition library for -DKEEP_IT_REAL - * - * Michael Brown <mbrown@fensystems.co.uk> - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) - -/**************************************************************************** - * This file defines libkir: an interface between external and - * internal environments when -DKEEP_IT_REAL is used, so that both - * internal and external environments are in real mode. It deals with - * switching data segments and the stack. It provides the following - * functions: - * - * ext_to_kir & switch between external and internal (kir) - * kir_to_ext environments, preserving all non-segment - * registers - * - * kir_call issue a call to an internal routine from external - * code - * - * libkir is written to avoid assuming that segments are anything - * other than opaque data types, and also avoids assuming that the - * stack pointer is 16-bit. This should enable it to run just as well - * in 16:16 or 16:32 protected mode as in real mode. - **************************************************************************** - */ - -/* Breakpoint for when debugging under bochs */ -#define BOCHSBP xchgw %bx, %bx - - .text - .arch i386 - .section ".text16", "awx", @progbits - .code16 - -/**************************************************************************** - * init_libkir (real-mode or 16:xx protected-mode far call) - * - * Initialise libkir ready for transitions to the kir environment - * - * Parameters: - * %cs : .text16 segment - * %ds : .data16 segment - **************************************************************************** - */ - .globl init_libkir -init_libkir: - /* Record segment registers */ - pushw %ds - popw %cs:kir_ds - lret - -/**************************************************************************** - * ext_to_kir (real-mode or 16:xx protected-mode near call) - * - * Switch from external stack and segment registers to internal stack - * and segment registers. %ss:sp is restored from the saved kir_ds - * and kir_sp. %ds, %es, %fs and %gs are all restored from the saved - * kir_ds. All other registers are preserved. - * - * %cs:0000 must point to the start of the runtime image code segment - * on entry. - * - * Parameters: none - **************************************************************************** - */ - - .globl ext_to_kir -ext_to_kir: - /* Record external segment registers */ - movw %ds, %cs:ext_ds - pushw %cs - popw %ds /* Set %ds = %cs for easier access to variables */ - movw %es, %ds:ext_es - movw %fs, %ds:ext_fs - movw %gs, %ds:ext_fs - - /* Preserve registers */ - movw %ax, %ds:save_ax - - /* Extract near return address from stack */ - popw %ds:save_retaddr - - /* Record external %ss:esp */ - movw %ss, %ds:ext_ss - movl %esp, %ds:ext_esp - - /* Load internal segment registers and stack pointer */ - movw %ds:kir_ds, %ax - movw %ax, %ss - movzwl %ds:kir_sp, %esp - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs -1: - - /* Place return address on new stack */ - pushw %cs:save_retaddr - - /* Restore registers and return */ - movw %cs:save_ax, %ax - ret - -/**************************************************************************** - * kir_to_ext (real-mode or 16:xx protected-mode near call) - * - * Switch from internal stack and segment registers to external stack - * and segment registers. %ss:%esp is restored from the saved ext_ss - * and ext_esp. Other segment registers are restored from the - * corresponding locations. All other registers are preserved. - * - * Note that it is actually %ss that is recorded as kir_ds, on the - * assumption that %ss == %ds when kir_to_ext is called. - * - * Parameters: none - **************************************************************************** - */ - - .globl kir_to_ext -kir_to_ext: - /* Record near return address */ - pushw %cs - popw %ds /* Set %ds = %cs for easier access to variables */ - popw %ds:save_retaddr - - /* Record internal segment registers and %sp */ - movw %ss, %ds:kir_ds - movw %sp, %ds:kir_sp - - /* Load external segment registers and stack pointer */ - movw %ds:ext_ss, %ss - movl %ds:ext_esp, %esp - movw %ds:ext_gs, %gs - movw %ds:ext_fs, %fs - movw %ds:ext_es, %es - movw %ds:ext_ds, %ds - - /* Return */ - pushw %cs:save_retaddr - ret - -/**************************************************************************** - * kir_call (real-mode or 16:xx protected-mode far call) - * - * Call a specific C function in the internal code. The prototype of - * the C function must be - * void function ( struct i386_all_resg *ix86 ); - * ix86 will point to a struct containing the real-mode registers - * at entry to kir_call. - * - * All registers will be preserved across kir_call(), unless the C - * function explicitly overwrites values in ix86. Interrupt status - * will also be preserved. - * - * Parameters: - * function : (32-bit) virtual address of C function to call - * - * Example usage: - * pushl $pxe_api_call - * lcall $UNDI_CS, $kir_call - * addw $4, %sp - * to call in to the C function - * void pxe_api_call ( struct i386_all_regs *ix86 ); - **************************************************************************** - */ - - .globl kir_call -kir_call: - /* Preserve flags. Must do this before any operation that may - * affect flags. - */ - pushfl - popl %cs:save_flags - - /* Disable interrupts. We do funny things with the stack, and - * we're not re-entrant. - */ - cli - - /* Extract address of internal routine from stack. We must do - * this without using (%bp), because we may be called with - * either a 16-bit or a 32-bit stack segment. - */ - popl %cs:save_retaddr /* Scratch location */ - popl %cs:save_function - subl $8, %esp /* Restore %esp */ - - /* Switch to internal stack. Note that the external stack is - * inaccessible once we're running internally (since we have - * no concept of 48-bit far pointers) - */ - call ext_to_kir - - /* Store external registers on internal stack */ - pushl %cs:save_flags - pushal - pushl %cs:ext_fs_and_gs - pushl %cs:ext_ds_and_es - pushl %cs:ext_cs_and_ss - - /* Push &ix86 on stack and call function */ - sti - pushl %esp - data32 call *%cs:save_function - popl %eax /* discard */ - - /* Restore external registers from internal stack */ - popl %cs:ext_cs_and_ss - popl %cs:ext_ds_and_es - popl %cs:ext_fs_and_gs - popal - popl %cs:save_flags - - /* Switch to external stack */ - call kir_to_ext - - /* Restore flags */ - pushl %cs:save_flags - popfl - - /* Return */ - lret - -/**************************************************************************** - * Stored internal and external stack and segment registers - **************************************************************************** - */ - -ext_cs_and_ss: -ext_cs: .word 0 -ext_ss: .word 0 -ext_ds_and_es: -ext_ds: .word 0 -ext_es: .word 0 -ext_fs_and_gs: -ext_fs: .word 0 -ext_gs: .word 0 -ext_esp: .long 0 - - .globl kir_ds -kir_ds: .word 0 - .globl kir_sp -kir_sp: .word _estack - -/**************************************************************************** - * Temporary variables - **************************************************************************** - */ -save_ax: .word 0 -save_retaddr: .long 0 -save_flags: .long 0 -save_function: .long 0 diff --git a/qemu/roms/ipxe/src/arch/i386/transitions/libpm.S b/qemu/roms/ipxe/src/arch/i386/transitions/libpm.S deleted file mode 100644 index e69de29bb..000000000 --- a/qemu/roms/ipxe/src/arch/i386/transitions/libpm.S +++ /dev/null diff --git a/qemu/roms/ipxe/src/arch/i386/transitions/librm.S b/qemu/roms/ipxe/src/arch/i386/transitions/librm.S deleted file mode 100644 index 863e22415..000000000 --- a/qemu/roms/ipxe/src/arch/i386/transitions/librm.S +++ /dev/null @@ -1,671 +0,0 @@ -/* - * librm: a library for interfacing to real-mode code - * - * Michael Brown <mbrown@fensystems.co.uk> - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) - -/* Drag in local definitions */ -#include "librm.h" - -/* For switches to/from protected mode */ -#define CR0_PE 1 - -/* Size of various C data structures */ -#define SIZEOF_I386_SEG_REGS 12 -#define SIZEOF_I386_REGS 32 -#define SIZEOF_REAL_MODE_REGS ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS ) -#define SIZEOF_I386_FLAGS 4 -#define SIZEOF_I386_ALL_REGS ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS ) - - .arch i386 - -/**************************************************************************** - * Global descriptor table - * - * Call init_librm to set up the GDT before attempting to use any - * protected-mode code. - * - * NOTE: This must be located before prot_to_real, otherwise gas - * throws a "can't handle non absolute segment in `ljmp'" error due to - * not knowing the value of REAL_CS when the ljmp is encountered. - * - * Note also that putting ".word gdt_end - gdt - 1" directly into - * gdt_limit, rather than going via gdt_length, will also produce the - * "non absolute segment" error. This is most probably a bug in gas. - **************************************************************************** - */ - .section ".data16", "aw", @progbits - .align 16 -gdt: -gdtr: /* The first GDT entry is unused, the GDTR can fit here. */ -gdt_limit: .word gdt_length - 1 -gdt_base: .long 0 - .word 0 /* padding */ - - .org gdt + VIRTUAL_CS, 0 -virtual_cs: /* 32 bit protected mode code segment, virtual addresses */ - .word 0xffff, 0 - .byte 0, 0x9f, 0xcf, 0 - - .org gdt + VIRTUAL_DS, 0 -virtual_ds: /* 32 bit protected mode data segment, virtual addresses */ - .word 0xffff, 0 - .byte 0, 0x93, 0xcf, 0 - - .org gdt + PHYSICAL_CS, 0 -physical_cs: /* 32 bit protected mode code segment, physical addresses */ - .word 0xffff, 0 - .byte 0, 0x9f, 0xcf, 0 - - .org gdt + PHYSICAL_DS, 0 -physical_ds: /* 32 bit protected mode data segment, physical addresses */ - .word 0xffff, 0 - .byte 0, 0x93, 0xcf, 0 - - .org gdt + REAL_CS, 0 -real_cs: /* 16 bit real mode code segment */ - .word 0xffff, 0 - .byte 0, 0x9b, 0x00, 0 - - .org gdt + REAL_DS -real_ds: /* 16 bit real mode data segment */ - .word 0xffff, ( REAL_DS << 4 ) - .byte 0, 0x93, 0x00, 0 - -gdt_end: - .equ gdt_length, gdt_end - gdt - -/**************************************************************************** - * init_librm (real-mode far call, 16-bit real-mode far return address) - * - * Initialise the GDT ready for transitions to protected mode. - * - * Parameters: - * %cs : .text16 segment - * %ds : .data16 segment - * %edi : Physical base of protected-mode code (virt_offset) - **************************************************************************** - */ - .section ".text16", "ax", @progbits - .code16 - .globl init_librm -init_librm: - /* Preserve registers */ - pushl %eax - pushl %ebx - - /* Store virt_offset and set up virtual_cs and virtual_ds segments */ - movl %edi, %eax - movw $virtual_cs, %bx - call set_seg_base - movw $virtual_ds, %bx - call set_seg_base - movl %edi, rm_virt_offset - - /* Negate virt_offset */ - negl %edi - - /* Store rm_cs and text16, set up real_cs segment */ - xorl %eax, %eax - movw %cs, %ax - movw %ax, %cs:rm_cs - shll $4, %eax - movw $real_cs, %bx - call set_seg_base - addr32 leal (%eax, %edi), %ebx - movl %ebx, rm_text16 - - /* Store rm_ds and data16 */ - xorl %eax, %eax - movw %ds, %ax - movw %ax, %cs:rm_ds - shll $4, %eax - addr32 leal (%eax, %edi), %ebx - movl %ebx, rm_data16 - - /* Set GDT base */ - movl %eax, gdt_base - addl $gdt, gdt_base - - /* Initialise IDT */ - pushl $init_idt - pushw %cs - call prot_call - popl %eax /* discard */ - - /* Restore registers */ - negl %edi - popl %ebx - popl %eax - lret - - .section ".text16", "ax", @progbits - .code16 -set_seg_base: -1: movw %ax, 2(%bx) - rorl $16, %eax - movb %al, 4(%bx) - movb %ah, 7(%bx) - roll $16, %eax - ret - -/**************************************************************************** - * real_to_prot (real-mode near call, 32-bit virtual return address) - * - * Switch from 16-bit real-mode to 32-bit protected mode with virtual - * addresses. The real-mode %ss:sp is stored in rm_ss and rm_sp, and - * the protected-mode %esp is restored from the saved pm_esp. - * Interrupts are disabled. All other registers may be destroyed. - * - * The return address for this function should be a 32-bit virtual - * address. - * - * Parameters: - * %ecx : number of bytes to move from RM stack to PM stack - * - **************************************************************************** - */ - .section ".text16", "ax", @progbits - .code16 -real_to_prot: - /* Enable A20 line */ - call enable_a20 - /* A failure at this point is fatal, and there's nothing we - * can do about it other than lock the machine to make the - * problem immediately visible. - */ -1: jc 1b - - /* Make sure we have our data segment available */ - movw %cs:rm_ds, %ax - movw %ax, %ds - - /* Add virt_offset, text16 and data16 to stack to be - * copied, and also copy the return address. - */ - pushl rm_virt_offset - pushl rm_text16 - pushl rm_data16 - addw $16, %cx /* %ecx must be less than 64kB anyway */ - - /* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */ - xorl %ebp, %ebp - movw %ss, %bp - movzwl %sp, %edx - movl %ebp, %eax - shll $4, %eax - addr32 leal (%eax,%edx), %esi - subl rm_virt_offset, %esi - - /* Load protected-mode global descriptor table */ - data32 lgdt gdtr - - /* Zero segment registers. This wastes around 12 cycles on - * real hardware, but saves a substantial number of emulated - * instructions under KVM. - */ - xorw %ax, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %ax, %ss - - /* Switch to protected mode */ - cli - movl %cr0, %eax - orb $CR0_PE, %al - movl %eax, %cr0 - data32 ljmp $VIRTUAL_CS, $r2p_pmode - .section ".text", "ax", @progbits - .code32 -r2p_pmode: - /* Set up protected-mode data segments and stack pointer */ - movw $VIRTUAL_DS, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %ax, %ss - movl pm_esp, %esp - - /* Load protected-mode interrupt descriptor table */ - lidt idtr - - /* Record real-mode %ss:sp (after removal of data) */ - movw %bp, rm_ss - addl %ecx, %edx - movw %dx, rm_sp - - /* Move data from RM stack to PM stack */ - subl %ecx, %esp - movl %esp, %edi - rep movsb - - /* Publish virt_offset, text16 and data16 for PM code to use */ - popl data16 - popl text16 - popl virt_offset - - /* Return to virtual address */ - ret - -/**************************************************************************** - * prot_to_real (protected-mode near call, 32-bit real-mode return address) - * - * Switch from 32-bit protected mode with virtual addresses to 16-bit - * real mode. The protected-mode %esp is stored in pm_esp and the - * real-mode %ss:sp is restored from the saved rm_ss and rm_sp. The - * high word of the real-mode %esp is set to zero. All real-mode data - * segment registers are loaded from the saved rm_ds. Interrupts are - * *not* enabled, since we want to be able to use prot_to_real in an - * ISR. All other registers may be destroyed. - * - * The return address for this function should be a 32-bit (sic) - * real-mode offset within .code16. - * - * Parameters: - * %ecx : number of bytes to move from PM stack to RM stack - * %esi : real-mode global and interrupt descriptor table registers - * - **************************************************************************** - */ - .section ".text", "ax", @progbits - .code32 -prot_to_real: - /* Copy real-mode global descriptor table register to RM code segment */ - movl text16, %edi - leal rm_gdtr(%edi), %edi - movsw - movsl - - /* Load real-mode interrupt descriptor table register */ - lidt (%esi) - - /* Add return address to data to be moved to RM stack */ - addl $4, %ecx - - /* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */ - movzwl rm_ss, %ebp - movzwl rm_sp, %edx - subl %ecx, %edx - movl %ebp, %eax - shll $4, %eax - leal (%eax,%edx), %edi - subl virt_offset, %edi - - /* Move data from PM stack to RM stack */ - movl %esp, %esi - rep movsb - - /* Record protected-mode %esp (after removal of data) */ - movl %esi, pm_esp - - /* Load real-mode segment limits */ - movw $REAL_DS, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %ax, %ss - ljmp $REAL_CS, $p2r_rmode - .section ".text16", "ax", @progbits - .code16 -p2r_rmode: - /* Load real-mode GDT */ - data32 lgdt %cs:rm_gdtr - /* Switch to real mode */ - movl %cr0, %eax - andb $0!CR0_PE, %al - movl %eax, %cr0 -p2r_ljmp_rm_cs: - ljmp $0, $1f -1: - /* Set up real-mode data segments and stack pointer */ - movw %cs:rm_ds, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %bp, %ss - movl %edx, %esp - - /* Return to real-mode address */ - data32 ret - - - /* Real-mode code and data segments. Assigned by the call to - * init_librm. rm_cs doubles as the segment part of the jump - * instruction used by prot_to_real. Both are located in - * .text16 rather than .data16: rm_cs since it forms part of - * the jump instruction within the code segment, and rm_ds - * since real-mode code needs to be able to locate the data - * segment with no other reference available. - */ - .globl rm_cs - .equ rm_cs, ( p2r_ljmp_rm_cs + 3 ) - - .section ".text16.data", "aw", @progbits - .globl rm_ds -rm_ds: .word 0 - - /* Real-mode global and interrupt descriptor table registers */ - .section ".text16.data", "aw", @progbits -rm_gdtr: - .word 0 /* Limit */ - .long 0 /* Base */ - -/**************************************************************************** - * prot_call (real-mode far call, 16-bit real-mode far return address) - * - * Call a specific C function in the protected-mode code. The - * prototype of the C function must be - * void function ( struct i386_all_regs *ix86 ); - * ix86 will point to a struct containing the real-mode registers - * at entry to prot_call. - * - * All registers will be preserved across prot_call(), unless the C - * function explicitly overwrites values in ix86. Interrupt status - * and GDT will also be preserved. Gate A20 will be enabled. - * - * Note that prot_call() does not rely on the real-mode stack - * remaining intact in order to return, since everything relevant is - * copied to the protected-mode stack for the duration of the call. - * In particular, this means that a real-mode prefix can make a call - * to main() which will return correctly even if the prefix's stack - * gets vapourised during the Etherboot run. (The prefix cannot rely - * on anything else on the stack being preserved, so should move any - * critical data to registers before calling main()). - * - * Parameters: - * function : virtual address of protected-mode function to call - * - * Example usage: - * pushl $pxe_api_call - * call prot_call - * addw $4, %sp - * to call in to the C function - * void pxe_api_call ( struct i386_all_regs *ix86 ); - **************************************************************************** - */ - -#define PC_OFFSET_GDT ( 0 ) -#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 6 ) -#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 6 ) -#define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS ) -#define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 ) -#define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 ) - - .section ".text16", "ax", @progbits - .code16 - .globl prot_call -prot_call: - /* Preserve registers, flags and GDT on external RM stack */ - pushfl - pushal - pushw %gs - pushw %fs - pushw %es - pushw %ds - pushw %ss - pushw %cs - subw $PC_OFFSET_IX86, %sp - movw %sp, %bp - sidt PC_OFFSET_IDT(%bp) - sgdt PC_OFFSET_GDT(%bp) - - /* For sanity's sake, clear the direction flag as soon as possible */ - cld - - /* Switch to protected mode and move register dump to PM stack */ - movl $PC_OFFSET_END, %ecx - pushl $pc_pmode - jmp real_to_prot - .section ".text", "ax", @progbits - .code32 -pc_pmode: - /* Call function */ - leal PC_OFFSET_IX86(%esp), %eax - pushl %eax - call *(PC_OFFSET_FUNCTION+4)(%esp) - popl %eax /* discard */ - - /* Switch to real mode and move register dump back to RM stack */ - movl $PC_OFFSET_END, %ecx - movl %esp, %esi - pushl $pc_rmode - jmp prot_to_real - .section ".text16", "ax", @progbits - .code16 -pc_rmode: - /* Restore registers and flags and return */ - addw $( PC_OFFSET_IX86 + 4 /* also skip %cs and %ss */ ), %sp - popw %ds - popw %es - popw %fs - popw %gs - popal - /* popal skips %esp. We therefore want to do "movl -20(%sp), - * %esp", but -20(%sp) is not a valid 80386 expression. - * Fortunately, prot_to_real() zeroes the high word of %esp, so - * we can just use -20(%esp) instead. - */ - addr32 movl -20(%esp), %esp - popfl - lret - -/**************************************************************************** - * real_call (protected-mode near call, 32-bit virtual return address) - * - * Call a real-mode function from protected-mode code. - * - * The non-segment register values will be passed directly to the - * real-mode code. The segment registers will be set as per - * prot_to_real. The non-segment register values set by the real-mode - * function will be passed back to the protected-mode caller. A - * result of this is that this routine cannot be called directly from - * C code, since it clobbers registers that the C ABI expects the - * callee to preserve. - * - * librm.h defines a convenient macro REAL_CODE() for using real_call. - * See librm.h and realmode.h for details and examples. - * - * Parameters: - * (32-bit) near pointer to real-mode function to call - * - * Returns: none - **************************************************************************** - */ - -#define RC_OFFSET_PRESERVE_REGS ( 0 ) -#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + SIZEOF_I386_REGS ) -#define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 ) -#define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 ) - - .section ".text", "ax", @progbits - .code32 - .globl real_call -real_call: - /* Create register dump and function pointer copy on PM stack */ - pushal - pushl RC_OFFSET_FUNCTION(%esp) - - /* Switch to real mode and move register dump to RM stack */ - movl $( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx - pushl $rc_rmode - movl $rm_default_gdtr_idtr, %esi - jmp prot_to_real - .section ".text16", "ax", @progbits - .code16 -rc_rmode: - /* Call real-mode function */ - popl rc_function - popal - call *rc_function - pushal - - /* For sanity's sake, clear the direction flag as soon as possible */ - cld - - /* Switch to protected mode and move register dump back to PM stack */ - movl $RC_OFFSET_RETADDR, %ecx - pushl $rc_pmode - jmp real_to_prot - .section ".text", "ax", @progbits - .code32 -rc_pmode: - /* Restore registers and return */ - popal - ret - - - /* Function vector, used because "call xx(%sp)" is not a valid - * 16-bit expression. - */ - .section ".data16", "aw", @progbits -rc_function: .word 0, 0 - - /* Default real-mode global and interrupt descriptor table registers */ - .section ".data", "aw", @progbits -rm_default_gdtr_idtr: - .word 0 /* Global descriptor table limit */ - .long 0 /* Global descriptor table base */ - .word 0x03ff /* Interrupt descriptor table limit */ - .long 0 /* Interrupt descriptor table base */ - -/**************************************************************************** - * flatten_real_mode (real-mode near call) - * - * Switch to flat real mode - * - **************************************************************************** - */ - .section ".text16", "ax", @progbits - .code16 - .globl flatten_real_mode -flatten_real_mode: - /* Modify GDT to use flat real mode */ - movb $0x8f, real_cs + 6 - movb $0x8f, real_ds + 6 - /* Call dummy protected-mode function */ - pushl $flatten_dummy - pushw %cs - call prot_call - addw $4, %sp - /* Restore GDT */ - movb $0x00, real_cs + 6 - movb $0x00, real_ds + 6 - /* Return */ - ret - - .section ".text", "ax", @progbits - .code32 -flatten_dummy: - ret - -/**************************************************************************** - * Interrupt wrapper - * - * Used by the protected-mode interrupt vectors to call the - * interrupt() function. - * - * May be entered with either physical or virtual stack segment. - **************************************************************************** - */ - .globl interrupt_wrapper -interrupt_wrapper: - /* Preserve segment registers and original %esp */ - pushl %ds - pushl %es - pushl %fs - pushl %gs - pushl %ss - pushl %esp - - /* Switch to virtual addressing */ - call _intr_to_virt - - /* Expand IRQ number to whole %eax register */ - movzbl %al, %eax - - /* Call interrupt handler */ - call interrupt - - /* Restore original stack and segment registers */ - lss (%esp), %esp - popl %ss - popl %gs - popl %fs - popl %es - popl %ds - - /* Restore registers and return */ - popal - iret - -/**************************************************************************** - * Stored real-mode and protected-mode stack pointers - * - * The real-mode stack pointer is stored here whenever real_to_prot - * is called and restored whenever prot_to_real is called. The - * converse happens for the protected-mode stack pointer. - * - * Despite initial appearances this scheme is, in fact re-entrant, - * because program flow dictates that we always return via the point - * we left by. For example: - * PXE API call entry - * 1 real => prot - * ... - * Print a text string - * ... - * 2 prot => real - * INT 10 - * 3 real => prot - * ... - * ... - * 4 prot => real - * PXE API call exit - * - * At point 1, the RM mode stack value, say RPXE, is stored in - * rm_ss,sp. We want this value to still be present in rm_ss,sp when - * we reach point 4. - * - * At point 2, the RM stack value is restored from RPXE. At point 3, - * the RM stack value is again stored in rm_ss,sp. This *does* - * overwrite the RPXE that we have stored there, but it's the same - * value, since the code between points 2 and 3 has managed to return - * to us. - **************************************************************************** - */ - .section ".data", "aw", @progbits - .globl rm_sp -rm_sp: .word 0 - .globl rm_ss -rm_ss: .word 0 -pm_esp: .long _estack - -/**************************************************************************** - * Virtual address offsets - * - * These are used by the protected-mode code to map between virtual - * and physical addresses, and to access variables in the .text16 or - * .data16 segments. - **************************************************************************** - */ - /* Internal copies, created by init_librm (which runs in real mode) */ - .section ".data16", "aw", @progbits -rm_virt_offset: .long 0 -rm_text16: .long 0 -rm_data16: .long 0 - - /* Externally-visible copies, created by real_to_prot */ - .section ".data", "aw", @progbits - .globl virt_offset -virt_offset: .long 0 - .globl text16 -text16: .long 0 - .globl data16 -data16: .long 0 diff --git a/qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c b/qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c deleted file mode 100644 index becb02677..000000000 --- a/qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * librm: a library for interfacing to real-mode code - * - * Michael Brown <mbrown@fensystems.co.uk> - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include <stdint.h> -#include <ipxe/profile.h> -#include <realmode.h> -#include <pic8259.h> - -/* - * This file provides functions for managing librm. - * - */ - -/** The interrupt wrapper */ -extern char interrupt_wrapper[]; - -/** The interrupt vectors */ -static struct interrupt_vector intr_vec[NUM_INT]; - -/** The interrupt descriptor table */ -struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) )); - -/** The interrupt descriptor table register */ -struct idtr idtr = { - .limit = ( sizeof ( idt ) - 1 ), -}; - -/** Timer interrupt profiler */ -static struct profiler timer_irq_profiler __profiler = { .name = "irq.timer" }; - -/** Other interrupt profiler */ -static struct profiler other_irq_profiler __profiler = { .name = "irq.other" }; - -/** - * Allocate space on the real-mode stack and copy data there from a - * user buffer - * - * @v data User buffer - * @v size Size of stack data - * @ret sp New value of real-mode stack pointer - */ -uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { - userptr_t rm_stack; - rm_sp -= size; - rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); - return rm_sp; -}; - -/** - * Deallocate space on the real-mode stack, optionally copying back - * data to a user buffer. - * - * @v data User buffer - * @v size Size of stack data - */ -void remove_user_from_rm_stack ( userptr_t data, size_t size ) { - if ( data ) { - userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); - } - rm_sp += size; -}; - -/** - * Set interrupt vector - * - * @v intr Interrupt number - * @v vector Interrupt vector, or NULL to disable - */ -void set_interrupt_vector ( unsigned int intr, void *vector ) { - struct interrupt_descriptor *idte; - - idte = &idt[intr]; - idte->segment = VIRTUAL_CS; - idte->attr = ( vector ? ( IDTE_PRESENT | IDTE_TYPE_IRQ32 ) : 0 ); - idte->low = ( ( ( uint32_t ) vector ) & 0xffff ); - idte->high = ( ( ( uint32_t ) vector ) >> 16 ); -} - -/** - * Initialise interrupt descriptor table - * - */ -void init_idt ( void ) { - struct interrupt_vector *vec; - unsigned int intr; - - /* Initialise the interrupt descriptor table and interrupt vectors */ - for ( intr = 0 ; intr < NUM_INT ; intr++ ) { - vec = &intr_vec[intr]; - vec->pushal = PUSHAL_INSN; - vec->movb = MOVB_INSN; - vec->intr = intr; - vec->jmp = JMP_INSN; - vec->offset = ( ( uint32_t ) interrupt_wrapper - - ( uint32_t ) vec->next ); - set_interrupt_vector ( intr, vec ); - } - DBGC ( &intr_vec[0], "INTn vector at %p+%zxn (phys %#lx+%zxn)\n", - intr_vec, sizeof ( intr_vec[0] ), - virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) ); - - /* Initialise the interrupt descriptor table register */ - idtr.base = virt_to_phys ( idt ); -} - -/** - * Determine interrupt profiler (for debugging) - * - * @v intr Interrupt number - * @ret profiler Profiler - */ -static struct profiler * interrupt_profiler ( int intr ) { - - switch ( intr ) { - case IRQ_INT ( 0 ) : - return &timer_irq_profiler; - default: - return &other_irq_profiler; - } -} - -/** - * Interrupt handler - * - * @v intr Interrupt number - */ -void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int intr ) { - struct profiler *profiler = interrupt_profiler ( intr ); - uint32_t discard_eax; - - /* Reissue interrupt in real mode */ - profile_start ( profiler ); - __asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t" - "\n1:\n\t" - "int $0x00\n\t" ) - : "=a" ( discard_eax ) : "0" ( intr ) ); - profile_stop ( profiler ); - profile_exclude ( profiler ); -} - -PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); -PROVIDE_UACCESS_INLINE ( librm, user_to_phys ); -PROVIDE_UACCESS_INLINE ( librm, virt_to_user ); -PROVIDE_UACCESS_INLINE ( librm, user_to_virt ); -PROVIDE_UACCESS_INLINE ( librm, userptr_add ); -PROVIDE_UACCESS_INLINE ( librm, memcpy_user ); -PROVIDE_UACCESS_INLINE ( librm, memmove_user ); -PROVIDE_UACCESS_INLINE ( librm, memset_user ); -PROVIDE_UACCESS_INLINE ( librm, strlen_user ); -PROVIDE_UACCESS_INLINE ( librm, memchr_user ); diff --git a/qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c b/qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c deleted file mode 100644 index f1a517eda..000000000 --- a/qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2014 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 ); - -/** @file - * - * Real mode transition self-tests - * - * This file allows for easy measurement of the time taken to perform - * real mode transitions, which may have a substantial overhead when - * running under a hypervisor. - * - */ - -/* Forcibly enable assertions */ -#undef NDEBUG - -#include <ipxe/test.h> -#include <ipxe/profile.h> -#include <realmode.h> - -/** Number of sample iterations for profiling */ -#define PROFILE_COUNT 4096 - -/** Protected-to-real mode transition profiler */ -static struct profiler p2r_profiler __profiler = { .name = "p2r" }; - -/** Real-to-protected mode transition profiler */ -static struct profiler r2p_profiler __profiler = { .name = "r2p" }; - -/** Real-mode call profiler */ -static struct profiler real_call_profiler __profiler = { .name = "real_call" }; - -/** Protected-mode call profiler */ -static struct profiler prot_call_profiler __profiler = { .name = "prot_call" }; - -/** - * Dummy protected-mode function - */ -static void librm_test_prot_call ( void ) { - /* Do nothing */ -} - -/** - * Perform real mode transition self-tests - * - */ -static void librm_test_exec ( void ) { - unsigned int i; - unsigned long timestamp; - unsigned long started; - unsigned long stopped; - unsigned int discard_d; - - /* Profile mode transitions. We want to profile each - * direction of the transition separately, so perform an RDTSC - * while in real mode and tweak the profilers' start/stop - * times appropriately. - */ - for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { - profile_start ( &p2r_profiler ); - __asm__ __volatile__ ( REAL_CODE ( "rdtsc\n\t" ) - : "=a" ( timestamp ), "=d" ( discard_d ) - : ); - profile_start_at ( &r2p_profiler, timestamp ); - profile_stop ( &r2p_profiler ); - profile_stop_at ( &p2r_profiler, timestamp ); - } - - /* Profile complete real-mode call cycle */ - for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { - profile_start ( &real_call_profiler ); - __asm__ __volatile__ ( REAL_CODE ( "" ) : : ); - profile_stop ( &real_call_profiler ); - } - - /* Profile complete protected-mode call cycle */ - for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { - __asm__ __volatile__ ( REAL_CODE ( "rdtsc\n\t" - "movl %0, %2\n\t" - "pushl %3\n\t" - "pushw %%cs\n\t" - "call prot_call\n\t" - "addw $4, %%sp\n\t" - "rdtsc\n\t" ) - : "=a" ( stopped ), "=d" ( discard_d ), - "=r" ( started ) - : "i" ( librm_test_prot_call ) ); - profile_start_at ( &prot_call_profiler, started ); - profile_stop_at ( &prot_call_profiler, stopped ); - } -} - -/** Real mode transition self-test */ -struct self_test librm_test __self_test = { - .name = "librm", - .exec = librm_test_exec, -}; - -REQUIRING_SYMBOL ( librm_test ); -REQUIRE_OBJECT ( test ); |