vgabios: Support allocating an extra stack for vgabios calls and default on.

Add code to allocate an extra stack for the main vgabios int 0x10
entry point.  The allocation is done via the PMM spec and uses a PCI
v3 permanent low memory region request.  This request will work with
SeaBIOS - it is unknown how many other main BIOS implementations
support this PMM call.

The extra stack is useful for old DOS programs that call the VGABIOS
and expect it to work with very small amounts of stack space.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2013-11-30 19:16:15 -05:00
parent 865bfedf10
commit 4a8b58cb6c
4 changed files with 111 additions and 1 deletions

View File

@ -215,7 +215,7 @@ $(OUT)vgaccode16.o: $(OUT)vgaccode16.raw.s scripts/vgafixup.py
$(Q)$(PYTHON) ./scripts/vgafixup.py $< $(OUT)vgaccode16.s
$(Q)$(AS) --32 src/code16gcc.s $(OUT)vgaccode16.s -o $@
$(OUT)vgaentry.o: vgasrc/vgaentry.S $(OUT)autoconf.h
$(OUT)vgaentry.o: vgasrc/vgaentry.S $(OUT)autoconf.h $(OUT)asm-offsets.h
@echo " Compiling (16bit) $@"
$(Q)$(CC) $(CFLAGS16VGA) -c -D__ASSEMBLY__ $< -o $@

View File

@ -68,6 +68,20 @@ menu "VGA ROM"
bool
default !NO_VGABIOS
config VGA_ALLOCATE_EXTRA_STACK
depends on BUILD_VGABIOS
bool "Allocate an internal stack for 16bit interrupt entry point"
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
config VGA_VBE
depends on BUILD_VGABIOS
bool "Video BIOS Extensions (VBE)"

View File

@ -13,6 +13,7 @@
#include "hw/pci_regs.h" // PCI_VENDOR_ID
#include "output.h" // dprintf
#include "std/optionrom.h" // struct pci_data
#include "std/pmm.h" // struct pmmheader
#include "std/vbe.h" // VBE_RETURN_STATUS_FAILED
#include "stdvga.h" // stdvga_set_cursor_shape
#include "string.h" // memset_far
@ -1277,6 +1278,46 @@ init_bios_area(void)
SET_BDA(video_msr, 0x09);
}
u16 ExtraStackSeg VAR16 VISIBLE16;
static void
allocate_extra_stack(void)
{
if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK)
return;
void *pmmscan = (void*)BUILD_BIOS_ADDR;
for (; pmmscan < (void*)BUILD_BIOS_ADDR+BUILD_BIOS_SIZE; pmmscan+=16) {
struct pmmheader *pmm = pmmscan;
if (pmm->signature != PMM_SIGNATURE)
continue;
if (checksum_far(0, pmm, pmm->length))
continue;
struct segoff_s entry = 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) "\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;
}
}
int VgaBDF VAR16 = -1;
int HaveRunInit VAR16;
@ -1314,6 +1355,8 @@ vga_post(struct bregs *regs)
extern void entry_10(void);
SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
allocate_extra_stack();
SET_VGA(HaveRunInit, 1);
// Fixup checksum

View File

@ -5,6 +5,7 @@
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "asm-offsets.h" // BREGS_*
#include "config.h" // CONFIG_*
#include "entryfuncs.S" // ENTRY_*
@ -75,3 +76,55 @@ _optionrom_entry:
entry_10:
ENTRY_ARG_VGA handle_10
iretw
// Entry point using extra stack
DECLFUNC entry_10_extrastack
entry_10_extrastack:
cli
cld
pushw %ds // Set %ds:%eax to space on ExtraStack
pushl %eax
movzwl %cs:ExtraStackSeg, %eax
movl %eax, %ds
movl $(CONFIG_VGA_EXTRA_STACK_SIZE-BREGS_size-8), %eax
popl BREGS_eax(%eax) // Backup registers
popw BREGS_ds(%eax)
movl %edi, BREGS_edi(%eax)
movl %esi, BREGS_esi(%eax)
movl %ebp, BREGS_ebp(%eax)
movl %ebx, BREGS_ebx(%eax)
movl %edx, BREGS_edx(%eax)
movl %ecx, BREGS_ecx(%eax)
movw %es, BREGS_es(%eax)
movl %esp, BREGS_size+0(%eax)
movzwl %sp, %esp
movw %ss, BREGS_size+4(%eax)
movl (%esp), %edx
movl %edx, BREGS_code(%eax)
movw 4(%esp), %dx
movw %dx, BREGS_flags(%eax)
movw %ds, %dx // Setup %ss/%esp and call function
movw %dx, %ss
movl %eax, %esp
pushw %ax ; callw handle_10
movl %esp, %eax // Restore registers and return
movw BREGS_size+4(%eax), %ss
movl BREGS_size+0(%eax), %esp
popl %edx
popw %dx
pushw BREGS_flags(%eax)
pushl BREGS_code(%eax)
movl BREGS_edi(%eax), %edi
movl BREGS_esi(%eax), %esi
movl BREGS_ebp(%eax), %ebp
movl BREGS_ebx(%eax), %ebx
movl BREGS_edx(%eax), %edx
movl BREGS_ecx(%eax), %ecx
movw BREGS_es(%eax), %es
pushw BREGS_ds(%eax)
pushl BREGS_eax(%eax)
popl %eax
popw %ds
iretw