This series adds support for migration to RISC-V QEMU and expands the
Microchip PFSoC to allow unmodified HSS and Linux boots. -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAl+hdREACgkQIeENKd+X cFSb8gf+M3djD952RKJkqRFYEDoRkdsmfgSCR1vv4gv8tZyRoEoFT0r91Ne3xnu4 8UN6esV+n2ugbpXNIYxb/ZfBo664jWPYLIPFxaslEUYjshzxPmpvKFxF33k0e0MA Xs41G8xeQmRijOFzERNWBTYdpez579MIy2mWUWlDcssZaayJyLkNDrdP4i938sry GYsyr88ekeO/u/2SbviKQ7wkneqJZCFDGeztsAi3j8VLFzQeA2WvKx2z/cG4e4u5 33rl6UGuYS9/g8uS9UqOodkzWtGe9Sw/ddMCgFkMcMqa9DNUznd4b9FoUv2zRmO8 qIC7UCBsjt1v+lkofH7m4+rqm1BaFQ== =SQpo -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20201103' into staging This series adds support for migration to RISC-V QEMU and expands the Microchip PFSoC to allow unmodified HSS and Linux boots. # gpg: Signature made Tue 03 Nov 2020 15:19:45 GMT # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full] # Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054 * remotes/alistair/tags/pull-riscv-to-apply-20201103: target/riscv/csr.c : add space before the open parenthesis '(' hw/riscv: microchip_pfsoc: Hook the I2C1 controller hw/riscv: microchip_pfsoc: Correct DDR memory map hw/riscv: microchip_pfsoc: Map the reserved memory at address 0 hw/riscv: microchip_pfsoc: Connect the SYSREG module hw/misc: Add Microchip PolarFire SoC SYSREG module support hw/riscv: microchip_pfsoc: Connect the IOSCB module hw/misc: Add Microchip PolarFire SoC IOSCB module support hw/riscv: microchip_pfsoc: Connect DDR memory controller modules hw/misc: Add Microchip PolarFire SoC DDR Memory Controller support hw/riscv: microchip_pfsoc: Document where to look at the SoC memory maps target/riscv: Add sifive_plic vmstate target/riscv: Add V extension state description target/riscv: Add H extension state description target/riscv: Add PMP state description target/riscv: Add basic vmstate description of CPU target/riscv: Merge m/vsstatus and m/vsstatush into one uint64_t unit hw/riscv: virt: Allow passing custom DTB hw/riscv: sifive_u: Allow passing custom DTB Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9167d34921
@ -1327,8 +1327,14 @@ L: qemu-riscv@nongnu.org
|
||||
S: Supported
|
||||
F: hw/riscv/microchip_pfsoc.c
|
||||
F: hw/char/mchp_pfsoc_mmuart.c
|
||||
F: hw/misc/mchp_pfsoc_dmc.c
|
||||
F: hw/misc/mchp_pfsoc_ioscb.c
|
||||
F: hw/misc/mchp_pfsoc_sysreg.c
|
||||
F: include/hw/riscv/microchip_pfsoc.h
|
||||
F: include/hw/char/mchp_pfsoc_mmuart.h
|
||||
F: include/hw/misc/mchp_pfsoc_dmc.h
|
||||
F: include/hw/misc/mchp_pfsoc_ioscb.h
|
||||
F: include/hw/misc/mchp_pfsoc_sysreg.h
|
||||
|
||||
RX Machines
|
||||
-----------
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "hw/intc/sifive_plic.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#define RISCV_DEBUG_PLIC 0
|
||||
|
||||
@ -448,11 +449,12 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp)
|
||||
TYPE_SIFIVE_PLIC, plic->aperture_size);
|
||||
parse_hart_config(plic);
|
||||
plic->bitfield_words = (plic->num_sources + 31) >> 5;
|
||||
plic->num_enables = plic->bitfield_words * plic->num_addrs;
|
||||
plic->source_priority = g_new0(uint32_t, plic->num_sources);
|
||||
plic->target_priority = g_new(uint32_t, plic->num_addrs);
|
||||
plic->pending = g_new0(uint32_t, plic->bitfield_words);
|
||||
plic->claimed = g_new0(uint32_t, plic->bitfield_words);
|
||||
plic->enable = g_new0(uint32_t, plic->bitfield_words * plic->num_addrs);
|
||||
plic->enable = g_new0(uint32_t, plic->num_enables);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio);
|
||||
qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources);
|
||||
|
||||
@ -472,12 +474,34 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp)
|
||||
msi_nonbroken = true;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_sifive_plic = {
|
||||
.name = "riscv_sifive_plic",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VARRAY_UINT32(source_priority, SiFivePLICState,
|
||||
num_sources, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(target_priority, SiFivePLICState,
|
||||
num_addrs, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(pending, SiFivePLICState, bitfield_words, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(claimed, SiFivePLICState, bitfield_words, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(enable, SiFivePLICState, num_enables, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void sifive_plic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
device_class_set_props(dc, sifive_plic_properties);
|
||||
dc->realize = sifive_plic_realize;
|
||||
dc->vmsd = &vmstate_sifive_plic;
|
||||
}
|
||||
|
||||
static const TypeInfo sifive_plic_info = {
|
||||
|
@ -139,6 +139,15 @@ config MAC_VIA
|
||||
config AVR_POWER
|
||||
bool
|
||||
|
||||
config MCHP_PFSOC_DMC
|
||||
bool
|
||||
|
||||
config MCHP_PFSOC_IOSCB
|
||||
bool
|
||||
|
||||
config MCHP_PFSOC_SYSREG
|
||||
bool
|
||||
|
||||
config SIFIVE_TEST
|
||||
bool
|
||||
|
||||
|
216
hw/misc/mchp_pfsoc_dmc.c
Normal file
216
hw/misc/mchp_pfsoc_dmc.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Microchip PolarFire SoC DDR Memory Controller module emulation
|
||||
*
|
||||
* Copyright (c) 2020 Wind River Systems, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Bin Meng <bin.meng@windriver.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/mchp_pfsoc_dmc.h"
|
||||
|
||||
/* DDR SGMII PHY module */
|
||||
|
||||
#define SGMII_PHY_IOC_REG1 0x208
|
||||
#define SGMII_PHY_TRAINING_STATUS 0x814
|
||||
#define SGMII_PHY_DQ_DQS_ERR_DONE 0x834
|
||||
#define SGMII_PHY_DQDQS_STATUS1 0x84c
|
||||
#define SGMII_PHY_PVT_STAT 0xc20
|
||||
|
||||
static uint64_t mchp_pfsoc_ddr_sgmii_phy_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
static int training_status_bit;
|
||||
|
||||
switch (offset) {
|
||||
case SGMII_PHY_IOC_REG1:
|
||||
/* See ddr_pvt_calibration() in HSS */
|
||||
val = BIT(4) | BIT(2);
|
||||
break;
|
||||
case SGMII_PHY_TRAINING_STATUS:
|
||||
/*
|
||||
* The codes logic emulates the training status change from
|
||||
* DDR_TRAINING_IP_SM_BCLKSCLK to DDR_TRAINING_IP_SM_DQ_DQS.
|
||||
*
|
||||
* See ddr_setup() in mss_ddr.c in the HSS source codes.
|
||||
*/
|
||||
val = 1 << training_status_bit;
|
||||
training_status_bit = (training_status_bit + 1) % 5;
|
||||
break;
|
||||
case SGMII_PHY_DQ_DQS_ERR_DONE:
|
||||
/*
|
||||
* DDR_TRAINING_IP_SM_VERIFY state in ddr_setup(),
|
||||
* check that DQ/DQS training passed without error.
|
||||
*/
|
||||
val = 8;
|
||||
break;
|
||||
case SGMII_PHY_DQDQS_STATUS1:
|
||||
/*
|
||||
* DDR_TRAINING_IP_SM_VERIFY state in ddr_setup(),
|
||||
* check that DQ/DQS calculated window is above 5 taps.
|
||||
*/
|
||||
val = 0xff;
|
||||
break;
|
||||
case SGMII_PHY_PVT_STAT:
|
||||
/* See sgmii_channel_setup() in HSS */
|
||||
val = BIT(14) | BIT(6);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_ddr_sgmii_phy_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
|
||||
"(size %d, value 0x%" PRIx64
|
||||
", offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, value, offset);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mchp_pfsoc_ddr_sgmii_phy_ops = {
|
||||
.read = mchp_pfsoc_ddr_sgmii_phy_read,
|
||||
.write = mchp_pfsoc_ddr_sgmii_phy_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_ddr_sgmii_phy_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MchpPfSoCDdrSgmiiPhyState *s = MCHP_PFSOC_DDR_SGMII_PHY(dev);
|
||||
|
||||
memory_region_init_io(&s->sgmii_phy, OBJECT(dev),
|
||||
&mchp_pfsoc_ddr_sgmii_phy_ops, s,
|
||||
"mchp.pfsoc.ddr_sgmii_phy",
|
||||
MCHP_PFSOC_DDR_SGMII_PHY_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sgmii_phy);
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_ddr_sgmii_phy_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "Microchip PolarFire SoC DDR SGMII PHY module";
|
||||
dc->realize = mchp_pfsoc_ddr_sgmii_phy_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo mchp_pfsoc_ddr_sgmii_phy_info = {
|
||||
.name = TYPE_MCHP_PFSOC_DDR_SGMII_PHY,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MchpPfSoCDdrSgmiiPhyState),
|
||||
.class_init = mchp_pfsoc_ddr_sgmii_phy_class_init,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_ddr_sgmii_phy_register_types(void)
|
||||
{
|
||||
type_register_static(&mchp_pfsoc_ddr_sgmii_phy_info);
|
||||
}
|
||||
|
||||
type_init(mchp_pfsoc_ddr_sgmii_phy_register_types)
|
||||
|
||||
/* DDR CFG module */
|
||||
|
||||
#define CFG_MT_DONE_ACK 0x4428
|
||||
#define CFG_STAT_DFI_INIT_COMPLETE 0x10034
|
||||
#define CFG_STAT_DFI_TRAINING_COMPLETE 0x10038
|
||||
|
||||
static uint64_t mchp_pfsoc_ddr_cfg_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
switch (offset) {
|
||||
case CFG_MT_DONE_ACK:
|
||||
/* memory test in MTC_test() */
|
||||
val = BIT(0);
|
||||
break;
|
||||
case CFG_STAT_DFI_INIT_COMPLETE:
|
||||
/* DDR_TRAINING_IP_SM_START_CHECK state in ddr_setup() */
|
||||
val = BIT(0);
|
||||
break;
|
||||
case CFG_STAT_DFI_TRAINING_COMPLETE:
|
||||
/* DDR_TRAINING_IP_SM_VERIFY state in ddr_setup() */
|
||||
val = BIT(0);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_ddr_cfg_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
|
||||
"(size %d, value 0x%" PRIx64
|
||||
", offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, value, offset);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mchp_pfsoc_ddr_cfg_ops = {
|
||||
.read = mchp_pfsoc_ddr_cfg_read,
|
||||
.write = mchp_pfsoc_ddr_cfg_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_ddr_cfg_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MchpPfSoCDdrCfgState *s = MCHP_PFSOC_DDR_CFG(dev);
|
||||
|
||||
memory_region_init_io(&s->cfg, OBJECT(dev),
|
||||
&mchp_pfsoc_ddr_cfg_ops, s,
|
||||
"mchp.pfsoc.ddr_cfg",
|
||||
MCHP_PFSOC_DDR_CFG_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->cfg);
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_ddr_cfg_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "Microchip PolarFire SoC DDR CFG module";
|
||||
dc->realize = mchp_pfsoc_ddr_cfg_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo mchp_pfsoc_ddr_cfg_info = {
|
||||
.name = TYPE_MCHP_PFSOC_DDR_CFG,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MchpPfSoCDdrCfgState),
|
||||
.class_init = mchp_pfsoc_ddr_cfg_class_init,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_ddr_cfg_register_types(void)
|
||||
{
|
||||
type_register_static(&mchp_pfsoc_ddr_cfg_info);
|
||||
}
|
||||
|
||||
type_init(mchp_pfsoc_ddr_cfg_register_types)
|
242
hw/misc/mchp_pfsoc_ioscb.c
Normal file
242
hw/misc/mchp_pfsoc_ioscb.c
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Microchip PolarFire SoC IOSCB module emulation
|
||||
*
|
||||
* Copyright (c) 2020 Wind River Systems, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Bin Meng <bin.meng@windriver.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/mchp_pfsoc_ioscb.h"
|
||||
|
||||
/*
|
||||
* The whole IOSCB module registers map into the system address at 0x3000_0000,
|
||||
* named as "System Port 0 (AXI-D0)".
|
||||
*/
|
||||
#define IOSCB_WHOLE_REG_SIZE 0x10000000
|
||||
#define IOSCB_SUBMOD_REG_SIZE 0x1000
|
||||
|
||||
/*
|
||||
* There are many sub-modules in the IOSCB module.
|
||||
* See Microchip PolarFire SoC documentation (Register_Map.zip),
|
||||
* Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm
|
||||
*
|
||||
* The following are sub-modules offsets that are of concern.
|
||||
*/
|
||||
#define IOSCB_LANE01_BASE 0x06500000
|
||||
#define IOSCB_LANE23_BASE 0x06510000
|
||||
#define IOSCB_CTRL_BASE 0x07020000
|
||||
#define IOSCB_CFG_BASE 0x07080000
|
||||
#define IOSCB_PLL_MSS_BASE 0x0E001000
|
||||
#define IOSCB_CFM_MSS_BASE 0x0E002000
|
||||
#define IOSCB_PLL_DDR_BASE 0x0E010000
|
||||
#define IOSCB_BC_DDR_BASE 0x0E020000
|
||||
#define IOSCB_IO_CALIB_DDR_BASE 0x0E040000
|
||||
#define IOSCB_PLL_SGMII_BASE 0x0E080000
|
||||
#define IOSCB_DLL_SGMII_BASE 0x0E100000
|
||||
#define IOSCB_CFM_SGMII_BASE 0x0E200000
|
||||
#define IOSCB_BC_SGMII_BASE 0x0E400000
|
||||
#define IOSCB_IO_CALIB_SGMII_BASE 0x0E800000
|
||||
|
||||
static uint64_t mchp_pfsoc_dummy_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_dummy_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
|
||||
"(size %d, value 0x%" PRIx64
|
||||
", offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, value, offset);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mchp_pfsoc_dummy_ops = {
|
||||
.read = mchp_pfsoc_dummy_read,
|
||||
.write = mchp_pfsoc_dummy_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
/* All PLL modules in IOSCB have the same register layout */
|
||||
|
||||
#define PLL_CTRL 0x04
|
||||
|
||||
static uint64_t mchp_pfsoc_pll_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
switch (offset) {
|
||||
case PLL_CTRL:
|
||||
/* PLL is locked */
|
||||
val = BIT(25);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mchp_pfsoc_pll_ops = {
|
||||
.read = mchp_pfsoc_pll_read,
|
||||
.write = mchp_pfsoc_dummy_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
/* IO_CALIB_DDR submodule */
|
||||
|
||||
#define IO_CALIB_DDR_IOC_REG1 0x08
|
||||
|
||||
static uint64_t mchp_pfsoc_io_calib_ddr_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
switch (offset) {
|
||||
case IO_CALIB_DDR_IOC_REG1:
|
||||
/* calibration completed */
|
||||
val = BIT(2);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops = {
|
||||
.read = mchp_pfsoc_io_calib_ddr_read,
|
||||
.write = mchp_pfsoc_dummy_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MchpPfSoCIoscbState *s = MCHP_PFSOC_IOSCB(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
memory_region_init(&s->container, OBJECT(s),
|
||||
"mchp.pfsoc.ioscb", IOSCB_WHOLE_REG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->container);
|
||||
|
||||
/* add subregions for all sub-modules in IOSCB */
|
||||
|
||||
memory_region_init_io(&s->lane01, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.lane01", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_LANE01_BASE, &s->lane01);
|
||||
|
||||
memory_region_init_io(&s->lane23, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.lane23", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_LANE23_BASE, &s->lane23);
|
||||
|
||||
memory_region_init_io(&s->ctrl, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.ctrl", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_CTRL_BASE, &s->ctrl);
|
||||
|
||||
memory_region_init_io(&s->cfg, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.cfg", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_CFG_BASE, &s->cfg);
|
||||
|
||||
memory_region_init_io(&s->pll_mss, OBJECT(s), &mchp_pfsoc_pll_ops, s,
|
||||
"mchp.pfsoc.ioscb.pll_mss", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_PLL_MSS_BASE, &s->pll_mss);
|
||||
|
||||
memory_region_init_io(&s->cfm_mss, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.cfm_mss", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_CFM_MSS_BASE, &s->cfm_mss);
|
||||
|
||||
memory_region_init_io(&s->pll_ddr, OBJECT(s), &mchp_pfsoc_pll_ops, s,
|
||||
"mchp.pfsoc.ioscb.pll_ddr", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_PLL_DDR_BASE, &s->pll_ddr);
|
||||
|
||||
memory_region_init_io(&s->bc_ddr, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.bc_ddr", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_BC_DDR_BASE, &s->bc_ddr);
|
||||
|
||||
memory_region_init_io(&s->io_calib_ddr, OBJECT(s),
|
||||
&mchp_pfsoc_io_calib_ddr_ops, s,
|
||||
"mchp.pfsoc.ioscb.io_calib_ddr",
|
||||
IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_DDR_BASE,
|
||||
&s->io_calib_ddr);
|
||||
|
||||
memory_region_init_io(&s->pll_sgmii, OBJECT(s), &mchp_pfsoc_pll_ops, s,
|
||||
"mchp.pfsoc.ioscb.pll_sgmii", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_PLL_SGMII_BASE,
|
||||
&s->pll_sgmii);
|
||||
|
||||
memory_region_init_io(&s->dll_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.dll_sgmii", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_DLL_SGMII_BASE,
|
||||
&s->dll_sgmii);
|
||||
|
||||
memory_region_init_io(&s->cfm_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.cfm_sgmii", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_CFM_SGMII_BASE,
|
||||
&s->cfm_sgmii);
|
||||
|
||||
memory_region_init_io(&s->bc_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
|
||||
"mchp.pfsoc.ioscb.bc_sgmii", IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_BC_SGMII_BASE,
|
||||
&s->bc_sgmii);
|
||||
|
||||
memory_region_init_io(&s->io_calib_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops,
|
||||
s, "mchp.pfsoc.ioscb.io_calib_sgmii",
|
||||
IOSCB_SUBMOD_REG_SIZE);
|
||||
memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_SGMII_BASE,
|
||||
&s->io_calib_sgmii);
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "Microchip PolarFire SoC IOSCB modules";
|
||||
dc->realize = mchp_pfsoc_ioscb_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo mchp_pfsoc_ioscb_info = {
|
||||
.name = TYPE_MCHP_PFSOC_IOSCB,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MchpPfSoCIoscbState),
|
||||
.class_init = mchp_pfsoc_ioscb_class_init,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_ioscb_register_types(void)
|
||||
{
|
||||
type_register_static(&mchp_pfsoc_ioscb_info);
|
||||
}
|
||||
|
||||
type_init(mchp_pfsoc_ioscb_register_types)
|
99
hw/misc/mchp_pfsoc_sysreg.c
Normal file
99
hw/misc/mchp_pfsoc_sysreg.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Microchip PolarFire SoC SYSREG module emulation
|
||||
*
|
||||
* Copyright (c) 2020 Wind River Systems, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Bin Meng <bin.meng@windriver.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/mchp_pfsoc_sysreg.h"
|
||||
|
||||
#define ENVM_CR 0xb8
|
||||
|
||||
static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
switch (offset) {
|
||||
case ENVM_CR:
|
||||
/* Indicate the eNVM is running at the configured divider rate */
|
||||
val = BIT(6);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
|
||||
"(size %d, value 0x%" PRIx64
|
||||
", offset 0x%" HWADDR_PRIx ")\n",
|
||||
__func__, size, value, offset);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mchp_pfsoc_sysreg_ops = {
|
||||
.read = mchp_pfsoc_sysreg_read,
|
||||
.write = mchp_pfsoc_sysreg_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_sysreg_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MchpPfSoCSysregState *s = MCHP_PFSOC_SYSREG(dev);
|
||||
|
||||
memory_region_init_io(&s->sysreg, OBJECT(dev),
|
||||
&mchp_pfsoc_sysreg_ops, s,
|
||||
"mchp.pfsoc.sysreg",
|
||||
MCHP_PFSOC_SYSREG_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sysreg);
|
||||
}
|
||||
|
||||
static void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "Microchip PolarFire SoC SYSREG module";
|
||||
dc->realize = mchp_pfsoc_sysreg_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo mchp_pfsoc_sysreg_info = {
|
||||
.name = TYPE_MCHP_PFSOC_SYSREG,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MchpPfSoCSysregState),
|
||||
.class_init = mchp_pfsoc_sysreg_class_init,
|
||||
};
|
||||
|
||||
static void mchp_pfsoc_sysreg_register_types(void)
|
||||
{
|
||||
type_register_static(&mchp_pfsoc_sysreg_info);
|
||||
}
|
||||
|
||||
type_init(mchp_pfsoc_sysreg_register_types)
|
@ -23,6 +23,9 @@ softmmu_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c'))
|
||||
|
||||
# RISC-V devices
|
||||
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true: files('mchp_pfsoc_dmc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_SYSREG', if_true: files('mchp_pfsoc_sysreg.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SIFIVE_TEST', if_true: files('sifive_test.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c'))
|
||||
|
@ -4,7 +4,10 @@ config IBEX
|
||||
config MICROCHIP_PFSOC
|
||||
bool
|
||||
select CADENCE_SDHCI
|
||||
select MCHP_PFSOC_DMC
|
||||
select MCHP_PFSOC_IOSCB
|
||||
select MCHP_PFSOC_MMUART
|
||||
select MCHP_PFSOC_SYSREG
|
||||
select MSI_NONBROKEN
|
||||
select SIFIVE_CLINT
|
||||
select SIFIVE_PDMA
|
||||
|
@ -15,6 +15,8 @@
|
||||
* 4) Cadence eMMC/SDHC controller and an SD card connected to it
|
||||
* 5) SiFive Platform DMA (Direct Memory Access Controller)
|
||||
* 6) GEM (Gigabit Ethernet MAC Controller)
|
||||
* 7) DMC (DDR Memory Controller)
|
||||
* 8) IOSCB modules
|
||||
*
|
||||
* This board currently generates devicetree dynamically that indicates at least
|
||||
* two harts and up to five harts.
|
||||
@ -66,11 +68,30 @@
|
||||
/* GEM version */
|
||||
#define GEM_REVISION 0x0107010c
|
||||
|
||||
/*
|
||||
* The complete description of the whole PolarFire SoC memory map is scattered
|
||||
* in different documents. There are several places to look at for memory maps:
|
||||
*
|
||||
* 1 Chapter 11 "MSS Memory Map", in the doc "UG0880: PolarFire SoC FPGA
|
||||
* Microprocessor Subsystem (MSS) User Guide", which can be downloaded from
|
||||
* https://www.microsemi.com/document-portal/doc_download/
|
||||
* 1244570-ug0880-polarfire-soc-fpga-microprocessor-subsystem-mss-user-guide,
|
||||
* describes the whole picture of the PolarFire SoC memory map.
|
||||
*
|
||||
* 2 A zip file for PolarFire soC memory map, which can be downloaded from
|
||||
* https://www.microsemi.com/document-portal/doc_download/
|
||||
* 1244581-polarfire-soc-register-map, contains the following 2 major parts:
|
||||
* - Register Map/PF_SoC_RegMap_V1_1/pfsoc_regmap.htm
|
||||
* describes the complete integrated peripherals memory map
|
||||
* - Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm
|
||||
* describes the complete IOSCB modules memory maps
|
||||
*/
|
||||
static const struct MemmapEntry {
|
||||
hwaddr base;
|
||||
hwaddr size;
|
||||
} microchip_pfsoc_memmap[] = {
|
||||
[MICROCHIP_PFSOC_DEBUG] = { 0x0, 0x1000 },
|
||||
[MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 },
|
||||
[MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 },
|
||||
[MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 },
|
||||
[MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 },
|
||||
@ -85,11 +106,14 @@ static const struct MemmapEntry {
|
||||
[MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 },
|
||||
[MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 },
|
||||
[MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 },
|
||||
[MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 },
|
||||
[MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 },
|
||||
@ -97,8 +121,11 @@ static const struct MemmapEntry {
|
||||
[MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 },
|
||||
[MICROCHIP_PFSOC_IOSCB_CFG] = { 0x37080000, 0x1000 },
|
||||
[MICROCHIP_PFSOC_DRAM] = { 0x80000000, 0x0 },
|
||||
[MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 },
|
||||
[MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 },
|
||||
[MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 },
|
||||
[MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 },
|
||||
[MICROCHIP_PFSOC_DRAM_HI_ALIAS] = { 0x1400000000, 0x0 },
|
||||
};
|
||||
|
||||
static void microchip_pfsoc_soc_instance_init(Object *obj)
|
||||
@ -131,11 +158,21 @@ static void microchip_pfsoc_soc_instance_init(Object *obj)
|
||||
object_initialize_child(obj, "dma-controller", &s->dma,
|
||||
TYPE_SIFIVE_PDMA);
|
||||
|
||||
object_initialize_child(obj, "sysreg", &s->sysreg,
|
||||
TYPE_MCHP_PFSOC_SYSREG);
|
||||
|
||||
object_initialize_child(obj, "ddr-sgmii-phy", &s->ddr_sgmii_phy,
|
||||
TYPE_MCHP_PFSOC_DDR_SGMII_PHY);
|
||||
object_initialize_child(obj, "ddr-cfg", &s->ddr_cfg,
|
||||
TYPE_MCHP_PFSOC_DDR_CFG);
|
||||
|
||||
object_initialize_child(obj, "gem0", &s->gem0, TYPE_CADENCE_GEM);
|
||||
object_initialize_child(obj, "gem1", &s->gem1, TYPE_CADENCE_GEM);
|
||||
|
||||
object_initialize_child(obj, "sd-controller", &s->sdhci,
|
||||
TYPE_CADENCE_SDHCI);
|
||||
|
||||
object_initialize_child(obj, "ioscb", &s->ioscb, TYPE_MCHP_PFSOC_IOSCB);
|
||||
}
|
||||
|
||||
static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
@ -144,6 +181,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev);
|
||||
const struct MemmapEntry *memmap = microchip_pfsoc_memmap;
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
MemoryRegion *rsvd0_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *envm_data = g_new(MemoryRegion, 1);
|
||||
@ -163,6 +201,13 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort);
|
||||
qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort);
|
||||
|
||||
/* Reserved Memory at address 0 */
|
||||
memory_region_init_ram(rsvd0_mem, NULL, "microchip.pfsoc.rsvd0_mem",
|
||||
memmap[MICROCHIP_PFSOC_RSVD0].size, &error_fatal);
|
||||
memory_region_add_subregion(system_memory,
|
||||
memmap[MICROCHIP_PFSOC_RSVD0].base,
|
||||
rsvd0_mem);
|
||||
|
||||
/* E51 DTIM */
|
||||
memory_region_init_ram(e51_dtim_mem, NULL, "microchip.pfsoc.e51_dtim_mem",
|
||||
memmap[MICROCHIP_PFSOC_E51_DTIM].size, &error_fatal);
|
||||
@ -251,15 +296,25 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* SYSREG */
|
||||
create_unimplemented_device("microchip.pfsoc.sysreg",
|
||||
memmap[MICROCHIP_PFSOC_SYSREG].base,
|
||||
memmap[MICROCHIP_PFSOC_SYSREG].size);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0,
|
||||
memmap[MICROCHIP_PFSOC_SYSREG].base);
|
||||
|
||||
/* MPUCFG */
|
||||
create_unimplemented_device("microchip.pfsoc.mpucfg",
|
||||
memmap[MICROCHIP_PFSOC_MPUCFG].base,
|
||||
memmap[MICROCHIP_PFSOC_MPUCFG].size);
|
||||
|
||||
/* DDR SGMII PHY */
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), 0,
|
||||
memmap[MICROCHIP_PFSOC_DDR_SGMII_PHY].base);
|
||||
|
||||
/* DDR CFG */
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->ddr_cfg), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_cfg), 0,
|
||||
memmap[MICROCHIP_PFSOC_DDR_CFG].base);
|
||||
|
||||
/* SDHCI */
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0,
|
||||
@ -289,6 +344,11 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART4_IRQ),
|
||||
serial_hd(4));
|
||||
|
||||
/* I2C1 */
|
||||
create_unimplemented_device("microchip.pfsoc.i2c1",
|
||||
memmap[MICROCHIP_PFSOC_I2C1].base,
|
||||
memmap[MICROCHIP_PFSOC_I2C1].size);
|
||||
|
||||
/* GEMs */
|
||||
|
||||
nd = &nd_table[0];
|
||||
@ -337,10 +397,10 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
|
||||
envm_data);
|
||||
|
||||
/* IOSCBCFG */
|
||||
create_unimplemented_device("microchip.pfsoc.ioscb.cfg",
|
||||
memmap[MICROCHIP_PFSOC_IOSCB_CFG].base,
|
||||
memmap[MICROCHIP_PFSOC_IOSCB_CFG].size);
|
||||
/* IOSCB */
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->ioscb), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioscb), 0,
|
||||
memmap[MICROCHIP_PFSOC_IOSCB].base);
|
||||
}
|
||||
|
||||
static void microchip_pfsoc_soc_class_init(ObjectClass *oc, void *data)
|
||||
@ -373,7 +433,11 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
const struct MemmapEntry *memmap = microchip_pfsoc_memmap;
|
||||
MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine);
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *mem_low = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *mem_low_alias = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *mem_high = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *mem_high_alias = g_new(MemoryRegion, 1);
|
||||
uint64_t mem_high_size;
|
||||
DriveInfo *dinfo = drive_get_next(IF_SD);
|
||||
|
||||
/* Sanity check on RAM size */
|
||||
@ -390,10 +454,33 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
|
||||
|
||||
/* Register RAM */
|
||||
memory_region_init_ram(main_mem, NULL, "microchip.icicle.kit.ram",
|
||||
machine->ram_size, &error_fatal);
|
||||
memory_region_init_ram(mem_low, NULL, "microchip.icicle.kit.ram_low",
|
||||
memmap[MICROCHIP_PFSOC_DRAM_LO].size,
|
||||
&error_fatal);
|
||||
memory_region_init_alias(mem_low_alias, NULL,
|
||||
"microchip.icicle.kit.ram_low.alias",
|
||||
mem_low, 0,
|
||||
memmap[MICROCHIP_PFSOC_DRAM_LO_ALIAS].size);
|
||||
memory_region_add_subregion(system_memory,
|
||||
memmap[MICROCHIP_PFSOC_DRAM].base, main_mem);
|
||||
memmap[MICROCHIP_PFSOC_DRAM_LO].base,
|
||||
mem_low);
|
||||
memory_region_add_subregion(system_memory,
|
||||
memmap[MICROCHIP_PFSOC_DRAM_LO_ALIAS].base,
|
||||
mem_low_alias);
|
||||
|
||||
mem_high_size = machine->ram_size - 1 * GiB;
|
||||
|
||||
memory_region_init_ram(mem_high, NULL, "microchip.icicle.kit.ram_high",
|
||||
mem_high_size, &error_fatal);
|
||||
memory_region_init_alias(mem_high_alias, NULL,
|
||||
"microchip.icicle.kit.ram_high.alias",
|
||||
mem_high, 0, mem_high_size);
|
||||
memory_region_add_subregion(system_memory,
|
||||
memmap[MICROCHIP_PFSOC_DRAM_HI].base,
|
||||
mem_high);
|
||||
memory_region_add_subregion(system_memory,
|
||||
memmap[MICROCHIP_PFSOC_DRAM_HI_ALIAS].base,
|
||||
mem_high_alias);
|
||||
|
||||
/* Load the firmware */
|
||||
riscv_find_and_load_firmware(machine, BIOS_FILENAME, RESET_VECTOR, NULL);
|
||||
@ -419,7 +506,15 @@ static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)
|
||||
MICROCHIP_PFSOC_COMPUTE_CPU_COUNT;
|
||||
mc->min_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + 1;
|
||||
mc->default_cpus = mc->min_cpus;
|
||||
mc->default_ram_size = 1 * GiB;
|
||||
|
||||
/*
|
||||
* Map 513 MiB high memory, the mimimum required high memory size, because
|
||||
* HSS will do memory test against the high memory address range regardless
|
||||
* of physical memory installed.
|
||||
*
|
||||
* See memory_tests() in mss_ddr.c in the HSS source code.
|
||||
*/
|
||||
mc->default_ram_size = 1537 * MiB;
|
||||
}
|
||||
|
||||
static const TypeInfo microchip_icicle_kit_machine_typeinfo = {
|
||||
|
@ -100,14 +100,25 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
int cpu;
|
||||
uint32_t *cells;
|
||||
char *nodename;
|
||||
const char *dtb_filename;
|
||||
char ethclk_names[] = "pclk\0hclk";
|
||||
uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1;
|
||||
uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
|
||||
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
|
||||
if (dtb_filename) {
|
||||
fdt = s->fdt = load_device_tree(dtb_filename, &s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("load_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
goto update_bootargs;
|
||||
} else {
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00");
|
||||
@ -390,13 +401,14 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
|
||||
if (cmdline) {
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename);
|
||||
|
||||
g_free(nodename);
|
||||
|
||||
update_bootargs:
|
||||
if (cmdline) {
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
static void sifive_u_machine_reset(void *opaque, int n, int level)
|
||||
|
@ -181,6 +181,7 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
{
|
||||
void *fdt;
|
||||
int i, cpu, socket;
|
||||
const char *dtb_filename;
|
||||
MachineState *mc = MACHINE(s);
|
||||
uint64_t addr, size;
|
||||
uint32_t *clint_cells, *plic_cells;
|
||||
@ -194,10 +195,20 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
|
||||
hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
|
||||
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
|
||||
if (dtb_filename) {
|
||||
fdt = s->fdt = load_device_tree(dtb_filename, &s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("load_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
goto update_bootargs;
|
||||
} else {
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
|
||||
@ -418,9 +429,6 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
|
||||
if (cmdline) {
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
g_free(name);
|
||||
|
||||
name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
|
||||
@ -441,6 +449,11 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(s->fdt, name, "bank-width", 4);
|
||||
g_free(name);
|
||||
|
||||
update_bootargs:
|
||||
if (cmdline) {
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
|
||||
|
@ -52,6 +52,7 @@ struct SiFivePLICState {
|
||||
uint32_t num_addrs;
|
||||
uint32_t num_harts;
|
||||
uint32_t bitfield_words;
|
||||
uint32_t num_enables;
|
||||
PLICAddr *addr_config;
|
||||
uint32_t *source_priority;
|
||||
uint32_t *target_priority;
|
||||
|
56
include/hw/misc/mchp_pfsoc_dmc.h
Normal file
56
include/hw/misc/mchp_pfsoc_dmc.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Microchip PolarFire SoC DDR Memory Controller module emulation
|
||||
*
|
||||
* Copyright (c) 2020 Wind River Systems, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Bin Meng <bin.meng@windriver.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MCHP_PFSOC_DMC_H
|
||||
#define MCHP_PFSOC_DMC_H
|
||||
|
||||
/* DDR SGMII PHY module */
|
||||
|
||||
#define MCHP_PFSOC_DDR_SGMII_PHY_REG_SIZE 0x1000
|
||||
|
||||
typedef struct MchpPfSoCDdrSgmiiPhyState {
|
||||
SysBusDevice parent;
|
||||
MemoryRegion sgmii_phy;
|
||||
} MchpPfSoCDdrSgmiiPhyState;
|
||||
|
||||
#define TYPE_MCHP_PFSOC_DDR_SGMII_PHY "mchp.pfsoc.ddr_sgmii_phy"
|
||||
|
||||
#define MCHP_PFSOC_DDR_SGMII_PHY(obj) \
|
||||
OBJECT_CHECK(MchpPfSoCDdrSgmiiPhyState, (obj), \
|
||||
TYPE_MCHP_PFSOC_DDR_SGMII_PHY)
|
||||
|
||||
/* DDR CFG module */
|
||||
|
||||
#define MCHP_PFSOC_DDR_CFG_REG_SIZE 0x40000
|
||||
|
||||
typedef struct MchpPfSoCDdrCfgState {
|
||||
SysBusDevice parent;
|
||||
MemoryRegion cfg;
|
||||
} MchpPfSoCDdrCfgState;
|
||||
|
||||
#define TYPE_MCHP_PFSOC_DDR_CFG "mchp.pfsoc.ddr_cfg"
|
||||
|
||||
#define MCHP_PFSOC_DDR_CFG(obj) \
|
||||
OBJECT_CHECK(MchpPfSoCDdrCfgState, (obj), \
|
||||
TYPE_MCHP_PFSOC_DDR_CFG)
|
||||
|
||||
#endif /* MCHP_PFSOC_DMC_H */
|
50
include/hw/misc/mchp_pfsoc_ioscb.h
Normal file
50
include/hw/misc/mchp_pfsoc_ioscb.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Microchip PolarFire SoC IOSCB module emulation
|
||||
*
|
||||
* Copyright (c) 2020 Wind River Systems, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Bin Meng <bin.meng@windriver.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MCHP_PFSOC_IOSCB_H
|
||||
#define MCHP_PFSOC_IOSCB_H
|
||||
|
||||
typedef struct MchpPfSoCIoscbState {
|
||||
SysBusDevice parent;
|
||||
MemoryRegion container;
|
||||
MemoryRegion lane01;
|
||||
MemoryRegion lane23;
|
||||
MemoryRegion ctrl;
|
||||
MemoryRegion cfg;
|
||||
MemoryRegion pll_mss;
|
||||
MemoryRegion cfm_mss;
|
||||
MemoryRegion pll_ddr;
|
||||
MemoryRegion bc_ddr;
|
||||
MemoryRegion io_calib_ddr;
|
||||
MemoryRegion pll_sgmii;
|
||||
MemoryRegion dll_sgmii;
|
||||
MemoryRegion cfm_sgmii;
|
||||
MemoryRegion bc_sgmii;
|
||||
MemoryRegion io_calib_sgmii;
|
||||
} MchpPfSoCIoscbState;
|
||||
|
||||
#define TYPE_MCHP_PFSOC_IOSCB "mchp.pfsoc.ioscb"
|
||||
|
||||
#define MCHP_PFSOC_IOSCB(obj) \
|
||||
OBJECT_CHECK(MchpPfSoCIoscbState, (obj), TYPE_MCHP_PFSOC_IOSCB)
|
||||
|
||||
#endif /* MCHP_PFSOC_IOSCB_H */
|
39
include/hw/misc/mchp_pfsoc_sysreg.h
Normal file
39
include/hw/misc/mchp_pfsoc_sysreg.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Microchip PolarFire SoC SYSREG module emulation
|
||||
*
|
||||
* Copyright (c) 2020 Wind River Systems, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Bin Meng <bin.meng@windriver.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MCHP_PFSOC_SYSREG_H
|
||||
#define MCHP_PFSOC_SYSREG_H
|
||||
|
||||
#define MCHP_PFSOC_SYSREG_REG_SIZE 0x2000
|
||||
|
||||
typedef struct MchpPfSoCSysregState {
|
||||
SysBusDevice parent;
|
||||
MemoryRegion sysreg;
|
||||
} MchpPfSoCSysregState;
|
||||
|
||||
#define TYPE_MCHP_PFSOC_SYSREG "mchp.pfsoc.sysreg"
|
||||
|
||||
#define MCHP_PFSOC_SYSREG(obj) \
|
||||
OBJECT_CHECK(MchpPfSoCSysregState, (obj), \
|
||||
TYPE_MCHP_PFSOC_SYSREG)
|
||||
|
||||
#endif /* MCHP_PFSOC_SYSREG_H */
|
@ -24,6 +24,9 @@
|
||||
|
||||
#include "hw/char/mchp_pfsoc_mmuart.h"
|
||||
#include "hw/dma/sifive_pdma.h"
|
||||
#include "hw/misc/mchp_pfsoc_dmc.h"
|
||||
#include "hw/misc/mchp_pfsoc_ioscb.h"
|
||||
#include "hw/misc/mchp_pfsoc_sysreg.h"
|
||||
#include "hw/net/cadence_gem.h"
|
||||
#include "hw/sd/cadence_sdhci.h"
|
||||
|
||||
@ -37,11 +40,15 @@ typedef struct MicrochipPFSoCState {
|
||||
RISCVHartArrayState e_cpus;
|
||||
RISCVHartArrayState u_cpus;
|
||||
DeviceState *plic;
|
||||
MchpPfSoCDdrSgmiiPhyState ddr_sgmii_phy;
|
||||
MchpPfSoCDdrCfgState ddr_cfg;
|
||||
MchpPfSoCIoscbState ioscb;
|
||||
MchpPfSoCMMUartState *serial0;
|
||||
MchpPfSoCMMUartState *serial1;
|
||||
MchpPfSoCMMUartState *serial2;
|
||||
MchpPfSoCMMUartState *serial3;
|
||||
MchpPfSoCMMUartState *serial4;
|
||||
MchpPfSoCSysregState sysreg;
|
||||
SiFivePDMAState dma;
|
||||
CadenceGEMState gem0;
|
||||
CadenceGEMState gem1;
|
||||
@ -67,6 +74,7 @@ typedef struct MicrochipIcicleKitState {
|
||||
TYPE_MICROCHIP_ICICLE_KIT_MACHINE)
|
||||
|
||||
enum {
|
||||
MICROCHIP_PFSOC_RSVD0,
|
||||
MICROCHIP_PFSOC_DEBUG,
|
||||
MICROCHIP_PFSOC_E51_DTIM,
|
||||
MICROCHIP_PFSOC_BUSERR_UNIT0,
|
||||
@ -82,11 +90,14 @@ enum {
|
||||
MICROCHIP_PFSOC_MMUART0,
|
||||
MICROCHIP_PFSOC_SYSREG,
|
||||
MICROCHIP_PFSOC_MPUCFG,
|
||||
MICROCHIP_PFSOC_DDR_SGMII_PHY,
|
||||
MICROCHIP_PFSOC_EMMC_SD,
|
||||
MICROCHIP_PFSOC_DDR_CFG,
|
||||
MICROCHIP_PFSOC_MMUART1,
|
||||
MICROCHIP_PFSOC_MMUART2,
|
||||
MICROCHIP_PFSOC_MMUART3,
|
||||
MICROCHIP_PFSOC_MMUART4,
|
||||
MICROCHIP_PFSOC_I2C1,
|
||||
MICROCHIP_PFSOC_GEM0,
|
||||
MICROCHIP_PFSOC_GEM1,
|
||||
MICROCHIP_PFSOC_GPIO0,
|
||||
@ -94,8 +105,11 @@ enum {
|
||||
MICROCHIP_PFSOC_GPIO2,
|
||||
MICROCHIP_PFSOC_ENVM_CFG,
|
||||
MICROCHIP_PFSOC_ENVM_DATA,
|
||||
MICROCHIP_PFSOC_IOSCB_CFG,
|
||||
MICROCHIP_PFSOC_DRAM,
|
||||
MICROCHIP_PFSOC_IOSCB,
|
||||
MICROCHIP_PFSOC_DRAM_LO,
|
||||
MICROCHIP_PFSOC_DRAM_LO_ALIAS,
|
||||
MICROCHIP_PFSOC_DRAM_HI,
|
||||
MICROCHIP_PFSOC_DRAM_HI_ALIAS
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "qemu/ctype.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
@ -216,13 +217,15 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", (target_ulong)env->mstatus);
|
||||
#ifdef TARGET_RISCV32
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatush ", env->mstatush);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatush ",
|
||||
(target_ulong)(env->mstatus >> 32));
|
||||
#endif
|
||||
if (riscv_has_ext(env, RVH)) {
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", env->vsstatus);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
|
||||
(target_ulong)env->vsstatus);
|
||||
}
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip);
|
||||
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie);
|
||||
@ -496,13 +499,6 @@ static void riscv_cpu_init(Object *obj)
|
||||
cpu_set_cpustate_pointers(cpu);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static const VMStateDescription vmstate_riscv_cpu = {
|
||||
.name = "cpu",
|
||||
.unmigratable = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
static Property riscv_cpu_properties[] = {
|
||||
DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true),
|
||||
DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false),
|
||||
|
@ -144,14 +144,14 @@ struct CPURISCVState {
|
||||
target_ulong resetvec;
|
||||
|
||||
target_ulong mhartid;
|
||||
target_ulong mstatus;
|
||||
/*
|
||||
* For RV32 this is 32-bit mstatus and 32-bit mstatush.
|
||||
* For RV64 this is a 64-bit mstatus.
|
||||
*/
|
||||
uint64_t mstatus;
|
||||
|
||||
target_ulong mip;
|
||||
|
||||
#ifdef TARGET_RISCV32
|
||||
target_ulong mstatush;
|
||||
#endif
|
||||
|
||||
uint32_t miclaim;
|
||||
|
||||
target_ulong mie;
|
||||
@ -183,16 +183,17 @@ struct CPURISCVState {
|
||||
uint64_t htimedelta;
|
||||
|
||||
/* Virtual CSRs */
|
||||
target_ulong vsstatus;
|
||||
/*
|
||||
* For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
|
||||
* For RV64 this is a 64-bit vsstatus.
|
||||
*/
|
||||
uint64_t vsstatus;
|
||||
target_ulong vstvec;
|
||||
target_ulong vsscratch;
|
||||
target_ulong vsepc;
|
||||
target_ulong vscause;
|
||||
target_ulong vstval;
|
||||
target_ulong vsatp;
|
||||
#ifdef TARGET_RISCV32
|
||||
target_ulong vsstatush;
|
||||
#endif
|
||||
|
||||
target_ulong mtval2;
|
||||
target_ulong mtinst;
|
||||
@ -204,10 +205,7 @@ struct CPURISCVState {
|
||||
target_ulong scause_hs;
|
||||
target_ulong stval_hs;
|
||||
target_ulong satp_hs;
|
||||
target_ulong mstatus_hs;
|
||||
#ifdef TARGET_RISCV32
|
||||
target_ulong mstatush_hs;
|
||||
#endif
|
||||
uint64_t mstatus_hs;
|
||||
|
||||
target_ulong scounteren;
|
||||
target_ulong mcounteren;
|
||||
|
@ -4,10 +4,10 @@
|
||||
#define TARGET_RISCV_CPU_BITS_H
|
||||
|
||||
#define get_field(reg, mask) (((reg) & \
|
||||
(target_ulong)(mask)) / ((mask) & ~((mask) << 1)))
|
||||
#define set_field(reg, mask, val) (((reg) & ~(target_ulong)(mask)) | \
|
||||
(((target_ulong)(val) * ((mask) & ~((mask) << 1))) & \
|
||||
(target_ulong)(mask)))
|
||||
(uint64_t)(mask)) / ((mask) & ~((mask) << 1)))
|
||||
#define set_field(reg, mask, val) (((reg) & ~(uint64_t)(mask)) | \
|
||||
(((uint64_t)(val) * ((mask) & ~((mask) << 1))) & \
|
||||
(uint64_t)(mask)))
|
||||
|
||||
/* Floating point round mode */
|
||||
#define FSR_RD_SHIFT 5
|
||||
@ -381,19 +381,8 @@
|
||||
#define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */
|
||||
#define MSTATUS_TW 0x20000000 /* since: priv-1.10 */
|
||||
#define MSTATUS_TSR 0x40000000 /* since: priv-1.10 */
|
||||
#if defined(TARGET_RISCV64)
|
||||
#define MSTATUS_GVA 0x4000000000ULL
|
||||
#define MSTATUS_MPV 0x8000000000ULL
|
||||
#elif defined(TARGET_RISCV32)
|
||||
#define MSTATUS_GVA 0x00000040
|
||||
#define MSTATUS_MPV 0x00000080
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_RISCV32
|
||||
# define MSTATUS_MPV_ISSET(env) get_field(env->mstatush, MSTATUS_MPV)
|
||||
#else
|
||||
# define MSTATUS_MPV_ISSET(env) get_field(env->mstatus, MSTATUS_MPV)
|
||||
#endif
|
||||
|
||||
#define MSTATUS64_UXL 0x0000000300000000ULL
|
||||
#define MSTATUS64_SXL 0x0000000C00000000ULL
|
||||
|
@ -110,27 +110,19 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
|
||||
|
||||
void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
|
||||
{
|
||||
target_ulong mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS |
|
||||
MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE;
|
||||
uint64_t mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS |
|
||||
MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE |
|
||||
MSTATUS64_UXL;
|
||||
bool current_virt = riscv_cpu_virt_enabled(env);
|
||||
|
||||
g_assert(riscv_has_ext(env, RVH));
|
||||
|
||||
#if defined(TARGET_RISCV64)
|
||||
mstatus_mask |= MSTATUS64_UXL;
|
||||
#endif
|
||||
|
||||
if (current_virt) {
|
||||
/* Current V=1 and we are about to change to V=0 */
|
||||
env->vsstatus = env->mstatus & mstatus_mask;
|
||||
env->mstatus &= ~mstatus_mask;
|
||||
env->mstatus |= env->mstatus_hs;
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
env->vsstatush = env->mstatush;
|
||||
env->mstatush |= env->mstatush_hs;
|
||||
#endif
|
||||
|
||||
env->vstvec = env->stvec;
|
||||
env->stvec = env->stvec_hs;
|
||||
|
||||
@ -154,11 +146,6 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
|
||||
env->mstatus &= ~mstatus_mask;
|
||||
env->mstatus |= env->vsstatus;
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
env->mstatush_hs = env->mstatush;
|
||||
env->mstatush |= env->vsstatush;
|
||||
#endif
|
||||
|
||||
env->stvec_hs = env->stvec;
|
||||
env->stvec = env->vstvec;
|
||||
|
||||
@ -727,7 +714,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
if (riscv_has_ext(env, RVH) && env->priv == PRV_M &&
|
||||
access_type != MMU_INST_FETCH &&
|
||||
get_field(env->mstatus, MSTATUS_MPRV) &&
|
||||
MSTATUS_MPV_ISSET(env)) {
|
||||
get_field(env->mstatus, MSTATUS_MPV)) {
|
||||
riscv_cpu_set_two_stage_lookup(env, true);
|
||||
}
|
||||
|
||||
@ -799,7 +786,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
if (riscv_has_ext(env, RVH) && env->priv == PRV_M &&
|
||||
access_type != MMU_INST_FETCH &&
|
||||
get_field(env->mstatus, MSTATUS_MPRV) &&
|
||||
MSTATUS_MPV_ISSET(env)) {
|
||||
get_field(env->mstatus, MSTATUS_MPV)) {
|
||||
riscv_cpu_set_two_stage_lookup(env, false);
|
||||
}
|
||||
|
||||
@ -862,7 +849,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
bool force_hs_execp = riscv_cpu_force_hs_excep_enabled(env);
|
||||
target_ulong s;
|
||||
uint64_t s;
|
||||
|
||||
/* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
|
||||
* so we mask off the MSB and separate into trap type and cause.
|
||||
@ -995,19 +982,11 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||
if (riscv_cpu_virt_enabled(env)) {
|
||||
riscv_cpu_swap_hypervisor_regs(env);
|
||||
}
|
||||
#ifdef TARGET_RISCV32
|
||||
env->mstatush = set_field(env->mstatush, MSTATUS_MPV,
|
||||
riscv_cpu_virt_enabled(env));
|
||||
if (riscv_cpu_virt_enabled(env) && tval) {
|
||||
env->mstatush = set_field(env->mstatush, MSTATUS_GVA, 1);
|
||||
}
|
||||
#else
|
||||
env->mstatus = set_field(env->mstatus, MSTATUS_MPV,
|
||||
riscv_cpu_virt_enabled(env));
|
||||
riscv_cpu_virt_enabled(env));
|
||||
if (riscv_cpu_virt_enabled(env) && tval) {
|
||||
env->mstatus = set_field(env->mstatus, MSTATUS_GVA, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
mtval2 = env->guest_phys_fault_addr;
|
||||
|
||||
|
@ -446,8 +446,8 @@ static int validate_vm(CPURISCVState *env, target_ulong vm)
|
||||
|
||||
static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
|
||||
{
|
||||
target_ulong mstatus = env->mstatus;
|
||||
target_ulong mask = 0;
|
||||
uint64_t mstatus = env->mstatus;
|
||||
uint64_t mask = 0;
|
||||
int dirty;
|
||||
|
||||
/* flush tlb on mstatus fields that affect VM */
|
||||
@ -480,19 +480,20 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
|
||||
#ifdef TARGET_RISCV32
|
||||
static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val)
|
||||
{
|
||||
*val = env->mstatush;
|
||||
*val = env->mstatus >> 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val)
|
||||
{
|
||||
if ((val ^ env->mstatush) & (MSTATUS_MPV)) {
|
||||
uint64_t valh = (uint64_t)val << 32;
|
||||
uint64_t mask = MSTATUS_MPV | MSTATUS_GVA;
|
||||
|
||||
if ((valh ^ env->mstatus) & (MSTATUS_MPV)) {
|
||||
tlb_flush(env_cpu(env));
|
||||
}
|
||||
|
||||
val &= MSTATUS_MPV | MSTATUS_GVA;
|
||||
|
||||
env->mstatush = val;
|
||||
env->mstatus = (env->mstatus & ~mask) | (valh & mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -881,7 +882,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
|
||||
if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
|
||||
return -RISCV_EXCP_ILLEGAL_INST;
|
||||
} else {
|
||||
if((val ^ env->satp) & SATP_ASID) {
|
||||
if ((val ^ env->satp) & SATP_ASID) {
|
||||
tlb_flush(env_cpu(env));
|
||||
}
|
||||
env->satp = val;
|
||||
@ -1105,7 +1106,8 @@ static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
|
||||
|
||||
static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val)
|
||||
{
|
||||
env->vsstatus = val;
|
||||
uint64_t mask = (target_ulong)-1;
|
||||
env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,10 @@ target_ulong fclass_d(uint64_t frs1);
|
||||
#define SEW32 2
|
||||
#define SEW64 3
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
extern const VMStateDescription vmstate_riscv_cpu;
|
||||
#endif
|
||||
|
||||
static inline uint64_t nanbox_s(float32 f)
|
||||
{
|
||||
return f | MAKE_64BIT_MASK(32, 32);
|
||||
|
196
target/riscv/machine.c
Normal file
196
target/riscv/machine.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* RISC-V VMState Description
|
||||
*
|
||||
* Copyright (c) 2020 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/cpu.h"
|
||||
|
||||
static bool pmp_needed(void *opaque)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
return riscv_feature(env, RISCV_FEATURE_PMP);
|
||||
}
|
||||
|
||||
static int pmp_post_load(void *opaque, int version_id)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_RISCV_PMPS; i++) {
|
||||
pmp_update_rule_addr(env, i);
|
||||
}
|
||||
pmp_update_rule_nums(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pmp_entry = {
|
||||
.name = "cpu/pmp/entry",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINTTL(addr_reg, pmp_entry_t),
|
||||
VMSTATE_UINT8(cfg_reg, pmp_entry_t),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_pmp = {
|
||||
.name = "cpu/pmp",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = pmp_needed,
|
||||
.post_load = pmp_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_ARRAY(env.pmp_state.pmp, RISCVCPU, MAX_RISCV_PMPS,
|
||||
0, vmstate_pmp_entry, pmp_entry_t),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static bool hyper_needed(void *opaque)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
return riscv_has_ext(env, RVH);
|
||||
}
|
||||
|
||||
static bool vector_needed(void *opaque)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
return riscv_has_ext(env, RVV);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_vector = {
|
||||
.name = "cpu/vector",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = vector_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64_ARRAY(env.vreg, RISCVCPU, 32 * RV_VLEN_MAX / 64),
|
||||
VMSTATE_UINTTL(env.vxrm, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vxsat, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vl, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vstart, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vtype, RISCVCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_hyper = {
|
||||
.name = "cpu/hyper",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = hyper_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINTTL(env.hstatus, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.hideleg, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.htval, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.htinst, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.hgatp, RISCVCPU),
|
||||
VMSTATE_UINT64(env.htimedelta, RISCVCPU),
|
||||
|
||||
VMSTATE_UINT64(env.vsstatus, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vstvec, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vsepc, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vscause, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vstval, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vsatp, RISCVCPU),
|
||||
|
||||
VMSTATE_UINTTL(env.mtval2, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mtinst, RISCVCPU),
|
||||
|
||||
VMSTATE_UINTTL(env.stvec_hs, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.sscratch_hs, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.sepc_hs, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.scause_hs, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.stval_hs, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.satp_hs, RISCVCPU),
|
||||
VMSTATE_UINT64(env.mstatus_hs, RISCVCPU),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
const VMStateDescription vmstate_riscv_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
|
||||
VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
|
||||
VMSTATE_UINTTL(env.pc, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.load_res, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.load_val, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.frm, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.badaddr, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.guest_phys_fault_addr, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.priv_ver, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vext_ver, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.misa, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.misa_mask, RISCVCPU),
|
||||
VMSTATE_UINT32(env.features, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.priv, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.virt, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.resetvec, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mhartid, RISCVCPU),
|
||||
VMSTATE_UINT64(env.mstatus, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mip, RISCVCPU),
|
||||
VMSTATE_UINT32(env.miclaim, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mie, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mideleg, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.sptbr, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.satp, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mbadaddr, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.medeleg, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.stvec, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.sepc, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.scause, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mtvec, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mepc, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mcause, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mtval, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.scounteren, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.sscratch, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.mscratch, RISCVCPU),
|
||||
VMSTATE_UINT64(env.mfromhost, RISCVCPU),
|
||||
VMSTATE_UINT64(env.mtohost, RISCVCPU),
|
||||
VMSTATE_UINT64(env.timecmp, RISCVCPU),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription * []) {
|
||||
&vmstate_pmp,
|
||||
&vmstate_hyper,
|
||||
&vmstate_vector,
|
||||
NULL
|
||||
}
|
||||
};
|
@ -27,7 +27,8 @@ riscv_ss.add(files(
|
||||
riscv_softmmu_ss = ss.source_set()
|
||||
riscv_softmmu_ss.add(files(
|
||||
'pmp.c',
|
||||
'monitor.c'
|
||||
'monitor.c',
|
||||
'machine.c'
|
||||
))
|
||||
|
||||
target_arch += {'riscv': riscv_ss}
|
||||
|
@ -78,7 +78,8 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
|
||||
|
||||
target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
{
|
||||
target_ulong prev_priv, prev_virt, mstatus;
|
||||
uint64_t mstatus;
|
||||
target_ulong prev_priv, prev_virt;
|
||||
|
||||
if (!(env->priv >= PRV_S)) {
|
||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
||||
@ -147,18 +148,14 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
|
||||
}
|
||||
|
||||
target_ulong mstatus = env->mstatus;
|
||||
uint64_t mstatus = env->mstatus;
|
||||
target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
|
||||
target_ulong prev_virt = MSTATUS_MPV_ISSET(env);
|
||||
target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV);
|
||||
mstatus = set_field(mstatus, MSTATUS_MIE,
|
||||
get_field(mstatus, MSTATUS_MPIE));
|
||||
mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
|
||||
mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
|
||||
#ifdef TARGET_RISCV32
|
||||
env->mstatush = set_field(env->mstatush, MSTATUS_MPV, 0);
|
||||
#else
|
||||
mstatus = set_field(mstatus, MSTATUS_MPV, 0);
|
||||
#endif
|
||||
env->mstatus = mstatus;
|
||||
riscv_cpu_set_mode(env, prev_priv);
|
||||
|
||||
|
@ -136,18 +136,8 @@ static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert cfg/addr reg values here into simple 'sa' --> start address and 'ea'
|
||||
* end address values.
|
||||
* This function is called relatively infrequently whereas the check that
|
||||
* an address is within a pmp rule is called often, so optimise that one
|
||||
*/
|
||||
static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index)
|
||||
void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
|
||||
{
|
||||
int i;
|
||||
|
||||
env->pmp_state.num_rules = 0;
|
||||
|
||||
uint8_t this_cfg = env->pmp_state.pmp[pmp_index].cfg_reg;
|
||||
target_ulong this_addr = env->pmp_state.pmp[pmp_index].addr_reg;
|
||||
target_ulong prev_addr = 0u;
|
||||
@ -186,7 +176,13 @@ static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index)
|
||||
|
||||
env->pmp_state.addr[pmp_index].sa = sa;
|
||||
env->pmp_state.addr[pmp_index].ea = ea;
|
||||
}
|
||||
|
||||
void pmp_update_rule_nums(CPURISCVState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
env->pmp_state.num_rules = 0;
|
||||
for (i = 0; i < MAX_RISCV_PMPS; i++) {
|
||||
const uint8_t a_field =
|
||||
pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
|
||||
@ -196,6 +192,17 @@ static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index)
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert cfg/addr reg values here into simple 'sa' --> start address and 'ea'
|
||||
* end address values.
|
||||
* This function is called relatively infrequently whereas the check that
|
||||
* an address is within a pmp rule is called often, so optimise that one
|
||||
*/
|
||||
static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index)
|
||||
{
|
||||
pmp_update_rule_addr(env, pmp_index);
|
||||
pmp_update_rule_nums(env);
|
||||
}
|
||||
|
||||
static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr)
|
||||
{
|
||||
int result = 0;
|
||||
|
@ -62,5 +62,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
||||
target_ulong size, pmp_priv_t priv, target_ulong mode);
|
||||
bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
|
||||
target_ulong *tlb_size);
|
||||
void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
|
||||
void pmp_update_rule_nums(CPURISCVState *env);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user