[comboot] Support COMBOOT in 64-bit builds

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/52/head
Michael Brown 2016-04-14 16:48:41 +01:00
parent 4afb758423
commit 5e5450c2d0
12 changed files with 180 additions and 102 deletions

View File

@ -83,9 +83,7 @@ endif
# i386-specific directories containing source files # i386-specific directories containing source files
# #
SRCDIRS += arch/i386/core SRCDIRS += arch/i386/core
SRCDIRS += arch/i386/image
SRCDIRS += arch/i386/tests SRCDIRS += arch/i386/tests
SRCDIRS += arch/i386/interface/syslinux
# Include common x86 Makefile # Include common x86 Makefile
# #

View File

@ -16,6 +16,7 @@ SRCDIRS += arch/x86/interface/pxe
SRCDIRS += arch/x86/interface/pxeparent SRCDIRS += arch/x86/interface/pxeparent
SRCDIRS += arch/x86/interface/efi SRCDIRS += arch/x86/interface/efi
SRCDIRS += arch/x86/interface/vmware SRCDIRS += arch/x86/interface/vmware
SRCDIRS += arch/x86/interface/syslinux
SRCDIRS += arch/x86/prefix SRCDIRS += arch/x86/prefix
SRCDIRS += arch/x86/hci/commands SRCDIRS += arch/x86/hci/commands
SRCDIRS += arch/x86/drivers/xen SRCDIRS += arch/x86/drivers/xen

View File

