]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[comboot] Restore the real-mode stack pointer on exit from a COMBOOT image
authorMichael Brown <mcb30@etherboot.org>
Tue, 17 Feb 2009 03:33:26 +0000 (03:33 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 17 Feb 2009 03:38:40 +0000 (03:38 +0000)
COMBOOT images use INTs to issue API calls; these end up making calls
into gPXE from real mode, and so temporarily change the real-mode
stack pointer.  When our COMBOOT code uses a longjmp() to implement
the various "exit COMBOOT image" API calls, this leaves the real-mode
stack pointer stuck with its temporary value, which causes problems if
we eventually try to exit out of gPXE back to the BIOS.

Fix by adding rmsetjmp() and rmlongjmp() calls (analogous to
sigsetjmp()/siglongjmp()); these save and restore the additional state
needed for real-mode calls to function correctly.

src/arch/i386/image/com32.c
src/arch/i386/image/comboot.c
src/arch/i386/include/comboot.h
src/arch/i386/include/setjmp.h
src/arch/i386/interface/syslinux/comboot_call.c

index 00f752634c1884e82fc584048b67f46e0cf69a69..d1b9a59fab9d5cb2efa99e58ad789b8622312d5a 100644 (file)
@@ -52,7 +52,7 @@ static int com32_exec ( struct image *image ) {
        int state;
        uint32_t avail_mem_top;
 
-       state = setjmp ( comboot_return );
+       state = rmsetjmp ( comboot_return );
 
        switch ( state ) {
        case 0: /* First time through; invoke COM32 program */
index d9b16c5713b96aa4ad605e96d89fa55653a6fc1d..40e3218583ac5fd7314118341075fa373b29e5dd 100644 (file)
@@ -133,7 +133,7 @@ static int comboot_exec ( struct image *image ) {
        userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
        int state;
 
-       state = setjmp ( comboot_return );
+       state = rmsetjmp ( comboot_return );
 
        switch ( state ) {
        case 0: /* First time through; invoke COMBOOT program */
index 6b8ea6b6854664ab825a6cb2128a985191c02b29..b5b1f8a0d0b9cc29d4acb55c5be2b7b8f745f5e6 100644 (file)
@@ -78,7 +78,7 @@ extern void com32_cfarcall_wrapper ( );
 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;
+extern rmjmp_buf comboot_return;
 
 /* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */
 extern struct image *comboot_replacement_image;
index 60e4b1209d2b28102dfa27f8a905dfef0401b9ed..c18d03e1d017136cc76c41a828731067f63e7859 100644 (file)
@@ -1,12 +1,38 @@
 #ifndef ETHERBOOT_SETJMP_H
 #define ETHERBOOT_SETJMP_H
 
+#include <stdint.h>
+#include <realmode.h>
 
-/* Define a type for use by setjmp and longjmp */
-#define JBLEN 6
-typedef unsigned long jmp_buf[JBLEN];
+/** A jump buffer */
+typedef struct {
+       uint32_t retaddr;
+       uint32_t ebx;
+       uint32_t esp;
+       uint32_t ebp;
+       uint32_t esi;
+       uint32_t edi;
+} jmp_buf[1];
 
-extern int __asmcall setjmp (jmp_buf env);
-extern void __asmcall longjmp (jmp_buf env, int val);
+/** A real-mode-extended jump buffer */
+typedef struct {
+       jmp_buf env;
+       uint16_t rm_ss;
+       uint16_t rm_sp;
+} rmjmp_buf[1];
+
+extern int __asmcall setjmp ( jmp_buf env );
+extern void __asmcall longjmp ( jmp_buf env, int val );
+
+#define rmsetjmp( _env ) ( {                   \
+       (_env)->rm_ss = rm_ss;                  \
+       (_env)->rm_sp = rm_sp;                  \
+       setjmp ( (_env)->env ); } )             \
+
+#define rmlongjmp( _env, _val ) do {           \
+       rm_ss = (_env)->rm_ss;                  \
+       rm_sp = (_env)->rm_sp;                  \
+       longjmp ( (_env)->env, (_val) );        \
+       } while ( 0 )
 
 #endif /* ETHERBOOT_SETJMP_H */
index c641c8402baada9f69577d3fbaa4c2ef36d386b4..290d94ac28b18f26f591cd7ce45c22fa282fa6c0 100644 (file)
@@ -67,7 +67,7 @@ extern void int21_wrapper ( void );
 extern void int22_wrapper ( void );
 
 /* setjmp/longjmp context buffer used to return after loading an image */
-jmp_buf comboot_return;
+rmjmp_buf comboot_return;
 
 /* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */
 struct image *comboot_replacement_image;
@@ -235,7 +235,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
  * Terminate program interrupt handler
  */
 static __asmcall void int20 ( struct i386_all_regs *ix86 __unused ) {
-       longjmp ( comboot_return, COMBOOT_EXIT );
+       rmlongjmp ( comboot_return, COMBOOT_EXIT );
 }
 
 
@@ -248,7 +248,7 @@ static __asmcall void int21 ( struct i386_all_regs *ix86 ) {
        switch ( ix86->regs.ah ) {
        case 0x00:
        case 0x4C: /* Terminate program */
-               longjmp ( comboot_return, COMBOOT_EXIT );
+               rmlongjmp ( comboot_return, COMBOOT_EXIT );
                break;
 
        case 0x01: /* Get Key with Echo */
@@ -347,13 +347,13 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
                        DBG ( "COMBOOT: executing command '%s'\n", cmd );
                        system ( cmd );
                        DBG ( "COMBOOT: exiting after executing command...\n" );
-                       longjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
+                       rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
                }
                break;
 
        case 0x0004: /* Run default command */
                /* FIXME: just exit for now */
-               longjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
+               rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
                break;
 
        case 0x0005: /* Force text mode */
@@ -552,7 +552,7 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
                         * part of the COMBOOT program's memory space.
                         */
                        DBG ( "COMBOOT: exiting to run kernel...\n" );
-                       longjmp ( comboot_return, COMBOOT_EXIT_RUN_KERNEL );
+                       rmlongjmp ( comboot_return, COMBOOT_EXIT_RUN_KERNEL );
                }
                break;