From 878c92bf7f9d0d2b214a30273f0d7f4892d4e040 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 18 Oct 2021 15:05:38 -0300 Subject: [PATCH] ACPI: Rework suspend types and remove bogus PMCNTRL mirrors (those are SMI traps instead) --- src/acpi.c | 107 +++++++++++++++++++++++++++------------ src/chipset/intel_piix.c | 8 +-- src/chipset/via_pipc.c | 1 - src/include/86box/acpi.h | 10 +++- 4 files changed, 86 insertions(+), 40 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index 6f5471faa..a7301304c 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -37,6 +37,7 @@ #include <86box/acpi.h> #include <86box/machine.h> #include <86box/i2c.h> +#include <86box/ui.h> int acpi_rtc_status = 0; @@ -643,38 +644,46 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) case 0x04: case 0x05: /* PMCNTRL - Power Management Control Register (IO) */ if ((addr == 0x05) && (val & 0x20)) { - sus_typ = (val >> 2) & 7; - switch (sus_typ) { - case 0: - case 6: /* Reserved according to the datasheet but used by eg. the ASUS P2B-LS. */ - /* Soft power off. */ - plat_power_off(); - break; - case 1: + sus_typ = dev->suspend_types[(val >> 2) & 7]; + + if (sus_typ & SUS_POWER_OFF) { + /* Soft power off. */ + plat_power_off(); + return; + } + + if (sus_typ & SUS_SUSPEND) { + if (sus_typ & SUS_NVR) { /* Suspend to RAM. */ nvr_reg_write(0x000f, 0xff, dev->nvr); + } - /* Do a hard reset. */ + if (sus_typ & SUS_RESET_PCI) device_reset_all_pci(); + if (sus_typ & SUS_RESET_CPU) cpu_alt_reset = 0; + if (sus_typ & SUS_RESET_PCI) { pci_reset(); keyboard_at_reset(); mem_a20_alt = 0; mem_a20_recalc(); + } + if (sus_typ & (SUS_RESET_CPU | SUS_RESET_CACHE)) flushmmucache(); + if (sus_typ & SUS_RESET_CPU) resetx86(); - break; - default: - dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3f07 /* 0x3c07 */; - break; + + /* Resume immediately as a power button is not implemented yet. */ + ui_msgbox_ex(MBX_INFO, L"Sleep mode", L"Press OK to resume the emulated machine.", NULL, NULL, NULL); + dev->regs.pmsts |= 0x8000; } - } else - dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3f07 /* 0x3c07 */; + } + dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3f07 /* 0x3c07 */; break; } } @@ -1195,11 +1204,7 @@ acpi_aux_reg_read_common(int size, uint16_t addr, void *p) acpi_t *dev = (acpi_t *) p; uint8_t ret = 0xff; - if (dev->vendor == VEN_VIA_596B) - ret = acpi_reg_read_via_596b(size, addr - (0xf0 - 0x04), p); - else if (dev->vendor == VEN_INTEL) - ret = acpi_reg_read_intel(size, addr - (0x40 - 0x04), p); - else if (dev->vendor == VEN_SMC) + if (dev->vendor == VEN_SMC) ret = acpi_aux_reg_read_smc(size, addr, p); return ret; @@ -1211,11 +1216,7 @@ acpi_aux_reg_write_common(int size, uint16_t addr, uint8_t val, void *p) { acpi_t *dev = (acpi_t *) p; - if (dev->vendor == VEN_VIA_596B) - acpi_reg_write_via_596b(size, addr - (0xf0 - 0x04), val, p); - else if (dev->vendor == VEN_INTEL) - acpi_reg_write_intel(size, addr - (0x40 - 0x04), val, p); - else if (dev->vendor == VEN_SMC) + if (dev->vendor == VEN_SMC) acpi_aux_reg_write_smc(size, addr, val, p); } @@ -1273,7 +1274,7 @@ acpi_aux_reg_readl(uint16_t addr, void *p) ret |= (acpi_aux_reg_read_common(4, addr + 2, p) << 16); ret |= (acpi_aux_reg_read_common(4, addr + 3, p) << 24); - acpi_log("ACPI: Read L %08X from %04X\n", ret, addr); + acpi_log("ACPI: Read Aux L %08X from %04X\n", ret, addr); return ret; } @@ -1287,7 +1288,7 @@ acpi_aux_reg_readw(uint16_t addr, void *p) ret = acpi_aux_reg_read_common(2, addr, p); ret |= (acpi_aux_reg_read_common(2, addr + 1, p) << 8); - acpi_log("ACPI: Read W %08X from %04X\n", ret, addr); + acpi_log("ACPI: Read Aux W %04X from %04X\n", ret, addr); return ret; } @@ -1300,6 +1301,8 @@ acpi_aux_reg_read(uint16_t addr, void *p) ret = acpi_aux_reg_read_common(1, addr, p); + acpi_log("ACPI: Read Aux B %02X from %04X\n", ret, addr); + return ret; } @@ -1338,6 +1341,8 @@ acpi_reg_write(uint16_t addr, uint8_t val, void *p) static void acpi_aux_reg_writel(uint16_t addr, uint32_t val, void *p) { + acpi_log("ACPI: Write Aux L %08X to %04X\n", val, addr); + acpi_aux_reg_write_common(4, addr, val & 0xff, p); acpi_aux_reg_write_common(4, addr + 1, (val >> 8) & 0xff, p); acpi_aux_reg_write_common(4, addr + 2, (val >> 16) & 0xff, p); @@ -1348,6 +1353,8 @@ acpi_aux_reg_writel(uint16_t addr, uint32_t val, void *p) static void acpi_aux_reg_writew(uint16_t addr, uint16_t val, void *p) { + acpi_log("ACPI: Write Aux W %04X to %04X\n", val, addr); + acpi_aux_reg_write_common(2, addr, val & 0xff, p); acpi_aux_reg_write_common(2, addr + 1, (val >> 8) & 0xff, p); } @@ -1356,6 +1363,8 @@ acpi_aux_reg_writew(uint16_t addr, uint16_t val, void *p) static void acpi_aux_reg_write(uint16_t addr, uint8_t val, void *p) { + acpi_log("ACPI: Write Aux B %02X to %04X\n", val, addr); + acpi_aux_reg_write_common(1, addr, val, p); } @@ -1385,6 +1394,8 @@ acpi_update_io_mapping(acpi_t *dev, uint32_t base, int chipset_en) break; } + acpi_log("ACPI: Update I/O %04X to %04X (%sabled)\n", dev->io_base, base, chipset_en ? "en" : "dis"); + if (dev->io_base != 0x0000) { io_removehandler(dev->io_base, size, acpi_reg_read, acpi_reg_readw, acpi_reg_readl, @@ -1407,11 +1418,6 @@ acpi_update_aux_io_mapping(acpi_t *dev, uint32_t base, int chipset_en) int size; switch (dev->vendor) { - case VEN_INTEL: - case VEN_VIA_596B: - /* Undocumented mirror of PMCNTRL. */ - size = 0x001; - break; case VEN_SMC: size = 0x008; break; @@ -1420,6 +1426,8 @@ acpi_update_aux_io_mapping(acpi_t *dev, uint32_t base, int chipset_en) break; } + acpi_log("ACPI: Update Aux I/O %04X to %04X (%sabled)\n", dev->aux_io_base, base, chipset_en ? "en" : "dis"); + if (dev->aux_io_base != 0x0000) { io_removehandler(dev->aux_io_base, size, acpi_aux_reg_read, acpi_aux_reg_readw, acpi_aux_reg_readl, @@ -1661,6 +1669,41 @@ acpi_init(const device_t *info) i2c_smbus = i2c_gpio_get_bus(dev->i2c); } + switch (dev->vendor) { + case VEN_ALI: + dev->suspend_types[0] = SUS_POWER_OFF; + dev->suspend_types[1] = SUS_POWER_OFF; + dev->suspend_types[2] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI; + dev->suspend_types[3] = SUS_SUSPEND; + break; + + case VEN_VIA: + dev->suspend_types[0] = SUS_POWER_OFF; + dev->suspend_types[2] = SUS_SUSPEND; + break; + + case VEN_VIA_596B: + dev->suspend_types[1] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI; + dev->suspend_types[2] = SUS_POWER_OFF; + dev->suspend_types[4] = SUS_SUSPEND; + dev->suspend_types[5] = SUS_SUSPEND | SUS_RESET_CPU; + dev->suspend_types[6] = SUS_SUSPEND | SUS_RESET_CPU | SUS_RESET_PCI; + break; + + case VEN_INTEL: + dev->suspend_types[0] = SUS_POWER_OFF; + dev->suspend_types[1] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI; + dev->suspend_types[2] = SUS_SUSPEND | SUS_RESET_CPU; + dev->suspend_types[3] = SUS_SUSPEND | SUS_RESET_CACHE; + dev->suspend_types[4] = SUS_SUSPEND; + break; + + case VEN_SIS: + dev->suspend_types[0] = SUS_SUSPEND; + dev->suspend_types[4] = SUS_POWER_OFF; + break; + } + timer_add(&dev->timer, acpi_timer_count, dev, 0); timer_set_delay_u64(&dev->timer, ACPICONST); diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 032a94351..a865e045a 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -813,13 +813,11 @@ piix_write(int func, int addr, uint8_t val, void *priv) fregs[0x40] = (val & 0xc0) | 1; dev->acpi_io_base = (dev->regs[3][0x41] << 8) | (dev->regs[3][0x40] & 0xc0); acpi_update_io_mapping(dev->acpi, dev->acpi_io_base, (dev->regs[3][0x80] & 0x01)); - acpi_update_aux_io_mapping(dev->acpi, dev->acpi_io_base + 0x40, (dev->regs[3][0x80] & 0x01)); break; case 0x41: fregs[0x41] = val; dev->acpi_io_base = (dev->regs[3][0x41] << 8) | (dev->regs[3][0x40] & 0xc0); acpi_update_io_mapping(dev->acpi, dev->acpi_io_base, (dev->regs[3][0x80] & 0x01)); - acpi_update_aux_io_mapping(dev->acpi, dev->acpi_io_base + 0x40, (dev->regs[3][0x80] & 0x01)); break; case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: @@ -846,12 +844,10 @@ piix_write(int func, int addr, uint8_t val, void *priv) break; case 0x4f: case 0x80: case 0xd2: fregs[addr] = val & 0x0f; - if (addr == 0x80) { + if (addr == 0x80) acpi_update_io_mapping(dev->acpi, dev->acpi_io_base, (dev->regs[3][0x80] & 0x01)); - acpi_update_aux_io_mapping(dev->acpi, dev->acpi_io_base + 0x40, (dev->regs[3][0x80] & 0x01)); - } else if (addr == 0xd2) { + else if (addr == 0xd2) smbus_update_io_mapping(dev); - } break; case 0x50: fregs[addr] = val & 0x3f; diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index d609f47b5..41667edfd 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -1128,7 +1128,6 @@ pipc_write(int func, int addr, uint8_t val, void *priv) c -= 0x400; acpi_set_timer32(dev->acpi, dev->power_regs[0x41] & 0x08); acpi_update_io_mapping(dev->acpi, c, dev->power_regs[0x41] & 0x80); - acpi_update_aux_io_mapping(dev->acpi, c + 0xf0, dev->power_regs[0x41] & 0x80); break; case 0x42: diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index 08019d352..4637262f8 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -39,6 +39,13 @@ extern "C" { #define SCI_EN (1 << 0) #define SUS_EN (1 << 13) +#define SUS_POWER_OFF (1 << 0) +#define SUS_SUSPEND (1 << 1) +#define SUS_NVR (1 << 2) +#define SUS_RESET_CPU (1 << 3) +#define SUS_RESET_CACHE (1 << 4) +#define SUS_RESET_PCI (1 << 5) + #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 @@ -79,7 +86,8 @@ typedef struct { acpi_regs_t regs; uint8_t gpireg2_default, pad[3], - gporeg_default[4]; + gporeg_default[4], + suspend_types[8]; uint16_t io_base, aux_io_base; int vendor, slot, irq_mode,