diff options
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/i386/image/com32.c | 40 | ||||
| -rw-r--r-- | src/arch/i386/image/comboot.c | 40 | ||||
| -rw-r--r-- | src/arch/i386/include/bits/errfile.h | 1 | ||||
| -rw-r--r-- | src/arch/i386/include/comboot.h | 14 | ||||
| -rw-r--r-- | src/arch/i386/interface/syslinux/comboot_call.c | 143 |
5 files changed, 134 insertions, 104 deletions
diff --git a/src/arch/i386/image/com32.c b/src/arch/i386/image/com32.c index da604625a..27ccbc02f 100644 --- a/src/arch/i386/image/com32.c +++ b/src/arch/i386/image/com32.c @@ -70,20 +70,20 @@ static int com32_exec ( struct image *image ) { } DBGC ( image, "COM32 %p: available memory top = 0x%x\n", - image, (int)avail_mem_top ); + image, avail_mem_top ); assert ( avail_mem_top != 0 ); com32_external_esp = phys_to_virt ( avail_mem_top ); /* Hook COMBOOT API interrupts */ - hook_comboot_interrupts( ); + hook_comboot_interrupts(); - /* Temporarily de-register image, so that a "boot" command - * doesn't throw us into an execution loop. Hold a reference - * to avoid the image's being freed. + /* Unregister image, so that a "boot" command doesn't + * throw us into an execution loop. We never + * reregister ourselves; COMBOOT images expect to be + * removed on exit. */ - image_get ( image ); unregister_image ( image ); __asm__ __volatile__ ( @@ -111,25 +111,31 @@ static int com32_exec ( struct image *image ) { /* %6 */ "r" ( COM32_START_PHYS ) : "memory" ); + DBGC ( image, "COM32 %p: returned\n", image ); break; - case COMBOOT_RETURN_RUN_KERNEL: - DBGC ( image, "COM32 %p: returned to run kernel...\n", image ); - comboot_run_kernel ( ); + case COMBOOT_EXIT: + DBGC ( image, "COM32 %p: exited\n", image ); break; - case COMBOOT_RETURN_EXIT: + case COMBOOT_EXIT_RUN_KERNEL: + DBGC ( image, "COM32 %p: exited to run kernel %p\n", + image, comboot_replacement_image ); + image->replacement = comboot_replacement_image; + image_autoload ( image->replacement ); break; - } - - comboot_force_text_mode ( ); + case COMBOOT_EXIT_COMMAND: + DBGC ( image, "COM32 %p: exited after executing command\n", + image ); + break; - DBGC ( image, "COM32 %p returned\n", image ); + default: + assert ( 0 ); + break; + } - /* Re-register image and return */ - register_image ( image ); - image_put ( image ); + comboot_force_text_mode(); return 0; } diff --git a/src/arch/i386/image/comboot.c b/src/arch/i386/image/comboot.c index 63d02c0fe..3ca9d28f4 100644 --- a/src/arch/i386/image/comboot.c +++ b/src/arch/i386/image/comboot.c @@ -142,16 +142,16 @@ static int comboot_exec ( struct image *image ) { comboot_init_psp ( image, seg_userptr ); /* Hook COMBOOT API interrupts */ - hook_comboot_interrupts ( ); + hook_comboot_interrupts(); DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n", - COMBOOT_PSP_SEG ); + COMBOOT_PSP_SEG ); - /* Temporarily de-register image, so that a "boot" command - * doesn't throw us into an execution loop. Hold a reference - * to avoid the image's being freed. + /* Unregister image, so that a "boot" command doesn't + * throw us into an execution loop. We never + * reregister ourselves; COMBOOT images expect to be + * removed on exit. */ - image_get ( image ); unregister_image ( image ); /* Store stack segment at 0x38 and stack pointer at 0x3A @@ -180,26 +180,32 @@ static int comboot_exec ( struct image *image ) { "xorw %%bp, %%bp\n\t" "lret\n\t" ) : : "r" ( COMBOOT_PSP_SEG ) : "eax" ); + DBGC ( image, "COMBOOT %p: returned\n", image ); break; - case COMBOOT_RETURN_RUN_KERNEL: - DBGC ( image, "COMBOOT %p: returned to run kernel...\n", image ); - comboot_run_kernel ( ); + case COMBOOT_EXIT: + DBGC ( image, "COMBOOT %p: exited\n", image ); break; - case COMBOOT_RETURN_EXIT: + case COMBOOT_EXIT_RUN_KERNEL: + DBGC ( image, "COMBOOT %p: exited to run kernel %p\n", + image, comboot_replacement_image ); + image->replacement = comboot_replacement_image; + image_autoload ( image->replacement ); break; - } + case COMBOOT_EXIT_COMMAND: + DBGC ( image, "COMBOOT %p: exited after executing command\n", + image ); + break; - comboot_force_text_mode ( ); + default: + assert ( 0 ); + break; + } - DBGC ( image, "COMBOOT %p returned\n", image ); + comboot_force_text_mode(); - /* Re-register image and return */ - register_image ( image ); - image_put ( image ); - return 0; } diff --git a/src/arch/i386/include/bits/errfile.h b/src/arch/i386/include/bits/errfile.h index 1723063b4..5ea8a3186 100644 --- a/src/arch/i386/include/bits/errfile.h +++ b/src/arch/i386/include/bits/errfile.h @@ -23,6 +23,7 @@ #define ERRFILE_comboot ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00070000 ) #define ERRFILE_com32 ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 ) #define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 ) +#define ERRFILE_comboot_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 ) #define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 ) #define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 ) diff --git a/src/arch/i386/include/comboot.h b/src/arch/i386/include/comboot.h index 1fc3b718b..4376650f6 100644 --- a/src/arch/i386/include/comboot.h +++ b/src/arch/i386/include/comboot.h @@ -79,18 +79,14 @@ extern int comboot_resolv ( const char *name, struct in_addr *address ); /* setjmp/longjmp context buffer used to return after loading an image */ extern jmp_buf comboot_return; -/* Command line to execute when returning via comboot_return - * with COMBOOT_RETURN_RUN_KERNEL - */ -extern char *comboot_kernel_cmdline; - -/* Execute comboot_image_cmdline */ -extern void comboot_run_kernel ( ); +/* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */ +extern struct image *comboot_replacement_image; extern void *com32_external_esp; -#define COMBOOT_RETURN_EXIT 1 -#define COMBOOT_RETURN_RUN_KERNEL 2 +#define COMBOOT_EXIT 1 +#define COMBOOT_EXIT_RUN_KERNEL 2 +#define COMBOOT_EXIT_COMMAND 3 extern void comboot_force_text_mode ( void ); diff --git a/src/arch/i386/interface/syslinux/comboot_call.c b/src/arch/i386/interface/syslinux/comboot_call.c index 977d44f3d..02b2250b2 100644 --- a/src/arch/i386/interface/syslinux/comboot_call.c +++ b/src/arch/i386/interface/syslinux/comboot_call.c @@ -35,6 +35,8 @@ #include <gpxe/process.h> #include <gpxe/serial.h> #include <gpxe/init.h> +#include <gpxe/image.h> +#include <usr/imgmgmt.h> /** The "SYSLINUX" version string */ static char __data16_array ( syslinux_version, [] ) = "gPXE " VERSION; @@ -67,10 +69,8 @@ extern void int22_wrapper ( void ); /* setjmp/longjmp context buffer used to return after loading an image */ jmp_buf comboot_return; -/* Command line to execute when returning via comboot_return - * with COMBOOT_RETURN_RUN_KERNEL - */ -char *comboot_kernel_cmdline; +/* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */ +struct image *comboot_replacement_image; /* Mode flags set by INT 22h AX=0017h */ static uint16_t comboot_graphics_mode = 0; @@ -154,58 +154,81 @@ void comboot_force_text_mode ( void ) { /** - * Run the kernel specified in comboot_kernel_cmdline + * Fetch kernel and optional initrd */ -void comboot_run_kernel ( ) -{ - char *initrd; - - comboot_force_text_mode ( ); - - DBG ( "COMBOOT: executing image '%s'\n", comboot_kernel_cmdline ); +static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) { + struct image *kernel; + struct image *initrd = NULL; + char *initrd_file; + int rc; /* Find initrd= parameter, if any */ - if ( ( initrd = strstr ( comboot_kernel_cmdline, "initrd=" ) ) ) { - char old_char = '\0'; - char *initrd_end = strchr( initrd, ' ' ); - - /* Replace space after end of parameter - * with a nul terminator if this is not - * the last parameter - */ - if ( initrd_end ) { - old_char = *initrd_end; - *initrd_end = '\0'; - } + if ( ( initrd_file = strstr ( cmdline, "initrd=" ) ) != NULL ) { + char *initrd_end; - /* Replace = with space to get 'initrd filename' - * command suitable for system() - */ - initrd[6] = ' '; + /* skip "initrd=" */ + initrd_file += 7; - DBG( "COMBOOT: loading initrd '%s'\n", initrd ); + /* Find terminating space, if any, and replace with NUL */ + initrd_end = strchr ( initrd_file, ' ' ); + if ( initrd_end ) + *initrd_end = '\0'; - system ( initrd ); + DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file ); - /* Restore space after parameter */ - if ( initrd_end ) { - *initrd_end = old_char; + /* Allocate and fetch initrd */ + initrd = alloc_image(); + if ( ! initrd ) { + DBG ( "COMBOOT: could not allocate initrd\n" ); + rc = -ENOMEM; + goto err_alloc_initrd; + } + if ( ( rc = imgfetch ( initrd, initrd_file, + register_image ) ) != 0 ) { + DBG ( "COMBOOT: could not fetch initrd: %s\n", + strerror ( rc ) ); + goto err_fetch_initrd; } - /* Restore = */ - initrd[6] = '='; + /* Restore space after initrd name, if applicable */ + if ( initrd_end ) + *initrd_end = ' '; } - /* Load kernel */ - DBG ( "COMBOOT: loading kernel '%s'\n", comboot_kernel_cmdline ); - system ( comboot_kernel_cmdline ); + DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file ); - free ( comboot_kernel_cmdline ); + /* Allocate and fetch kernel */ + kernel = alloc_image(); + if ( ! kernel ) { + DBG ( "COMBOOT: could not allocate kernel\n" ); + rc = -ENOMEM; + goto err_alloc_kernel; + } + if ( ( rc = imgfetch ( kernel, kernel_file, + register_image ) ) != 0 ) { + DBG ( "COMBOOT: could not fetch kernel: %s\n", + strerror ( rc ) ); + goto err_fetch_kernel; + } + if ( ( rc = image_set_cmdline ( kernel, cmdline ) ) != 0 ) { + DBG ( "COMBOOT: could not set kernel command line: %s\n", + strerror ( rc ) ); + goto err_set_cmdline; + } - /* Boot */ - system ( "boot" ); + /* Store kernel as replacement image */ + comboot_replacement_image = kernel; - DBG ( "COMBOOT: back from executing command\n" ); + return 0; + + err_set_cmdline: + err_fetch_kernel: + image_put ( kernel ); + err_alloc_kernel: + err_fetch_initrd: + image_put ( initrd ); + err_alloc_initrd: + return rc; } @@ -213,7 +236,7 @@ void comboot_run_kernel ( ) * Terminate program interrupt handler */ static __asmcall void int20 ( struct i386_all_regs *ix86 __unused ) { - longjmp ( comboot_return, COMBOOT_RETURN_EXIT ); + longjmp ( comboot_return, COMBOOT_EXIT ); } @@ -226,7 +249,7 @@ static __asmcall void int21 ( struct i386_all_regs *ix86 ) { switch ( ix86->regs.ah ) { case 0x00: case 0x4C: /* Terminate program */ - longjmp ( comboot_return, COMBOOT_RETURN_EXIT ); + longjmp ( comboot_return, COMBOOT_EXIT ); break; case 0x01: /* Get Key with Echo */ @@ -323,17 +346,15 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) { char cmd[len + 1]; copy_from_user ( cmd, cmd_u, 0, len + 1 ); DBG ( "COMBOOT: executing command '%s'\n", cmd ); - - comboot_kernel_cmdline = strdup ( cmd ); - - DBG ( "COMBOOT: returning to run image...\n" ); - longjmp ( comboot_return, COMBOOT_RETURN_RUN_KERNEL ); + system ( cmd ); + DBG ( "COMBOOT: exiting after executing command...\n" ); + longjmp ( comboot_return, COMBOOT_EXIT_COMMAND ); } break; case 0x0004: /* Run default command */ /* FIXME: just exit for now */ - longjmp ( comboot_return, COMBOOT_RETURN_EXIT ); + longjmp ( comboot_return, COMBOOT_EXIT_COMMAND ); break; case 0x0005: /* Force text mode */ @@ -518,21 +539,21 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) { userptr_t cmd_u = real_to_user ( ix86->segs.es, ix86->regs.bx ); int file_len = strlen_user ( file_u, 0 ); int cmd_len = strlen_user ( cmd_u, 0 ); - char file[file_len + 1 + cmd_len + 7 + 1]; + char file[file_len + 1]; char cmd[cmd_len + 1]; - memcpy( file, "kernel ", 7 ); - copy_from_user ( file + 7, file_u, 0, file_len + 1 ); + copy_from_user ( file, file_u, 0, file_len + 1 ); copy_from_user ( cmd, cmd_u, 0, cmd_len + 1 ); - strcat ( file, " " ); - strcat ( file, cmd ); - - DBG ( "COMBOOT: run kernel image '%s'\n", file ); - comboot_kernel_cmdline = strdup ( file ); - - DBG ( "COMBOOT: returning to run image...\n" ); - longjmp ( comboot_return, COMBOOT_RETURN_RUN_KERNEL ); + DBG ( "COMBOOT: run kernel %s %s\n", file, cmd ); + comboot_fetch_kernel ( file, cmd ); + /* Technically, we should return if we + * couldn't load the kernel, but it's not safe + * to do that since we have just overwritten + * part of the COMBOOT program's memory space. + */ + DBG ( "COMBOOT: exiting to run kernel...\n" ); + longjmp ( comboot_return, COMBOOT_EXIT_RUN_KERNEL ); } break; |
