mirror of https://github.com/ipxe/ipxe.git
[comboot] Support COMBOOT in 64-bit builds
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/52/head
parent
4afb758423
commit
5e5450c2d0
|
@ -83,9 +83,7 @@ endif
|
|||
# i386-specific directories containing source files
|
||||
#
|
||||
SRCDIRS += arch/i386/core
|
||||
SRCDIRS += arch/i386/image
|
||||
SRCDIRS += arch/i386/tests
|
||||
SRCDIRS += arch/i386/interface/syslinux
|
||||
|
||||
# Include common x86 Makefile
|
||||
#
|
||||
|
|
|
@ -16,6 +16,7 @@ SRCDIRS += arch/x86/interface/pxe
|
|||
SRCDIRS += arch/x86/interface/pxeparent
|
||||
SRCDIRS += arch/x86/interface/efi
|
||||
SRCDIRS += arch/x86/interface/vmware
|
||||
SRCDIRS += arch/x86/interface/syslinux
|
||||
SRCDIRS += arch/x86/prefix
|
||||
SRCDIRS += arch/x86/hci/commands
|
||||
SRCDIRS += arch/x86/drivers/xen
|
||||
|
|
|
@ -76,8 +76,6 @@ static int com32_exec_loop ( struct image *image ) {
|
|||
|
||||
assert ( avail_mem_top != 0 );
|
||||
|
||||
com32_external_esp = phys_to_virt ( avail_mem_top );
|
||||
|
||||
/* Hook COMBOOT API interrupts */
|
||||
hook_comboot_interrupts();
|
||||
|
||||
|
@ -88,34 +86,44 @@ static int com32_exec_loop ( struct image *image ) {
|
|||
*/
|
||||
unregister_image ( image );
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */
|
||||
"movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */
|
||||
"call _virt_to_phys\n\t" /* Switch to flat physical address space */
|
||||
"sti\n\t" /* Enable interrupts */
|
||||
"pushl %0\n\t" /* Pointer to CDECL helper function */
|
||||
"pushl %1\n\t" /* Pointer to FAR call helper function */
|
||||
"pushl %2\n\t" /* Size of low memory bounce buffer */
|
||||
"pushl %3\n\t" /* Pointer to low memory bounce buffer */
|
||||
"pushl %4\n\t" /* Pointer to INT call helper function */
|
||||
"pushl %5\n\t" /* Pointer to the command line arguments */
|
||||
"pushl $6\n\t" /* Number of additional arguments */
|
||||
"call *%6\n\t" /* Execute image */
|
||||
"cli\n\t" /* Disable interrupts */
|
||||
"call _phys_to_virt\n\t" /* Switch back to internal virtual address space */
|
||||
"movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */
|
||||
:
|
||||
:
|
||||
/* %0 */ "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
|
||||
/* %1 */ "r" ( virt_to_phys ( com32_farcall_wrapper ) ),
|
||||
/* %2 */ "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ),
|
||||
/* %3 */ "i" ( COM32_BOUNCE_SEG << 4 ),
|
||||
/* %4 */ "r" ( virt_to_phys ( com32_intcall_wrapper ) ),
|
||||
/* %5 */ "r" ( virt_to_phys ( image->cmdline ?
|
||||
image->cmdline : "" ) ),
|
||||
/* %6 */ "r" ( COM32_START_PHYS )
|
||||
:
|
||||
"memory" );
|
||||
__asm__ __volatile__ ( PHYS_CODE (
|
||||
/* Preserve registers */
|
||||
"pushal\n\t"
|
||||
/* Preserve stack pointer */
|
||||
"subl $4, %k0\n\t"
|
||||
"movl %%esp, (%k0)\n\t"
|
||||
/* Switch to COM32 stack */
|
||||
"movl %k0, %%esp\n\t"
|
||||
/* Enable interrupts */
|
||||
"sti\n\t"
|
||||
/* Construct stack frame */
|
||||
"pushl %k1\n\t"
|
||||
"pushl %k2\n\t"
|
||||
"pushl %k3\n\t"
|
||||
"pushl %k4\n\t"
|
||||
"pushl %k5\n\t"
|
||||
"pushl %k6\n\t"
|
||||
"pushl $6\n\t"
|
||||
/* Call COM32 entry point */
|
||||
"movl %k7, %k0\n\t"
|
||||
"call *%k0\n\t"
|
||||
/* Disable interrupts */
|
||||
"cli\n\t"
|
||||
/* Restore stack pointer */
|
||||
"movl 24(%%esp), %%esp\n\t"
|
||||
/* Restore registers */
|
||||
"popal\n\t" )
|
||||
:
|
||||
: "r" ( avail_mem_top ),
|
||||
"r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
|
||||
"r" ( virt_to_phys ( com32_farcall_wrapper ) ),
|
||||
"r" ( get_fbms() * 1024 - ( COM32_BOUNCE_SEG << 4 ) ),
|
||||
"i" ( COM32_BOUNCE_SEG << 4 ),
|
||||
"r" ( virt_to_phys ( com32_intcall_wrapper ) ),
|
||||
"r" ( virt_to_phys ( image->cmdline ?
|
||||
image->cmdline : "" ) ),
|
||||
"i" ( COM32_START_PHYS )
|
||||
: "memory" );
|
||||
DBGC ( image, "COM32 %p: returned\n", image );
|
||||
break;
|
||||
|
||||
|
@ -147,7 +155,7 @@ static int com32_exec_loop ( struct image *image ) {
|
|||
|
||||
/**
|
||||
* Check image name extension
|
||||
*
|
||||
*
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
|
@ -155,7 +163,7 @@ static int com32_identify ( struct image *image ) {
|
|||
const char *ext;
|
||||
static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
|
||||
uint8_t buf[5];
|
||||
|
||||
|
||||
if ( image->len >= 5 ) {
|
||||
/* Check for magic number
|
||||
* mov eax,21cd4cffh
|
|
@ -64,7 +64,7 @@ struct comboot_psp {
|
|||
|
||||
/**
|
||||
* Copy command line to PSP
|
||||
*
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
*/
|
||||
static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) {
|
||||
|
@ -97,7 +97,7 @@ static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr )
|
|||
|
||||
/**
|
||||
* Initialize PSP
|
||||
*
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
* @v seg_userptr segment to initialize
|
||||
*/
|
||||
|
@ -213,7 +213,7 @@ static int comboot_exec_loop ( struct image *image ) {
|
|||
|
||||
/**
|
||||
* Check image name extension
|
||||
*
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
|
@ -254,7 +254,7 @@ static int comboot_prepare_segment ( struct image *image )
|
|||
seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
|
||||
|
||||
/* Allow etra 0x100 bytes before image for PSP */
|
||||
filesz = image->len + 0x100;
|
||||
filesz = image->len + 0x100;
|
||||
|
||||
/* Ensure the entire 64k segment is free */
|
||||
memsz = 0xFFFF;
|
||||
|
@ -289,7 +289,7 @@ static int comboot_probe ( struct image *image ) {
|
|||
|
||||
/* Check if this is a COMBOOT image */
|
||||
if ( ( rc = comboot_identify ( image ) ) != 0 ) {
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -304,7 +304,7 @@ static int comboot_probe ( struct image *image ) {
|
|||
*/
|
||||
static int comboot_exec ( struct image *image ) {
|
||||
int rc;
|
||||
|
||||
|
||||
/* Sanity check for filesize */
|
||||
if( image->len >= 0xFF00 ) {
|
||||
DBGC( image, "COMBOOT %p: image too large\n",
|
|
@ -29,7 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
#define COMBOOT_FEATURE_LOCAL_BOOT (1 << 0)
|
||||
#define COMBOOT_FEATURE_IDLE_LOOP (1 << 1)
|
||||
|
||||
/** Maximum number of shuffle descriptors for
|
||||
/** Maximum number of shuffle descriptors for
|
||||
* shuffle and boot functions
|
||||
* (INT 22h AX=0012h, 001Ah, 001Bh)
|
||||
*/
|
||||
|
@ -102,7 +102,7 @@ typedef struct {
|
|||
extern void hook_comboot_interrupts ( );
|
||||
extern void unhook_comboot_interrupts ( );
|
||||
|
||||
/* These are not the correct prototypes, but it doens't matter,
|
||||
/* These are not the correct prototypes, but it doens't matter,
|
||||
* as we only ever get the address of these functions;
|
||||
* they are only called from COM32 code running in PHYS_CODE
|
||||
*/
|
||||
|
@ -116,8 +116,6 @@ extern int comboot_resolv ( const char *name, struct in_addr *address );
|
|||
/* setjmp/longjmp context buffer used to return after loading an image */
|
||||
extern rmjmp_buf comboot_return;
|
||||
|
||||
extern void *com32_external_esp;
|
||||
|
||||
#define COMBOOT_EXIT 1
|
||||
#define COMBOOT_EXIT_RUN_KERNEL 2
|
||||
#define COMBOOT_EXIT_COMMAND 3
|
|
@ -46,6 +46,9 @@ uint16_t __bss16 ( com32_saved_sp );
|
|||
*/
|
||||
void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
|
||||
|
||||
DBGC ( &com32_regs, "COM32 INT%x in %#08lx out %#08lx\n",
|
||||
interrupt, inregs_phys, outregs_phys );
|
||||
|
||||
memcpy_user ( virt_to_user( &com32_regs ), 0,
|
||||
phys_to_user ( inregs_phys ), 0,
|
||||
sizeof(com32sys_t) );
|
||||
|
@ -76,7 +79,7 @@ void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physad
|
|||
/* patch INT instruction */
|
||||
"pushw %%ax\n\t"
|
||||
"movb %%ss:(com32_int_vector), %%al\n\t"
|
||||
"movb %%al, %%cs:(com32_intcall_instr + 1)\n\t"
|
||||
"movb %%al, %%cs:(com32_intcall_instr + 1)\n\t"
|
||||
/* perform a jump to avoid problems with cache
|
||||
* consistency in self-modifying code on some CPUs (486)
|
||||
*/
|
||||
|
@ -106,7 +109,7 @@ void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physad
|
|||
|
||||
if ( outregs_phys ) {
|
||||
memcpy_user ( phys_to_user ( outregs_phys ), 0,
|
||||
virt_to_user( &com32_regs ), 0,
|
||||
virt_to_user( &com32_regs ), 0,
|
||||
sizeof(com32sys_t) );
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +119,9 @@ void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physad
|
|||
*/
|
||||
void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
|
||||
|
||||
DBGC ( &com32_regs, "COM32 farcall %04x:%04x in %#08lx out %#08lx\n",
|
||||
( proc >> 16 ), ( proc & 0xffff ), inregs_phys, outregs_phys );
|
||||
|
||||
memcpy_user ( virt_to_user( &com32_regs ), 0,
|
||||
phys_to_user ( inregs_phys ), 0,
|
||||
sizeof(com32sys_t) );
|
||||
|
@ -165,7 +171,7 @@ void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t
|
|||
|
||||
if ( outregs_phys ) {
|
||||
memcpy_user ( phys_to_user ( outregs_phys ), 0,
|
||||
virt_to_user( &com32_regs ), 0,
|
||||
virt_to_user( &com32_regs ), 0,
|
||||
sizeof(com32sys_t) );
|
||||
}
|
||||
}
|
||||
|
@ -176,13 +182,16 @@ void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t
|
|||
int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
|
||||
int32_t eax;
|
||||
|
||||
DBGC ( &com32_regs, "COM32 cfarcall %04x:%04x params %#08lx+%#zx\n",
|
||||
( proc >> 16 ), ( proc & 0xffff ), stack, stacksz );
|
||||
|
||||
copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz );
|
||||
com32_farcall_proc = proc;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" )
|
||||
: "=a" (eax)
|
||||
:
|
||||
:
|
||||
: "ecx", "edx" );
|
||||
|
||||
remove_user_from_rm_stack ( 0, stacksz );
|
|
@ -19,79 +19,82 @@
|
|||
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.code32
|
||||
#include "librm.h"
|
||||
|
||||
.text
|
||||
|
||||
.code32
|
||||
.globl com32_farcall_wrapper
|
||||
com32_farcall_wrapper:
|
||||
movl $VIRTUAL(com32_farcall), %eax
|
||||
jmp com32_wrapper
|
||||
|
||||
movl $com32_farcall, %eax
|
||||
jmp com32_wrapper
|
||||
|
||||
|
||||
.code32
|
||||
.globl com32_cfarcall_wrapper
|
||||
com32_cfarcall_wrapper:
|
||||
movl $VIRTUAL(com32_cfarcall), %eax
|
||||
jmp com32_wrapper
|
||||
|
||||
movl $com32_cfarcall, %eax
|
||||
jmp com32_wrapper
|
||||
|
||||
|
||||
.code32
|
||||
.globl com32_intcall_wrapper
|
||||
com32_intcall_wrapper:
|
||||
movl $VIRTUAL(com32_intcall), %eax
|
||||
/* fall through */
|
||||
|
||||
movl $com32_intcall, %eax
|
||||
/*jmp com32_wrapper*/ /* fall through */
|
||||
|
||||
.code32
|
||||
com32_wrapper:
|
||||
|
||||
/* Disable interrupts */
|
||||
cli
|
||||
|
||||
/* Switch to internal virtual address space */
|
||||
call _phys_to_virt
|
||||
call _phys_to_virt
|
||||
|
||||
mov %eax, (com32_helper_function)
|
||||
#ifdef __x86_64__
|
||||
|
||||
/* Save external COM32 stack pointer */
|
||||
movl %esp, (com32_external_esp)
|
||||
.code64
|
||||
|
||||
/* Copy arguments to caller-save registers */
|
||||
movl 12(%esp), %eax
|
||||
movl 8(%esp), %ecx
|
||||
movl 4(%esp), %edx
|
||||
/* Preserve registers which are callee-save for COM32 (i386 API) */
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %rbp
|
||||
|
||||
/* Switch to internal stack */
|
||||
movl (com32_internal_esp), %esp
|
||||
/* Extract parameters from stack */
|
||||
movl 28(%rsp), %edi
|
||||
movl 32(%rsp), %esi
|
||||
movl 36(%rsp), %edx
|
||||
|
||||
/* Copy arguments to internal stack */
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
/* Align stack pointer */
|
||||
movq %rsp, %rbp
|
||||
andq $~0x07, %rsp
|
||||
|
||||
call *(com32_helper_function)
|
||||
/* Call helper function */
|
||||
movslq %eax, %rax
|
||||
call *%rax
|
||||
|
||||
/* Clean up stack */
|
||||
addl $12, %esp
|
||||
/* Restore stack pointer */
|
||||
movq %rbp, %rsp
|
||||
|
||||
/* Save internal stack pointer and restore external stack pointer */
|
||||
movl %esp, (com32_internal_esp)
|
||||
movl (com32_external_esp), %esp
|
||||
/* Restore registers */
|
||||
popq %rbp
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
|
||||
#else /* _x86_64 */
|
||||
|
||||
/* Call helper function */
|
||||
pushl 12(%esp)
|
||||
pushl 12(%esp)
|
||||
pushl 12(%esp)
|
||||
call *%eax
|
||||
addl $12, %esp
|
||||
|
||||
#endif /* _x86_64 */
|
||||
|
||||
/* Switch to external flat physical address space */
|
||||
call _virt_to_phys
|
||||
call _virt_to_phys
|
||||
.code32
|
||||
|
||||
/* Reenable interrupts and return */
|
||||
sti
|
||||
ret
|
||||
|
||||
|
||||
.data
|
||||
|
||||
/* Internal iPXE virtual address space %esp */
|
||||
.globl com32_internal_esp
|
||||
.lcomm com32_internal_esp, 4
|
||||
|
||||
/* External flat physical address space %esp */
|
||||
.globl com32_external_esp
|
||||
.lcomm com32_external_esp, 4
|
||||
|
||||
/* Function pointer of helper to call */
|
||||
.lcomm com32_helper_function, 4
|
|
@ -489,7 +489,7 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
|
|||
struct in_addr addr;
|
||||
|
||||
copy_from_user ( hostname, hostname_u, 0, len + 1 );
|
||||
|
||||
|
||||
/* TODO:
|
||||
* "If the hostname does not contain a dot (.), the
|
||||
* local domain name is automatically appended."
|
||||
|
@ -519,7 +519,7 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
|
|||
|
||||
/* Jump to real-mode entry point */
|
||||
__asm__ __volatile__ (
|
||||
REAL_CODE (
|
||||
REAL_CODE (
|
||||
"pushw %0\n\t"
|
||||
"popw %%ds\n\t"
|
||||
"pushl %1\n\t"
|
|
@ -37,4 +37,3 @@ source: dd 0
|
|||
dd shuffle_len
|
||||
|
||||
num_shuffle_descriptors equ 1
|
||||
|
|
@ -567,9 +567,10 @@ phys_to_prot:
|
|||
popl %eax
|
||||
ret
|
||||
|
||||
/* Expose as _phys_to_virt for use by COMBOOT */
|
||||
.if32 /* Expose as _phys_to_virt for use by COMBOOT, if applicable */
|
||||
.globl _phys_to_virt
|
||||
.equ _phys_to_virt, phys_to_prot
|
||||
.endif
|
||||
|
||||
/****************************************************************************
|
||||
* prot_to_phys (protected-mode near call, 32-bit virtual return address)
|
||||
|
@ -615,9 +616,10 @@ prot_to_phys:
|
|||
popl %eax
|
||||
ret
|
||||
|
||||
/* Expose as _virt_to_phys for use by COMBOOT */
|
||||
.if32 /* Expose as _virt_to_phys for use by COMBOOT, if applicable */
|
||||
.globl _virt_to_phys
|
||||
.equ _virt_to_phys, prot_to_phys
|
||||
.endif
|
||||
|
||||
/****************************************************************************
|
||||
* intr_to_prot (protected-mode near call, 32-bit virtual return address)
|
||||
|
@ -1202,6 +1204,66 @@ phys_call:
|
|||
/* Return and discard function parameters */
|
||||
ret $( PHC_OFFSET_END - PHC_OFFSET_PARAMS )
|
||||
|
||||
/****************************************************************************
|
||||
* phys_to_long (protected-mode near call, 32-bit physical return address)
|
||||
*
|
||||
* Used by COMBOOT.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.if64
|
||||
|
||||
.section ".text.phys_to_long", "ax", @progbits
|
||||
.code32
|
||||
phys_to_long:
|
||||
|
||||
/* Switch to virtual addresses */
|
||||
call phys_to_prot
|
||||
|
||||
/* Convert to 32-bit virtual return address */
|
||||
pushl %eax
|
||||
movl VIRTUAL(virt_offset), %eax
|
||||
subl %eax, 4(%esp)
|
||||
popl %eax
|
||||
|
||||
/* Switch to long mode and return */
|
||||
jmp prot_to_long
|
||||
|
||||
/* Expose as _phys_to_virt for use by COMBOOT */
|
||||
.globl _phys_to_virt
|
||||
.equ _phys_to_virt, phys_to_long
|
||||
|
||||
.endif
|
||||
|
||||
/****************************************************************************
|
||||
* long_to_phys (long-mode near call, 64-bit virtual return address)
|
||||
*
|
||||
* Used by COMBOOT.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.if64
|
||||
|
||||
.section ".text.long_to_phys", "ax", @progbits
|
||||
.code64
|
||||
long_to_phys:
|
||||
|
||||
/* Switch to protected mode */
|
||||
call long_to_prot
|
||||
.code32
|
||||
|
||||
/* Convert to 32-bit virtual return address */
|
||||
popl (%esp)
|
||||
|
||||
/* Switch to physical addresses and return */
|
||||
jmp prot_to_phys
|
||||
|
||||
/* Expose as _virt_to_phys for use by COMBOOT */
|
||||
.globl _virt_to_phys
|
||||
.equ _virt_to_phys, long_to_phys
|
||||
|
||||
.endif
|
||||
|
||||
/****************************************************************************
|
||||
* flatten_real_mode (real-mode near call)
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue