// Main VGA bios initialization // // Copyright (C) 2009-2013 Kevin O'Connor // Copyright (C) 2001-2008 the LGPL VGABios developers Team // // This file may be distributed under the terms of the GNU LGPLv3 license. #include "biosvar.h" // SET_BDA #include "bregs.h" // struct bregs #include "hw/pci.h" // pci_config_readw #include "hw/pci_regs.h" // PCI_VENDOR_ID #include "hw/serialio.h" // serial_debug_preinit #include "output.h" // dprintf #include "std/optionrom.h" // struct pci_data #include "std/pmm.h" // struct pmmheader #include "string.h" // checksum_far #include "vgabios.h" // SET_VGA #include "vgahw.h" // vgahw_setup #include "vgautil.h" // swcursor_check_event #if CONFIG_X86 // Type of emulator platform - for dprintf with certain compile options. int PlatformRunningOn VAR16; #endif /**************************************************************** * PCI Data ****************************************************************/ struct pci_data rom_pci_data VAR16 VISIBLE16 = { .signature = PCI_ROM_SIGNATURE, .vendor = CONFIG_VGA_VID, .device = CONFIG_VGA_DID, .dlen = 0x18, .class_hi = 0x300, .irevision = 1, .type = PCIROM_CODETYPE_X86, .indicator = 0x80, }; /**************************************************************** * PMM call and extra stack setup ****************************************************************/ u32 allocate_pmm(u32 size, int highmem, int aligned) { 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 %u bytes %s via pmm call to %04x:%04lx\n" , size, highmem ? "highmem" : "lowmem" , entry.seg, entry.offset); u16 res1, res2; u16 flags = 8 | ( highmem ? 2 : 1 )| ( aligned ? 4 : 0 ); size >>= 4; asm volatile( "pushl %0\n" "pushw %2\n" // flags "pushl $0xffffffff\n" // Anonymous handle "pushl %1\n" // size "pushw $0x00\n" // PMM allocation request "lcallw *12(%%esp)\n" "addl $16, %%esp\n" "cli\n" "cld\n" : "+r" (entry.segoff), "+r" (size), "+r" (flags), "=a" (res1), "=d" (res2) : : "cc", "memory"); u32 res = res1 | (res2 << 16); if (!res || res == PMM_FUNCTION_NOT_SUPPORTED) return 0; return res; } return 0; } u16 ExtraStackSeg VAR16 VISIBLE16; static void allocate_extra_stack(void) { if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK) return; u32 res = allocate_pmm(CONFIG_VGA_EXTRA_STACK_SIZE, 0, 0); if (!res) 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 ****************************************************************/ struct segoff_s Timer_Hook_Resume VAR16 VISIBLE16; void VISIBLE16 handle_timer_hook(void) { swcursor_check_event(); } static void hook_timer_irq(void) { if (!CONFIG_VGA_EMULATE_TEXT) return; extern void entry_timer_hook(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)) 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); SET_VGA(Timer_Hook_Resume, oldirq); SET_IVT(0x08, newirq); } /**************************************************************** * VGA post ****************************************************************/ static void init_bios_area(void) { // init detected hardware BIOS Area // set 80x25 color (not clear from RBIL but usual) set_equipment_flags(0x30, 0x20); // Set the basic modeset options SET_BDA(modeset_ctl, 0x51); SET_BDA(dcc_index, CONFIG_VGA_STDVGA_PORTS ? 0x08 : 0xff); // FIXME SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but... SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but... } int VgaBDF VAR16 = -1; int HaveRunInit VAR16; void VISIBLE16 vga_post(struct bregs *regs) { serial_debug_preinit(); dprintf(1, "Start SeaVGABIOS (version %s)\n", VERSION); dprintf(1, "VGABUILD: %s\n", BUILDINFO); debug_enter(regs, DEBUG_VGA_POST); if (CONFIG_VGA_PCI && !GET_GLOBAL(HaveRunInit)) { u16 bdf = regs->ax; if ((pci_config_readw(bdf, PCI_VENDOR_ID) == GET_GLOBAL(rom_pci_data.vendor)) && (pci_config_readw(bdf, PCI_DEVICE_ID) == GET_GLOBAL(rom_pci_data.device))) SET_VGA(VgaBDF, bdf); } int ret = vgahw_setup(); if (ret) { dprintf(1, "Failed to initialize VGA hardware. Exiting.\n"); return; } if (GET_GLOBAL(HaveRunInit)) return; init_bios_area(); if (CONFIG_VGA_STDVGA_PORTS) stdvga_build_video_param(); extern void entry_10(void); SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10)); allocate_extra_stack(); hook_timer_irq(); SET_VGA(HaveRunInit, 1); // Fixup checksum extern u8 _rom_header_size, _rom_header_checksum; SET_VGA(_rom_header_checksum, 0); u8 sum = -checksum_far(get_global_seg(), 0, GET_GLOBAL(_rom_header_size) * 512); SET_VGA(_rom_header_checksum, sum); }