[SeaBIOS] [PATCH] vgabios: Use EBDA (instead of PMM) for extra stack

Kevin O'Connor kevin at koconnor.net
Mon Jan 19 19:12:24 CET 2015


Instead of allocating the SeaVGABIOS extra stack via a PCIv3 style PMM
call, use the EBDA to store the stack.  The stack is placed at the end
of the first 1KiB of the EBDA.  Normally this EBDA space is reserved
for the main BIOS, but SeaBIOS doesn't use the space.

This works around an issue with 16bit code running on Windows Vista
(and likely later versions of Windows).  The Windows 16bit emulator
can not handle a stack in the e-segment.  Using the EBDA, and thus
relocating the stack to the 9-segment, works around the issue.

Reported-by: Richard Laager <rlaager at wiktel.com>
Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---

There were several possible ways to resolve the main issue.  I'm
leaning torwards the "use the EBDA for the stack" approach, and the
patch below implements that.

-Kevin

---
 vgasrc/Kconfig    | 18 ++++++++----------
 vgasrc/vgaentry.S | 20 +++++++++++++-------
 vgasrc/vgainit.c  | 56 +++++++------------------------------------------------
 3 files changed, 28 insertions(+), 66 deletions(-)

diff --git a/vgasrc/Kconfig b/vgasrc/Kconfig
index 400e8da..bc1ea48 100644
--- a/vgasrc/Kconfig
+++ b/vgasrc/Kconfig
@@ -90,19 +90,17 @@ menu "VGA ROM"
             Support emulating text mode features when only a
             framebuffer is available.
 
-    config VGA_ALLOCATE_EXTRA_STACK
+    config VGA_EXTRA_STACK
         depends on BUILD_VGABIOS
-        bool "Allocate an internal stack for 16bit interrupt entry point"
+        bool "Use an extra stack located in the EBDA"
         default y
         help
-            Attempt to allocate (via BIOS PMM call) an internal stack
-            for the legacy 16bit 0x10 interrupt entry point.  This
-            reduces the amount of space on the caller's stack that
-            SeaVGABIOS uses.
-
-    config VGA_EXTRA_STACK_SIZE
-        int
-        default 512
+            Use space at the end of the first 1KiB of the EBDA for an
+            internal stack when the legacy 16bit 0x10 interrupt entry
+            point is called.  This reduces the amount of space on the
+            caller's stack that SeaVGABIOS uses.  Normally the first
+            1KiB of the EBDA is reserved for the main BIOS, but
+            SeaBIOS does not use this space.
 
     config VGA_VBE
         depends on BUILD_VGABIOS
diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S
index f9cf656..2e4b200 100644
--- a/vgasrc/vgaentry.S
+++ b/vgasrc/vgaentry.S
@@ -104,15 +104,19 @@ entry_10:
         ENTRY_ARG_VGA handle_10
         iretw
 
+#define BDA_ebda_seg 0x0e
+
         // Entry point using extra stack
         DECLFUNC entry_10_extrastack
 entry_10_extrastack:
         cli
         cld
-        pushw %ds               // Set %ds:%eax to space on ExtraStack
+        pushw %ds               // Set %ds:%eax to end of first 1K of EBDA
         pushl %eax
-        movw %cs:ExtraStackSeg, %ds
-        movl $(CONFIG_VGA_EXTRA_STACK_SIZE-PUSHBREGS_size-16), %eax
+        movw $SEG_BDA, %ax
+        movw %ax, %ds
+        movw BDA_ebda_seg, %ds
+        movl $(1024-PUSHBREGS_size-16), %eax
         SAVEBREGS_POP_DSEAX     // Save registers on extra stack
         movl %esp, PUSHBREGS_size+8(%eax)
         movw %ss, PUSHBREGS_size+12(%eax)
@@ -145,11 +149,13 @@ entry_timer_hook:
 entry_timer_hook_extrastack:
         cli
         cld
-        pushw %ds               // Set %ds:%eax to space on ExtraStack
+        pushw %ds               // Set %ds:%eax to end of first 1K of EBDA
         pushl %eax