@ -76,8 +76,6 @@ static int com32_exec_loop ( struct image *image ) {
assert ( avail_mem_top != 0 ); assert ( avail_mem_top != 0 );
com32_external_esp = phys_to_virt ( avail_mem_top );
/* Hook COMBOOT API interrupts */ /* Hook COMBOOT API interrupts */
hook_comboot_interrupts(); hook_comboot_interrupts();
@ -88,34 +86,44 @@ static int com32_exec_loop ( struct image *image ) {
*/ */
unregister_image ( image ); unregister_image ( image );
__asm__ __volatile__ ( __asm__ __volatile__ ( PHYS_CODE (
"movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */ /* Preserve registers */
"movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */ "pushal\n\t"
"call _virt_to_phys\n\t" /* Switch to flat physical address space */ /* Preserve stack pointer */
"sti\n\t" /* Enable interrupts */ "subl $4, %k0\n\t"
"pushl %0\n\t" /* Pointer to CDECL helper function */ "movl %%esp, (%k0)\n\t"
"pushl %1\n\t" /* Pointer to FAR call helper function */ /* Switch to COM32 stack */
"pushl %2\n\t" /* Size of low memory bounce buffer */ "movl %k0, %%esp\n\t"
"pushl %3\n\t" /* Pointer to low memory bounce buffer */ /* Enable interrupts */
"pushl %4\n\t" /* Pointer to INT call helper function */ "sti\n\t"
"pushl %5\n\t" /* Pointer to the command line arguments */ /* Construct stack frame */
"pushl $6\n\t" /* Number of additional arguments */ "pushl %k1\n\t"
"call *%6\n\t" /* Execute image */ "pushl %k2\n\t"
"cli\n\t" /* Disable interrupts */ "pushl %k3\n\t"
"call _phys_to_virt\n\t" /* Switch back to internal virtual address space */ "pushl %k4\n\t"
"movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */ "pushl %k5\n\t"
: "pushl %k6\n\t"
: "pushl $6\n\t"
/* %0 */ "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ), /* Call COM32 entry point */
/* %1 */ "r" ( virt_to_phys ( com32_farcall_wrapper ) ), "movl %k7, %k0\n\t"
/* %2 */ "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ), "call *%k0\n\t"
/* %3 */ "i" ( COM32_BOUNCE_SEG << 4 ), /* Disable interrupts */
/* %4 */ "r" ( virt_to_phys ( com32_intcall_wrapper ) ), "cli\n\t"
/* %5 */ "r" ( virt_to_phys ( image->cmdline ? /* Restore stack pointer */
image->cmdline : "" ) ), "movl 24(%%esp), %%esp\n\t"
/* %6 */ "r" ( COM32_START_PHYS ) /* Restore registers */
: "popal\n\t" )
"memory" ); :
: "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 ); DBGC ( image, "COM32 %p: returned\n", image );
break; break;
@ -147,7 +155,7 @@ static int com32_exec_loop ( struct image *image ) {
/** /**
* Check image name extension * Check image name extension
* *
* @v image COM32 image * @v image COM32 image
* @ret rc Return status code * @ret rc Return status code
*/ */
@ -155,7 +163,7 @@ static int com32_identify ( struct image *image ) {
const char *ext; const char *ext;
static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 }; static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
uint8_t buf[5]; uint8_t buf[5];
if ( image->len >= 5 ) { if ( image->len >= 5 ) {
/* Check for magic number /* Check for magic number
* mov eax,21cd4cffh * mov eax,21cd4cffh

View File

@ -64,7 +64,7 @@ struct comboot_psp {
/** /**
* Copy command line to PSP * Copy command line to PSP
* *
* @v image COMBOOT image * @v image COMBOOT image
*/ */
static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) { 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 * Initialize PSP
* *
* @v image COMBOOT image * @v image COMBOOT image
* @v seg_userptr segment to initialize * @v seg_userptr segment to initialize
*/ */
@ -213,7 +213,7 @@ static int comboot_exec_loop ( struct image *image ) {
/** /**
* Check image name extension * Check image name extension
* *
* @v image COMBOOT image * @v image COMBOOT image
* @ret rc Return status code * @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 ); seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
/* Allow etra 0x100 bytes before image for PSP */ /* Allow etra 0x100 bytes before image for PSP */
filesz = image->len + 0x100; filesz = image->len + 0x100;
/* Ensure the entire 64k segment is free */ /* Ensure the entire 64k segment is free */
memsz = 0xFFFF; memsz = 0xFFFF;
@ -289,7 +289,7 @@ static int comboot_probe ( struct image *image ) {
/* Check if this is a COMBOOT image */ /* Check if this is a COMBOOT image */
if ( ( rc = comboot_identify ( image ) ) != 0 ) { if ( ( rc = comboot_identify ( image ) ) != 0 ) {
return rc; return rc;
} }
@ -304,7 +304,7 @@ static int comboot_probe ( struct image *image ) {
*/ */
static int comboot_exec ( struct image *image ) { static int comboot_exec ( struct image *image ) {
int rc; int rc;
/* Sanity check for filesize */ /* Sanity check for filesize */
if( image->len >= 0xFF00 ) { if( image->len >= 0xFF00 ) {
DBGC( image, "COMBOOT %p: image too large\n", DBGC( image, "COMBOOT %p: image too large\n",

View File

@ -29,7 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define COMBOOT_FEATURE_LOCAL_BOOT (1 << 0) #define COMBOOT_FEATURE_LOCAL_BOOT (1 << 0)
#define COMBOOT_FEATURE_IDLE_LOOP (1 << 1) #define COMBOOT_FEATURE_IDLE_LOOP (1 << 1)
/** Maximum number of shuffle descriptors for /** Maximum number of shuffle descriptors for
* shuffle and boot functions * shuffle and boot functions
* (INT 22h AX=0012h, 001Ah, 001Bh) * (INT 22h AX=0012h, 001Ah, 001Bh)
*/ */
@ -102,7 +102,7 @@ typedef struct {
extern void hook_comboot_interrupts ( ); extern void hook_comboot_interrupts ( );
extern void unhook_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; * as we only ever get the address of these functions;
* they are only called from COM32 code running in PHYS_CODE * 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 */ /* setjmp/longjmp context buffer used to return after loading an image */
extern rmjmp_buf comboot_return; extern rmjmp_buf comboot_return;
extern void *com32_external_esp;
#define COMBOOT_EXIT 1 #define COMBOOT_EXIT 1
#define COMBOOT_EXIT_RUN_KERNEL 2 #define COMBOOT_EXIT_RUN_KERNEL 2
#define COMBOOT_EXIT_COMMAND 3 #define COMBOOT_EXIT_COMMAND 3

View File

@ -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 ) { 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, memcpy_user ( virt_to_user( &com32_regs ), 0,
phys_to_user ( inregs_phys ), 0, phys_to_user ( inregs_phys ), 0,
sizeof(com32sys_t) ); sizeof(com32sys_t) );
@ -76,7 +79,7 @@ void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physad
/* patch INT instruction */ /* patch INT instruction */
"pushw %%ax\n\t" "pushw %%ax\n\t"
"movb %%ss:(com32_int_vector), %%al\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 /* perform a jump to avoid problems with cache
* consistency in self-modifying code on some CPUs (486) * 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 ) { if ( outregs_phys ) {
memcpy_user ( phys_to_user ( outregs_phys ), 0, memcpy_user ( phys_to_user ( outregs_phys ), 0,
virt_to_user( &com32_regs ), 0, virt_to_user( &com32_regs ), 0,
sizeof(com32sys_t) ); 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 ) { 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, memcpy_user ( virt_to_user( &com32_regs ), 0,
phys_to_user ( inregs_phys ), 0, phys_to_user ( inregs_phys ), 0,
sizeof(com32sys_t) ); sizeof(com32sys_t) );
@ -165,7 +171,7 @@ void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t
if ( outregs_phys ) { if ( outregs_phys ) {
memcpy_user ( phys_to_user ( outregs_phys ), 0, memcpy_user ( phys_to_user ( outregs_phys ), 0,
virt_to_user( &com32_regs ), 0, virt_to_user( &com32_regs ), 0,
sizeof(com32sys_t) ); 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 ) { int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
int32_t eax; 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 ); copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz );
com32_farcall_proc = proc; com32_farcall_proc = proc;
__asm__ __volatile__ ( __asm__ __volatile__ (
REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" ) REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" )
: "=a" (eax) : "=a" (eax)
: :
: "ecx", "edx" ); : "ecx", "edx" );
remove_user_from_rm_stack ( 0, stacksz ); remove_user_from_rm_stack ( 0, stacksz );

View File

@ -19,79 +19,82 @@
FILE_LICENCE ( GPL2_OR_LATER ) FILE_LICENCE ( GPL2_OR_LATER )
.text #include "librm.h"
.arch i386
.code32
.text
.code32
.globl com32_farcall_wrapper .globl com32_farcall_wrapper
com32_farcall_wrapper: com32_farcall_wrapper:
movl $VIRTUAL(com32_farcall), %eax
jmp com32_wrapper
movl $com32_farcall, %eax .code32
jmp com32_wrapper
.globl com32_cfarcall_wrapper .globl com32_cfarcall_wrapper
com32_cfarcall_wrapper: com32_cfarcall_wrapper:
movl $VIRTUAL(com32_cfarcall), %eax
jmp com32_wrapper
movl $com32_cfarcall, %eax .code32
jmp com32_wrapper
.globl com32_intcall_wrapper .globl com32_intcall_wrapper
com32_intcall_wrapper: com32_intcall_wrapper:
movl $VIRTUAL(com32_intcall), %eax
/* fall through */
movl $com32_intcall, %eax .code32
/*jmp com32_wrapper*/ /* fall through */
com32_wrapper: com32_wrapper:
/* Disable interrupts */
cli cli
/* Switch to internal virtual address space */ /* 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 */ .code64
movl %esp, (com32_external_esp)
/* Copy arguments to caller-save registers */ /* Preserve registers which are callee-save for COM32 (i386 API) */
movl 12(%esp), %eax pushq %rdi
movl 8(%esp), %ecx pushq %rsi
movl 4(%esp), %edx pushq %rbp
/* Switch to internal stack */ /* Extract parameters from stack */
movl (com32_internal_esp), %esp movl 28(%rsp), %edi
movl 32(%rsp), %esi
movl 36(%rsp), %edx
/* Copy arguments to internal stack */ /* Align stack pointer */
pushl %eax movq %rsp, %rbp
pushl %ecx andq $~0x07, %rsp
pushl %edx
call *(com32_helper_function) /* Call helper function */
movslq %eax, %rax
call *%rax
/* Clean up stack */ /* Restore stack pointer */
addl $12, %esp movq %rbp, %rsp
/* Save internal stack pointer and restore external stack pointer */ /* Restore registers */
movl %esp, (com32_internal_esp) popq %rbp
movl (com32_external_esp), %esp 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 */ /* Switch to external flat physical address space */
call _virt_to_phys call _virt_to_phys
.code32
/* Reenable interrupts and return */
sti sti
ret 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

View File

@ -489,7 +489,7 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
struct in_addr addr; struct in_addr addr;
copy_from_user ( hostname, hostname_u, 0, len + 1 ); copy_from_user ( hostname, hostname_u, 0, len + 1 );
/* TODO: /* TODO:
* "If the hostname does not contain a dot (.), the * "If the hostname does not contain a dot (.), the
* local domain name is automatically appended." * 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 */ /* Jump to real-mode entry point */
__asm__ __volatile__ ( __asm__ __volatile__ (
REAL_CODE ( REAL_CODE (
"pushw %0\n\t" "pushw %0\n\t"
"popw %%ds\n\t" "popw %%ds\n\t"
"pushl %1\n\t" "pushl %1\n\t"

View File

@ -37,4 +37,3 @@ source: dd 0
dd shuffle_len dd shuffle_len
num_shuffle_descriptors equ 1 num_shuffle_descriptors equ 1

View File

@ -567,9 +567,10 @@ phys_to_prot:
popl %eax popl %eax
ret 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 .globl _phys_to_virt
.equ _phys_to_virt, phys_to_prot .equ _phys_to_virt, phys_to_prot
.endif
/**************************************************************************** /****************************************************************************
* prot_to_phys (protected-mode near call, 32-bit virtual return address) * prot_to_phys (protected-mode near call, 32-bit virtual return address)
@ -615,9 +616,10 @@ prot_to_phys:
popl %eax popl %eax
ret 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 .globl _virt_to_phys
.equ _virt_to_phys, prot_to_phys .equ _virt_to_phys, prot_to_phys
.endif
/**************************************************************************** /****************************************************************************
* intr_to_prot (protected-mode near call, 32-bit virtual return address) * intr_to_prot (protected-mode near call, 32-bit virtual return address)
@ -1202,6 +1204,66 @@ phys_call:
/* Return and discard function parameters */ /* Return and discard function parameters */
ret $( PHC_OFFSET_END - PHC_OFFSET_PARAMS ) 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) * flatten_real_mode (real-mode near call)
* *