Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[comboot] Support COMBOOT in 64-bit builds
Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Apr 15, 2016
1 parent 4afb758 commit 5e5450c
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 101 deletions.
2 changes: 0 additions & 2 deletions src/arch/i386/Makefile
Expand Up @@ -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
#
Expand Down
1 change: 1 addition & 0 deletions src/arch/x86/Makefile
Expand Up @@ -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
Expand Down
72 changes: 40 additions & 32 deletions src/arch/i386/image/com32.c → src/arch/x86/image/com32.c
Expand Up @@ -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();

Expand All @@ -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;

Expand Down Expand Up @@ -147,15 +155,15 @@ static int com32_exec_loop ( struct image *image ) {

/**
* Check image name extension
*
*
* @v image COM32 image
* @ret rc Return status code
*/
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
Expand Down
12 changes: 6 additions & 6 deletions src/arch/i386/image/comboot.c → src/arch/x86/image/comboot.c
Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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",
Expand Down
Expand Up @@ -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)
*/
Expand Down Expand Up @@ -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
*/
Expand All @@ -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
Expand Down
Expand Up @@ -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) );
Expand Down Expand Up @@ -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)
*/
Expand Down Expand Up @@ -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) );
}
}
Expand All @@ -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) );
Expand Down Expand Up @@ -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) );
}
}
Expand All @@ -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 );
Expand Down
Expand Up @@ -19,79 +19,82 @@

FILE_LICENCE ( GPL2_OR_LATER )

#include "librm.h"

.text
.arch i386
.code32

.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

mov %eax, (com32_helper_function)
call _phys_to_virt

/* Save external COM32 stack pointer */
movl %esp, (com32_external_esp)
#ifdef __x86_64__

/* Copy arguments to caller-save registers */
movl 12(%esp), %eax
movl 8(%esp), %ecx
movl 4(%esp), %edx
.code64

/* Switch to internal stack */
movl (com32_internal_esp), %esp
/* Preserve registers which are callee-save for COM32 (i386 API) */
pushq %rdi
pushq %rsi
pushq %rbp

/* Copy arguments to internal stack */
pushl %eax
pushl %ecx
pushl %edx
/* Extract parameters from stack */
movl 28(%rsp), %edi
movl 32(%rsp), %esi
movl 36(%rsp), %edx

call *(com32_helper_function)
/* Align stack pointer */
movq %rsp, %rbp
andq $~0x07, %rsp

/* Clean up stack */
addl $12, %esp
/* Call helper function */
movslq %eax, %rax
call *%rax

/* Save internal stack pointer and restore external stack pointer */
movl %esp, (com32_internal_esp)
movl (com32_external_esp), %esp
/* Restore stack pointer */
movq %rbp, %rsp

/* Switch to external flat physical address space */
call _virt_to_phys

sti
ret
/* Restore registers */
popq %rbp
popq %rsi
popq %rdi

#else /* _x86_64 */

.data
/* Call helper function */
pushl 12(%esp)
pushl 12(%esp)
pushl 12(%esp)
call *%eax
addl $12, %esp

/* Internal iPXE virtual address space %esp */
.globl com32_internal_esp
.lcomm com32_internal_esp, 4
#endif /* _x86_64 */

/* External flat physical address space %esp */
.globl com32_external_esp
.lcomm com32_external_esp, 4
/* Switch to external flat physical address space */
call _virt_to_phys
.code32

/* Function pointer of helper to call */
.lcomm com32_helper_function, 4
/* Reenable interrupts and return */
sti
ret

0 comments on commit 5e5450c

Please sign in to comment.