[SeaBIOS] [PATCH 04/13] post: Export functions which will be used individually by CSM

Kevin O'Connor kevin at koconnor.net
Tue Feb 5 08:53:42 CET 2013


On Tue, Feb 05, 2013 at 12:52:50AM -0500, Kevin O'Connor wrote:
> On Sat, Feb 02, 2013 at 07:32:42PM -0500, Kevin O'Connor wrote:
> > I'm not sure how to best address this.  One way is to go forward and
> > sprinkle VISIBLE32INIT.  Another way would be to revert patch 1, pass
> > a function pointer to reloc_preinit() instead of hard-coding maininit,
> > and teach the CSM code how to "longjmp" back to UEFI after relocation
> > so it doesn't have to unwind the stack.  I'm not sure that would be
> > any less "ugly" though.
> 
> FYI, below is one way to "longjmp" back to UEFI without unwinding the
> stack (based on your latest git tree and totally untested).  This
> assumes it is okay to clobber %fs, %gs and the gdt.

This may be slightly nicer (still totally untested).

-Kevin


diff --git a/src/csm.c b/src/csm.c
index a773f0d..d5ed8ad 100644
--- a/src/csm.c
+++ b/src/csm.c
@@ -36,6 +36,8 @@ EFI_COMPATIBILITY16_TABLE csm_compat_table VAR32FLATVISIBLE __aligned(16) = {
 EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
 EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
 
+extern void csm_return(struct bregs *regs) __noreturn;
+
 /* Legacy16InitializeYourself */
 void handle_csm_0000(struct bregs *regs)
 {
@@ -67,6 +69,9 @@ void handle_csm_0000(struct bregs *regs)
     csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
 
     regs->ax = 0;
+
+    // Return directly to UEFI instead of unwinding stack.
+    csm_return(regs);
 }
 
 /* Legacy16UpdateBbs */
diff --git a/src/romlayout.S b/src/romlayout.S
index 420bf4e..42aeaff 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -469,38 +469,53 @@ irqentryarg:
         DECL_IRQ_ENTRY hwpic2
 
         EXPORTFUNC entry_csm16
+        .global csm_return
 entry_csm16:
+        // Backup register state
+        pushfw
+        cli
+        cld
+        pushl %eax                      // dummy
         PUSHBREGS
 
-        // Reset stack and store EFI's old SS:SP on it
-        movl %esp, %edx
-        movw %ss, %cx
+        // Backup stack location and convert to a "flat pointer"
+        movl %ss, %ebx
+        movw %bx, BREGS_code+2(%esp)    // Store %ss in bregs->code.seg
+        shll $4, %ebx
+        addl %esp, %ebx
 
+        // Change to BUILD_STACK_ADDR stack
         xorl %eax, %eax
         movw %ax, %ss
-        movw %ax, %ds
         movl $BUILD_STACK_ADDR, %esp
 
-        pushl %ecx // EFI's SS
-        pushl %edx // EFI's SP
-
-        // Turn %edx into a flat pointer (including segment base)
-        shll $4, %ecx
-        addl %ecx, %edx
+        // Jump to 32bit mode and call handle_csm32(bregs)
+        movl $(1f + BUILD_BIOS_ADDR), %edx
+        jmp transition32
+        .code32
+1:      movl %ebx, %eax
+        calll _cfunc32flat_handle_csm32
+        movl $2f, %edx
+        jmp transition16big
 
-        // call32(handle_csm32, bregs, -1)
-        movl $_cfunc32flat_handle_csm32, %eax
-        movl $-1, %ecx
-        calll call32
+csm_return:
+        movl %eax, %ebx
+        movl $2f, %edx
+        jmp transition16big
+        .code16gcc
 
-        // Switch back to EFI's stack and return
-        popl %edx
-        popl %ecx
-        movw %cx, %ss
-        movw %cx, %ds
-        movl %edx, %esp
+        // Switch back to original stack
+2:      movzwl BREGS_code+2(%ebx), %eax
+        movl %eax, %ecx
+        shll $4, %ecx
+        subl %ecx, %ebx
+        movl %eax, %ss
+        movl %ebx, %esp
 
+        // Restore register state and return.
         POPBREGS
+        addw $4, %sp                    // pop dummy
+        popfw
         lretw
 
         // int 18/19 are special - they reset stack and call into 32bit mode.



More information about the SeaBIOS mailing list