-        movw %cs:ExtraStackSeg, %ds
-        movl $(CONFIG_VGA_EXTRA_STACK_SIZE-PUSHBREGS_size-8), %eax
-        SAVEBREGS_POP_DSEAX
+        movw $SEG_BDA, %ax
+        movw %ax, %ds
+        movw BDA_ebda_seg, %ds
+        movl $(1024-PUSHBREGS_size-8), %eax
+        SAVEBREGS_POP_DSEAX     // Save registers on extra stack
         movl %esp, PUSHBREGS_size(%eax)
         movw %ss, PUSHBREGS_size+4(%eax)
 
diff --git a/vgasrc/vgainit.c b/vgasrc/vgainit.c
index 8d12261..78d5556 100644
--- a/vgasrc/vgainit.c
+++ b/vgasrc/vgainit.c
@@ -43,51 +43,6 @@ struct pci_data rom_pci_data VAR16 VISIBLE16 = {
 
 
 /****************************************************************
- * PMM call and extra stack setup
- ****************************************************************/
-
-u16 ExtraStackSeg VAR16 VISIBLE16;
-
-static void
-allocate_extra_stack(void)
-{
-    if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK)
-        return;
-    u32 pmmscan;
-    for (pmmscan=0; pmmscan < BUILD_BIOS_SIZE; pmmscan+=16) {
-        struct pmmheader *pmm = (void*)pmmscan;
-        if (GET_FARVAR(SEG_BIOS, pmm->signature) != PMM_SIGNATURE)
-            continue;
-        if (checksum_far(SEG_BIOS, pmm, GET_FARVAR(SEG_BIOS, pmm->length)))
-            continue;
-        struct segoff_s entry = GET_FARVAR(SEG_BIOS, pmm->entry);
-        dprintf(1, "Attempting to allocate VGA stack via pmm call to %04x:%04x\n"
-                , entry.seg, entry.offset);
-        u16 res1, res2;
-        asm volatile(
-            "pushl %0\n"
-            "pushw $(8|1)\n"            // Permanent low memory request
-            "pushl $0xffffffff\n"       // Anonymous handle
-            "pushl $" __stringify(CONFIG_VGA_EXTRA_STACK_SIZE/16) "\n"
-            "pushw $0x00\n"             // PMM allocation request
-            "lcallw *12(%%esp)\n"
-            "addl $16, %%esp\n"
-            "cli\n"
-            "cld\n"
-            : "+r" (entry.segoff), "=a" (res1), "=d" (res2) : : "cc", "memory");
-        u32 res = res1 | (res2 << 16);
-        if (!res || res == PMM_FUNCTION_NOT_SUPPORTED)
-            return;
-        dprintf(1, "VGA stack allocated at %x\n", res);
-        SET_VGA(ExtraStackSeg, res >> 4);
-        extern void entry_10_extrastack(void);
-        SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10_extrastack));
-        return;
-    }
-}
-
-
-/****************************************************************
  * Timer hook
  ****************************************************************/
 
@@ -110,7 +65,7 @@ hook_timer_irq(void)
     extern void entry_timer_hook_extrastack(void);
     struct segoff_s oldirq = GET_IVT(0x08);
     struct segoff_s newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook);
-    if (CONFIG_VGA_ALLOCATE_EXTRA_STACK && GET_GLOBAL(ExtraStackSeg))
+    if (CONFIG_VGA_EXTRA_STACK)
         newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook_extrastack);
     dprintf(1, "Hooking hardware timer irq (old=%x new=%x)\n"
             , oldirq.segoff, newirq.segoff);
@@ -177,10 +132,13 @@ vga_post(struct bregs *regs)
     if (CONFIG_VGA_STDVGA_PORTS)
         stdvga_build_video_param();
 
+    // Setup int10 entry point
     extern void entry_10(void);
-    SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
-
-    allocate_extra_stack();
+    extern void entry_10_extrastack(void);
+    struct segoff_s newirq = SEGOFF(get_global_seg(), (u32)entry_10);
+    if (CONFIG_VGA_EXTRA_STACK)
+        newirq = SEGOFF(get_global_seg(), (u32)entry_10_extrastack);
+    SET_IVT(0x10, newirq);
 
     hook_timer_irq();
 
-- 
1.9.3




More information about the SeaBIOS mailing list