diff --git a/MAINTAINERS b/MAINTAINERS index da10756abf..9b2aa18e1f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1183,6 +1183,7 @@ F: hw/intc/loongson_liointc.c F: hw/mips/loongson3_bootp.c F: hw/mips/loongson3_bootp.h F: hw/mips/loongson3_virt.c +F: tests/acceptance/machine_mips_loongson3v.py Boston M: Paul Burton diff --git a/hw/intc/loongson_liointc.c b/hw/intc/loongson_liointc.c index f823d484e0..cc11b544cb 100644 --- a/hw/intc/loongson_liointc.c +++ b/hw/intc/loongson_liointc.c @@ -41,7 +41,7 @@ #define R_IEN_CLR 0x2c #define R_ISR_SIZE 0x8 #define R_START 0x40 -#define R_END 0x64 +#define R_END (R_START + R_ISR_SIZE * NUM_CORES) struct loongson_liointc { SysBusDevice parent_obj; @@ -125,7 +125,12 @@ liointc_read(void *opaque, hwaddr addr, unsigned int size) } if (addr >= R_START && addr < R_END) { - int core = (addr - R_START) / R_ISR_SIZE; + hwaddr offset = addr - R_START; + int core = offset / R_ISR_SIZE; + + if (offset % R_ISR_SIZE) { + goto out; + } r = p->per_core_isr[core]; goto out; } @@ -169,7 +174,12 @@ liointc_write(void *opaque, hwaddr addr, } if (addr >= R_START && addr < R_END) { - int core = (addr - R_START) / R_ISR_SIZE; + hwaddr offset = addr - R_START; + int core = offset / R_ISR_SIZE; + + if (offset % R_ISR_SIZE) { + goto out; + } p->per_core_isr[core] = value; goto out; } diff --git a/hw/isa/trace-events b/hw/isa/trace-events index d267d3e652..641d69eedf 100644 --- a/hw/isa/trace-events +++ b/hw/isa/trace-events @@ -17,5 +17,7 @@ apm_io_write(uint8_t addr, uint8_t val) "write addr=0x%x val=0x%02x" # vt82c686.c via_isa_write(uint32_t addr, uint32_t val, int len) "addr 0x%x val 0x%x len 0x%x" via_pm_write(uint32_t addr, uint32_t val, int len) "addr 0x%x val 0x%x len 0x%x" +via_pm_io_read(uint32_t addr, uint32_t val, int len) "addr 0x%x val 0x%x len 0x%x" +via_pm_io_write(uint32_t addr, uint32_t val, int len) "addr 0x%x val 0x%x len 0x%x" via_superio_read(uint8_t addr, uint8_t val) "addr 0x%x val 0x%x" via_superio_write(uint8_t addr, uint32_t val) "addr 0x%x val 0x%x" diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index a6f5a0843d..5db9b1706c 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -16,70 +16,291 @@ #include "hw/qdev-properties.h" #include "hw/isa/isa.h" #include "hw/isa/superio.h" +#include "hw/intc/i8259.h" +#include "hw/irq.h" +#include "hw/dma/i8257.h" +#include "hw/timer/i8254.h" +#include "hw/rtc/mc146818rtc.h" #include "migration/vmstate.h" #include "hw/isa/apm.h" #include "hw/acpi/acpi.h" #include "hw/i2c/pm_smbus.h" #include "qapi/error.h" +#include "qemu/log.h" #include "qemu/module.h" +#include "qemu/range.h" #include "qemu/timer.h" #include "exec/address-spaces.h" #include "trace.h" -typedef struct SuperIOConfig { - uint8_t regs[0x100]; - uint8_t index; - uint8_t data; -} SuperIOConfig; +#define TYPE_VIA_PM "via-pm" +OBJECT_DECLARE_SIMPLE_TYPE(ViaPMState, VIA_PM) -struct VT82C686BISAState { +struct ViaPMState { PCIDevice dev; - MemoryRegion superio; - SuperIOConfig superio_cfg; + MemoryRegion io; + ACPIREGS ar; + APMState apm; + PMSMBus smb; }; -OBJECT_DECLARE_SIMPLE_TYPE(VT82C686BISAState, VT82C686B_ISA) +static void pm_io_space_update(ViaPMState *s) +{ + uint32_t pmbase = pci_get_long(s->dev.config + 0x48) & 0xff80UL; + + memory_region_transaction_begin(); + memory_region_set_address(&s->io, pmbase); + memory_region_set_enabled(&s->io, s->dev.config[0x41] & BIT(7)); + memory_region_transaction_commit(); +} + +static void smb_io_space_update(ViaPMState *s) +{ + uint32_t smbase = pci_get_long(s->dev.config + 0x90) & 0xfff0UL; + + memory_region_transaction_begin(); + memory_region_set_address(&s->smb.io, smbase); + memory_region_set_enabled(&s->smb.io, s->dev.config[0xd2] & BIT(0)); + memory_region_transaction_commit(); +} + +static int vmstate_acpi_post_load(void *opaque, int version_id) +{ + ViaPMState *s = opaque; + + pm_io_space_update(s); + smb_io_space_update(s); + return 0; +} + +static const VMStateDescription vmstate_acpi = { + .name = "vt82c686b_pm", + .version_id = 1, + .minimum_version_id = 1, + .post_load = vmstate_acpi_post_load, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, ViaPMState), + VMSTATE_UINT16(ar.pm1.evt.sts, ViaPMState), + VMSTATE_UINT16(ar.pm1.evt.en, ViaPMState), + VMSTATE_UINT16(ar.pm1.cnt.cnt, ViaPMState), + VMSTATE_STRUCT(apm, ViaPMState, 0, vmstate_apm, APMState), + VMSTATE_TIMER_PTR(ar.tmr.timer, ViaPMState), + VMSTATE_INT64(ar.tmr.overflow_time, ViaPMState), + VMSTATE_END_OF_LIST() + } +}; + +static void pm_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len) +{ + ViaPMState *s = VIA_PM(d); + + trace_via_pm_write(addr, val, len); + pci_default_write_config(d, addr, val, len); + if (ranges_overlap(addr, len, 0x48, 4)) { + uint32_t v = pci_get_long(s->dev.config + 0x48); + pci_set_long(s->dev.config + 0x48, (v & 0xff80UL) | 1); + } + if (range_covers_byte(addr, len, 0x41)) { + pm_io_space_update(s); + } + if (ranges_overlap(addr, len, 0x90, 4)) { + uint32_t v = pci_get_long(s->dev.config + 0x90); + pci_set_long(s->dev.config + 0x90, (v & 0xfff0UL) | 1); + } + if (range_covers_byte(addr, len, 0xd2)) { + s->dev.config[0xd2] &= 0xf; + smb_io_space_update(s); + } +} + +static void pm_io_write(void *op, hwaddr addr, uint64_t data, unsigned size) +{ + trace_via_pm_io_write(addr, data, size); +} + +static uint64_t pm_io_read(void *op, hwaddr addr, unsigned size) +{ + trace_via_pm_io_read(addr, 0, size); + return 0; +} + +static const MemoryRegionOps pm_io_ops = { + .read = pm_io_read, + .write = pm_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void pm_update_sci(ViaPMState *s) +{ + int sci_level, pmsts; + + pmsts = acpi_pm1_evt_get_sts(&s->ar); + sci_level = (((pmsts & s->ar.pm1.evt.en) & + (ACPI_BITMASK_RT_CLOCK_ENABLE | + ACPI_BITMASK_POWER_BUTTON_ENABLE | + ACPI_BITMASK_GLOBAL_LOCK_ENABLE | + ACPI_BITMASK_TIMER_ENABLE)) != 0); + pci_set_irq(&s->dev, sci_level); + /* schedule a timer interruption if needed */ + acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); +} + +static void pm_tmr_timer(ACPIREGS *ar) +{ + ViaPMState *s = container_of(ar, ViaPMState, ar); + pm_update_sci(s); +} + +static void via_pm_reset(DeviceState *d) +{ + ViaPMState *s = VIA_PM(d); + + memset(s->dev.config + PCI_CONFIG_HEADER_SIZE, 0, + PCI_CONFIG_SPACE_SIZE - PCI_CONFIG_HEADER_SIZE); + /* Power Management IO base */ + pci_set_long(s->dev.config + 0x48, 1); + /* SMBus IO base */ + pci_set_long(s->dev.config + 0x90, 1); + + pm_io_space_update(s); + smb_io_space_update(s); +} + +static void via_pm_realize(PCIDevice *dev, Error **errp) +{ + ViaPMState *s = VIA_PM(dev); + + pci_set_word(dev->config + PCI_STATUS, PCI_STATUS_FAST_BACK | + PCI_STATUS_DEVSEL_MEDIUM); + + pm_smbus_init(DEVICE(s), &s->smb, false); + memory_region_add_subregion(pci_address_space_io(dev), 0, &s->smb.io); + memory_region_set_enabled(&s->smb.io, false); + + apm_init(dev, &s->apm, NULL, s); + + memory_region_init_io(&s->io, OBJECT(dev), &pm_io_ops, s, "via-pm", 128); + memory_region_add_subregion(pci_address_space_io(dev), 0, &s->io); + memory_region_set_enabled(&s->io, false); + + acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_cnt_init(&s->ar, &s->io, false, false, 2); +} + +typedef struct via_pm_init_info { + uint16_t device_id; +} ViaPMInitInfo; + +static void via_pm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + ViaPMInitInfo *info = data; + + k->realize = via_pm_realize; + k->config_write = pm_write_config; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = info->device_id; + k->class_id = PCI_CLASS_BRIDGE_OTHER; + k->revision = 0x40; + dc->reset = via_pm_reset; + /* Reason: part of VIA south bridge, does not exist stand alone */ + dc->user_creatable = false; + dc->vmsd = &vmstate_acpi; +} + +static const TypeInfo via_pm_info = { + .name = TYPE_VIA_PM, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(ViaPMState), + .abstract = true, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static const ViaPMInitInfo vt82c686b_pm_init_info = { + .device_id = PCI_DEVICE_ID_VIA_82C686B_PM, +}; + +static const TypeInfo vt82c686b_pm_info = { + .name = TYPE_VT82C686B_PM, + .parent = TYPE_VIA_PM, + .class_init = via_pm_class_init, + .class_data = (void *)&vt82c686b_pm_init_info, +}; + +static const ViaPMInitInfo vt8231_pm_init_info = { + .device_id = PCI_DEVICE_ID_VIA_8231_PM, +}; + +static const TypeInfo vt8231_pm_info = { + .name = TYPE_VT8231_PM, + .parent = TYPE_VIA_PM, + .class_init = via_pm_class_init, + .class_data = (void *)&vt8231_pm_init_info, +}; + + +typedef struct SuperIOConfig { + uint8_t regs[0x100]; + MemoryRegion io; +} SuperIOConfig; static void superio_cfg_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { SuperIOConfig *sc = opaque; + uint8_t idx = sc->regs[0]; - if (addr == 0x3f0) { /* config index register */ - sc->index = data & 0xff; - } else { - bool can_write = true; - /* 0x3f1, config data register */ - trace_via_superio_write(sc->index, data & 0xff); - switch (sc->index) { - case 0x00 ... 0xdf: - case 0xe4: - case 0xe5: - case 0xe9 ... 0xed: - case 0xf3: - case 0xf5: - case 0xf7: - case 0xf9 ... 0xfb: - case 0xfd ... 0xff: - can_write = false; - break; - /* case 0xe6 ... 0xe8: Should set base port of parallel and serial */ - default: - break; - - } - if (can_write) { - sc->regs[sc->index] = data & 0xff; - } + if (addr == 0) { /* config index register */ + sc->regs[0] = data; + return; } + + /* config data register */ + trace_via_superio_write(idx, data); + switch (idx) { + case 0x00 ... 0xdf: + case 0xe4: + case 0xe5: + case 0xe9 ... 0xed: + case 0xf3: + case 0xf5: + case 0xf7: + case 0xf9 ... 0xfb: + case 0xfd ... 0xff: + /* ignore write to read only registers */ + return; + /* case 0xe6 ... 0xe8: Should set base port of parallel and serial */ + default: + qemu_log_mask(LOG_UNIMP, + "via_superio_cfg: unimplemented register 0x%x\n", idx); + break; + } + sc->regs[idx] = data; } static uint64_t superio_cfg_read(void *opaque, hwaddr addr, unsigned size) { SuperIOConfig *sc = opaque; - uint8_t val = sc->regs[sc->index]; + uint8_t idx = sc->regs[0]; + uint8_t val = sc->regs[idx]; - trace_via_superio_read(sc->index, val); + if (addr == 0) { + return idx; + } + if (addr == 1 && idx == 0) { + val = 0; /* reading reg 0 where we store index value */ + } + trace_via_superio_read(idx, val); return val; } @@ -93,6 +314,44 @@ static const MemoryRegionOps superio_cfg_ops = { }, }; + +OBJECT_DECLARE_SIMPLE_TYPE(VT82C686BISAState, VT82C686B_ISA) + +struct VT82C686BISAState { + PCIDevice dev; + qemu_irq cpu_intr; + SuperIOConfig superio_cfg; +}; + +static void via_isa_request_i8259_irq(void *opaque, int irq, int level) +{ + VT82C686BISAState *s = opaque; + qemu_set_irq(s->cpu_intr, level); +} + +static void vt82c686b_write_config(PCIDevice *d, uint32_t addr, + uint32_t val, int len) +{ + VT82C686BISAState *s = VT82C686B_ISA(d); + + trace_via_isa_write(addr, val, len); + pci_default_write_config(d, addr, val, len); + if (addr == 0x85) { + /* BIT(1): enable or disable superio config io ports */ + memory_region_set_enabled(&s->superio_cfg.io, val & BIT(1)); + } +} + +static const VMStateDescription vmstate_via = { + .name = "vt82c686b", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, VT82C686BISAState), + VMSTATE_END_OF_LIST() + } +}; + static void vt82c686b_isa_reset(DeviceState *dev) { VT82C686BISAState *s = VT82C686B_ISA(dev); @@ -120,206 +379,39 @@ static void vt82c686b_isa_reset(DeviceState *dev) s->superio_cfg.regs[0xe8] = 0xbe; /* Serial port 2 base addr */ } -/* write config pci function0 registers. PCI-ISA bridge */ -static void vt82c686b_write_config(PCIDevice *d, uint32_t addr, - uint32_t val, int len) -{ - VT82C686BISAState *s = VT82C686B_ISA(d); - - trace_via_isa_write(addr, val, len); - pci_default_write_config(d, addr, val, len); - if (addr == 0x85) { /* enable or disable super IO configure */ - memory_region_set_enabled(&s->superio, val & 0x2); - } -} - -struct VT686PMState { - PCIDevice dev; - MemoryRegion io; - ACPIREGS ar; - APMState apm; - PMSMBus smb; - uint32_t smb_io_base; -}; - -OBJECT_DECLARE_SIMPLE_TYPE(VT686PMState, VT82C686B_PM) - -static void pm_update_sci(VT686PMState *s) -{ - int sci_level, pmsts; - - pmsts = acpi_pm1_evt_get_sts(&s->ar); - sci_level = (((pmsts & s->ar.pm1.evt.en) & - (ACPI_BITMASK_RT_CLOCK_ENABLE | - ACPI_BITMASK_POWER_BUTTON_ENABLE | - ACPI_BITMASK_GLOBAL_LOCK_ENABLE | - ACPI_BITMASK_TIMER_ENABLE)) != 0); - pci_set_irq(&s->dev, sci_level); - /* schedule a timer interruption if needed */ - acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && - !(pmsts & ACPI_BITMASK_TIMER_STATUS)); -} - -static void pm_tmr_timer(ACPIREGS *ar) -{ - VT686PMState *s = container_of(ar, VT686PMState, ar); - pm_update_sci(s); -} - -static void pm_io_space_update(VT686PMState *s) -{ - uint32_t pm_io_base; - - pm_io_base = pci_get_long(s->dev.config + 0x40); - pm_io_base &= 0xffc0; - - memory_region_transaction_begin(); - memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1); - memory_region_set_address(&s->io, pm_io_base); - memory_region_transaction_commit(); -} - -static void pm_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len) -{ - trace_via_pm_write(addr, val, len); - pci_default_write_config(d, addr, val, len); -} - -static int vmstate_acpi_post_load(void *opaque, int version_id) -{ - VT686PMState *s = opaque; - - pm_io_space_update(s); - return 0; -} - -static const VMStateDescription vmstate_acpi = { - .name = "vt82c686b_pm", - .version_id = 1, - .minimum_version_id = 1, - .post_load = vmstate_acpi_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, VT686PMState), - VMSTATE_UINT16(ar.pm1.evt.sts, VT686PMState), - VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState), - VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState), - VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER_PTR(ar.tmr.timer, VT686PMState), - VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState), - VMSTATE_END_OF_LIST() - } -}; - -/* vt82c686 pm init */ -static void vt82c686b_pm_realize(PCIDevice *dev, Error **errp) -{ - VT686PMState *s = VT82C686B_PM(dev); - uint8_t *pci_conf; - - pci_conf = s->dev.config; - pci_set_word(pci_conf + PCI_COMMAND, 0); - pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK | - PCI_STATUS_DEVSEL_MEDIUM); - - /* 0x48-0x4B is Power Management I/O Base */ - pci_set_long(pci_conf + 0x48, 0x00000001); - - /* SMB ports:0xeee0~0xeeef */ - s->smb_io_base = ((s->smb_io_base & 0xfff0) + 0x0); - pci_conf[0x90] = s->smb_io_base | 1; - pci_conf[0x91] = s->smb_io_base >> 8; - pci_conf[0xd2] = 0x90; - pm_smbus_init(DEVICE(s), &s->smb, false); - memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io); - - apm_init(dev, &s->apm, NULL, s); - - memory_region_init(&s->io, OBJECT(dev), "vt82c686-pm", 64); - memory_region_set_enabled(&s->io, false); - memory_region_add_subregion(get_system_io(), 0, &s->io); - - acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); - acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); - acpi_pm1_cnt_init(&s->ar, &s->io, false, false, 2); -} - -static Property via_pm_properties[] = { - DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void via_pm_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->realize = vt82c686b_pm_realize; - k->config_write = pm_write_config; - k->vendor_id = PCI_VENDOR_ID_VIA; - k->device_id = PCI_DEVICE_ID_VIA_ACPI; - k->class_id = PCI_CLASS_BRIDGE_OTHER; - k->revision = 0x40; - dc->desc = "PM"; - dc->vmsd = &vmstate_acpi; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - device_class_set_props(dc, via_pm_properties); -} - -static const TypeInfo via_pm_info = { - .name = TYPE_VT82C686B_PM, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VT686PMState), - .class_init = via_pm_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -static const VMStateDescription vmstate_via = { - .name = "vt82c686b", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, VT82C686BISAState), - VMSTATE_END_OF_LIST() - } -}; - -/* init the PCI-to-ISA bridge */ static void vt82c686b_realize(PCIDevice *d, Error **errp) { VT82C686BISAState *s = VT82C686B_ISA(d); - uint8_t *pci_conf; + DeviceState *dev = DEVICE(d); ISABus *isa_bus; - uint8_t *wmask; + qemu_irq *isa_irq; int i; - isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), - pci_address_space_io(d), errp); - if (!isa_bus) { - return; - } + qdev_init_gpio_out(dev, &s->cpu_intr, 1); + isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1); + isa_bus = isa_bus_new(dev, get_system_memory(), pci_address_space_io(d), + &error_fatal); + isa_bus_irqs(isa_bus, i8259_init(isa_bus, *isa_irq)); + i8254_pit_init(isa_bus, 0x40, 0, NULL); + i8257_dma_init(isa_bus, 0); + isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO); + mc146818_rtc_init(isa_bus, 2000, NULL); - pci_conf = d->config; - pci_config_set_prog_interface(pci_conf, 0x0); - - wmask = d->wmask; - for (i = 0x00; i < 0xff; i++) { - if (i <= 0x03 || (i >= 0x08 && i <= 0x3f)) { - wmask[i] = 0x00; + for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) { + if (i < PCI_COMMAND || i >= PCI_REVISION_ID) { + d->wmask[i] = 0; } } - memory_region_init_io(&s->superio, OBJECT(d), &superio_cfg_ops, - &s->superio_cfg, "superio", 2); - memory_region_set_enabled(&s->superio, false); + memory_region_init_io(&s->superio_cfg.io, OBJECT(d), &superio_cfg_ops, + &s->superio_cfg, "superio_cfg", 2); + memory_region_set_enabled(&s->superio_cfg.io, false); /* * The floppy also uses 0x3f0 and 0x3f1. * But we do not emulate a floppy, so just set it here. */ memory_region_add_subregion(isa_bus->address_space_io, 0x3f0, - &s->superio); + &s->superio_cfg.io); } static void via_class_init(ObjectClass *klass, void *data) @@ -354,6 +446,7 @@ static const TypeInfo via_info = { }, }; + static void vt82c686b_superio_class_init(ObjectClass *klass, void *data) { ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); @@ -372,11 +465,14 @@ static const TypeInfo via_superio_info = { .class_init = vt82c686b_superio_class_init, }; + static void vt82c686b_register_types(void) { type_register_static(&via_pm_info); - type_register_static(&via_superio_info); + type_register_static(&vt82c686b_pm_info); + type_register_static(&vt8231_pm_info); type_register_static(&via_info); + type_register_static(&via_superio_info); } type_init(vt82c686b_register_types) diff --git a/hw/mips/bootloader.c b/hw/mips/bootloader.c new file mode 100644 index 0000000000..6ec8314490 --- /dev/null +++ b/hw/mips/bootloader.c @@ -0,0 +1,200 @@ +/* + * Utility for QEMU MIPS to generate it's simple bootloader + * + * Instructions used here are carefully selected to keep compatibility with + * MIPS Release 6. + * + * Copyright (C) 2020 Jiaxun Yang + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "cpu.h" +#include "hw/mips/bootloader.h" + +typedef enum bl_reg { + BL_REG_ZERO = 0, + BL_REG_AT = 1, + BL_REG_V0 = 2, + BL_REG_V1 = 3, + BL_REG_A0 = 4, + BL_REG_A1 = 5, + BL_REG_A2 = 6, + BL_REG_A3 = 7, + BL_REG_T0 = 8, + BL_REG_T1 = 9, + BL_REG_T2 = 10, + BL_REG_T3 = 11, + BL_REG_T4 = 12, + BL_REG_T5 = 13, + BL_REG_T6 = 14, + BL_REG_T7 = 15, + BL_REG_S0 = 16, + BL_REG_S1 = 17, + BL_REG_S2 = 18, + BL_REG_S3 = 19, + BL_REG_S4 = 20, + BL_REG_S5 = 21, + BL_REG_S6 = 22, + BL_REG_S7 = 23, + BL_REG_T8 = 24, + BL_REG_T9 = 25, + BL_REG_K0 = 26, + BL_REG_K1 = 27, + BL_REG_GP = 28, + BL_REG_SP = 29, + BL_REG_FP = 30, + BL_REG_RA = 31, +} bl_reg; + +static bool bootcpu_supports_isa(uint64_t isa_mask) +{ + return cpu_supports_isa(&MIPS_CPU(first_cpu)->env, isa_mask); +} + +/* Base types */ +static void bl_gen_nop(uint32_t **p) +{ + stl_p(*p, 0); + *p = *p + 1; +} + +static void bl_gen_r_type(uint32_t **p, uint8_t opcode, + bl_reg rs, bl_reg rt, bl_reg rd, + uint8_t shift, uint8_t funct) +{ + uint32_t insn = 0; + + insn = deposit32(insn, 26, 6, opcode); + insn = deposit32(insn, 21, 5, rs); + insn = deposit32(insn, 16, 5, rt); + insn = deposit32(insn, 11, 5, rd); + insn = deposit32(insn, 6, 5, shift); + insn = deposit32(insn, 0, 6, funct); + + stl_p(*p, insn); + *p = *p + 1; +} + +static void bl_gen_i_type(uint32_t **p, uint8_t opcode, + bl_reg rs, bl_reg rt, uint16_t imm) +{ + uint32_t insn = 0; + + insn = deposit32(insn, 26, 6, opcode); + insn = deposit32(insn, 21, 5, rs); + insn = deposit32(insn, 16, 5, rt); + insn = deposit32(insn, 0, 16, imm); + + stl_p(*p, insn); + *p = *p + 1; +} + +/* Single instructions */ +static void bl_gen_dsll(uint32_t **p, bl_reg rd, bl_reg rt, uint8_t sa) +{ + if (bootcpu_supports_isa(ISA_MIPS3)) { + bl_gen_r_type(p, 0, 0, rt, rd, sa, 0x38); + } else { + g_assert_not_reached(); /* unsupported */ + } +} + +static void bl_gen_jalr(uint32_t **p, bl_reg rs) +{ + bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09); +} + +static void bl_gen_lui(uint32_t **p, bl_reg rt, uint16_t imm) +{ + /* R6: It's a alias of AUI with RS = 0 */ + bl_gen_i_type(p, 0x0f, 0, rt, imm); +} + +static void bl_gen_ori(uint32_t **p, bl_reg rt, bl_reg rs, uint16_t imm) +{ + bl_gen_i_type(p, 0x0d, rs, rt, imm); +} + +static void bl_gen_sw(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset) +{ + bl_gen_i_type(p, 0x2b, base, rt, offset); +} + +static void bl_gen_sd(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset) +{ + if (bootcpu_supports_isa(ISA_MIPS3)) { + bl_gen_i_type(p, 0x3f, base, rt, offset); + } else { + g_assert_not_reached(); /* unsupported */ + } +} + +/* Pseudo instructions */ +static void bl_gen_li(uint32_t **p, bl_reg rt, uint32_t imm) +{ + bl_gen_lui(p, rt, extract32(imm, 16, 16)); + bl_gen_ori(p, rt, rt, extract32(imm, 0, 16)); +} + +static void bl_gen_dli(uint32_t **p, bl_reg rt, uint64_t imm) +{ + bl_gen_li(p, rt, extract64(imm, 32, 32)); + bl_gen_dsll(p, rt, rt, 16); + bl_gen_ori(p, rt, rt, extract64(imm, 16, 16)); + bl_gen_dsll(p, rt, rt, 16); + bl_gen_ori(p, rt, rt, extract64(imm, 0, 16)); +} + +static void bl_gen_load_ulong(uint32_t **p, bl_reg rt, target_ulong imm) +{ + if (bootcpu_supports_isa(ISA_MIPS3)) { + bl_gen_dli(p, rt, imm); /* 64bit */ + } else { + bl_gen_li(p, rt, imm); /* 32bit */ + } +} + +/* Helpers */ +void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr) +{ + bl_gen_load_ulong(p, BL_REG_T9, jump_addr); + bl_gen_jalr(p, BL_REG_T9); + bl_gen_nop(p); /* delay slot */ +} + +void bl_gen_jump_kernel(uint32_t **p, target_ulong sp, target_ulong a0, + target_ulong a1, target_ulong a2, target_ulong a3, + target_ulong kernel_addr) +{ + bl_gen_load_ulong(p, BL_REG_SP, sp); + bl_gen_load_ulong(p, BL_REG_A0, a0); + bl_gen_load_ulong(p, BL_REG_A1, a1); + bl_gen_load_ulong(p, BL_REG_A2, a2); + bl_gen_load_ulong(p, BL_REG_A3, a3); + + bl_gen_jump_to(p, kernel_addr); +} + +void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val) +{ + bl_gen_load_ulong(p, BL_REG_K0, val); + bl_gen_load_ulong(p, BL_REG_K1, addr); + bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0); +} + +void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val) +{ + bl_gen_li(p, BL_REG_K0, val); + bl_gen_load_ulong(p, BL_REG_K1, addr); + bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0); +} + +void bl_gen_write_u64(uint32_t **p, target_ulong addr, uint64_t val) +{ + bl_gen_dli(p, BL_REG_K0, val); + bl_gen_load_ulong(p, BL_REG_K1, addr); + bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0); +} diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 467fbc1c8b..ac2e93a05a 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -27,6 +27,7 @@ #include "hw/ide/ahci.h" #include "hw/loader.h" #include "hw/loader-fit.h" +#include "hw/mips/bootloader.h" #include "hw/mips/cps.h" #include "hw/pci-host/xilinx-pcie.h" #include "hw/qdev-clock.h" @@ -273,48 +274,26 @@ static void boston_register_types(void) } type_init(boston_register_types) -static void gen_firmware(uint32_t *p, hwaddr kernel_entry, hwaddr fdt_addr, - bool is_64b) +static void gen_firmware(uint32_t *p, hwaddr kernel_entry, hwaddr fdt_addr) { const uint32_t cm_base = 0x16100000; const uint32_t gic_base = 0x16120000; const uint32_t cpc_base = 0x16200000; /* Move CM GCRs */ - if (is_64b) { - stl_p(p++, 0x40287803); /* dmfc0 $8, CMGCRBase */ - stl_p(p++, 0x00084138); /* dsll $8, $8, 4 */ - } else { - stl_p(p++, 0x40087803); /* mfc0 $8, CMGCRBase */ - stl_p(p++, 0x00084100); /* sll $8, $8, 4 */ - } - stl_p(p++, 0x3c09a000); /* lui $9, 0xa000 */ - stl_p(p++, 0x01094025); /* or $8, $9 */ - stl_p(p++, 0x3c0a0000 | (cm_base >> 16)); /* lui $10, cm_base >> 16 */ - if (is_64b) { - stl_p(p++, 0xfd0a0008); /* sd $10, 0x8($8) */ - } else { - stl_p(p++, 0xad0a0008); /* sw $10, 0x8($8) */ - } - stl_p(p++, 0x012a4025); /* or $8, $10 */ + bl_gen_write_ulong(&p, + cpu_mips_phys_to_kseg1(NULL, GCR_BASE_ADDR + GCR_BASE_OFS), + cm_base); /* Move & enable GIC GCRs */ - stl_p(p++, 0x3c090000 | (gic_base >> 16)); /* lui $9, gic_base >> 16 */ - stl_p(p++, 0x35290001); /* ori $9, 0x1 */ - if (is_64b) { - stl_p(p++, 0xfd090080); /* sd $9, 0x80($8) */ - } else { - stl_p(p++, 0xad090080); /* sw $9, 0x80($8) */ - } + bl_gen_write_ulong(&p, + cpu_mips_phys_to_kseg1(NULL, cm_base + GCR_GIC_BASE_OFS), + gic_base | GCR_GIC_BASE_GICEN_MSK); /* Move & enable CPC GCRs */ - stl_p(p++, 0x3c090000 | (cpc_base >> 16)); /* lui $9, cpc_base >> 16 */ - stl_p(p++, 0x35290001); /* ori $9, 0x1 */ - if (is_64b) { - stl_p(p++, 0xfd090088); /* sd $9, 0x88($8) */ - } else { - stl_p(p++, 0xad090088); /* sw $9, 0x88($8) */ - } + bl_gen_write_ulong(&p, + cpu_mips_phys_to_kseg1(NULL, cm_base + GCR_CPC_BASE_OFS), + cpc_base | GCR_CPC_BASE_CPCEN_MSK); /* * Setup argument registers to follow the UHI boot protocol: @@ -324,21 +303,7 @@ static void gen_firmware(uint32_t *p, hwaddr kernel_entry, hwaddr fdt_addr, * a2/$6 = 0 * a3/$7 = 0 */ - stl_p(p++, 0x2404fffe); /* li $4, -2 */ - /* lui $5, hi(fdt_addr) */ - stl_p(p++, 0x3c050000 | ((fdt_addr >> 16) & 0xffff)); - if (fdt_addr & 0xffff) { /* ori $5, lo(fdt_addr) */ - stl_p(p++, 0x34a50000 | (fdt_addr & 0xffff)); - } - stl_p(p++, 0x34060000); /* li $6, 0 */ - stl_p(p++, 0x34070000); /* li $7, 0 */ - - /* Load kernel entry address & jump to it */ - /* lui $25, hi(kernel_entry) */ - stl_p(p++, 0x3c190000 | ((kernel_entry >> 16) & 0xffff)); - /* ori $25, lo(kernel_entry) */ - stl_p(p++, 0x37390000 | (kernel_entry & 0xffff)); - stl_p(p++, 0x03200009); /* jr $25 */ + bl_gen_jump_kernel(&p, 0, (int32_t)-2, fdt_addr, 0, 0, kernel_entry); } static const void *boston_fdt_filter(void *opaque, const void *fdt_orig, @@ -542,8 +507,7 @@ static void boston_mach_init(MachineState *machine) } gen_firmware(memory_region_get_ram_ptr(flash) + 0x7c00000, - s->kernel_entry, s->fdt_base, - cpu_type_is_64bit(machine->cpu_type)); + s->kernel_entry, s->fdt_base); } else if (!qtest_enabled()) { error_report("Please provide either a -kernel or -bios argument"); exit(1); diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index bac2adbd5a..4f61f2c873 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -25,26 +25,24 @@ #include "qapi/error.h" #include "cpu.h" #include "hw/clock.h" -#include "hw/intc/i8259.h" -#include "hw/dma/i8257.h" -#include "hw/isa/superio.h" #include "net/net.h" #include "hw/boards.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/block/flash.h" #include "hw/mips/mips.h" +#include "hw/mips/bootloader.h" #include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" #include "qemu/log.h" #include "hw/loader.h" #include "hw/ide/pci.h" +#include "hw/qdev-properties.h" #include "elf.h" #include "hw/isa/vt82c686.h" -#include "hw/rtc/mc146818rtc.h" -#include "hw/timer/i8254.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" +#include "sysemu/sysemu.h" #include "qemu/error-report.h" #define ENVP_PADDR 0x2000 @@ -185,30 +183,8 @@ static void write_bootloader(CPUMIPSState *env, uint8_t *base, /* Second part of the bootloader */ p = (uint32_t *)(base + 0x040); - /* lui a0, 0 */ - stl_p(p++, 0x3c040000); - /* ori a0, a0, 2 */ - stl_p(p++, 0x34840002); - /* lui a1, high(ENVP_VADDR) */ - stl_p(p++, 0x3c050000 | ((ENVP_VADDR >> 16) & 0xffff)); - /* ori a1, a0, low(ENVP_VADDR) */ - stl_p(p++, 0x34a50000 | (ENVP_VADDR & 0xffff)); - /* lui a2, high(ENVP_VADDR + 8) */ - stl_p(p++, 0x3c060000 | (((ENVP_VADDR + 8) >> 16) & 0xffff)); - /* ori a2, a2, low(ENVP_VADDR + 8) */ - stl_p(p++, 0x34c60000 | ((ENVP_VADDR + 8) & 0xffff)); - /* lui a3, high(env->ram_size) */ - stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); - /* ori a3, a3, low(env->ram_size) */ - stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); - /* lui ra, high(kernel_addr) */ - stl_p(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); - /* ori ra, ra, low(kernel_addr) */ - stl_p(p++, 0x37ff0000 | (kernel_addr & 0xffff)); - /* jr ra */ - stl_p(p++, 0x03e00008); - /* nop */ - stl_p(p++, 0x00000000); + bl_gen_jump_kernel(&p, ENVP_VADDR - 64, 2, ENVP_VADDR, ENVP_VADDR + 8, + loaderparams.ram_size, kernel_addr); } static void main_cpu_reset(void *opaque) @@ -224,26 +200,13 @@ static void main_cpu_reset(void *opaque) } static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, - I2CBus **i2c_bus, ISABus **p_isa_bus) + I2CBus **i2c_bus) { - qemu_irq *i8259; - ISABus *isa_bus; PCIDevice *dev; dev = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(slot, 0), true, TYPE_VT82C686B_ISA); - isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(dev), "isa.0")); - assert(isa_bus); - *p_isa_bus = isa_bus; - /* Interrupt controller */ - /* The 8259 -> IP5 */ - i8259 = i8259_init(isa_bus, intc); - isa_bus_irqs(isa_bus, i8259); - /* init other devices */ - i8254_pit_init(isa_bus, 0x40, 0, NULL); - i8257_dma_init(isa_bus, 0); - /* Super I/O */ - isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO); + qdev_connect_gpio_out(DEVICE(dev), 0, intc); dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 1), "via-ide"); pci_ide_create_devs(dev); @@ -251,9 +214,7 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci"); pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci"); - dev = pci_new(PCI_DEVFN(slot, 4), TYPE_VT82C686B_PM); - qdev_prop_set_uint32(DEVICE(dev), "smb_io_base", 0xeee1); - pci_realize_and_unref(dev, pci_bus, &error_fatal); + dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 4), TYPE_VT82C686B_PM); *i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c")); /* Audio support */ @@ -292,7 +253,6 @@ static void mips_fuloong2e_init(MachineState *machine) uint64_t kernel_entry; PCIDevice *pci_dev; PCIBus *pci_bus; - ISABus *isa_bus; I2CBus *smbus; Clock *cpuclk; MIPSCPU *cpu; @@ -359,7 +319,7 @@ static void mips_fuloong2e_init(MachineState *machine) /* South bridge -> IP5 */ vt82c686b_southbridge_init(pci_bus, FULOONG2E_VIA_SLOT, env->irq[5], - &smbus, &isa_bus); + &smbus); /* GPU */ if (vga_interface_type != VGA_NONE) { @@ -374,8 +334,6 @@ static void mips_fuloong2e_init(MachineState *machine) spd_data = spd_data_generate(DDR, machine->ram_size); smbus_eeprom_init_one(smbus, 0x50, spd_data); - mc146818_rtc_init(isa_bus, 2000, NULL); - /* Network card: RTL8139D */ network_init(pci_bus); } diff --git a/hw/mips/loongson3_bootp.h b/hw/mips/loongson3_bootp.h index 09f8480abf..d525ab745a 100644 --- a/hw/mips/loongson3_bootp.h +++ b/hw/mips/loongson3_bootp.h @@ -228,12 +228,7 @@ enum { LOADER_PARAM, }; -struct MemmapEntry { - hwaddr base; - hwaddr size; -}; - -extern const struct MemmapEntry virt_memmap[]; +extern const MemMapEntry virt_memmap[]; void init_loongson_params(struct loongson_params *lp, void *p, uint64_t cpu_freq, uint64_t ram_size); void init_reset_system(struct efi_reset_system_t *reset); diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index d4a82fa536..b15071defc 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -72,7 +72,7 @@ #define RTC_IRQ 1 #define PCIE_IRQ_BASE 2 -const struct MemmapEntry virt_memmap[] = { +const MemMapEntry virt_memmap[] = { [VIRT_LOWMEM] = { 0x00000000, 0x10000000 }, [VIRT_PM] = { 0x10080000, 0x100 }, [VIRT_FW_CFG] = { 0x10080100, 0x100 }, @@ -86,13 +86,13 @@ const struct MemmapEntry virt_memmap[] = { [VIRT_HIGHMEM] = { 0x80000000, 0x0 }, /* Variable */ }; -static const struct MemmapEntry loader_memmap[] = { +static const MemMapEntry loader_memmap[] = { [LOADER_KERNEL] = { 0x00000000, 0x4000000 }, [LOADER_INITRD] = { 0x04000000, 0x0 }, /* Variable */ [LOADER_CMDLINE] = { 0x0ff00000, 0x100000 }, }; -static const struct MemmapEntry loader_rommap[] = { +static const MemMapEntry loader_rommap[] = { [LOADER_BOOTROM] = { 0x1fc00000, 0x1000 }, [LOADER_PARAM] = { 0x1fc01000, 0x10000 }, }; diff --git a/hw/mips/meson.build b/hw/mips/meson.build index ee19cc204d..1195716dc7 100644 --- a/hw/mips/meson.build +++ b/hw/mips/meson.build @@ -1,5 +1,5 @@ mips_ss = ss.source_set() -mips_ss.add(files('mips_int.c')) +mips_ss.add(files('bootloader.c', 'mips_int.c')) mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c')) mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c')) mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c')) diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h index 5b0a1ffe72..9b6d610e83 100644 --- a/include/hw/isa/vt82c686.h +++ b/include/hw/isa/vt82c686.h @@ -4,6 +4,7 @@ #define TYPE_VT82C686B_ISA "vt82c686b-isa" #define TYPE_VT82C686B_SUPERIO "vt82c686b-superio" #define TYPE_VT82C686B_PM "vt82c686b-pm" +#define TYPE_VT8231_PM "vt8231-pm" #define TYPE_VIA_AC97 "via-ac97" #define TYPE_VIA_MC97 "via-mc97" diff --git a/include/hw/mips/bootloader.h b/include/hw/mips/bootloader.h new file mode 100644 index 0000000000..b5f48d71bb --- /dev/null +++ b/include/hw/mips/bootloader.h @@ -0,0 +1,22 @@ +/* + * Utility for QEMU MIPS to generate it's simple bootloader + * + * Copyright (C) 2020 Jiaxun Yang + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MIPS_BOOTLOADER_H +#define HW_MIPS_BOOTLOADER_H + +#include "exec/cpu-defs.h" + +void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr); +void bl_gen_jump_kernel(uint32_t **p, target_ulong sp, target_ulong a0, + target_ulong a1, target_ulong a2, target_ulong a3, + target_ulong kernel_addr); +void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val); +void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val); +void bl_gen_write_u64(uint32_t **p, target_ulong addr, uint64_t val); + +#endif diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index bd0c17dc78..ea28dcc850 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -207,9 +207,10 @@ #define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 #define PCI_DEVICE_ID_VIA_IDE 0x0571 #define PCI_DEVICE_ID_VIA_UHCI 0x3038 -#define PCI_DEVICE_ID_VIA_ACPI 0x3057 +#define PCI_DEVICE_ID_VIA_82C686B_PM 0x3057 #define PCI_DEVICE_ID_VIA_AC97 0x3058 #define PCI_DEVICE_ID_VIA_MC97 0x3068 +#define PCI_DEVICE_ID_VIA_8231_PM 0x8235 #define PCI_VENDOR_ID_MARVELL 0x11ab diff --git a/target/mips/cpu.h b/target/mips/cpu.h index b9e227a30e..075c24abda 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -460,6 +460,13 @@ typedef struct mips_def_t mips_def_t; typedef struct TCState TCState; struct TCState { target_ulong gpr[32]; +#if defined(TARGET_MIPS64) + /* + * For CPUs using 128-bit GPR registers, we put the lower halves in gpr[]) + * and the upper halves in gpr_hi[]. + */ + uint64_t gpr_hi[32]; +#endif /* TARGET_MIPS64 */ target_ulong PC; target_ulong HI[MIPS_DSP_ACC]; target_ulong LO[MIPS_DSP_ACC]; @@ -505,9 +512,6 @@ struct TCState { float_status msa_fp_status; - /* Upper 64-bit MMRs (multimedia registers); the lower 64-bit are GPRs */ - uint64_t mmr[32]; - #define NUMBER_OF_MXU_REGISTERS 16 target_ulong mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1]; target_ulong mxu_cr; @@ -1220,22 +1224,6 @@ typedef MIPSCPU ArchCPU; #include "exec/cpu-all.h" -/* - * Memory access type : - * may be needed for precise access rights control and precise exceptions. - */ -enum { - /* 1 bit to define user level / supervisor access */ - ACCESS_USER = 0x00, - ACCESS_SUPER = 0x01, - /* 1 bit to indicate direction */ - ACCESS_STORE = 0x02, - /* Type of instruction that generated the access */ - ACCESS_CODE = 0x10, /* Code fetch access */ - ACCESS_INT = 0x20, /* Integer load/store access */ - ACCESS_FLOAT = 0x30, /* floating point load/store access */ -}; - /* Exceptions */ enum { EXCP_NONE = -1, diff --git a/target/mips/internal.h b/target/mips/internal.h index 5dd17ff733..99264b8bf6 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -111,7 +111,7 @@ struct CPUMIPSTLBContext { uint32_t nb_tlb; uint32_t tlb_in_use; int (*map_address)(struct CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type); + target_ulong address, MMUAccessType access_type); void (*helper_tlbwi)(struct CPUMIPSState *env); void (*helper_tlbwr)(struct CPUMIPSState *env); void (*helper_tlbp)(struct CPUMIPSState *env); @@ -126,11 +126,11 @@ struct CPUMIPSTLBContext { }; int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type); + target_ulong address, MMUAccessType access_type); int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type); + target_ulong address, MMUAccessType access_type); int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type); + target_ulong address, MMUAccessType access_type); void r4k_helper_tlbwi(CPUMIPSState *env); void r4k_helper_tlbwr(CPUMIPSState *env); void r4k_helper_tlbp(CPUMIPSState *env); @@ -146,7 +146,7 @@ void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr); hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, - int rw); + MMUAccessType access_type); #endif #define cpu_signal_handler cpu_mips_signal_handler diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 1298a1917c..4caefe29ad 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "internal.h" +#include "tcg/tcg.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exec/memop.h" diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 89c7d4556a..b80e8f7540 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -288,13 +288,14 @@ target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx, #ifndef CONFIG_USER_ONLY static inline hwaddr do_translate_address(CPUMIPSState *env, - target_ulong address, - int rw, uintptr_t retaddr) + target_ulong address, + MMUAccessType access_type, + uintptr_t retaddr) { hwaddr paddr; CPUState *cs = env_cpu(env); - paddr = cpu_mips_translate_address(env, address, rw); + paddr = cpu_mips_translate_address(env, address, access_type); if (paddr == -1LL) { cpu_loop_exit_restore(cs, retaddr); @@ -312,7 +313,7 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \ } \ do_raise_exception(env, EXCP_AdEL, GETPC()); \ } \ - env->CP0_LLAddr = do_translate_address(env, arg, 0, GETPC()); \ + env->CP0_LLAddr = do_translate_address(env, arg, MMU_DATA_LOAD, GETPC()); \ env->lladdr = arg; \ env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \ return env->llval; \ diff --git a/target/mips/tlb_helper.c b/target/mips/tlb_helper.c index 082c17928d..8d3ea49780 100644 --- a/target/mips/tlb_helper.c +++ b/target/mips/tlb_helper.c @@ -39,7 +39,7 @@ enum { /* no MMU emulation */ int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type) + target_ulong address, MMUAccessType access_type) { *physical = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -48,7 +48,7 @@ int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, /* fixed mapping MMU emulation */ int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type) + target_ulong address, MMUAccessType access_type) { if (address <= (int32_t)0x7FFFFFFFUL) { if (!(env->CP0_Status & (1 << CP0St_ERL))) { @@ -68,7 +68,7 @@ int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, /* MIPS32/MIPS64 R4000-style MMU emulation */ int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type) + target_ulong address, MMUAccessType access_type) { uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; uint32_t MMID = env->CP0_MemoryMapID; @@ -97,13 +97,13 @@ int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, if (!(n ? tlb->V1 : tlb->V0)) { return TLBRET_INVALID; } - if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) { + if (access_type == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) { return TLBRET_XI; } - if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) { + if (access_type == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) { return TLBRET_RI; } - if (rw != MMU_DATA_STORE || (n ? tlb->D1 : tlb->D0)) { + if (access_type != MMU_DATA_STORE || (n ? tlb->D1 : tlb->D0)) { *physical = tlb->PFN[n] | (address & (mask >> 1)); *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) { @@ -222,7 +222,7 @@ static int is_seg_am_mapped(unsigned int am, bool eu, int mmu_idx) static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong real_address, - int rw, int access_type, int mmu_idx, + MMUAccessType access_type, int mmu_idx, unsigned int am, bool eu, target_ulong segmask, hwaddr physical_base) @@ -234,7 +234,7 @@ static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical, return mapped; } else if (mapped) { /* The segment is TLB mapped */ - return env->tlb->map_address(env, physical, prot, real_address, rw, + return env->tlb->map_address(env, physical, prot, real_address, access_type); } else { /* The segment is unmapped */ @@ -246,21 +246,21 @@ static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical, static int get_segctl_physical_address(CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong real_address, - int rw, int access_type, int mmu_idx, + MMUAccessType access_type, int mmu_idx, uint16_t segctl, target_ulong segmask) { unsigned int am = (segctl & CP0SC_AM_MASK) >> CP0SC_AM; bool eu = (segctl >> CP0SC_EU) & 1; hwaddr pa = ((hwaddr)segctl & CP0SC_PA_MASK) << 20; - return get_seg_physical_address(env, physical, prot, real_address, rw, + return get_seg_physical_address(env, physical, prot, real_address, access_type, mmu_idx, am, eu, segmask, pa & ~(hwaddr)segmask); } static int get_physical_address(CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong real_address, - int rw, int access_type, int mmu_idx) + MMUAccessType access_type, int mmu_idx) { /* User mode can only access useg/xuseg */ #if defined(TARGET_MIPS64) @@ -307,14 +307,14 @@ static int get_physical_address(CPUMIPSState *env, hwaddr *physical, segctl = env->CP0_SegCtl2 >> 16; } ret = get_segctl_physical_address(env, physical, prot, - real_address, rw, access_type, + real_address, access_type, mmu_idx, segctl, 0x3FFFFFFF); #if defined(TARGET_MIPS64) } else if (address < 0x4000000000000000ULL) { /* xuseg */ if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, - real_address, rw, access_type); + real_address, access_type); } else { ret = TLBRET_BADADDR; } @@ -323,7 +323,7 @@ static int get_physical_address(CPUMIPSState *env, hwaddr *physical, if ((supervisor_mode || kernel_mode) && SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, - real_address, rw, access_type); + real_address, access_type); } else { ret = TLBRET_BADADDR; } @@ -350,7 +350,7 @@ static int get_physical_address(CPUMIPSState *env, hwaddr *physical, /* Does CP0_Status.KX/SX/UX permit the access mode (am) */ if (env->CP0_Status & am_ksux[am]) { ret = get_seg_physical_address(env, physical, prot, - real_address, rw, access_type, + real_address, access_type, mmu_idx, am, false, env->PAMask, 0); } else { @@ -364,24 +364,24 @@ static int get_physical_address(CPUMIPSState *env, hwaddr *physical, if (kernel_mode && KX && address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, - real_address, rw, access_type); + real_address, access_type); } else { ret = TLBRET_BADADDR; } #endif } else if (address < KSEG1_BASE) { /* kseg0 */ - ret = get_segctl_physical_address(env, physical, prot, real_address, rw, + ret = get_segctl_physical_address(env, physical, prot, real_address, access_type, mmu_idx, env->CP0_SegCtl1 >> 16, 0x1FFFFFFF); } else if (address < KSEG2_BASE) { /* kseg1 */ - ret = get_segctl_physical_address(env, physical, prot, real_address, rw, + ret = get_segctl_physical_address(env, physical, prot, real_address, access_type, mmu_idx, env->CP0_SegCtl1, 0x1FFFFFFF); } else if (address < KSEG3_BASE) { /* sseg (kseg2) */ - ret = get_segctl_physical_address(env, physical, prot, real_address, rw, + ret = get_segctl_physical_address(env, physical, prot, real_address, access_type, mmu_idx, env->CP0_SegCtl0 >> 16, 0x1FFFFFFF); } else { @@ -389,7 +389,7 @@ static int get_physical_address(CPUMIPSState *env, hwaddr *physical, * kseg3 * XXX: debug segment is not emulated */ - ret = get_segctl_physical_address(env, physical, prot, real_address, rw, + ret = get_segctl_physical_address(env, physical, prot, real_address, access_type, mmu_idx, env->CP0_SegCtl0, 0x1FFFFFFF); } @@ -406,12 +406,12 @@ void cpu_mips_tlb_flush(CPUMIPSState *env) #endif /* !CONFIG_USER_ONLY */ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, - int rw, int tlb_error) + MMUAccessType access_type, int tlb_error) { CPUState *cs = env_cpu(env); int exception = 0, error_code = 0; - if (rw == MMU_INST_FETCH) { + if (access_type == MMU_INST_FETCH) { error_code |= EXCP_INST_NOTAVAIL; } @@ -420,7 +420,7 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, case TLBRET_BADADDR: /* Reference to kernel address from user mode or supervisor mode */ /* Reference to supervisor address from user mode */ - if (rw == MMU_DATA_STORE) { + if (access_type == MMU_DATA_STORE) { exception = EXCP_AdES; } else { exception = EXCP_AdEL; @@ -428,7 +428,7 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, break; case TLBRET_NOMATCH: /* No TLB match for a mapped address */ - if (rw == MMU_DATA_STORE) { + if (access_type == MMU_DATA_STORE) { exception = EXCP_TLBS; } else { exception = EXCP_TLBL; @@ -437,7 +437,7 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, break; case TLBRET_INVALID: /* TLB match with no valid bit */ - if (rw == MMU_DATA_STORE) { + if (access_type == MMU_DATA_STORE) { exception = EXCP_TLBS; } else { exception = EXCP_TLBL; @@ -493,7 +493,7 @@ hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) hwaddr phys_addr; int prot; - if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT, + if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD, cpu_mmu_index(env, false)) != 0) { return -1; } @@ -571,7 +571,7 @@ static int walk_directory(CPUMIPSState *env, uint64_t *vaddr, uint64_t w = 0; if (get_physical_address(env, &paddr, &prot, *vaddr, MMU_DATA_LOAD, - ACCESS_INT, cpu_mmu_index(env, false)) != + cpu_mmu_index(env, false)) != TLBRET_MATCH) { /* wrong base address */ return 0; @@ -599,7 +599,7 @@ static int walk_directory(CPUMIPSState *env, uint64_t *vaddr, *pw_entrylo0 = entry; } if (get_physical_address(env, &paddr, &prot, vaddr2, MMU_DATA_LOAD, - ACCESS_INT, cpu_mmu_index(env, false)) != + cpu_mmu_index(env, false)) != TLBRET_MATCH) { return 0; } @@ -622,8 +622,8 @@ static int walk_directory(CPUMIPSState *env, uint64_t *vaddr, } } -static bool page_table_walk_refill(CPUMIPSState *env, vaddr address, int rw, - int mmu_idx) +static bool page_table_walk_refill(CPUMIPSState *env, vaddr address, + int mmu_idx) { int gdw = (env->CP0_PWSize >> CP0PS_GDW) & 0x3F; int udw = (env->CP0_PWSize >> CP0PS_UDW) & 0x3F; @@ -753,7 +753,7 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address, int rw, /* Leaf Level Page Table - First half of PTE pair */ vaddr |= ptoffset0; if (get_physical_address(env, &paddr, &prot, vaddr, MMU_DATA_LOAD, - ACCESS_INT, cpu_mmu_index(env, false)) != + cpu_mmu_index(env, false)) != TLBRET_MATCH) { return false; } @@ -766,7 +766,7 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address, int rw, /* Leaf Level Page Table - Second half of PTE pair */ vaddr |= ptoffset1; if (get_physical_address(env, &paddr, &prot, vaddr, MMU_DATA_LOAD, - ACCESS_INT, cpu_mmu_index(env, false)) != + cpu_mmu_index(env, false)) != TLBRET_MATCH) { return false; } @@ -844,16 +844,14 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #if !defined(CONFIG_USER_ONLY) hwaddr physical; int prot; - int mips_access_type; #endif int ret = TLBRET_BADADDR; /* data access */ #if !defined(CONFIG_USER_ONLY) /* XXX: put correct access by using cpu_restore_state() correctly */ - mips_access_type = ACCESS_INT; ret = get_physical_address(env, &physical, &prot, address, - access_type, mips_access_type, mmu_idx); + access_type, mmu_idx); switch (ret) { case TLBRET_MATCH: qemu_log_mask(CPU_LOG_MMU, @@ -881,11 +879,11 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, int mode = (env->hflags & MIPS_HFLAG_KSU); bool ret_walker; env->hflags &= ~MIPS_HFLAG_KSU; - ret_walker = page_table_walk_refill(env, address, access_type, mmu_idx); + ret_walker = page_table_walk_refill(env, address, mmu_idx); env->hflags |= mode; if (ret_walker) { ret = get_physical_address(env, &physical, &prot, address, - access_type, mips_access_type, mmu_idx); + access_type, mmu_idx); if (ret == TLBRET_MATCH) { tlb_set_page(cs, address & TARGET_PAGE_MASK, physical & TARGET_PAGE_MASK, prot, @@ -906,19 +904,17 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #ifndef CONFIG_USER_ONLY hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, - int rw) + MMUAccessType access_type) { hwaddr physical; int prot; - int access_type; int ret = 0; /* data access */ - access_type = ACCESS_INT; - ret = get_physical_address(env, &physical, &prot, address, rw, access_type, + ret = get_physical_address(env, &physical, &prot, address, access_type, cpu_mmu_index(env, false)); if (ret != TLBRET_MATCH) { - raise_mmu_exception(env, address, rw, ret); + raise_mmu_exception(env, address, access_type, ret); return -1LL; } else { return physical; diff --git a/target/mips/translate.c b/target/mips/translate.c index a5cf1742a8..70891c37cd 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -26,7 +26,7 @@ #include "cpu.h" #include "internal.h" #include "tcg/tcg-op.h" -#include "exec/cpu_ldst.h" +#include "exec/translator.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "hw/semihosting/semihost.h" @@ -2179,7 +2179,12 @@ enum { /* global register indices */ TCGv cpu_gpr[32], cpu_PC; -static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC]; +/* + * For CPUs using 128-bit GPR registers, we put the lower halves in cpu_gpr[]) + * and the upper halves in cpu_gpr_hi[]. + */ +TCGv_i64 cpu_gpr_hi[32]; +TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC]; static TCGv cpu_dspctrl, btarget; TCGv bcond; static TCGv cpu_lladdr, cpu_llval; @@ -2187,11 +2192,6 @@ static TCGv_i32 hflags; TCGv_i32 fpu_fcr0, fpu_fcr31; TCGv_i64 fpu_f64[32]; -#if defined(TARGET_MIPS64) -/* Upper halves of R5900's 128-bit registers: MMRs (multimedia registers) */ -static TCGv_i64 cpu_mmr[32]; -#endif - #if !defined(TARGET_MIPS64) /* MXU registers */ static TCGv mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1]; @@ -2291,6 +2291,24 @@ void gen_store_gpr(TCGv t, int reg) } } +#if defined(TARGET_MIPS64) +void gen_load_gpr_hi(TCGv_i64 t, int reg) +{ + if (reg == 0) { + tcg_gen_movi_i64(t, 0); + } else { + tcg_gen_mov_i64(t, cpu_gpr_hi[reg]); + } +} + +void gen_store_gpr_hi(TCGv_i64 t, int reg) +{ + if (reg != 0) { + tcg_gen_mov_i64(cpu_gpr_hi[reg], t); + } +} +#endif /* TARGET_MIPS64 */ + /* Moves to/from shadow registers. */ static inline void gen_load_srsgpr(int from, int to) { @@ -4108,31 +4126,18 @@ static void gen_shift(DisasContext *ctx, uint32_t opc, /* Copy GPR to and from TX79 HI1/LO1 register. */ static void gen_HILO1_tx79(DisasContext *ctx, uint32_t opc, int reg) { - if (reg == 0 && (opc == MMI_OPC_MFHI1 || opc == MMI_OPC_MFLO1)) { - /* Treat as NOP. */ - return; - } - switch (opc) { case MMI_OPC_MFHI1: - tcg_gen_mov_tl(cpu_gpr[reg], cpu_HI[1]); + gen_store_gpr(cpu_HI[1], reg); break; case MMI_OPC_MFLO1: - tcg_gen_mov_tl(cpu_gpr[reg], cpu_LO[1]); + gen_store_gpr(cpu_LO[1], reg); break; case MMI_OPC_MTHI1: - if (reg != 0) { - tcg_gen_mov_tl(cpu_HI[1], cpu_gpr[reg]); - } else { - tcg_gen_movi_tl(cpu_HI[1], 0); - } + gen_load_gpr(cpu_HI[1], reg); break; case MMI_OPC_MTLO1: - if (reg != 0) { - tcg_gen_mov_tl(cpu_LO[1], cpu_gpr[reg]); - } else { - tcg_gen_movi_tl(cpu_LO[1], 0); - } + gen_load_gpr(cpu_LO[1], reg); break; default: MIPS_INVAL("mfthilo1 TX79"); @@ -13911,7 +13916,7 @@ static void decode_i64_mips16(DisasContext *ctx, static int decode_extended_mips16_opc(CPUMIPSState *env, DisasContext *ctx) { - int extend = cpu_lduw_code(env, ctx->base.pc_next + 2); + int extend = translator_lduw(env, ctx->base.pc_next + 2); int op, rx, ry, funct, sa; int16_t imm, offset; @@ -14161,7 +14166,7 @@ static int decode_mips16_opc(CPUMIPSState *env, DisasContext *ctx) /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_JAL: - offset = cpu_lduw_code(env, ctx->base.pc_next + 2); + offset = translator_lduw(env, ctx->base.pc_next + 2); offset = (((ctx->opcode & 0x1f) << 21) | ((ctx->opcode >> 5) & 0x1f) << 16 | offset) << 2; @@ -16295,7 +16300,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) uint32_t op, minor, minor2, mips32_op; uint32_t cond, fmt, cc; - insn = cpu_lduw_code(env, ctx->base.pc_next + 2); + insn = translator_lduw(env, ctx->base.pc_next + 2); ctx->opcode = (ctx->opcode << 16) | insn; rt = (ctx->opcode >> 21) & 0x1f; @@ -21350,7 +21355,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) int offset; int imm; - insn = cpu_lduw_code(env, ctx->base.pc_next + 2); + insn = translator_lduw(env, ctx->base.pc_next + 2); ctx->opcode = (ctx->opcode << 16) | insn; rt = extract32(ctx->opcode, 21, 5); @@ -21469,7 +21474,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) break; case NM_P48I: { - insn = cpu_lduw_code(env, ctx->base.pc_next + 4); + insn = translator_lduw(env, ctx->base.pc_next + 4); target_long addr_off = extract32(ctx->opcode, 0, 16) | insn << 16; switch (extract32(ctx->opcode, 16, 5)) { case NM_LI48: @@ -24784,7 +24789,7 @@ static void gen_mmi_pcpyh(DisasContext *ctx) /* nop */ } else if (rt == 0) { tcg_gen_movi_i64(cpu_gpr[rd], 0); - tcg_gen_movi_i64(cpu_mmr[rd], 0); + tcg_gen_movi_i64(cpu_gpr_hi[rd], 0); } else { TCGv_i64 t0 = tcg_temp_new(); TCGv_i64 t1 = tcg_temp_new(); @@ -24802,7 +24807,7 @@ static void gen_mmi_pcpyh(DisasContext *ctx) tcg_gen_mov_i64(cpu_gpr[rd], t1); - tcg_gen_andi_i64(t0, cpu_mmr[rt], mask); + tcg_gen_andi_i64(t0, cpu_gpr_hi[rt], mask); tcg_gen_movi_i64(t1, 0); tcg_gen_or_i64(t1, t0, t1); tcg_gen_shli_i64(t0, t0, 16); @@ -24812,7 +24817,7 @@ static void gen_mmi_pcpyh(DisasContext *ctx) tcg_gen_shli_i64(t0, t0, 16); tcg_gen_or_i64(t1, t0, t1); - tcg_gen_mov_i64(cpu_mmr[rd], t1); + tcg_gen_mov_i64(cpu_gpr_hi[rd], t1); tcg_temp_free(t0); tcg_temp_free(t1); @@ -24844,9 +24849,9 @@ static void gen_mmi_pcpyld(DisasContext *ctx) /* nop */ } else { if (rs == 0) { - tcg_gen_movi_i64(cpu_mmr[rd], 0); + tcg_gen_movi_i64(cpu_gpr_hi[rd], 0); } else { - tcg_gen_mov_i64(cpu_mmr[rd], cpu_gpr[rs]); + tcg_gen_mov_i64(cpu_gpr_hi[rd], cpu_gpr[rs]); } if (rt == 0) { tcg_gen_movi_i64(cpu_gpr[rd], 0); @@ -24885,13 +24890,13 @@ static void gen_mmi_pcpyud(DisasContext *ctx) if (rs == 0) { tcg_gen_movi_i64(cpu_gpr[rd], 0); } else { - tcg_gen_mov_i64(cpu_gpr[rd], cpu_mmr[rs]); + tcg_gen_mov_i64(cpu_gpr[rd], cpu_gpr_hi[rs]); } if (rt == 0) { - tcg_gen_movi_i64(cpu_mmr[rd], 0); + tcg_gen_movi_i64(cpu_gpr_hi[rd], 0); } else { if (rd != rt) { - tcg_gen_mov_i64(cpu_mmr[rd], cpu_mmr[rt]); + tcg_gen_mov_i64(cpu_gpr_hi[rd], cpu_gpr_hi[rt]); } } } @@ -29087,17 +29092,17 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) is_slot = ctx->hflags & MIPS_HFLAG_BMASK; if (ctx->insn_flags & ISA_NANOMIPS32) { - ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next); + ctx->opcode = translator_lduw(env, ctx->base.pc_next); insn_bytes = decode_nanomips_opc(env, ctx); } else if (!(ctx->hflags & MIPS_HFLAG_M16)) { - ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); + ctx->opcode = translator_ldl(env, ctx->base.pc_next); insn_bytes = 4; decode_opc(env, ctx); } else if (ctx->insn_flags & ASE_MICROMIPS) { - ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next); + ctx->opcode = translator_lduw(env, ctx->base.pc_next); insn_bytes = decode_micromips_opc(env, ctx); } else if (ctx->insn_flags & ASE_MIPS16) { - ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next); + ctx->opcode = translator_lduw(env, ctx->base.pc_next); insn_bytes = decode_mips16_opc(env, ctx); } else { gen_reserved_instruction(ctx); @@ -29285,6 +29290,18 @@ void mips_tcg_init(void) offsetof(CPUMIPSState, active_tc.gpr[i]), regnames[i]); +#if defined(TARGET_MIPS64) + cpu_gpr_hi[0] = NULL; + + for (unsigned i = 1; i < 32; i++) { + g_autofree char *rname = g_strdup_printf("%s[hi]", regnames[i]); + + cpu_gpr_hi[i] = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUMIPSState, + active_tc.gpr_hi[i]), + rname); + } +#endif /* !TARGET_MIPS64 */ for (i = 0; i < 32; i++) { int off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[0]); @@ -29323,16 +29340,6 @@ void mips_tcg_init(void) cpu_llval = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, llval), "llval"); -#if defined(TARGET_MIPS64) - cpu_mmr[0] = NULL; - for (i = 1; i < 32; i++) { - cpu_mmr[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUMIPSState, - active_tc.mmr[i]), - regnames[i]); - } -#endif - #if !defined(TARGET_MIPS64) for (i = 0; i < NUMBER_OF_MXU_REGISTERS - 1; i++) { mxu_gpr[i] = tcg_global_mem_new(cpu_env, @@ -29344,7 +29351,7 @@ void mips_tcg_init(void) mxu_CR = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, active_tc.mxu_cr), mxuregnames[NUMBER_OF_MXU_REGISTERS - 1]); -#endif +#endif /* !TARGET_MIPS64 */ } void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, diff --git a/target/mips/translate.h b/target/mips/translate.h index f47b5f2c8d..468e29d757 100644 --- a/target/mips/translate.h +++ b/target/mips/translate.h @@ -131,6 +131,10 @@ void gen_move_low32(TCGv ret, TCGv_i64 arg); void gen_move_high32(TCGv ret, TCGv_i64 arg); void gen_load_gpr(TCGv t, int reg); void gen_store_gpr(TCGv t, int reg); +#if defined(TARGET_MIPS64) +void gen_load_gpr_hi(TCGv_i64 t, int reg); +void gen_store_gpr_hi(TCGv_i64 t, int reg); +#endif /* TARGET_MIPS64 */ void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg); void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg); void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg); @@ -145,6 +149,10 @@ bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa); bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa); extern TCGv cpu_gpr[32], cpu_PC; +#if defined(TARGET_MIPS64) +extern TCGv_i64 cpu_gpr_hi[32]; +#endif +extern TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC]; extern TCGv_i32 fpu_fcr0, fpu_fcr31; extern TCGv_i64 fpu_f64[32]; extern TCGv bcond; diff --git a/tests/acceptance/machine_mips_loongson3v.py b/tests/acceptance/machine_mips_loongson3v.py new file mode 100644 index 0000000000..85b131a40f --- /dev/null +++ b/tests/acceptance/machine_mips_loongson3v.py @@ -0,0 +1,39 @@ +# Functional tests for the Generic Loongson-3 Platform. +# +# Copyright (c) 2021 Jiaxun Yang +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. +# See the COPYING file in the top-level directory. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os +import time + +from avocado import skipUnless +from avocado_qemu import Test +from avocado_qemu import wait_for_console_pattern + +class MipsLoongson3v(Test): + timeout = 60 + + @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') + def test_pmon_serial_console(self): + """ + :avocado: tags=arch:mips64el + :avocado: tags=endian:little + :avocado: tags=machine:loongson3-virt + :avocado: tags=cpu:Loongson-3A1000 + :avocado: tags=device:liointc + :avocado: tags=device:goldfish_rtc + """ + + pmon_hash = '7c8b45dd81ccfc55ff28f5aa267a41c3' + pmon_path = self.fetch_asset('https://github.com/loongson-community/pmon/' + 'releases/download/20210112/pmon-3avirt.bin', + asset_hash=pmon_hash, algorithm='md5') + + self.vm.set_console() + self.vm.add_args('-bios', pmon_path) + self.vm.launch() + wait_for_console_pattern(self, 'CPU GODSON3 BogoMIPS:')