mirror of https://gitee.com/openkylin/qemu.git
MIPS patches queue
- Drop redundant struct MemmapEntry (Bin) - Fix for Coverity CID 1438965 and 1438967 (Jiaxun) - Add MIPS bootloader API (Jiaxun) - Use MIPS bootloader API on fuloong2e and boston machines (Jiaxun) - Add PMON test for Loongson-3A1000 CPU (Jiaxun) - Convert to translator API (Philippe) - MMU cleanups (Philippe) - Promote 128-bit multimedia registers as global ones (Philippe) - Various cleanups/fixes on the VT82C686B southbridge (Zoltan) -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmAyqe0ACgkQ4+MsLN6t wN5Vbw/7BbLUjqZzs4pDVUv4XXeSoVIP9fEmEUoxbVgb58cD6ZE6PeEN7fT+I++E fTu6Fw2WTHrGOWGkHRSOAGIAz4DqSsLJ2Qub4SRThdWgl9NgAgPDV32L7hCSJNfJ ejK9PL/B4dYS1RoRPULdrsiuKYsXcl/QBo99nQoa+0fquPQBnA3LlPJX7my9s2SB QoTK29V4KjLnTf4ebFP9mOHm4Z96lzl7jITjRUg4g5fh/IH+qlWlDUtMV5n2EL2b Jp798z1ydsEGHmM1O5xbjQixwZZYSgt+mjRn4fHH/mSLyfanJW/0pK1o6Ktl2zDC Ks1N0RNMsCZrvPXkUz6h7i6rXJsxzh0e96CmzOqBbKMzKuozig8ZMhmQTEGEvzf5 cMxAKYJu95ndmRISV8p3fdsT/t0j08WZ5m3Syz/VqV57mVP3fj2yqiDXl1vwoPjM O2zYgK1VOgVsr0GPcJ5bHxDvuzbPvCd7YE0RhK2eFKkYLjQz7SEtC8RzmkKXoYze 8nj7eBgG37vaPUGOyjZROOftrTXvqx6swB9kmQ38FrIfM/tZQYa54w4kFXF7nI06 HIdiPIXPv+xqfwYUcsMuE/Mq/cXMTlgUF6445FHJ2yhaySrsch7BDR6BOgOmiNkM iXT0PdlS5P1J4y5HBzwQhrGslZGdXz+UsmF+zq4vgfbMul4VsoQ= =g7Kx -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/philmd-gitlab/tags/mips-20210221' into staging MIPS patches queue - Drop redundant struct MemmapEntry (Bin) - Fix for Coverity CID 1438965 and 1438967 (Jiaxun) - Add MIPS bootloader API (Jiaxun) - Use MIPS bootloader API on fuloong2e and boston machines (Jiaxun) - Add PMON test for Loongson-3A1000 CPU (Jiaxun) - Convert to translator API (Philippe) - MMU cleanups (Philippe) - Promote 128-bit multimedia registers as global ones (Philippe) - Various cleanups/fixes on the VT82C686B southbridge (Zoltan) # gpg: Signature made Sun 21 Feb 2021 18:43:57 GMT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * remotes/philmd-gitlab/tags/mips-20210221: (43 commits) vt82c686: Fix superio_cfg_{read,write}() functions vt82c686: Log superio_cfg unimplemented accesses vt82c686: Simplify by returning earlier vt82c686: Reduce indentation by returning early vt82c686: Remove index field of SuperIOConfig vt82c686: Move creation of ISA devices to the ISA bridge vt82c686: Simplify vt82c686b_realize() vt82c686: Make vt82c686b-pm an abstract base class and add vt8231-pm based on it vt82c686: Set user_creatable=false for VT82C686B_PM vt82c686: Fix up power management io base and config vt82c686: Correctly reset all registers to default values on reset vt82c686: Correct vt82c686-pm I/O size vt82c686: Make vt82c686-pm an I/O tracing region vt82c686: Fix SMBus IO base and configuration registers vt82c686: Reorganise code vt82c686: Move superio memory region to SuperIOConfig struct target/mips: Use GPR move functions in gen_HILO1_tx79() target/mips: Introduce gen_load_gpr_hi() / gen_store_gpr_hi() helpers target/mips: Rename 128-bit upper halve GPR registers target/mips: Promote 128-bit multimedia registers as global ones ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
00d8ba9e0d
|
@ -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 <paulburton@kernel.org>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 <jiaxun.yang@flygoat.com>
|
||||
*
|
||||
* 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Utility for QEMU MIPS to generate it's simple bootloader
|
||||
*
|
||||
* Copyright (C) 2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
|
||||
*
|
||||
* 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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; \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Functional tests for the Generic Loongson-3 Platform.
|
||||
#
|
||||
# Copyright (c) 2021 Jiaxun Yang <jiaxun.yang@flygoat.com>
|
||||
#
|
||||
# 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:')
|
Loading…
Reference in New Issue