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.
-Kevin
diff --git a/src/csm.c b/src/csm.c index a773f0d..ee14486 100644 --- a/src/csm.c +++ b/src/csm.c @@ -67,6 +67,14 @@ 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. + extern void csm_return(); + asm volatile( + " jmp transition16" + : : "d"((u32)csm_return - BUILD_BIOS_ADDR), "S"(regs->code.seg) + , "b"((u32)regs - (regs->code.seg << 4)) + : "memory"); }
/* Legacy16UpdateBbs */ diff --git a/src/romlayout.S b/src/romlayout.S index 420bf4e..98f2b11 100644 --- a/src/romlayout.S +++ b/src/romlayout.S @@ -470,37 +470,48 @@ irqentryarg:
EXPORTFUNC entry_csm16 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 + movl %ss, %esi + movl %esp, %ebx + movl %esi, BREGS_code+2(%esp) // Also store %ss in bregs->code.seg
+ // Change to BUILD_STACK_ADDR stack xorl %eax, %eax - movw %ax, %ss movw %ax, %ds + movw %ax, %ss movl $BUILD_STACK_ADDR, %esp
- pushl %ecx // EFI's SS - pushl %edx // EFI's SP + // Turn %eax into a flat pointer of struct bregs + movl %esi, %eax + shll $4, %eax + addl %ebx, %eax
- // Turn %edx into a flat pointer (including segment base) - shll $4, %ecx - addl %ecx, %edx - - // call32(handle_csm32, bregs, -1) - movl $_cfunc32flat_handle_csm32, %eax - movl $-1, %ecx - calll call32 + // Jump to 32bit mode and call handle_csm32(bregs) + movl $(1f + BUILD_BIOS_ADDR), %edx + jmp transition32 + .code32 +1: calll _cfunc32flat_handle_csm32 + movl $csm_return, %edx + jmp transition16 + .code16gcc
- // Switch back to EFI's stack and return - popl %edx - popl %ecx - movw %cx, %ss - movw %cx, %ds - movl %edx, %esp + .global csm_return +csm_return: + // Switch back to original stack + movl %esi, %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.