/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * * This file is part of the 86Box distribution. * * Skeleton I/O APIC implementation, currently housing the MPS * table patcher for machines that require it. * * * * Author: RichardG, * * Copyright 2020 RichardG. */ #include #include #include #include #include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> #include <86box/device.h> #include <86box/machine.h> #include <86box/mem.h> #include <86box/chipset.h> typedef struct { uint8_t dummy; } ioapic_t; #ifdef ENABLE_IOAPIC_LOG int ioapic_do_log = ENABLE_IOAPIC_LOG; static void ioapic_log(const char *fmt, ...) { va_list ap; if (ioapic_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else #define ioapic_log(fmt, ...) #endif static void ioapic_write(uint16_t port, uint8_t val, void *priv) { uint32_t addr, pcmp; /* target POST FF, issued by Award before jumping to the bootloader */ if (val != 0xff) return; ioapic_log("IOAPIC: Caught POST %02X\n", val); /* The _MP_ table must be located in the BIOS area, the EBDA, or the last 1k of conventional memory; at a 16-byte boundary in all cases. Award writes both tables to the BIOS area. */ for (addr = 0xf0000; addr <= 0xfffff; addr += 16) { /* check signature for the _MP_ table (Floating Point Structure) */ if (mem_readl_phys(addr) != 0x5f504d5f) /* ASCII "_MP_" */ continue; /* read and check pointer to the PCMP table (Configuration Table) */ pcmp = mem_readl_phys(addr + 4); if ((pcmp < 0xf0000) || (pcmp > 0xfffff) || (mem_readl_phys(pcmp) != 0x504d4350)) /* ASCII "PCMP" */ continue; /* patch over the signature on both tables */ ioapic_log("IOAPIC: Patching _MP_ [%08x] and PCMP [%08x] tables\n", addr, pcmp); ram[addr] = ram[addr + 1] = ram[addr + 2] = ram[addr + 3] = 0xff; ram[pcmp] = ram[pcmp + 1] = ram[pcmp + 2] = ram[pcmp + 3] = 0xff; break; } } static void ioapic_reset(ioapic_t *dev) { } static void ioapic_close(void *priv) { ioapic_t *dev = (ioapic_t *) priv; io_removehandler(0x80, 1, NULL, NULL, NULL, ioapic_write, NULL, NULL, NULL); free(dev); } static void * ioapic_init(const device_t *info) { ioapic_t *dev = (ioapic_t *) malloc(sizeof(ioapic_t)); memset(dev, 0, sizeof(ioapic_t)); ioapic_reset(dev); io_sethandler(0x80, 1, NULL, NULL, NULL, ioapic_write, NULL, NULL, NULL); return dev; } const device_t ioapic_device = { "I/O Advanced Programmable Interrupt Controller", DEVICE_AT, 0, ioapic_init, ioapic_close, NULL, { NULL }, NULL, NULL, NULL };