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:
Peter Maydell 2020-11-03 16:53:20 +00:00
commit 9167d34921
27 changed files with 1180 additions and 127 deletions

View File

@ -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
-----------

View File

@ -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 = {

View File

@ -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
View 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
View 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)

View 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)

View File

@ -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'))

View File

@ -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

View File

@ -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 = {

View File

@ -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)

View File

@ -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,

View File

@ -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;

View 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 */

View 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 */

View 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 */

View File

@ -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 {

View File

@ -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),

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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
View 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
}
};

View File

@ -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}

View File

@ -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);

View File

@ -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;

View File

@ -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