On Tue, Sep 05, 2017 at 10:01:41AM +0200, Gerd Hoffmann wrote: > > Note, though, in addition to checking for broken x86emu, the > > assembler > > entry code would also have to check that the last mode was not set > > via > > a vesa call (to avoid the "skifree" bug). > > Ok, Is there some easy way to access the BDA from assembler code > (specifically the video_mode field)? Guess I must set a segment > register for that. Maybe it's easier to just place an additional flag > in the fseg which we can easily reach via cs override ...
The flag can't be in the f-segment because it needs to be read/writable at runtime. I ran some tests - it looks like it is okay to access the varlow segment - one just can't write to it. Unfortunately, it's not enough to simply test for a legacy modeset call (int 0x10 ah=0x00) as it looks like Vista calls that in its emulation mode during startup. However, it looks like it is okay if one verifies that the legacy modeset call is for a text mode (eg, int 0x10 ax=0x0003). I put together the patch below (based off of current seabios master). It doesn't do anything except test that one can safely enter the C code. It survives winxp, winvista, winvista+skifree, and xorg on fedora 13 (these were my typical trouble spots with vgabios testing). -Kevin >From ad37047c3bbd7b5d92b849acfee3844a64ac1a28 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor <ke...@koconnor.net> Date: Tue, 5 Sep 2017 11:45:08 -0400 Subject: [PATCH] sercon: Add support for hooking vga handler Signed-off-by: Gerd Hoffmann <kra...@redhat.com> Signed-off-by: Kevin O'Connor <ke...@koconnor.net> --- Makefile | 1 + src/Kconfig | 5 +++++ src/config.h | 1 + src/optionroms.c | 6 +++++- src/romlayout.S | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sercon.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util.h | 3 +++ 7 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/sercon.c diff --git a/Makefile b/Makefile index 946df7e..07ac747 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ LD32BIT_FLAG:=-melf_i386 # Source files SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \ + sercon.c \ hw/pci.c hw/timer.c hw/rtc.c hw/dma.c hw/pic.c hw/ps2port.c hw/serialio.c \ hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \ hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \ diff --git a/src/Kconfig b/src/Kconfig index 77ec9c7..55a87cb 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -306,6 +306,11 @@ menu "Hardware support" default y help Support serial ports. This also enables int 14 serial port calls. + config SERCON + bool "Serial console" + default y + help + Support redirecting vga output to the serial console. config LPT bool "Parallel port" default y diff --git a/src/config.h b/src/config.h index baca029..e56d4a7 100644 --- a/src/config.h +++ b/src/config.h @@ -100,6 +100,7 @@ #define DEBUG_HDL_pmm 1 #define DEBUG_HDL_pcibios 9 #define DEBUG_HDL_apm 9 +#define DEBUG_HDL_sercon 9 #define DEBUG_unimplemented 2 #define DEBUG_invalid 3 diff --git a/src/optionroms.c b/src/optionroms.c index 65f7fe0..4f6611e 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -404,8 +404,10 @@ struct rom_header *VgaROM; void vgarom_setup(void) { - if (! CONFIG_OPTIONROMS) + if (! CONFIG_OPTIONROMS) { + sercon_setup(); return; + } dprintf(1, "Scan for VGA option rom\n"); @@ -432,6 +434,8 @@ vgarom_setup(void) run_file_roms("vgaroms/", 1, NULL); rom_reserve(0); + sercon_setup(); + if (rom_get_last() == BUILD_ROM_START) // No VGA rom found return; diff --git a/src/romlayout.S b/src/romlayout.S index 89b3784..8ed53dc 100644 --- a/src/romlayout.S +++ b/src/romlayout.S @@ -414,6 +414,61 @@ __csm_return: popfw lretw +// Serial console "hooked vga" entry point + DECLFUNC entry_sercon +entry_sercon: + // Setup for chain loading to real vga handler + pushfw + pushl %cs:sercon_real_vga_handler + + // Set %ds to varlow segment + cli + cld + pushw %ds + pushl %eax + movl $_zonelow_seg, %eax + movl %eax, %ds + + // Test if the sercon handler can be called + movl %esp, %eax // Test for broken x86emu + pushl $1f + retl +1: cmpl %esp, %eax + jne 4f + cmpb $0, sercon_enable // Test that sercon is enabled + je 3f + + // Call handle_sercon() on the extra stack +2: movl StackPos, %eax + subl $PUSHBREGS_size+8, %eax + SAVEBREGS_POP_DSEAX + movl %esp, PUSHBREGS_size(%eax) + movw %ss, PUSHBREGS_size+4(%eax) + + movw %ds, %dx // Setup %ss/%esp and call function + movw %dx, %ss + movl %eax, %esp + calll handle_sercon + + movl %esp, %eax // Restore registers and return + movw PUSHBREGS_size+4(%eax), %ss + movl PUSHBREGS_size(%eax), %esp + RESTOREBREGS_DSEAX + iretw + + // sercon disabled - verify not 0x03 modeset and otherwise exit +3: popl %eax + cmpw $0x0003, %ax + jne 5f + pushl %eax + jmp 2b + + // Running on broken x86emu - restore stack and exit +4: movl %eax, %esp + popl %eax +5: popw %ds + iretw + /**************************************************************** * Interrupt entry points diff --git a/src/sercon.c b/src/sercon.c new file mode 100644 index 0000000..7307772 --- /dev/null +++ b/src/sercon.c @@ -0,0 +1,54 @@ +// Serial console support +// +// Copyright (C) 2017 Kevin O'Connor <ke...@koconnor.net> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // GET_IVT +#include "bregs.h" // struct bregs +#include "output.h" // dprintf +#include "romfile.h" // romfile_loadint +#include "util.h" // sercon_setup + +struct segoff_s sercon_real_vga_handler VARFSEG; +u8 sercon_enable VARLOW; + +void +sercon_setup(void) +{ + ASSERT32FLAT(); + if (!CONFIG_SERCON || (GET_IVT(0x10).segoff != FUNC16(entry_10).segoff + && !romfile_loadint("etc/sercon-hook", 0))) + return; + + dprintf(3, "init sercon\n"); + sercon_real_vga_handler = GET_IVT(0x10); + SET_IVT(0x10, FUNC16(entry_sercon)); +} + +static void +sercon_1000(struct bregs *regs) +{ + int mode = regs->al & 0x7f; + SET_LOW(sercon_enable, (mode == 0x03)); +} + +static void +sercon_104f(struct bregs *regs) +{ + // Disable sercon entry point on any vesa modeset + if (regs->al == 0x00) + SET_LOW(sercon_enable, 0); +} + +void VISIBLE16 +handle_sercon(struct bregs *regs) +{ + if (!CONFIG_SERCON) + return; + debug_enter(regs, DEBUG_HDL_sercon); + switch (regs->ah) { + case 0x00: sercon_1000(regs); break; + case 0x4f: sercon_104f(regs); break; + } +} diff --git a/src/util.h b/src/util.h index 8269057..8b747b3 100644 --- a/src/util.h +++ b/src/util.h @@ -229,6 +229,9 @@ void startBoot(void); void reloc_preinit(void *f, void *arg); void code_mutable_preinit(void); +// sercon.c +void sercon_setup(void); + // serial.c void serial_setup(void); void lpt_setup(void); -- 2.9.5 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://mail.coreboot.org/mailman/listinfo/seabios