RISC-V Patches for the 4.2 Soft Freeze, Part 1, v3
This contains quite a few patches that I'd like to target for 4.2. They're mostly emulation fixes for the sifive_u board, which now much more closely matches the hardware and can therefor run the same fireware as what gets loaded onto the board. Additional user-visible improvements include: * support for loading initrd files from the command line into Linux, via /chosen/linux,initrd-{start,end} device tree nodes. * The conversion of LOG_TRACE to trace events. * The addition of clock DT nodes for our uart and ethernet. This also includes some preliminary work for the H extension patches, but does not include the H extension patches as I haven't had time to review them yet. This passes my OE boot test on 32-bit and 64-bit virt machines, as well as a 64-bit upstream Linux boot on the sifive_u machine. It has been fixed to actually pass "make check" this time. Changes since v2 (never made it to the list): * Sets the sifive_u machine default core count to 2 instead of 5. Changes since v1 <20190910190513.21160-1-palmer@sifive.com>: * Sets the sifive_u machine default core count to 5 instead of 1, as it's impossible to have a single core sifive_u machine. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEAM520YNJYN/OiG3470yhUCzLq0EFAl2A/yITHHBhbG1lckBk YWJiZWx0LmNvbQAKCRDvTKFQLMurQTr/D/9HUJ7GKIrZ5j++RO47fy/IkJtv3Irb leOCGQdNBlyqiq9bPIQpcCprhpTDr7s0YyPzzztxWxAfpN3Pku2YgYhkOwiwCDPU 5M55Zu8ppEBmU4Zh9p7A7ARbKEymBJ2ZwFxoKgXQ6bCzlmFdyHiA5tTfAxGEyRhB lt3u472DWMnfNakJp13CyLOM1FTDD6LyT8PDjpefCoWZWDU8gC2ALQHRLkdYeRYE XM4XXSvud+DkRjI0Lh5gG8gmFpkk5/ekSb914Ry9G1MhSgkKPzoh/DtIhqtkHClT yRDl4ZW7P6AqKJcwVAgZXyCK/kFpSqDyw2cgysozWvklH6bKnTobkJYB5iLlQ9HW O6R4DmXpJj9SFLV+bbDSzlGw0cl2meDCIl2t9FJj3Y9etNWaX5kgZ8Aqc6ehiYKa N0FU0VbVqqyfwXUyZOU8N160YDnLyPiKnAK7AkCt8CJxWodyFmoHvZcEsHGZOlv3 5gnsDUPA/+FGsN5mu9SkmG3UE6rGedxJ2PIpyvwqzb1bjOtxBY/5WK7Kr2EjaBX8 iVod4bzKCqnEWabmZKzxpd3VcWCyoEtlzfe6Xuy5hL0MX6OC3I8S49/BBLnm9qcl PeKk01WTOgOX6GfudY0Lt+gILMMJ3IQF91/jmmA2H3LN8pyMKYcx7NSb7hPYNz0U bF3fUnZF2nyeHQ== =yDSj -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-4.2-sf1-v3' into staging RISC-V Patches for the 4.2 Soft Freeze, Part 1, v3 This contains quite a few patches that I'd like to target for 4.2. They're mostly emulation fixes for the sifive_u board, which now much more closely matches the hardware and can therefor run the same fireware as what gets loaded onto the board. Additional user-visible improvements include: * support for loading initrd files from the command line into Linux, via /chosen/linux,initrd-{start,end} device tree nodes. * The conversion of LOG_TRACE to trace events. * The addition of clock DT nodes for our uart and ethernet. This also includes some preliminary work for the H extension patches, but does not include the H extension patches as I haven't had time to review them yet. This passes my OE boot test on 32-bit and 64-bit virt machines, as well as a 64-bit upstream Linux boot on the sifive_u machine. It has been fixed to actually pass "make check" this time. Changes since v2 (never made it to the list): * Sets the sifive_u machine default core count to 2 instead of 5. Changes since v1 <20190910190513.21160-1-palmer@sifive.com>: * Sets the sifive_u machine default core count to 5 instead of 1, as it's impossible to have a single core sifive_u machine. # gpg: Signature made Tue 17 Sep 2019 16:43:30 BST # gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41 # gpg: issuer "palmer@dabbelt.com" # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown] # gpg: aka "Palmer Dabbelt <palmer@sifive.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 * remotes/palmer/tags/riscv-for-master-4.2-sf1-v3: (48 commits) gdbstub: riscv: fix the fflags registers target/riscv: Use TB_FLAGS_MSTATUS_FS for floating point target/riscv: Fix mstatus dirty mask target/riscv: Use both register name and ABI name riscv: sifive_u: Update model and compatible strings in device tree riscv: sifive_u: Remove handcrafted clock nodes for UART and ethernet riscv: sifive_u: Fix broken GEM support riscv: sifive_u: Instantiate OTP memory with a serial number riscv: sifive: Implement a model for SiFive FU540 OTP riscv: roms: Update default bios for sifive_u machine riscv: sifive_u: Change UART node name in device tree riscv: sifive_u: Update UART base addresses and IRQs riscv: sifive_u: Reference PRCI clocks in UART and ethernet nodes riscv: sifive_u: Add PRCI block to the SoC riscv: sifive_u: Generate hfclk and rtcclk nodes riscv: sifive: Implement PRCI model for FU540 riscv: sifive_u: Update PLIC hart topology configuration string riscv: sifive_u: Update hart configuration to reflect the real FU540 SoC riscv: sifive_u: Set the minimum number of cpus to 2 riscv: hart: Add a "hartid-base" property to RISC-V hart array ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7cc0cdcd6a
|
@ -249,7 +249,7 @@ STEXI
|
|||
Show virtual to physical memory mappings.
|
||||
ETEXI
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#if defined(TARGET_I386) || defined(TARGET_RISCV)
|
||||
{
|
||||
.name = "mem",
|
||||
.args_type = "",
|
||||
|
|
|
@ -12,12 +12,14 @@ config SIFIVE_E
|
|||
bool
|
||||
select HART
|
||||
select SIFIVE
|
||||
select UNIMP
|
||||
|
||||
config SIFIVE_U
|
||||
bool
|
||||
select CADENCE
|
||||
select HART
|
||||
select SIFIVE
|
||||
select UNIMP
|
||||
|
||||
config SPIKE
|
||||
bool
|
||||
|
|
|
@ -2,12 +2,14 @@ obj-y += boot.o
|
|||
obj-$(CONFIG_SPIKE) += riscv_htif.o
|
||||
obj-$(CONFIG_HART) += riscv_hart.o
|
||||
obj-$(CONFIG_SIFIVE_E) += sifive_e.o
|
||||
obj-$(CONFIG_SIFIVE_E) += sifive_e_prci.o
|
||||
obj-$(CONFIG_SIFIVE) += sifive_clint.o
|
||||
obj-$(CONFIG_SIFIVE) += sifive_gpio.o
|
||||
obj-$(CONFIG_SIFIVE) += sifive_prci.o
|
||||
obj-$(CONFIG_SIFIVE) += sifive_plic.o
|
||||
obj-$(CONFIG_SIFIVE) += sifive_test.o
|
||||
obj-$(CONFIG_SIFIVE_U) += sifive_u.o
|
||||
obj-$(CONFIG_SIFIVE_U) += sifive_u_otp.o
|
||||
obj-$(CONFIG_SIFIVE_U) += sifive_u_prci.o
|
||||
obj-$(CONFIG_SIFIVE) += sifive_uart.o
|
||||
obj-$(CONFIG_SPIKE) += spike.o
|
||||
obj-$(CONFIG_RISCV_VIRT) += virt.o
|
||||
|
|
|
@ -69,27 +69,35 @@ void riscv_find_and_load_firmware(MachineState *machine,
|
|||
* so then in the future we can make "-bios default" the default option
|
||||
* if no -bios option is set without breaking anything.
|
||||
*/
|
||||
firmware_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
|
||||
default_machine_firmware);
|
||||
if (firmware_filename == NULL) {
|
||||
error_report("Unable to load the default RISC-V firmware \"%s\"",
|
||||
default_machine_firmware);
|
||||
exit(1);
|
||||
}
|
||||
firmware_filename = riscv_find_firmware(default_machine_firmware);
|
||||
} else {
|
||||
firmware_filename = machine->firmware;
|
||||
if (strcmp(firmware_filename, "none")) {
|
||||
firmware_filename = riscv_find_firmware(firmware_filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(firmware_filename, "none")) {
|
||||
/* If not "none" load the firmware */
|
||||
riscv_load_firmware(firmware_filename, firmware_load_addr);
|
||||
}
|
||||
|
||||
if (!strcmp(machine->firmware, "default")) {
|
||||
g_free(firmware_filename);
|
||||
}
|
||||
}
|
||||
|
||||
char *riscv_find_firmware(const char *firmware_filename)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename);
|
||||
if (filename == NULL) {
|
||||
error_report("Unable to load the RISC-V firmware \"%s\"",
|
||||
firmware_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
target_ulong riscv_load_firmware(const char *firmware_filename,
|
||||
hwaddr firmware_load_addr)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2017 SiFive, Inc.
|
||||
*
|
||||
* Holds the state of a heterogenous array of RISC-V harts
|
||||
* Holds the state of a homogeneous array of RISC-V harts
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -29,6 +29,7 @@
|
|||
|
||||
static Property riscv_harts_props[] = {
|
||||
DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1),
|
||||
DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0),
|
||||
DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
@ -39,26 +40,33 @@ static void riscv_harts_cpu_reset(void *opaque)
|
|||
cpu_reset(CPU(cpu));
|
||||
}
|
||||
|
||||
static void riscv_hart_realize(RISCVHartArrayState *s, int idx,
|
||||
char *cpu_type, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
||||
object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx],
|
||||
sizeof(RISCVCPU), cpu_type,
|
||||
&error_abort, NULL);
|
||||
s->harts[idx].env.mhartid = s->hartid_base + idx;
|
||||
qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
|
||||
object_property_set_bool(OBJECT(&s->harts[idx]), true,
|
||||
"realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void riscv_harts_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
RISCVHartArrayState *s = RISCV_HART_ARRAY(dev);
|
||||
Error *err = NULL;
|
||||
int n;
|
||||
|
||||
s->harts = g_new0(RISCVCPU, s->num_harts);
|
||||
|
||||
for (n = 0; n < s->num_harts; n++) {
|
||||
object_initialize_child(OBJECT(s), "harts[*]", &s->harts[n],
|
||||
sizeof(RISCVCPU), s->cpu_type,
|
||||
&error_abort, NULL);
|
||||
s->harts[n].env.mhartid = n;
|
||||
qemu_register_reset(riscv_harts_cpu_reset, &s->harts[n]);
|
||||
object_property_set_bool(OBJECT(&s->harts[n]), true,
|
||||
"realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
riscv_hart_realize(s, n, s->cpu_type, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,13 +36,14 @@
|
|||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/sifive_plic.h"
|
||||
#include "hw/riscv/sifive_clint.h"
|
||||
#include "hw/riscv/sifive_prci.h"
|
||||
#include "hw/riscv/sifive_uart.h"
|
||||
#include "hw/riscv/sifive_e.h"
|
||||
#include "hw/riscv/sifive_e_prci.h"
|
||||
#include "hw/riscv/boot.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
|
@ -74,14 +75,6 @@ static const struct MemmapEntry {
|
|||
[SIFIVE_E_DTIM] = { 0x80000000, 0x4000 }
|
||||
};
|
||||
|
||||
static void sifive_mmio_emulate(MemoryRegion *parent, const char *name,
|
||||
uintptr_t offset, uintptr_t length)
|
||||
{
|
||||
MemoryRegion *mock_mmio = g_new(MemoryRegion, 1);
|
||||
memory_region_init_ram(mock_mmio, NULL, name, length, &error_fatal);
|
||||
memory_region_add_subregion(parent, offset, mock_mmio);
|
||||
}
|
||||
|
||||
static void riscv_sifive_e_init(MachineState *machine)
|
||||
{
|
||||
const struct MemmapEntry *memmap = sifive_e_memmap;
|
||||
|
@ -172,9 +165,9 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
|
|||
sifive_clint_create(memmap[SIFIVE_E_CLINT].base,
|
||||
memmap[SIFIVE_E_CLINT].size, ms->smp.cpus,
|
||||
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.aon",
|
||||
create_unimplemented_device("riscv.sifive.e.aon",
|
||||
memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size);
|
||||
sifive_prci_create(memmap[SIFIVE_E_PRCI].base);
|
||||
sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base);
|
||||
|
||||
/* GPIO */
|
||||
|
||||
|
@ -199,19 +192,19 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART0].base,
|
||||
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ));
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi0",
|
||||
create_unimplemented_device("riscv.sifive.e.qspi0",
|
||||
memmap[SIFIVE_E_QSPI0].base, memmap[SIFIVE_E_QSPI0].size);
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0",
|
||||
create_unimplemented_device("riscv.sifive.e.pwm0",
|
||||
memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size);
|
||||
sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
|
||||
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART1_IRQ));
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1",
|
||||
create_unimplemented_device("riscv.sifive.e.qspi1",
|
||||
memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size);
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1",
|
||||
create_unimplemented_device("riscv.sifive.e.pwm1",
|
||||
memmap[SIFIVE_E_PWM1].base, memmap[SIFIVE_E_PWM1].size);
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi2",
|
||||
create_unimplemented_device("riscv.sifive.e.qspi2",
|
||||
memmap[SIFIVE_E_QSPI2].base, memmap[SIFIVE_E_QSPI2].size);
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm2",
|
||||
create_unimplemented_device("riscv.sifive.e.pwm2",
|
||||
memmap[SIFIVE_E_PWM2].base, memmap[SIFIVE_E_PWM2].size);
|
||||
|
||||
/* Flash memory */
|
||||
|
|
124
hw/riscv/sifive_e_prci.c
Normal file
124
hw/riscv/sifive_e_prci.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* QEMU SiFive E PRCI (Power, Reset, Clock, Interrupt)
|
||||
*
|
||||
* Copyright (c) 2017 SiFive, Inc.
|
||||
*
|
||||
* Simple model of the PRCI to emulate register reads made by the SDK BSP
|
||||
*
|
||||
* 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 "hw/sysbus.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/riscv/sifive_e_prci.h"
|
||||
|
||||
static uint64_t sifive_e_prci_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
SiFiveEPRCIState *s = opaque;
|
||||
switch (addr) {
|
||||
case SIFIVE_E_PRCI_HFROSCCFG:
|
||||
return s->hfrosccfg;
|
||||
case SIFIVE_E_PRCI_HFXOSCCFG:
|
||||
return s->hfxosccfg;
|
||||
case SIFIVE_E_PRCI_PLLCFG:
|
||||
return s->pllcfg;
|
||||
case SIFIVE_E_PRCI_PLLOUTDIV:
|
||||
return s->plloutdiv;
|
||||
}
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%x\n",
|
||||
__func__, (int)addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sifive_e_prci_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
SiFiveEPRCIState *s = opaque;
|
||||
switch (addr) {
|
||||
case SIFIVE_E_PRCI_HFROSCCFG:
|
||||
s->hfrosccfg = (uint32_t) val64;
|
||||
/* OSC stays ready */
|
||||
s->hfrosccfg |= SIFIVE_E_PRCI_HFROSCCFG_RDY;
|
||||
break;
|
||||
case SIFIVE_E_PRCI_HFXOSCCFG:
|
||||
s->hfxosccfg = (uint32_t) val64;
|
||||
/* OSC stays ready */
|
||||
s->hfxosccfg |= SIFIVE_E_PRCI_HFXOSCCFG_RDY;
|
||||
break;
|
||||
case SIFIVE_E_PRCI_PLLCFG:
|
||||
s->pllcfg = (uint32_t) val64;
|
||||
/* PLL stays locked */
|
||||
s->pllcfg |= SIFIVE_E_PRCI_PLLCFG_LOCK;
|
||||
break;
|
||||
case SIFIVE_E_PRCI_PLLOUTDIV:
|
||||
s->plloutdiv = (uint32_t) val64;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
|
||||
__func__, (int)addr, (int)val64);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_e_prci_ops = {
|
||||
.read = sifive_e_prci_read,
|
||||
.write = sifive_e_prci_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static void sifive_e_prci_init(Object *obj)
|
||||
{
|
||||
SiFiveEPRCIState *s = SIFIVE_E_PRCI(obj);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &sifive_e_prci_ops, s,
|
||||
TYPE_SIFIVE_E_PRCI, SIFIVE_E_PRCI_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
s->hfrosccfg = (SIFIVE_E_PRCI_HFROSCCFG_RDY | SIFIVE_E_PRCI_HFROSCCFG_EN);
|
||||
s->hfxosccfg = (SIFIVE_E_PRCI_HFXOSCCFG_RDY | SIFIVE_E_PRCI_HFXOSCCFG_EN);
|
||||
s->pllcfg = (SIFIVE_E_PRCI_PLLCFG_REFSEL | SIFIVE_E_PRCI_PLLCFG_BYPASS |
|
||||
SIFIVE_E_PRCI_PLLCFG_LOCK);
|
||||
s->plloutdiv = SIFIVE_E_PRCI_PLLOUTDIV_DIV1;
|
||||
}
|
||||
|
||||
static const TypeInfo sifive_e_prci_info = {
|
||||
.name = TYPE_SIFIVE_E_PRCI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SiFiveEPRCIState),
|
||||
.instance_init = sifive_e_prci_init,
|
||||
};
|
||||
|
||||
static void sifive_e_prci_register_types(void)
|
||||
{
|
||||
type_register_static(&sifive_e_prci_info);
|
||||
}
|
||||
|
||||
type_init(sifive_e_prci_register_types)
|
||||
|
||||
|
||||
/*
|
||||
* Create PRCI device.
|
||||
*/
|
||||
DeviceState *sifive_e_prci_create(hwaddr addr)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_E_PRCI);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
return dev;
|
||||
}
|
|
@ -162,18 +162,6 @@ static void sifive_plic_update(SiFivePLICState *plic)
|
|||
}
|
||||
}
|
||||
|
||||
void sifive_plic_raise_irq(SiFivePLICState *plic, uint32_t irq)
|
||||
{
|
||||
sifive_plic_set_pending(plic, irq, true);
|
||||
sifive_plic_update(plic);
|
||||
}
|
||||
|
||||
void sifive_plic_lower_irq(SiFivePLICState *plic, uint32_t irq)
|
||||
{
|
||||
sifive_plic_set_pending(plic, irq, false);
|
||||
sifive_plic_update(plic);
|
||||
}
|
||||
|
||||
static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid)
|
||||
{
|
||||
int i, j;
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* QEMU SiFive PRCI (Power, Reset, Clock, Interrupt)
|
||||
*
|
||||
* Copyright (c) 2017 SiFive, Inc.
|
||||
*
|
||||
* Simple model of the PRCI to emulate register reads made by the SDK BSP
|
||||
*
|
||||
* 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 "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/module.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/riscv/sifive_prci.h"
|
||||
|
||||
static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
SiFivePRCIState *s = opaque;
|
||||
switch (addr) {
|
||||
case SIFIVE_PRCI_HFROSCCFG:
|
||||
return s->hfrosccfg;
|
||||
case SIFIVE_PRCI_HFXOSCCFG:
|
||||
return s->hfxosccfg;
|
||||
case SIFIVE_PRCI_PLLCFG:
|
||||
return s->pllcfg;
|
||||
case SIFIVE_PRCI_PLLOUTDIV:
|
||||
return s->plloutdiv;
|
||||
}
|
||||
hw_error("%s: read: addr=0x%x\n", __func__, (int)addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sifive_prci_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
SiFivePRCIState *s = opaque;
|
||||
switch (addr) {
|
||||
case SIFIVE_PRCI_HFROSCCFG:
|
||||
s->hfrosccfg = (uint32_t) val64;
|
||||
/* OSC stays ready */
|
||||
s->hfrosccfg |= SIFIVE_PRCI_HFROSCCFG_RDY;
|
||||
break;
|
||||
case SIFIVE_PRCI_HFXOSCCFG:
|
||||
s->hfxosccfg = (uint32_t) val64;
|
||||
/* OSC stays ready */
|
||||
s->hfxosccfg |= SIFIVE_PRCI_HFXOSCCFG_RDY;
|
||||
break;
|
||||
case SIFIVE_PRCI_PLLCFG:
|
||||
s->pllcfg = (uint32_t) val64;
|
||||
/* PLL stays locked */
|
||||
s->pllcfg |= SIFIVE_PRCI_PLLCFG_LOCK;
|
||||
break;
|
||||
case SIFIVE_PRCI_PLLOUTDIV:
|
||||
s->plloutdiv = (uint32_t) val64;
|
||||
break;
|
||||
default:
|
||||
hw_error("%s: bad write: addr=0x%x v=0x%x\n",
|
||||
__func__, (int)addr, (int)val64);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_prci_ops = {
|
||||
.read = sifive_prci_read,
|
||||
.write = sifive_prci_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static void sifive_prci_init(Object *obj)
|
||||
{
|
||||
SiFivePRCIState *s = SIFIVE_PRCI(obj);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &sifive_prci_ops, s,
|
||||
TYPE_SIFIVE_PRCI, 0x8000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
s->hfrosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
|
||||
s->hfxosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
|
||||
s->pllcfg = (SIFIVE_PRCI_PLLCFG_REFSEL | SIFIVE_PRCI_PLLCFG_BYPASS |
|
||||
SIFIVE_PRCI_PLLCFG_LOCK);
|
||||
s->plloutdiv = SIFIVE_PRCI_PLLOUTDIV_DIV1;
|
||||
|
||||
}
|
||||
|
||||
static const TypeInfo sifive_prci_info = {
|
||||
.name = TYPE_SIFIVE_PRCI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SiFivePRCIState),
|
||||
.instance_init = sifive_prci_init,
|
||||
};
|
||||
|
||||
static void sifive_prci_register_types(void)
|
||||
{
|
||||
type_register_static(&sifive_prci_info);
|
||||
}
|
||||
|
||||
type_init(sifive_prci_register_types)
|
||||
|
||||
|
||||
/*
|
||||
* Create PRCI device.
|
||||
*/
|
||||
DeviceState *sifive_prci_create(hwaddr addr)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_PRCI);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
return dev;
|
||||
}
|
|
@ -19,10 +19,10 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/riscv/sifive_test.h"
|
||||
|
||||
|
@ -42,12 +42,15 @@ static void sifive_test_write(void *opaque, hwaddr addr,
|
|||
exit(code);
|
||||
case FINISHER_PASS:
|
||||
exit(0);
|
||||
case FINISHER_RESET:
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
hw_error("%s: write: addr=0x%x val=0x%016" PRIx64 "\n",
|
||||
__func__, (int)addr, val64);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: write: addr=0x%x val=0x%016" PRIx64 "\n",
|
||||
__func__, (int)addr, val64);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_test_ops = {
|
||||
|
|
|
@ -3,14 +3,19 @@
|
|||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2017 SiFive, Inc.
|
||||
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Provides a board compatible with the SiFive Freedom U SDK:
|
||||
*
|
||||
* 0) UART
|
||||
* 1) CLINT (Core Level Interruptor)
|
||||
* 2) PLIC (Platform Level Interrupt Controller)
|
||||
* 3) PRCI (Power, Reset, Clock, Interrupt)
|
||||
* 4) OTP (One-Time Programmable) memory with stored serial number
|
||||
* 5) GEM (Gigabit Ethernet Controller) and management block
|
||||
*
|
||||
* This board currently uses a hardcoded devicetree that indicates one hart.
|
||||
* This board currently generates devicetree dynamically that indicates at least
|
||||
* two harts and up to five harts.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -33,15 +38,17 @@
|
|||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/cpu/cluster.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/sifive_plic.h"
|
||||
#include "hw/riscv/sifive_clint.h"
|
||||
#include "hw/riscv/sifive_uart.h"
|
||||
#include "hw/riscv/sifive_prci.h"
|
||||
#include "hw/riscv/sifive_u.h"
|
||||
#include "hw/riscv/boot.h"
|
||||
#include "chardev/char.h"
|
||||
#include "net/eth.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@ -59,23 +66,29 @@ static const struct MemmapEntry {
|
|||
[SIFIVE_U_MROM] = { 0x1000, 0x11000 },
|
||||
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
|
||||
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
|
||||
[SIFIVE_U_UART0] = { 0x10013000, 0x1000 },
|
||||
[SIFIVE_U_UART1] = { 0x10023000, 0x1000 },
|
||||
[SIFIVE_U_PRCI] = { 0x10000000, 0x1000 },
|
||||
[SIFIVE_U_UART0] = { 0x10010000, 0x1000 },
|
||||
[SIFIVE_U_UART1] = { 0x10011000, 0x1000 },
|
||||
[SIFIVE_U_OTP] = { 0x10070000, 0x1000 },
|
||||
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
|
||||
[SIFIVE_U_GEM] = { 0x100900FC, 0x2000 },
|
||||
[SIFIVE_U_GEM] = { 0x10090000, 0x2000 },
|
||||
[SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 },
|
||||
};
|
||||
|
||||
#define OTP_SERIAL 1
|
||||
#define GEM_REVISION 0x10070109
|
||||
|
||||
static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
uint64_t mem_size, const char *cmdline)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
void *fdt;
|
||||
int cpu;
|
||||
uint32_t *cells;
|
||||
char *nodename;
|
||||
char ethclk_names[] = "pclk\0hclk\0tx_clk";
|
||||
uint32_t plic_phandle, ethclk_phandle, phandle = 1;
|
||||
char ethclk_names[] = "pclk\0hclk";
|
||||
uint32_t plic_phandle, prci_phandle, phandle = 1;
|
||||
uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
|
||||
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
|
@ -83,8 +96,9 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||
exit(1);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_string(fdt, "/", "model", "ucbbar,spike-bare,qemu");
|
||||
qemu_fdt_setprop_string(fdt, "/", "compatible", "ucbbar,spike-bare-dev");
|
||||
qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00");
|
||||
qemu_fdt_setprop_string(fdt, "/", "compatible",
|
||||
"sifive,hifive-unleashed-a00");
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
|
||||
|
||||
|
@ -94,6 +108,28 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
|
||||
|
||||
hfclk_phandle = phandle++;
|
||||
nodename = g_strdup_printf("/hfclk");
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", hfclk_phandle);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "clock-output-names", "hfclk");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_HFCLK_FREQ);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
|
||||
g_free(nodename);
|
||||
|
||||
rtcclk_phandle = phandle++;
|
||||
nodename = g_strdup_printf("/rtcclk");
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", rtcclk_phandle);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "clock-output-names", "rtcclk");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_RTCCLK_FREQ);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/memory@%lx",
|
||||
(long)memmap[SIFIVE_U_DRAM].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
|
@ -109,15 +145,21 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
||||
|
||||
for (cpu = s->soc.cpus.num_harts - 1; cpu >= 0; cpu--) {
|
||||
for (cpu = ms->smp.cpus - 1; cpu >= 0; cpu--) {
|
||||
int cpu_phandle = phandle++;
|
||||
nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
|
||||
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||
char *isa = riscv_isa_string(&s->soc.cpus.harts[cpu]);
|
||||
char *isa;
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_CLOCK_FREQ);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||
/* cpu 0 is the management hart that does not have mmu */
|
||||
if (cpu != 0) {
|
||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||
isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]);
|
||||
} else {
|
||||
isa = riscv_isa_string(&s->soc.e_cpus.harts[0]);
|
||||
}
|
||||
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
||||
qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
|
||||
|
@ -125,7 +167,6 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
|
||||
qemu_fdt_add_subnode(fdt, intc);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle);
|
||||
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
|
||||
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
|
||||
|
@ -134,8 +175,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||
g_free(nodename);
|
||||
}
|
||||
|
||||
cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4);
|
||||
for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) {
|
||||
cells = g_new0(uint32_t, ms->smp.cpus * 4);
|
||||
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
||||
nodename =
|
||||
g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||
uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
||||
|
@ -153,20 +194,41 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||
0x0, memmap[SIFIVE_U_CLINT].base,
|
||||
0x0, memmap[SIFIVE_U_CLINT].size);
|
||||
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
|
||||
cells, s->soc.cpus.num_harts * sizeof(uint32_t) * 4);
|
||||
cells, ms->smp.cpus * sizeof(uint32_t) * 4);
|
||||
g_free(cells);
|
||||
g_free(nodename);
|
||||
|
||||
prci_phandle = phandle++;
|
||||
nodename = g_strdup_printf("/soc/clock-controller@%lx",
|
||||
(long)memmap[SIFIVE_U_PRCI].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", prci_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x1);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
||||
hfclk_phandle, rtcclk_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[SIFIVE_U_PRCI].base,
|
||||
0x0, memmap[SIFIVE_U_PRCI].size);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible",
|
||||
"sifive,fu540-c000-prci");
|
||||
g_free(nodename);
|
||||
|
||||
plic_phandle = phandle++;
|
||||
cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4);
|
||||
for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) {
|
||||
cells = g_new0(uint32_t, ms->smp.cpus * 4 - 2);
|
||||
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
||||
nodename =
|
||||
g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||
uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
||||
cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
|
||||
cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
|
||||
cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
|
||||
cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
|
||||
/* cpu 0 is the management hart that does not have S-mode */
|
||||
if (cpu == 0) {
|
||||
cells[0] = cpu_to_be32(intc_phandle);
|
||||
cells[1] = cpu_to_be32(IRQ_M_EXT);
|
||||
} else {
|
||||
cells[cpu * 4 - 2] = cpu_to_be32(intc_phandle);
|
||||
cells[cpu * 4 - 1] = cpu_to_be32(IRQ_M_EXT);
|
||||
cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
|
||||
cells[cpu * 4 + 1] = cpu_to_be32(IRQ_S_EXT);
|
||||
}
|
||||
g_free(nodename);
|
||||
}
|
||||
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
|
||||
|
@ -176,73 +238,70 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
|
||||
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
|
||||
cells, s->soc.cpus.num_harts * sizeof(uint32_t) * 4);
|
||||
cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t));
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[SIFIVE_U_PLIC].base,
|
||||
0x0, memmap[SIFIVE_U_PLIC].size);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
|
||||
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
||||
g_free(cells);
|
||||
g_free(nodename);
|
||||
|
||||
ethclk_phandle = phandle++;
|
||||
nodename = g_strdup_printf("/soc/ethclk");
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_GEM_CLOCK_FREQ);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", ethclk_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", ethclk_phandle);
|
||||
ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
||||
g_free(nodename);
|
||||
|
||||
phy_phandle = phandle++;
|
||||
nodename = g_strdup_printf("/soc/ethernet@%lx",
|
||||
(long)memmap[SIFIVE_U_GEM].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "cdns,macb");
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible",
|
||||
"sifive,fu540-c000-gem");
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[SIFIVE_U_GEM].base,
|
||||
0x0, memmap[SIFIVE_U_GEM].size);
|
||||
0x0, memmap[SIFIVE_U_GEM].size,
|
||||
0x0, memmap[SIFIVE_U_GEM_MGMT].base,
|
||||
0x0, memmap[SIFIVE_U_GEM_MGMT].size);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
|
||||
qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii");
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phy-handle", phy_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
||||
ethclk_phandle, ethclk_phandle, ethclk_phandle);
|
||||
qemu_fdt_setprop(fdt, nodename, "clocks-names", ethclk_names,
|
||||
prci_phandle, PRCI_CLK_GEMGXLPLL, prci_phandle, PRCI_CLK_GEMGXLPLL);
|
||||
qemu_fdt_setprop(fdt, nodename, "clock-names", ethclk_names,
|
||||
sizeof(ethclk_names));
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 1);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0);
|
||||
qemu_fdt_setprop(fdt, nodename, "local-mac-address",
|
||||
s->soc.gem.conf.macaddr.a, ETH_ALEN);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0);
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/soc/ethernet@%lx/ethernet-phy@0",
|
||||
(long)memmap[SIFIVE_U_GEM].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", phy_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "reg", 0x0);
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/soc/uart@%lx",
|
||||
nodename = g_strdup_printf("/soc/serial@%lx",
|
||||
(long)memmap[SIFIVE_U_UART0].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,uart0");
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[SIFIVE_U_UART0].base,
|
||||
0x0, memmap[SIFIVE_U_UART0].size);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_CLOCK_FREQ / 2);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
||||
prci_phandle, PRCI_CLK_TLCLK);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ);
|
||||
|
||||
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_add_subnode(fdt, "/aliases");
|
||||
qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename);
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
|
@ -275,7 +334,18 @@ static void riscv_sifive_u_init(MachineState *machine)
|
|||
memmap[SIFIVE_U_DRAM].base);
|
||||
|
||||
if (machine->kernel_filename) {
|
||||
riscv_load_kernel(machine->kernel_filename);
|
||||
uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename);
|
||||
|
||||
if (machine->initrd_filename) {
|
||||
hwaddr start;
|
||||
hwaddr end = riscv_load_initrd(machine->initrd_filename,
|
||||
machine->ram_size, kernel_entry,
|
||||
&start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen",
|
||||
"linux,initrd-start", start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
|
||||
end);
|
||||
}
|
||||
}
|
||||
|
||||
/* reset vector */
|
||||
|
@ -319,13 +389,37 @@ static void riscv_sifive_u_soc_init(Object *obj)
|
|||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
SiFiveUSoCState *s = RISCV_U_SOC(obj);
|
||||
|
||||
object_initialize_child(obj, "cpus", &s->cpus, sizeof(s->cpus),
|
||||
TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
|
||||
object_property_set_str(OBJECT(&s->cpus), SIFIVE_U_CPU, "cpu-type",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts",
|
||||
&error_abort);
|
||||
object_initialize_child(obj, "e-cluster", &s->e_cluster,
|
||||
sizeof(s->e_cluster), TYPE_CPU_CLUSTER,
|
||||
&error_abort, NULL);
|
||||
qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0);
|
||||
|
||||
object_initialize_child(OBJECT(&s->e_cluster), "e-cpus",
|
||||
&s->e_cpus, sizeof(s->e_cpus),
|
||||
TYPE_RISCV_HART_ARRAY, &error_abort,
|
||||
NULL);
|
||||
qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1);
|
||||
qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0);
|
||||
qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU);
|
||||
|
||||
object_initialize_child(obj, "u-cluster", &s->u_cluster,
|
||||
sizeof(s->u_cluster), TYPE_CPU_CLUSTER,
|
||||
&error_abort, NULL);
|
||||
qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);
|
||||
|
||||
object_initialize_child(OBJECT(&s->u_cluster), "u-cpus",
|
||||
&s->u_cpus, sizeof(s->u_cpus),
|
||||
TYPE_RISCV_HART_ARRAY, &error_abort,
|
||||
NULL);
|
||||
qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1);
|
||||
qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1);
|
||||
qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU);
|
||||
|
||||
sysbus_init_child_obj(obj, "prci", &s->prci, sizeof(s->prci),
|
||||
TYPE_SIFIVE_U_PRCI);
|
||||
sysbus_init_child_obj(obj, "otp", &s->otp, sizeof(s->otp),
|
||||
TYPE_SIFIVE_U_OTP);
|
||||
qdev_prop_set_uint32(DEVICE(&s->otp), "serial", OTP_SERIAL);
|
||||
sysbus_init_child_obj(obj, "gem", &s->gem, sizeof(s->gem),
|
||||
TYPE_CADENCE_GEM);
|
||||
}
|
||||
|
@ -344,7 +438,19 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
|||
Error *err = NULL;
|
||||
NICInfo *nd = &nd_table[0];
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cpus), true, "realized",
|
||||
object_property_set_bool(OBJECT(&s->e_cpus), true, "realized",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->u_cpus), true, "realized",
|
||||
&error_abort);
|
||||
/*
|
||||
* The cluster must be realized after the RISC-V hart array container,
|
||||
* as the container's CPU object is only created on realize, and the
|
||||
* CPU must exist and have been parented into the cluster before the
|
||||
* cluster is realized.
|
||||
*/
|
||||
object_property_set_bool(OBJECT(&s->e_cluster), true, "realized",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->u_cluster), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
/* boot rom */
|
||||
|
@ -359,10 +465,11 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
|||
plic_hart_config = g_malloc0(plic_hart_config_len);
|
||||
for (i = 0; i < ms->smp.cpus; i++) {
|
||||
if (i != 0) {
|
||||
strncat(plic_hart_config, ",", plic_hart_config_len);
|
||||
strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG,
|
||||
plic_hart_config_len);
|
||||
} else {
|
||||
strncat(plic_hart_config, "M", plic_hart_config_len);
|
||||
}
|
||||
strncat(plic_hart_config, SIFIVE_U_PLIC_HART_CONFIG,
|
||||
plic_hart_config_len);
|
||||
plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
|
||||
}
|
||||
|
||||
|
@ -386,6 +493,12 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
|||
memmap[SIFIVE_U_CLINT].size, ms->smp.cpus,
|
||||
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->prci), true, "realized", &err);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->otp), true, "realized", &err);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);
|
||||
|
||||
for (i = 0; i < SIFIVE_U_PLIC_NUM_SOURCES; i++) {
|
||||
plic_gpios[i] = qdev_get_gpio_in(DEVICE(s->plic), i);
|
||||
}
|
||||
|
@ -404,16 +517,18 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0,
|
||||
plic_gpios[SIFIVE_U_GEM_IRQ]);
|
||||
|
||||
create_unimplemented_device("riscv.sifive.u.gem-mgmt",
|
||||
memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size);
|
||||
}
|
||||
|
||||
static void riscv_sifive_u_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "RISC-V Board compatible with SiFive U SDK";
|
||||
mc->init = riscv_sifive_u_init;
|
||||
/* The real hardware has 5 CPUs, but one of them is a small embedded power
|
||||
* management CPU.
|
||||
*/
|
||||
mc->max_cpus = 4;
|
||||
mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT;
|
||||
mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1;
|
||||
mc->default_cpus = mc->min_cpus;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("sifive_u", riscv_sifive_u_machine_init)
|
||||
|
|
191
hw/riscv/sifive_u_otp.c
Normal file
191
hw/riscv/sifive_u_otp.c
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* QEMU SiFive U OTP (One-Time Programmable) Memory interface
|
||||
*
|
||||
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Simple model of the OTP to emulate register reads made by the SDK BSP
|
||||
*
|
||||
* 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 "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/riscv/sifive_u_otp.h"
|
||||
|
||||
static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
SiFiveUOTPState *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case SIFIVE_U_OTP_PA:
|
||||
return s->pa;
|
||||
case SIFIVE_U_OTP_PAIO:
|
||||
return s->paio;
|
||||
case SIFIVE_U_OTP_PAS:
|
||||
return s->pas;
|
||||
case SIFIVE_U_OTP_PCE:
|
||||
return s->pce;
|
||||
case SIFIVE_U_OTP_PCLK:
|
||||
return s->pclk;
|
||||
case SIFIVE_U_OTP_PDIN:
|
||||
return s->pdin;
|
||||
case SIFIVE_U_OTP_PDOUT:
|
||||
if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
|
||||
(s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
|
||||
(s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {
|
||||
return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
|
||||
} else {
|
||||
return 0xff;
|
||||
}
|
||||
case SIFIVE_U_OTP_PDSTB:
|
||||
return s->pdstb;
|
||||
case SIFIVE_U_OTP_PPROG:
|
||||
return s->pprog;
|
||||
case SIFIVE_U_OTP_PTC:
|
||||
return s->ptc;
|
||||
case SIFIVE_U_OTP_PTM:
|
||||
return s->ptm;
|
||||
case SIFIVE_U_OTP_PTM_REP:
|
||||
return s->ptm_rep;
|
||||
case SIFIVE_U_OTP_PTR:
|
||||
return s->ptr;
|
||||
case SIFIVE_U_OTP_PTRIM:
|
||||
return s->ptrim;
|
||||
case SIFIVE_U_OTP_PWE:
|
||||
return s->pwe;
|
||||
}
|
||||
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sifive_u_otp_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
SiFiveUOTPState *s = opaque;
|
||||
uint32_t val32 = (uint32_t)val64;
|
||||
|
||||
switch (addr) {
|
||||
case SIFIVE_U_OTP_PA:
|
||||
s->pa = val32 & SIFIVE_U_OTP_PA_MASK;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PAIO:
|
||||
s->paio = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PAS:
|
||||
s->pas = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PCE:
|
||||
s->pce = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PCLK:
|
||||
s->pclk = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PDIN:
|
||||
s->pdin = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PDOUT:
|
||||
/* read-only */
|
||||
break;
|
||||
case SIFIVE_U_OTP_PDSTB:
|
||||
s->pdstb = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PPROG:
|
||||
s->pprog = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PTC:
|
||||
s->ptc = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PTM:
|
||||
s->ptm = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PTM_REP:
|
||||
s->ptm_rep = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PTR:
|
||||
s->ptr = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PTRIM:
|
||||
s->ptrim = val32;
|
||||
break;
|
||||
case SIFIVE_U_OTP_PWE:
|
||||
s->pwe = val32;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
|
||||
" v=0x%x\n", __func__, addr, val32);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_u_otp_ops = {
|
||||
.read = sifive_u_otp_read,
|
||||
.write = sifive_u_otp_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static Property sifive_u_otp_properties[] = {
|
||||
DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,
|
||||
TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
|
||||
}
|
||||
|
||||
static void sifive_u_otp_reset(DeviceState *dev)
|
||||
{
|
||||
SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
|
||||
|
||||
/* Initialize all fuses' initial value to 0xFFs */
|
||||
memset(s->fuse, 0xff, sizeof(s->fuse));
|
||||
|
||||
/* Make a valid content of serial number */
|
||||
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
|
||||
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);
|
||||
}
|
||||
|
||||
static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = sifive_u_otp_properties;
|
||||
dc->realize = sifive_u_otp_realize;
|
||||
dc->reset = sifive_u_otp_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo sifive_u_otp_info = {
|
||||
.name = TYPE_SIFIVE_U_OTP,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SiFiveUOTPState),
|
||||
.class_init = sifive_u_otp_class_init,
|
||||
};
|
||||
|
||||
static void sifive_u_otp_register_types(void)
|
||||
{
|
||||
type_register_static(&sifive_u_otp_info);
|
||||
}
|
||||
|
||||
type_init(sifive_u_otp_register_types)
|
169
hw/riscv/sifive_u_prci.c
Normal file
169
hw/riscv/sifive_u_prci.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt)
|
||||
*
|
||||
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Simple model of the PRCI to emulate register reads made by the SDK BSP
|
||||
*
|
||||
* 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 "hw/sysbus.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/riscv/sifive_u_prci.h"
|
||||
|
||||
static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
SiFiveUPRCIState *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case SIFIVE_U_PRCI_HFXOSCCFG:
|
||||
return s->hfxosccfg;
|
||||
case SIFIVE_U_PRCI_COREPLLCFG0:
|
||||
return s->corepllcfg0;
|
||||
case SIFIVE_U_PRCI_DDRPLLCFG0:
|
||||
return s->ddrpllcfg0;
|
||||
case SIFIVE_U_PRCI_DDRPLLCFG1:
|
||||
return s->ddrpllcfg1;
|
||||
case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
|
||||
return s->gemgxlpllcfg0;
|
||||
case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
|
||||
return s->gemgxlpllcfg1;
|
||||
case SIFIVE_U_PRCI_CORECLKSEL:
|
||||
return s->coreclksel;
|
||||
case SIFIVE_U_PRCI_DEVICESRESET:
|
||||
return s->devicesreset;
|
||||
case SIFIVE_U_PRCI_CLKMUXSTATUS:
|
||||
return s->clkmuxstatus;
|
||||
}
|
||||
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sifive_u_prci_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
SiFiveUPRCIState *s = opaque;
|
||||
uint32_t val32 = (uint32_t)val64;
|
||||
|
||||
switch (addr) {
|
||||
case SIFIVE_U_PRCI_HFXOSCCFG:
|
||||
s->hfxosccfg = val32;
|
||||
/* OSC stays ready */
|
||||
s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_COREPLLCFG0:
|
||||
s->corepllcfg0 = val32;
|
||||
/* internal feedback */
|
||||
s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
|
||||
/* PLL stays locked */
|
||||
s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_DDRPLLCFG0:
|
||||
s->ddrpllcfg0 = val32;
|
||||
/* internal feedback */
|
||||
s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
|
||||
/* PLL stays locked */
|
||||
s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_DDRPLLCFG1:
|
||||
s->ddrpllcfg1 = val32;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
|
||||
s->gemgxlpllcfg0 = val32;
|
||||
/* internal feedback */
|
||||
s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
|
||||
/* PLL stays locked */
|
||||
s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
|
||||
s->gemgxlpllcfg1 = val32;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_CORECLKSEL:
|
||||
s->coreclksel = val32;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_DEVICESRESET:
|
||||
s->devicesreset = val32;
|
||||
break;
|
||||
case SIFIVE_U_PRCI_CLKMUXSTATUS:
|
||||
s->clkmuxstatus = val32;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
|
||||
" v=0x%x\n", __func__, addr, val32);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_u_prci_ops = {
|
||||
.read = sifive_u_prci_read,
|
||||
.write = sifive_u_prci_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static void sifive_u_prci_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s,
|
||||
TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
|
||||
}
|
||||
|
||||
static void sifive_u_prci_reset(DeviceState *dev)
|
||||
{
|
||||
SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
|
||||
|
||||
/* Initialize register to power-on-reset values */
|
||||
s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN;
|
||||
s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
|
||||
SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
|
||||
SIFIVE_U_PRCI_PLLCFG0_LOCK;
|
||||
s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
|
||||
SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
|
||||
SIFIVE_U_PRCI_PLLCFG0_LOCK;
|
||||
s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
|
||||
SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
|
||||
SIFIVE_U_PRCI_PLLCFG0_LOCK;
|
||||
s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK;
|
||||
}
|
||||
|
||||
static void sifive_u_prci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = sifive_u_prci_realize;
|
||||
dc->reset = sifive_u_prci_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo sifive_u_prci_info = {
|
||||
.name = TYPE_SIFIVE_U_PRCI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SiFiveUPRCIState),
|
||||
.class_init = sifive_u_prci_class_init,
|
||||
};
|
||||
|
||||
static void sifive_u_prci_register_types(void)
|
||||
{
|
||||
type_register_static(&sifive_u_prci_info);
|
||||
}
|
||||
|
||||
type_init(sifive_u_prci_register_types)
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "chardev/char.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/riscv/sifive_uart.h"
|
||||
|
@ -95,8 +95,8 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
|
|||
return s->div;
|
||||
}
|
||||
|
||||
hw_error("%s: bad read: addr=0x%x\n",
|
||||
__func__, (int)addr);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
|
||||
__func__, (int)addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -127,8 +127,8 @@ uart_write(void *opaque, hwaddr addr,
|
|||
s->div = val64;
|
||||
return;
|
||||
}
|
||||
hw_error("%s: bad write: addr=0x%x v=0x%x\n",
|
||||
__func__, (int)addr, (int)value);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
|
||||
__func__, (int)addr, (int)value);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps uart_ops = {
|
||||
|
|
|
@ -112,7 +112,6 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
|
||||
qemu_fdt_add_subnode(fdt, intc);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "phandle", 1);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", 1);
|
||||
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
|
||||
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
|
||||
|
|
|
@ -112,7 +112,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
|
|||
0x1800, 0, 0, 0x7);
|
||||
}
|
||||
|
||||
static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
uint64_t mem_size, const char *cmdline)
|
||||
{
|
||||
void *fdt;
|
||||
|
@ -170,11 +170,9 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", cpu_phandle);
|
||||
intc_phandle = phandle++;
|
||||
qemu_fdt_add_subnode(fdt, intc);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", intc_phandle);
|
||||
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
|
||||
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
|
||||
|
@ -235,8 +233,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
|
||||
(long)memmap[VIRT_PLIC].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
|
||||
FDT_PLIC_ADDR_CELLS);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells",
|
||||
FDT_PLIC_ADDR_CELLS);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
|
||||
FDT_PLIC_INT_CELLS);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
|
||||
|
@ -246,11 +244,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[VIRT_PLIC].base,
|
||||
0x0, memmap[VIRT_PLIC].size);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", VIRTIO_NDEV);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
|
||||
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
||||
g_free(cells);
|
||||
g_free(nodename);
|
||||
|
@ -263,19 +258,19 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
|
||||
0x0, memmap[VIRT_VIRTIO].size);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", VIRTIO_IRQ + i);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", VIRTIO_IRQ + i);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
nodename = g_strdup_printf("/soc/pci@%lx",
|
||||
(long) memmap[VIRT_PCIE_ECAM].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
|
||||
FDT_PCI_ADDR_CELLS);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells",
|
||||
FDT_PCI_INT_CELLS);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells",
|
||||
FDT_PCI_ADDR_CELLS);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
|
||||
FDT_PCI_INT_CELLS);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0x2);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible",
|
||||
"pci-host-ecam-generic");
|
||||
qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
|
||||
|
@ -312,8 +307,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||
0x0, memmap[VIRT_UART0].base,
|
||||
0x0, memmap[VIRT_UART0].size);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 3686400);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", UART0_IRQ);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", UART0_IRQ);
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
|
||||
|
@ -321,8 +316,6 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
g_free(nodename);
|
||||
|
||||
return fdt;
|
||||
}
|
||||
|
||||
|
||||
|
@ -378,7 +371,6 @@ static void riscv_virt_board_init(MachineState *machine)
|
|||
size_t plic_hart_config_len;
|
||||
int i;
|
||||
unsigned int smp_cpus = machine->smp.cpus;
|
||||
void *fdt;
|
||||
|
||||
/* Initialize SOC */
|
||||
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
|
||||
|
@ -397,7 +389,7 @@ static void riscv_virt_board_init(MachineState *machine)
|
|||
main_mem);
|
||||
|
||||
/* create device tree */
|
||||
fdt = create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
||||
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
||||
|
||||
/* boot rom */
|
||||
memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom",
|
||||
|
@ -416,9 +408,9 @@ static void riscv_virt_board_init(MachineState *machine)
|
|||
hwaddr end = riscv_load_initrd(machine->initrd_filename,
|
||||
machine->ram_size, kernel_entry,
|
||||
&start);
|
||||
qemu_fdt_setprop_cell(fdt, "/chosen",
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen",
|
||||
"linux,initrd-start", start);
|
||||
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
|
||||
end);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
void riscv_find_and_load_firmware(MachineState *machine,
|
||||
const char *default_machine_firmware,
|
||||
hwaddr firmware_load_addr);
|
||||
char *riscv_find_firmware(const char *firmware_filename);
|
||||
target_ulong riscv_load_firmware(const char *firmware_filename,
|
||||
hwaddr firmware_load_addr);
|
||||
target_ulong riscv_load_kernel(const char *kernel_filename);
|
||||
|
|
|
@ -35,6 +35,7 @@ typedef struct RISCVHartArrayState {
|
|||
|
||||
/*< public >*/
|
||||
uint32_t num_harts;
|
||||
uint32_t hartid_base;
|
||||
char *cpu_type;
|
||||
RISCVCPU *harts;
|
||||
} RISCVHartArrayState;
|
||||
|
|
31
include/hw/riscv/sifive_cpu.h
Normal file
31
include/hw/riscv/sifive_cpu.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* SiFive CPU types
|
||||
*
|
||||
* Copyright (c) 2017 SiFive, Inc.
|
||||
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_SIFIVE_CPU_H
|
||||
#define HW_SIFIVE_CPU_H
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E31
|
||||
#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U34
|
||||
#elif defined(TARGET_RISCV64)
|
||||
#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E51
|
||||
#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U54
|
||||
#endif
|
||||
|
||||
#endif /* HW_SIFIVE_CPU_H */
|
|
@ -20,6 +20,7 @@
|
|||
#define HW_SIFIVE_E_H
|
||||
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/sifive_cpu.h"
|
||||
#include "hw/riscv/sifive_gpio.h"
|
||||
|
||||
#define TYPE_RISCV_E_SOC "riscv.sifive.e.soc"
|
||||
|
@ -84,10 +85,4 @@ enum {
|
|||
#define SIFIVE_E_PLIC_CONTEXT_BASE 0x200000
|
||||
#define SIFIVE_E_PLIC_CONTEXT_STRIDE 0x1000
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E31
|
||||
#elif defined(TARGET_RISCV64)
|
||||
#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E51
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
71
include/hw/riscv/sifive_e_prci.h
Normal file
71
include/hw/riscv/sifive_e_prci.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* QEMU SiFive E PRCI (Power, Reset, Clock, Interrupt) interface
|
||||
*
|
||||
* Copyright (c) 2017 SiFive, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_SIFIVE_E_PRCI_H
|
||||
#define HW_SIFIVE_E_PRCI_H
|
||||
|
||||
enum {
|
||||
SIFIVE_E_PRCI_HFROSCCFG = 0x0,
|
||||
SIFIVE_E_PRCI_HFXOSCCFG = 0x4,
|
||||
SIFIVE_E_PRCI_PLLCFG = 0x8,
|
||||
SIFIVE_E_PRCI_PLLOUTDIV = 0xC
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_E_PRCI_HFROSCCFG_RDY = (1 << 31),
|
||||
SIFIVE_E_PRCI_HFROSCCFG_EN = (1 << 30)
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_E_PRCI_HFXOSCCFG_RDY = (1 << 31),
|
||||
SIFIVE_E_PRCI_HFXOSCCFG_EN = (1 << 30)
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_E_PRCI_PLLCFG_PLLSEL = (1 << 16),
|
||||
SIFIVE_E_PRCI_PLLCFG_REFSEL = (1 << 17),
|
||||
SIFIVE_E_PRCI_PLLCFG_BYPASS = (1 << 18),
|
||||
SIFIVE_E_PRCI_PLLCFG_LOCK = (1 << 31)
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_E_PRCI_PLLOUTDIV_DIV1 = (1 << 8)
|
||||
};
|
||||
|
||||
#define SIFIVE_E_PRCI_REG_SIZE 0x1000
|
||||
|
||||
#define TYPE_SIFIVE_E_PRCI "riscv.sifive.e.prci"
|
||||
|
||||
#define SIFIVE_E_PRCI(obj) \
|
||||
OBJECT_CHECK(SiFiveEPRCIState, (obj), TYPE_SIFIVE_E_PRCI)
|
||||
|
||||
typedef struct SiFiveEPRCIState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion mmio;
|
||||
uint32_t hfrosccfg;
|
||||
uint32_t hfxosccfg;
|
||||
uint32_t pllcfg;
|
||||
uint32_t plloutdiv;
|
||||
} SiFiveEPRCIState;
|
||||
|
||||
DeviceState *sifive_e_prci_create(hwaddr addr);
|
||||
|
||||
#endif
|
|
@ -69,9 +69,6 @@ typedef struct SiFivePLICState {
|
|||
uint32_t aperture_size;
|
||||
} SiFivePLICState;
|
||||
|
||||
void sifive_plic_raise_irq(SiFivePLICState *plic, uint32_t irq);
|
||||
void sifive_plic_lower_irq(SiFivePLICState *plic, uint32_t irq);
|
||||
|
||||
DeviceState *sifive_plic_create(hwaddr addr, char *hart_config,
|
||||
uint32_t num_sources, uint32_t num_priorities,
|
||||
uint32_t priority_base, uint32_t pending_base,
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* QEMU SiFive PRCI (Power, Reset, Clock, Interrupt) interface
|
||||
*
|
||||
* Copyright (c) 2017 SiFive, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_SIFIVE_PRCI_H
|
||||
#define HW_SIFIVE_PRCI_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
enum {
|
||||
SIFIVE_PRCI_HFROSCCFG = 0x0,
|
||||
SIFIVE_PRCI_HFXOSCCFG = 0x4,
|
||||
SIFIVE_PRCI_PLLCFG = 0x8,
|
||||
SIFIVE_PRCI_PLLOUTDIV = 0xC
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_PRCI_HFROSCCFG_RDY = (1 << 31),
|
||||
SIFIVE_PRCI_HFROSCCFG_EN = (1 << 30)
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_PRCI_HFXOSCCFG_RDY = (1 << 31),
|
||||
SIFIVE_PRCI_HFXOSCCFG_EN = (1 << 30)
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_PRCI_PLLCFG_PLLSEL = (1 << 16),
|
||||
SIFIVE_PRCI_PLLCFG_REFSEL = (1 << 17),
|
||||
SIFIVE_PRCI_PLLCFG_BYPASS = (1 << 18),
|
||||
SIFIVE_PRCI_PLLCFG_LOCK = (1 << 31)
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_PRCI_PLLOUTDIV_DIV1 = (1 << 8)
|
||||
};
|
||||
|
||||
#define TYPE_SIFIVE_PRCI "riscv.sifive.prci"
|
||||
|
||||
#define SIFIVE_PRCI(obj) \
|
||||
OBJECT_CHECK(SiFivePRCIState, (obj), TYPE_SIFIVE_PRCI)
|
||||
|
||||
typedef struct SiFivePRCIState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion mmio;
|
||||
uint32_t hfrosccfg;
|
||||
uint32_t hfxosccfg;
|
||||
uint32_t pllcfg;
|
||||
uint32_t plloutdiv;
|
||||
} SiFivePRCIState;
|
||||
|
||||
DeviceState *sifive_prci_create(hwaddr addr);
|
||||
|
||||
#endif
|
|
@ -36,7 +36,8 @@ typedef struct SiFiveTestState {
|
|||
|
||||
enum {
|
||||
FINISHER_FAIL = 0x3333,
|
||||
FINISHER_PASS = 0x5555
|
||||
FINISHER_PASS = 0x5555,
|
||||
FINISHER_RESET = 0x7777
|
||||
};
|
||||
|
||||
DeviceState *sifive_test_create(hwaddr addr);
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
#include "hw/net/cadence_gem.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/sifive_cpu.h"
|
||||
#include "hw/riscv/sifive_u_prci.h"
|
||||
#include "hw/riscv/sifive_u_otp.h"
|
||||
|
||||
#define TYPE_RISCV_U_SOC "riscv.sifive.u.soc"
|
||||
#define RISCV_U_SOC(obj) \
|
||||
|
@ -31,8 +34,13 @@ typedef struct SiFiveUSoCState {
|
|||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
RISCVHartArrayState cpus;
|
||||
CPUClusterState e_cluster;
|
||||
CPUClusterState u_cluster;
|
||||
RISCVHartArrayState e_cpus;
|
||||
RISCVHartArrayState u_cpus;
|
||||
DeviceState *plic;
|
||||
SiFiveUPRCIState prci;
|
||||
SiFiveUOTPState otp;
|
||||
CadenceGEMState gem;
|
||||
} SiFiveUSoCState;
|
||||
|
||||
|
@ -51,23 +59,30 @@ enum {
|
|||
SIFIVE_U_MROM,
|
||||
SIFIVE_U_CLINT,
|
||||
SIFIVE_U_PLIC,
|
||||
SIFIVE_U_PRCI,
|
||||
SIFIVE_U_UART0,
|
||||
SIFIVE_U_UART1,
|
||||
SIFIVE_U_OTP,
|
||||
SIFIVE_U_DRAM,
|
||||
SIFIVE_U_GEM
|
||||
SIFIVE_U_GEM,
|
||||
SIFIVE_U_GEM_MGMT
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_U_UART0_IRQ = 3,
|
||||
SIFIVE_U_UART1_IRQ = 4,
|
||||
SIFIVE_U_UART0_IRQ = 4,
|
||||
SIFIVE_U_UART1_IRQ = 5,
|
||||
SIFIVE_U_GEM_IRQ = 0x35
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_U_CLOCK_FREQ = 1000000000,
|
||||
SIFIVE_U_GEM_CLOCK_FREQ = 125000000
|
||||
SIFIVE_U_HFCLK_FREQ = 33333333,
|
||||
SIFIVE_U_RTCCLK_FREQ = 1000000
|
||||
};
|
||||
|
||||
#define SIFIVE_U_MANAGEMENT_CPU_COUNT 1
|
||||
#define SIFIVE_U_COMPUTE_CPU_COUNT 4
|
||||
|
||||
#define SIFIVE_U_PLIC_HART_CONFIG "MS"
|
||||
#define SIFIVE_U_PLIC_NUM_SOURCES 54
|
||||
#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
|
||||
|
@ -78,10 +93,4 @@ enum {
|
|||
#define SIFIVE_U_PLIC_CONTEXT_BASE 0x200000
|
||||
#define SIFIVE_U_PLIC_CONTEXT_STRIDE 0x1000
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U34
|
||||
#elif defined(TARGET_RISCV64)
|
||||
#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U54
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
80
include/hw/riscv/sifive_u_otp.h
Normal file
80
include/hw/riscv/sifive_u_otp.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* QEMU SiFive U OTP (One-Time Programmable) Memory interface
|
||||
*
|
||||
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_SIFIVE_U_OTP_H
|
||||
#define HW_SIFIVE_U_OTP_H
|
||||
|
||||
#define SIFIVE_U_OTP_PA 0x00
|
||||
#define SIFIVE_U_OTP_PAIO 0x04
|
||||
#define SIFIVE_U_OTP_PAS 0x08
|
||||
#define SIFIVE_U_OTP_PCE 0x0C
|
||||
#define SIFIVE_U_OTP_PCLK 0x10
|
||||
#define SIFIVE_U_OTP_PDIN 0x14
|
||||
#define SIFIVE_U_OTP_PDOUT 0x18
|
||||
#define SIFIVE_U_OTP_PDSTB 0x1C
|
||||
#define SIFIVE_U_OTP_PPROG 0x20
|
||||
#define SIFIVE_U_OTP_PTC 0x24
|
||||
#define SIFIVE_U_OTP_PTM 0x28
|
||||
#define SIFIVE_U_OTP_PTM_REP 0x2C
|
||||
#define SIFIVE_U_OTP_PTR 0x30
|
||||
#define SIFIVE_U_OTP_PTRIM 0x34
|
||||
#define SIFIVE_U_OTP_PWE 0x38
|
||||
|
||||
#define SIFIVE_U_OTP_PCE_EN (1 << 0)
|
||||
|
||||
#define SIFIVE_U_OTP_PDSTB_EN (1 << 0)
|
||||
|
||||
#define SIFIVE_U_OTP_PTRIM_EN (1 << 0)
|
||||
|
||||
#define SIFIVE_U_OTP_PA_MASK 0xfff
|
||||
#define SIFIVE_U_OTP_NUM_FUSES 0x1000
|
||||
#define SIFIVE_U_OTP_SERIAL_ADDR 0xfc
|
||||
|
||||
#define SIFIVE_U_OTP_REG_SIZE 0x1000
|
||||
|
||||
#define TYPE_SIFIVE_U_OTP "riscv.sifive.u.otp"
|
||||
|
||||
#define SIFIVE_U_OTP(obj) \
|
||||
OBJECT_CHECK(SiFiveUOTPState, (obj), TYPE_SIFIVE_U_OTP)
|
||||
|
||||
typedef struct SiFiveUOTPState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion mmio;
|
||||
uint32_t pa;
|
||||
uint32_t paio;
|
||||
uint32_t pas;
|
||||
uint32_t pce;
|
||||
uint32_t pclk;
|
||||
uint32_t pdin;
|
||||
uint32_t pdstb;
|
||||
uint32_t pprog;
|
||||
uint32_t ptc;
|
||||
uint32_t ptm;
|
||||
uint32_t ptm_rep;
|
||||
uint32_t ptr;
|
||||
uint32_t ptrim;
|
||||
uint32_t pwe;
|
||||
uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES];
|
||||
/* config */
|
||||
uint32_t serial;
|
||||
} SiFiveUOTPState;
|
||||
|
||||
#endif /* HW_SIFIVE_U_OTP_H */
|
91
include/hw/riscv/sifive_u_prci.h
Normal file
91
include/hw/riscv/sifive_u_prci.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) interface
|
||||
*
|
||||
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_SIFIVE_U_PRCI_H
|
||||
#define HW_SIFIVE_U_PRCI_H
|
||||
|
||||
#define SIFIVE_U_PRCI_HFXOSCCFG 0x00
|
||||
#define SIFIVE_U_PRCI_COREPLLCFG0 0x04
|
||||
#define SIFIVE_U_PRCI_DDRPLLCFG0 0x0C
|
||||
#define SIFIVE_U_PRCI_DDRPLLCFG1 0x10
|
||||
#define SIFIVE_U_PRCI_GEMGXLPLLCFG0 0x1C
|
||||
#define SIFIVE_U_PRCI_GEMGXLPLLCFG1 0x20
|
||||
#define SIFIVE_U_PRCI_CORECLKSEL 0x24
|
||||
#define SIFIVE_U_PRCI_DEVICESRESET 0x28
|
||||
#define SIFIVE_U_PRCI_CLKMUXSTATUS 0x2C
|
||||
|
||||
/*
|
||||
* Current FU540-C000 manual says ready bit is at bit 29, but
|
||||
* freedom-u540-c000-bootloader codes (ux00prci.h) says it is at bit 31.
|
||||
* We have to trust the actual code that works.
|
||||
*
|
||||
* see https://github.com/sifive/freedom-u540-c000-bootloader
|
||||
*/
|
||||
|
||||
#define SIFIVE_U_PRCI_HFXOSCCFG_EN (1 << 30)
|
||||
#define SIFIVE_U_PRCI_HFXOSCCFG_RDY (1 << 31)
|
||||
|
||||
/* xxxPLLCFG0 register bits */
|
||||
#define SIFIVE_U_PRCI_PLLCFG0_DIVR (1 << 0)
|
||||
#define SIFIVE_U_PRCI_PLLCFG0_DIVF (31 << 6)
|
||||
#define SIFIVE_U_PRCI_PLLCFG0_DIVQ (3 << 15)
|
||||
#define SIFIVE_U_PRCI_PLLCFG0_FSE (1 << 25)
|
||||
#define SIFIVE_U_PRCI_PLLCFG0_LOCK (1 << 31)
|
||||
|
||||
/* xxxPLLCFG1 register bits */
|
||||
#define SIFIVE_U_PRCI_PLLCFG1_CKE (1 << 24)
|
||||
|
||||
/* coreclksel register bits */
|
||||
#define SIFIVE_U_PRCI_CORECLKSEL_HFCLK (1 << 0)
|
||||
|
||||
|
||||
#define SIFIVE_U_PRCI_REG_SIZE 0x1000
|
||||
|
||||
#define TYPE_SIFIVE_U_PRCI "riscv.sifive.u.prci"
|
||||
|
||||
#define SIFIVE_U_PRCI(obj) \
|
||||
OBJECT_CHECK(SiFiveUPRCIState, (obj), TYPE_SIFIVE_U_PRCI)
|
||||
|
||||
typedef struct SiFiveUPRCIState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion mmio;
|
||||
uint32_t hfxosccfg;
|
||||
uint32_t corepllcfg0;
|
||||
uint32_t ddrpllcfg0;
|
||||
uint32_t ddrpllcfg1;
|
||||
uint32_t gemgxlpllcfg0;
|
||||
uint32_t gemgxlpllcfg1;
|
||||
uint32_t coreclksel;
|
||||
uint32_t devicesreset;
|
||||
uint32_t clkmuxstatus;
|
||||
} SiFiveUPRCIState;
|
||||
|
||||
/*
|
||||
* Clock indexes for use by Device Tree data and the PRCI driver.
|
||||
*
|
||||
* These values are from sifive-fu540-prci.h in the Linux kernel.
|
||||
*/
|
||||
#define PRCI_CLK_COREPLL 0
|
||||
#define PRCI_CLK_DDRPLL 1
|
||||
#define PRCI_CLK_GEMGXLPLL 2
|
||||
#define PRCI_CLK_TLCLK 3
|
||||
|
||||
#endif /* HW_SIFIVE_U_PRCI_H */
|
0
pc-bios/opensbi-riscv32-virt-fw_jump.bin
Executable file → Normal file
0
pc-bios/opensbi-riscv32-virt-fw_jump.bin
Executable file → Normal file
BIN
pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
Executable file → Normal file
BIN
pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
Executable file → Normal file
Binary file not shown.
0
pc-bios/opensbi-riscv64-virt-fw_jump.bin
Executable file → Normal file
0
pc-bios/opensbi-riscv64-virt-fw_jump.bin
Executable file → Normal file
|
@ -182,8 +182,8 @@ opensbi64-virt:
|
|||
opensbi64-sifive_u:
|
||||
$(MAKE) -C opensbi \
|
||||
CROSS_COMPILE=$(riscv64_cross_prefix) \
|
||||
PLATFORM="qemu/sifive_u"
|
||||
cp opensbi/build/platform/qemu/sifive_u/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
|
||||
PLATFORM="sifive/fu540"
|
||||
cp opensbi/build/platform/sifive/fu540/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
|
||||
|
||||
clean:
|
||||
rm -rf seabios/.config seabios/out seabios/builds
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o
|
||||
obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o
|
||||
obj-$(CONFIG_SOFTMMU) += pmp.o
|
||||
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
obj-y += monitor.o
|
||||
endif
|
||||
|
||||
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
|
||||
|
||||
|
|
|
@ -34,17 +34,20 @@
|
|||
static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
|
||||
|
||||
const char * const riscv_int_regnames[] = {
|
||||
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
||||
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
||||
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
|
||||
"x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
|
||||
"x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
|
||||
"x14/a4", "x15/a5", "x16/a6", "x17/a7", "x18/s2", "x19/s3", "x20/s4",
|
||||
"x21/s5", "x22/s6", "x23/s7", "x24/s8", "x25/s9", "x26/s10", "x27/s11",
|
||||
"x28/t3", "x29/t4", "x30/t5", "x31/t6"
|
||||
};
|
||||
|
||||
const char * const riscv_fpr_regnames[] = {
|
||||
"ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
|
||||
"fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
|
||||
"fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
|
||||
"fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
|
||||
"f0/ft0", "f1/ft1", "f2/ft2", "f3/ft3", "f4/ft4", "f5/ft5",
|
||||
"f6/ft6", "f7/ft7", "f8/fs0", "f9/fs1", "f10/fa0", "f11/fa1",
|
||||
"f12/fa2", "f13/fa3", "f14/fa4", "f15/fa5", "f16/fa6", "f17/fa7",
|
||||
"f18/fs2", "f19/fs3", "f20/fs4", "f21/fs5", "f22/fs6", "f23/fs7",
|
||||
"f24/fs8", "f25/fs9", "f26/fs10", "f27/fs11", "f28/ft8", "f29/ft9",
|
||||
"f30/ft10", "f31/ft11"
|
||||
};
|
||||
|
||||
const char * const riscv_excp_names[] = {
|
||||
|
|
|
@ -255,6 +255,7 @@ void riscv_cpu_do_interrupt(CPUState *cpu);
|
|||
int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
|
||||
bool riscv_cpu_fp_enabled(CPURISCVState *env);
|
||||
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
|
||||
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
|
@ -298,7 +299,10 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
|||
#ifdef CONFIG_USER_ONLY
|
||||
*flags = TB_FLAGS_MSTATUS_FS;
|
||||
#else
|
||||
*flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS);
|
||||
*flags = cpu_mmu_index(env, 0);
|
||||
if (riscv_cpu_fp_enabled(env)) {
|
||||
*flags |= TB_FLAGS_MSTATUS_FS;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -173,6 +173,24 @@
|
|||
#define CSR_SPTBR 0x180
|
||||
#define CSR_SATP 0x180
|
||||
|
||||
/* Hpervisor CSRs */
|
||||
#define CSR_HSTATUS 0x600
|
||||
#define CSR_HEDELEG 0x602
|
||||
#define CSR_HIDELEG 0x603
|
||||
#define CSR_HCOUNTERNEN 0x606
|
||||
#define CSR_HGATP 0x680
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define HGATP_MODE SATP32_MODE
|
||||
#define HGATP_VMID SATP32_ASID
|
||||
#define HGATP_PPN SATP32_PPN
|
||||
#endif
|
||||
#if defined(TARGET_RISCV64)
|
||||
#define HGATP_MODE SATP64_MODE
|
||||
#define HGATP_VMID SATP64_ASID
|
||||
#define HGATP_PPN SATP64_PPN
|
||||
#endif
|
||||
|
||||
/* Physical Memory Protection */
|
||||
#define CSR_PMPCFG0 0x3a0
|
||||
#define CSR_PMPCFG1 0x3a1
|
||||
|
@ -206,23 +224,6 @@
|
|||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DSCRATCH 0x7b2
|
||||
|
||||
/* Hpervisor CSRs */
|
||||
#define CSR_HSTATUS 0xa00
|
||||
#define CSR_HEDELEG 0xa02
|
||||
#define CSR_HIDELEG 0xa03
|
||||
#define CSR_HGATP 0xa80
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define HGATP_MODE SATP32_MODE
|
||||
#define HGATP_ASID SATP32_ASID
|
||||
#define HGATP_PPN SATP32_PPN
|
||||
#endif
|
||||
#if defined(TARGET_RISCV64)
|
||||
#define HGATP_MODE SATP64_MODE
|
||||
#define HGATP_ASID SATP64_ASID
|
||||
#define HGATP_PPN SATP64_PPN
|
||||
#endif
|
||||
|
||||
/* Performance Counters */
|
||||
#define CSR_MHPMCOUNTER3 0xb03
|
||||
#define CSR_MHPMCOUNTER4 0xb04
|
||||
|
|
|
@ -71,6 +71,16 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
|||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* Return true is floating point support is currently enabled */
|
||||
bool riscv_cpu_fp_enabled(CPURISCVState *env)
|
||||
{
|
||||
if (env->mstatus & MSTATUS_FS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
@ -176,12 +186,12 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
|
|||
|
||||
*prot = 0;
|
||||
|
||||
target_ulong base;
|
||||
hwaddr base;
|
||||
int levels, ptidxbits, ptesize, vm, sum;
|
||||
int mxr = get_field(env->mstatus, MSTATUS_MXR);
|
||||
|
||||
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||
base = get_field(env->satp, SATP_PPN) << PGSHIFT;
|
||||
base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
|
||||
sum = get_field(env->mstatus, MSTATUS_SUM);
|
||||
vm = get_field(env->satp, SATP_MODE);
|
||||
switch (vm) {
|
||||
|
@ -201,7 +211,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
|
|||
g_assert_not_reached();
|
||||
}
|
||||
} else {
|
||||
base = env->sptbr << PGSHIFT;
|
||||
base = (hwaddr)(env->sptbr) << PGSHIFT;
|
||||
sum = !get_field(env->mstatus, MSTATUS_PUM);
|
||||
vm = get_field(env->mstatus, MSTATUS_VM);
|
||||
switch (vm) {
|
||||
|
@ -239,7 +249,7 @@ restart:
|
|||
((1 << ptidxbits) - 1);
|
||||
|
||||
/* check that physical address of PTE is legal */
|
||||
target_ulong pte_addr = base + idx * ptesize;
|
||||
hwaddr pte_addr = base + idx * ptesize;
|
||||
|
||||
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
|
||||
!pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
|
||||
|
@ -251,7 +261,7 @@ restart:
|
|||
#elif defined(TARGET_RISCV64)
|
||||
target_ulong pte = ldq_phys(cs->as, pte_addr);
|
||||
#endif
|
||||
target_ulong ppn = pte >> PTE_PPN_SHIFT;
|
||||
hwaddr ppn = pte >> PTE_PPN_SHIFT;
|
||||
|
||||
if (!(pte & PTE_V)) {
|
||||
/* Invalid PTE */
|
||||
|
|
|
@ -46,7 +46,7 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
|
|||
static int fs(CPURISCVState *env, int csrno)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
@ -108,7 +108,7 @@ static int pmp(CPURISCVState *env, int csrno)
|
|||
static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
@ -119,7 +119,7 @@ static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
|
|||
static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return -1;
|
||||
}
|
||||
env->mstatus |= MSTATUS_FS;
|
||||
|
@ -131,7 +131,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
|
|||
static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
@ -142,7 +142,7 @@ static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
|
|||
static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return -1;
|
||||
}
|
||||
env->mstatus |= MSTATUS_FS;
|
||||
|
@ -154,7 +154,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
|
|||
static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
@ -166,7 +166,7 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
|
|||
static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
|
||||
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
|
||||
return -1;
|
||||
}
|
||||
env->mstatus |= MSTATUS_FS;
|
||||
|
@ -307,6 +307,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
|
|||
{
|
||||
target_ulong mstatus = env->mstatus;
|
||||
target_ulong mask = 0;
|
||||
int dirty;
|
||||
|
||||
/* flush tlb on mstatus fields that affect VM */
|
||||
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
|
||||
|
@ -334,14 +335,15 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
|
|||
* RV32: MPV and MTL are not in mstatus. The current plan is to
|
||||
* add them to mstatush. For now, we just don't support it.
|
||||
*/
|
||||
mask |= MSTATUS_MPP | MSTATUS_MPV;
|
||||
mask |= MSTATUS_MTL | MSTATUS_MPV;
|
||||
#endif
|
||||
}
|
||||
|
||||
mstatus = (mstatus & ~mask) | (val & mask);
|
||||
|
||||
int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
|
||||
((mstatus & MSTATUS_XS) == MSTATUS_XS);
|
||||
dirty = (riscv_cpu_fp_enabled(env) &&
|
||||
((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
|
||||
((mstatus & MSTATUS_XS) == MSTATUS_XS);
|
||||
mstatus = set_field(mstatus, MSTATUS_SD, dirty);
|
||||
env->mstatus = mstatus;
|
||||
|
||||
|
|
|
@ -313,7 +313,8 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
|
|||
* register 33, so we recalculate the map index.
|
||||
* This also works for CSR_FRM and CSR_FCSR.
|
||||
*/
|
||||
result = riscv_csrrw_debug(env, n - 33 + 8, &val, 0, 0);
|
||||
result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
|
||||
0, 0);
|
||||
if (result == 0) {
|
||||
return gdb_get_regl(mem_buf, val);
|
||||
}
|
||||
|
@ -335,7 +336,8 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
|
|||
* register 33, so we recalculate the map index.
|
||||
* This also works for CSR_FRM and CSR_FCSR.
|
||||
*/
|
||||
result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1);
|
||||
result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], NULL,
|
||||
val, -1);
|
||||
if (result == 0) {
|
||||
return sizeof(target_ulong);
|
||||
}
|
||||
|
|
229
target/riscv/monitor.c
Normal file
229
target/riscv/monitor.c
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* QEMU monitor for RISC-V
|
||||
*
|
||||
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* RISC-V specific monitor commands implementation
|
||||
*
|
||||
* 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 "cpu_bits.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "monitor/hmp-target.h"
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
#define PTE_HEADER_FIELDS "vaddr paddr "\
|
||||
"size attr\n"
|
||||
#define PTE_HEADER_DELIMITER "---------------- ---------------- "\
|
||||
"---------------- -------\n"
|
||||
#else
|
||||
#define PTE_HEADER_FIELDS "vaddr paddr size attr\n"
|
||||
#define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n"
|
||||
#endif
|
||||
|
||||
/* Perform linear address sign extension */
|
||||
static target_ulong addr_canonical(int va_bits, target_ulong addr)
|
||||
{
|
||||
#ifdef TARGET_RISCV64
|
||||
if (addr & (1UL << (va_bits - 1))) {
|
||||
addr |= (hwaddr)-(1L << va_bits);
|
||||
}
|
||||
#endif
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void print_pte_header(Monitor *mon)
|
||||
{
|
||||
monitor_printf(mon, PTE_HEADER_FIELDS);
|
||||
monitor_printf(mon, PTE_HEADER_DELIMITER);
|
||||
}
|
||||
|
||||
static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr,
|
||||
hwaddr paddr, target_ulong size, int attr)
|
||||
{
|
||||
/* santity check on vaddr */
|
||||
if (vaddr >= (1UL << va_bits)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, TARGET_FMT_lx " " TARGET_FMT_plx " " TARGET_FMT_lx
|
||||
" %c%c%c%c%c%c%c\n",
|
||||
addr_canonical(va_bits, vaddr),
|
||||
paddr, size,
|
||||
attr & PTE_R ? 'r' : '-',
|
||||
attr & PTE_W ? 'w' : '-',
|
||||
attr & PTE_X ? 'x' : '-',
|
||||
attr & PTE_U ? 'u' : '-',
|
||||
attr & PTE_G ? 'g' : '-',
|
||||
attr & PTE_A ? 'a' : '-',
|
||||
attr & PTE_D ? 'd' : '-');
|
||||
}
|
||||
|
||||
static void walk_pte(Monitor *mon, hwaddr base, target_ulong start,
|
||||
int level, int ptidxbits, int ptesize, int va_bits,
|
||||
target_ulong *vbase, hwaddr *pbase, hwaddr *last_paddr,
|
||||
target_ulong *last_size, int *last_attr)
|
||||
{
|
||||
hwaddr pte_addr;
|
||||
hwaddr paddr;
|
||||
target_ulong pgsize;
|
||||
target_ulong pte;
|
||||
int ptshift;
|
||||
int attr;
|
||||
int idx;
|
||||
|
||||
if (level < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ptshift = level * ptidxbits;
|
||||
pgsize = 1UL << (PGSHIFT + ptshift);
|
||||
|
||||
for (idx = 0; idx < (1UL << ptidxbits); idx++) {
|
||||
pte_addr = base + idx * ptesize;
|
||||
cpu_physical_memory_read(pte_addr, &pte, ptesize);
|
||||
|
||||
paddr = (hwaddr)(pte >> PTE_PPN_SHIFT) << PGSHIFT;
|
||||
attr = pte & 0xff;
|
||||
|
||||
/* PTE has to be valid */
|
||||
if (attr & PTE_V) {
|
||||
if (attr & (PTE_R | PTE_W | PTE_X)) {
|
||||
/*
|
||||
* A leaf PTE has been found
|
||||
*
|
||||
* If current PTE's permission bits differ from the last one,
|
||||
* or current PTE's ppn does not make a contiguous physical
|
||||
* address block together with the last one, print out the last
|
||||
* contiguous mapped block details.
|
||||
*/
|
||||
if ((*last_attr != attr) ||
|
||||
(*last_paddr + *last_size != paddr)) {
|
||||
print_pte(mon, va_bits, *vbase, *pbase,
|
||||
*last_paddr + *last_size - *pbase, *last_attr);
|
||||
|
||||
*vbase = start;
|
||||
*pbase = paddr;
|
||||
*last_attr = attr;
|
||||
}
|
||||
|
||||
*last_paddr = paddr;
|
||||
*last_size = pgsize;
|
||||
} else {
|
||||
/* pointer to the next level of the page table */
|
||||
walk_pte(mon, paddr, start, level - 1, ptidxbits, ptesize,
|
||||
va_bits, vbase, pbase, last_paddr,
|
||||
last_size, last_attr);
|
||||
}
|
||||
}
|
||||
|
||||
start += pgsize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void mem_info_svxx(Monitor *mon, CPUArchState *env)
|
||||
{
|
||||
int levels, ptidxbits, ptesize, vm, va_bits;
|
||||
hwaddr base;
|
||||
target_ulong vbase;
|
||||
hwaddr pbase;
|
||||
hwaddr last_paddr;
|
||||
target_ulong last_size;
|
||||
int last_attr;
|
||||
|
||||
base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
|
||||
|
||||
vm = get_field(env->satp, SATP_MODE);
|
||||
switch (vm) {
|
||||
case VM_1_10_SV32:
|
||||
levels = 2;
|
||||
ptidxbits = 10;
|
||||
ptesize = 4;
|
||||
break;
|
||||
case VM_1_10_SV39:
|
||||
levels = 3;
|
||||
ptidxbits = 9;
|
||||
ptesize = 8;
|
||||
break;
|
||||
case VM_1_10_SV48:
|
||||
levels = 4;
|
||||
ptidxbits = 9;
|
||||
ptesize = 8;
|
||||
break;
|
||||
case VM_1_10_SV57:
|
||||
levels = 5;
|
||||
ptidxbits = 9;
|
||||
ptesize = 8;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
|
||||
/* calculate virtual address bits */
|
||||
va_bits = PGSHIFT + levels * ptidxbits;
|
||||
|
||||
/* print header */
|
||||
print_pte_header(mon);
|
||||
|
||||
vbase = -1;
|
||||
pbase = -1;
|
||||
last_paddr = -1;
|
||||
last_size = 0;
|
||||
last_attr = 0;
|
||||
|
||||
/* walk page tables, starting from address 0 */
|
||||
walk_pte(mon, base, 0, levels - 1, ptidxbits, ptesize, va_bits,
|
||||
&vbase, &pbase, &last_paddr, &last_size, &last_attr);
|
||||
|
||||
/* don't forget the last one */
|
||||
print_pte(mon, va_bits, vbase, pbase,
|
||||
last_paddr + last_size - pbase, last_attr);
|
||||
}
|
||||
|
||||
void hmp_info_mem(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
CPUArchState *env;
|
||||
|
||||
env = mon_get_cpu_env();
|
||||
if (!env) {
|
||||
monitor_printf(mon, "No CPU available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
|
||||
monitor_printf(mon, "S-mode MMU unavailable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (env->priv_ver < PRIV_VERSION_1_10_0) {
|
||||
monitor_printf(mon, "Privileged mode < 1.10 unsupported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(env->satp & SATP_MODE)) {
|
||||
monitor_printf(mon, "No translation or protection\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mem_info_svxx(mon, env);
|
||||
}
|
|
@ -27,16 +27,7 @@
|
|||
#include "qemu/log.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
#define RISCV_DEBUG_PMP 0
|
||||
#define PMP_DEBUG(fmt, ...) \
|
||||
do { \
|
||||
if (RISCV_DEBUG_PMP) { \
|
||||
qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\
|
||||
} \
|
||||
} while (0)
|
||||
#include "trace.h"
|
||||
|
||||
static void pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
|
||||
uint8_t val);
|
||||
|
@ -304,8 +295,7 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
|
|||
int i;
|
||||
uint8_t cfg_val;
|
||||
|
||||
PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx,
|
||||
env->mhartid, reg_index, val);
|
||||
trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
|
||||
|
||||
if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
@ -334,9 +324,7 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
|
|||
val = pmp_read_cfg(env, (reg_index * sizeof(target_ulong)) + i);
|
||||
cfg_val |= (val << (i * 8));
|
||||
}
|
||||
|
||||
PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx,
|
||||
env->mhartid, reg_index, cfg_val);
|
||||
trace_pmpcfg_csr_read(env->mhartid, reg_index, cfg_val);
|
||||
|
||||
return cfg_val;
|
||||
}
|
||||
|
@ -348,9 +336,7 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
|
|||
void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
||||
target_ulong val)
|
||||
{
|
||||
PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx,
|
||||
env->mhartid, addr_index, val);
|
||||
|
||||
trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
|
||||
if (addr_index < MAX_RISCV_PMPS) {
|
||||
if (!pmp_is_locked(env, addr_index)) {
|
||||
env->pmp_state.pmp[addr_index].addr_reg = val;
|
||||
|
@ -371,16 +357,15 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
|||
*/
|
||||
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
|
||||
{
|
||||
PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx,
|
||||
env->mhartid, addr_index,
|
||||
env->pmp_state.pmp[addr_index].addr_reg);
|
||||
target_ulong val = 0;
|
||||
|
||||
if (addr_index < MAX_RISCV_PMPS) {
|
||||
return env->pmp_state.pmp[addr_index].addr_reg;
|
||||
val = env->pmp_state.pmp[addr_index].addr_reg;
|
||||
trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpaddr read - out of bounds\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -1,2 +1,8 @@
|
|||
# target/riscv/cpu_helper.c
|
||||
riscv_trap(uint64_t hartid, bool async, uint64_t cause, uint64_t epc, uint64_t tval, const char *desc) "hart:%"PRId64", async:%d, cause:%"PRId64", epc:0x%"PRIx64", tval:0x%"PRIx64", desc=%s"
|
||||
|
||||
# pmp.c
|
||||
pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": read reg%" PRIu32", val: 0x%" PRIx64
|
||||
pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64
|
||||
pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64
|
||||
pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64
|
||||
|
|
Loading…
Reference in a new issue