From a47ef6e93ab2ca1db8d5ecb61fda3c41f926a26b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 1 Sep 2020 09:39:10 +0800 Subject: hw/riscv: clint: Avoid using hard-coded timebase frequency At present the CLINT timestamp is using a hard-coded timebase frequency value SIFIVE_CLINT_TIMEBASE_FREQ. This might not be true for all boards. Add a new 'timebase-freq' property to the CLINT device, and update various functions to accept this as a parameter. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1598924352-89526-16-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 6fca513ec9..c67a910e48 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -541,7 +541,8 @@ static void virt_machine_init(MachineState *machine) sifive_clint_create( memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size, memmap[VIRT_CLINT].size, base_hartid, hart_count, - SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, true); + SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, + SIFIVE_CLINT_TIMEBASE_FREQ, true); /* Per-socket PLIC hart topology configuration string */ plic_hart_config_len = -- cgit v1.2.3-55-g7522 From 406fafd5d0f9a1c6a365ff1733c26a043b1c4877 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 3 Sep 2020 18:40:16 +0800 Subject: hw/riscv: Move sifive_clint model to hw/intc This is an effort to clean up the hw/riscv directory. Ideally it should only contain the RISC-V SoC / machine codes plus generic codes. Let's move sifive_clint model to hw/intc directory. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1599129623-68957-6-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/intc/Kconfig | 3 + hw/intc/meson.build | 1 + hw/intc/sifive_clint.c | 266 ++++++++++++++++++++++++++++++++++++++++ hw/riscv/Kconfig | 5 + hw/riscv/meson.build | 1 - hw/riscv/microchip_pfsoc.c | 2 +- hw/riscv/sifive_clint.c | 266 ---------------------------------------- hw/riscv/sifive_e.c | 2 +- hw/riscv/sifive_u.c | 2 +- hw/riscv/spike.c | 2 +- hw/riscv/virt.c | 2 +- include/hw/intc/sifive_clint.h | 60 +++++++++ include/hw/riscv/sifive_clint.h | 60 --------- 13 files changed, 340 insertions(+), 332 deletions(-) create mode 100644 hw/intc/sifive_clint.c delete mode 100644 hw/riscv/sifive_clint.c create mode 100644 include/hw/intc/sifive_clint.h delete mode 100644 include/hw/riscv/sifive_clint.h (limited to 'hw/riscv/virt.c') diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 2ae1e89497..f499d0f8df 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -67,3 +67,6 @@ config RX_ICU config LOONGSON_LIOINTC bool + +config SIFIVE_CLINT + bool diff --git a/hw/intc/meson.build b/hw/intc/meson.build index c16f7f036e..1e20daab77 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -47,6 +47,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c')) specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c')) specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c')) specific_ss.add(when: 'CONFIG_SH4', if_true: files('sh_intc.c')) +specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c')) specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c')) specific_ss.add(when: 'CONFIG_XICS_KVM', if_true: files('xics_kvm.c')) specific_ss.add(when: 'CONFIG_XICS_SPAPR', if_true: files('xics_spapr.c')) diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c new file mode 100644 index 0000000000..0f41e5ea1c --- /dev/null +++ b/hw/intc/sifive_clint.c @@ -0,0 +1,266 @@ +/* + * SiFive CLINT (Core Local Interruptor) + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2017 SiFive, Inc. + * + * This provides real-time clock, timer and interprocessor interrupts. + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/module.h" +#include "hw/sysbus.h" +#include "target/riscv/cpu.h" +#include "hw/qdev-properties.h" +#include "hw/intc/sifive_clint.h" +#include "qemu/timer.h" + +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) +{ + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + timebase_freq, NANOSECONDS_PER_SECOND); +} + +/* + * Called when timecmp is written to update the QEMU timer or immediately + * trigger timer interrupt if mtimecmp <= current timer value. + */ +static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value, + uint32_t timebase_freq) +{ + uint64_t next; + uint64_t diff; + + uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq); + + cpu->env.timecmp = value; + if (cpu->env.timecmp <= rtc_r) { + /* if we're setting an MTIMECMP value in the "past", + immediately raise the timer interrupt */ + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); + return; + } + + /* otherwise, set up the future timer interrupt */ + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0)); + diff = cpu->env.timecmp - rtc_r; + /* back to ns (note args switched in muldiv64) */ + next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq); + timer_mod(cpu->env.timer, next); +} + +/* + * Callback used when the timer set using timer_mod expires. + * Should raise the timer interrupt line + */ +static void sifive_clint_timer_cb(void *opaque) +{ + RISCVCPU *cpu = opaque; + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); +} + +/* CPU wants to read rtc or timecmp register */ +static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size) +{ + SiFiveCLINTState *clint = opaque; + if (addr >= clint->sip_base && + addr < clint->sip_base + (clint->num_harts << 2)) { + size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2); + CPUState *cpu = qemu_get_cpu(hartid); + CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + if (!env) { + error_report("clint: invalid timecmp hartid: %zu", hartid); + } else if ((addr & 0x3) == 0) { + return (env->mip & MIP_MSIP) > 0; + } else { + error_report("clint: invalid read: %08x", (uint32_t)addr); + return 0; + } + } else if (addr >= clint->timecmp_base && + addr < clint->timecmp_base + (clint->num_harts << 3)) { + size_t hartid = clint->hartid_base + + ((addr - clint->timecmp_base) >> 3); + CPUState *cpu = qemu_get_cpu(hartid); + CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + if (!env) { + error_report("clint: invalid timecmp hartid: %zu", hartid); + } else if ((addr & 0x7) == 0) { + /* timecmp_lo */ + uint64_t timecmp = env->timecmp; + return timecmp & 0xFFFFFFFF; + } else if ((addr & 0x7) == 4) { + /* timecmp_hi */ + uint64_t timecmp = env->timecmp; + return (timecmp >> 32) & 0xFFFFFFFF; + } else { + error_report("clint: invalid read: %08x", (uint32_t)addr); + return 0; + } + } else if (addr == clint->time_base) { + /* time_lo */ + return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF; + } else if (addr == clint->time_base + 4) { + /* time_hi */ + return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF; + } + + error_report("clint: invalid read: %08x", (uint32_t)addr); + return 0; +} + +/* CPU wrote to rtc or timecmp register */ +static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + SiFiveCLINTState *clint = opaque; + + if (addr >= clint->sip_base && + addr < clint->sip_base + (clint->num_harts << 2)) { + size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2); + CPUState *cpu = qemu_get_cpu(hartid); + CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + if (!env) { + error_report("clint: invalid timecmp hartid: %zu", hartid); + } else if ((addr & 0x3) == 0) { + riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value)); + } else { + error_report("clint: invalid sip write: %08x", (uint32_t)addr); + } + return; + } else if (addr >= clint->timecmp_base && + addr < clint->timecmp_base + (clint->num_harts << 3)) { + size_t hartid = clint->hartid_base + + ((addr - clint->timecmp_base) >> 3); + CPUState *cpu = qemu_get_cpu(hartid); + CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + if (!env) { + error_report("clint: invalid timecmp hartid: %zu", hartid); + } else if ((addr & 0x7) == 0) { + /* timecmp_lo */ + uint64_t timecmp_hi = env->timecmp >> 32; + sifive_clint_write_timecmp(RISCV_CPU(cpu), + timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq); + return; + } else if ((addr & 0x7) == 4) { + /* timecmp_hi */ + uint64_t timecmp_lo = env->timecmp; + sifive_clint_write_timecmp(RISCV_CPU(cpu), + value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq); + } else { + error_report("clint: invalid timecmp write: %08x", (uint32_t)addr); + } + return; + } else if (addr == clint->time_base) { + /* time_lo */ + error_report("clint: time_lo write not implemented"); + return; + } else if (addr == clint->time_base + 4) { + /* time_hi */ + error_report("clint: time_hi write not implemented"); + return; + } + + error_report("clint: invalid write: %08x", (uint32_t)addr); +} + +static const MemoryRegionOps sifive_clint_ops = { + .read = sifive_clint_read, + .write = sifive_clint_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8 + } +}; + +static Property sifive_clint_properties[] = { + DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0), + DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0), + DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0), + DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0), + DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0), + DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0), + DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_clint_realize(DeviceState *dev, Error **errp) +{ + SiFiveCLINTState *s = SIFIVE_CLINT(dev); + memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s, + TYPE_SIFIVE_CLINT, s->aperture_size); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void sifive_clint_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = sifive_clint_realize; + device_class_set_props(dc, sifive_clint_properties); +} + +static const TypeInfo sifive_clint_info = { + .name = TYPE_SIFIVE_CLINT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveCLINTState), + .class_init = sifive_clint_class_init, +}; + +static void sifive_clint_register_types(void) +{ + type_register_static(&sifive_clint_info); +} + +type_init(sifive_clint_register_types) + + +/* + * Create CLINT device. + */ +DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, + uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, + uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq, + bool provide_rdtime) +{ + int i; + for (i = 0; i < num_harts; i++) { + CPUState *cpu = qemu_get_cpu(hartid_base + i); + CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + if (!env) { + continue; + } + if (provide_rdtime) { + riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq); + } + env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + &sifive_clint_timer_cb, cpu); + env->timecmp = 0; + } + + DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT); + qdev_prop_set_uint32(dev, "hartid-base", hartid_base); + qdev_prop_set_uint32(dev, "num-harts", num_harts); + qdev_prop_set_uint32(dev, "sip-base", sip_base); + qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); + qdev_prop_set_uint32(dev, "time-base", time_base); + qdev_prop_set_uint32(dev, "aperture-size", size); + qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); + return dev; +} diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 5a8335bfec..f8bb7e7a05 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -15,6 +15,7 @@ config SIFIVE_E bool select HART select SIFIVE + select SIFIVE_CLINT select SIFIVE_GPIO select SIFIVE_E_PRCI select UNIMP @@ -24,6 +25,7 @@ config SIFIVE_U select CADENCE select HART select SIFIVE + select SIFIVE_CLINT select SIFIVE_GPIO select SIFIVE_PDMA select SIFIVE_U_OTP @@ -35,6 +37,7 @@ config SPIKE select HART select HTIF select SIFIVE + select SIFIVE_CLINT config OPENTITAN bool @@ -54,11 +57,13 @@ config RISCV_VIRT select PCI_EXPRESS_GENERIC_BRIDGE select PFLASH_CFI01 select SIFIVE + select SIFIVE_CLINT config MICROCHIP_PFSOC bool select HART select SIFIVE + select SIFIVE_CLINT select UNIMP select MCHP_PFSOC_MMUART select SIFIVE_PDMA diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 90003793d4..d0b4cafaec 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -4,7 +4,6 @@ riscv_ss.add(files('numa.c')) riscv_ss.add(when: 'CONFIG_HART', if_true: files('riscv_hart.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) -riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_clint.c')) riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_plic.c')) riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_test.c')) riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_uart.c')) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index da6bd295ce..131eea1ef3 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -48,9 +48,9 @@ #include "hw/misc/unimp.h" #include "hw/riscv/boot.h" #include "hw/riscv/riscv_hart.h" -#include "hw/riscv/sifive_clint.h" #include "hw/riscv/sifive_plic.h" #include "hw/riscv/microchip_pfsoc.h" +#include "hw/intc/sifive_clint.h" #include "sysemu/sysemu.h" /* diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c deleted file mode 100644 index fa1ddf2ccd..0000000000 --- a/hw/riscv/sifive_clint.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * SiFive CLINT (Core Local Interruptor) - * - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu - * Copyright (c) 2017 SiFive, Inc. - * - * This provides real-time clock, timer and interprocessor interrupts. - * - * 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 . - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "hw/sysbus.h" -#include "target/riscv/cpu.h" -#include "hw/qdev-properties.h" -#include "hw/riscv/sifive_clint.h" -#include "qemu/timer.h" - -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) -{ - return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), - timebase_freq, NANOSECONDS_PER_SECOND); -} - -/* - * Called when timecmp is written to update the QEMU timer or immediately - * trigger timer interrupt if mtimecmp <= current timer value. - */ -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value, - uint32_t timebase_freq) -{ - uint64_t next; - uint64_t diff; - - uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq); - - cpu->env.timecmp = value; - if (cpu->env.timecmp <= rtc_r) { - /* if we're setting an MTIMECMP value in the "past", - immediately raise the timer interrupt */ - riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); - return; - } - - /* otherwise, set up the future timer interrupt */ - riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0)); - diff = cpu->env.timecmp - rtc_r; - /* back to ns (note args switched in muldiv64) */ - next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq); - timer_mod(cpu->env.timer, next); -} - -/* - * Callback used when the timer set using timer_mod expires. - * Should raise the timer interrupt line - */ -static void sifive_clint_timer_cb(void *opaque) -{ - RISCVCPU *cpu = opaque; - riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); -} - -/* CPU wants to read rtc or timecmp register */ -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size) -{ - SiFiveCLINTState *clint = opaque; - if (addr >= clint->sip_base && - addr < clint->sip_base + (clint->num_harts << 2)) { - size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2); - CPUState *cpu = qemu_get_cpu(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; - if (!env) { - error_report("clint: invalid timecmp hartid: %zu", hartid); - } else if ((addr & 0x3) == 0) { - return (env->mip & MIP_MSIP) > 0; - } else { - error_report("clint: invalid read: %08x", (uint32_t)addr); - return 0; - } - } else if (addr >= clint->timecmp_base && - addr < clint->timecmp_base + (clint->num_harts << 3)) { - size_t hartid = clint->hartid_base + - ((addr - clint->timecmp_base) >> 3); - CPUState *cpu = qemu_get_cpu(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; - if (!env) { - error_report("clint: invalid timecmp hartid: %zu", hartid); - } else if ((addr & 0x7) == 0) { - /* timecmp_lo */ - uint64_t timecmp = env->timecmp; - return timecmp & 0xFFFFFFFF; - } else if ((addr & 0x7) == 4) { - /* timecmp_hi */ - uint64_t timecmp = env->timecmp; - return (timecmp >> 32) & 0xFFFFFFFF; - } else { - error_report("clint: invalid read: %08x", (uint32_t)addr); - return 0; - } - } else if (addr == clint->time_base) { - /* time_lo */ - return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF; - } else if (addr == clint->time_base + 4) { - /* time_hi */ - return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF; - } - - error_report("clint: invalid read: %08x", (uint32_t)addr); - return 0; -} - -/* CPU wrote to rtc or timecmp register */ -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - SiFiveCLINTState *clint = opaque; - - if (addr >= clint->sip_base && - addr < clint->sip_base + (clint->num_harts << 2)) { - size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2); - CPUState *cpu = qemu_get_cpu(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; - if (!env) { - error_report("clint: invalid timecmp hartid: %zu", hartid); - } else if ((addr & 0x3) == 0) { - riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value)); - } else { - error_report("clint: invalid sip write: %08x", (uint32_t)addr); - } - return; - } else if (addr >= clint->timecmp_base && - addr < clint->timecmp_base + (clint->num_harts << 3)) { - size_t hartid = clint->hartid_base + - ((addr - clint->timecmp_base) >> 3); - CPUState *cpu = qemu_get_cpu(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; - if (!env) { - error_report("clint: invalid timecmp hartid: %zu", hartid); - } else if ((addr & 0x7) == 0) { - /* timecmp_lo */ - uint64_t timecmp_hi = env->timecmp >> 32; - sifive_clint_write_timecmp(RISCV_CPU(cpu), - timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq); - return; - } else if ((addr & 0x7) == 4) { - /* timecmp_hi */ - uint64_t timecmp_lo = env->timecmp; - sifive_clint_write_timecmp(RISCV_CPU(cpu), - value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq); - } else { - error_report("clint: invalid timecmp write: %08x", (uint32_t)addr); - } - return; - } else if (addr == clint->time_base) { - /* time_lo */ - error_report("clint: time_lo write not implemented"); - return; - } else if (addr == clint->time_base + 4) { - /* time_hi */ - error_report("clint: time_hi write not implemented"); - return; - } - - error_report("clint: invalid write: %08x", (uint32_t)addr); -} - -static const MemoryRegionOps sifive_clint_ops = { - .read = sifive_clint_read, - .write = sifive_clint_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 8 - } -}; - -static Property sifive_clint_properties[] = { - DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0), - DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0), - DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0), - DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0), - DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0), - DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0), - DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sifive_clint_realize(DeviceState *dev, Error **errp) -{ - SiFiveCLINTState *s = SIFIVE_CLINT(dev); - memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s, - TYPE_SIFIVE_CLINT, s->aperture_size); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); -} - -static void sifive_clint_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = sifive_clint_realize; - device_class_set_props(dc, sifive_clint_properties); -} - -static const TypeInfo sifive_clint_info = { - .name = TYPE_SIFIVE_CLINT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SiFiveCLINTState), - .class_init = sifive_clint_class_init, -}; - -static void sifive_clint_register_types(void) -{ - type_register_static(&sifive_clint_info); -} - -type_init(sifive_clint_register_types) - - -/* - * Create CLINT device. - */ -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, - uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, - uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq, - bool provide_rdtime) -{ - int i; - for (i = 0; i < num_harts; i++) { - CPUState *cpu = qemu_get_cpu(hartid_base + i); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; - if (!env) { - continue; - } - if (provide_rdtime) { - riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq); - } - env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - &sifive_clint_timer_cb, cpu); - env->timecmp = 0; - } - - DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT); - qdev_prop_set_uint32(dev, "hartid-base", hartid_base); - qdev_prop_set_uint32(dev, "num-harts", num_harts); - qdev_prop_set_uint32(dev, "sip-base", sip_base); - qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); - qdev_prop_set_uint32(dev, "time-base", time_base); - qdev_prop_set_uint32(dev, "aperture-size", size); - qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); - return dev; -} diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 7f43ed953a..3bdb16e697 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -40,10 +40,10 @@ #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_e.h" #include "hw/riscv/boot.h" +#include "hw/intc/sifive_clint.h" #include "hw/misc/sifive_e_prci.h" #include "chardev/char.h" #include "sysemu/arch_init.h" diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 79975372ef..7187d1ad17 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -47,10 +47,10 @@ #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_u.h" #include "hw/riscv/boot.h" +#include "hw/intc/sifive_clint.h" #include "chardev/char.h" #include "net/eth.h" #include "sysemu/arch_init.h" diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index b54a396107..59d9d87c56 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -33,10 +33,10 @@ #include "target/riscv/cpu.h" #include "hw/riscv/riscv_htif.h" #include "hw/riscv/riscv_hart.h" -#include "hw/riscv/sifive_clint.h" #include "hw/riscv/spike.h" #include "hw/riscv/boot.h" #include "hw/riscv/numa.h" +#include "hw/intc/sifive_clint.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index c67a910e48..bce2020d02 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -31,11 +31,11 @@ #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_test.h" #include "hw/riscv/virt.h" #include "hw/riscv/boot.h" #include "hw/riscv/numa.h" +#include "hw/intc/sifive_clint.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h new file mode 100644 index 0000000000..a30be0f3d6 --- /dev/null +++ b/include/hw/intc/sifive_clint.h @@ -0,0 +1,60 @@ +/* + * SiFive CLINT (Core Local Interruptor) interface + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * 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 . + */ + +#ifndef HW_SIFIVE_CLINT_H +#define HW_SIFIVE_CLINT_H + +#include "hw/sysbus.h" + +#define TYPE_SIFIVE_CLINT "riscv.sifive.clint" + +#define SIFIVE_CLINT(obj) \ + OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT) + +typedef struct SiFiveCLINTState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion mmio; + uint32_t hartid_base; + uint32_t num_harts; + uint32_t sip_base; + uint32_t timecmp_base; + uint32_t time_base; + uint32_t aperture_size; + uint32_t timebase_freq; +} SiFiveCLINTState; + +DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, + uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, + uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq, + bool provide_rdtime); + +enum { + SIFIVE_SIP_BASE = 0x0, + SIFIVE_TIMECMP_BASE = 0x4000, + SIFIVE_TIME_BASE = 0xBFF8 +}; + +enum { + SIFIVE_CLINT_TIMEBASE_FREQ = 10000000 +}; + +#endif diff --git a/include/hw/riscv/sifive_clint.h b/include/hw/riscv/sifive_clint.h deleted file mode 100644 index a30be0f3d6..0000000000 --- a/include/hw/riscv/sifive_clint.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SiFive CLINT (Core Local Interruptor) interface - * - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu - * 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 . - */ - -#ifndef HW_SIFIVE_CLINT_H -#define HW_SIFIVE_CLINT_H - -#include "hw/sysbus.h" - -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint" - -#define SIFIVE_CLINT(obj) \ - OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT) - -typedef struct SiFiveCLINTState { - /*< private >*/ - SysBusDevice parent_obj; - - /*< public >*/ - MemoryRegion mmio; - uint32_t hartid_base; - uint32_t num_harts; - uint32_t sip_base; - uint32_t timecmp_base; - uint32_t time_base; - uint32_t aperture_size; - uint32_t timebase_freq; -} SiFiveCLINTState; - -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, - uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, - uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq, - bool provide_rdtime); - -enum { - SIFIVE_SIP_BASE = 0x0, - SIFIVE_TIMECMP_BASE = 0x4000, - SIFIVE_TIME_BASE = 0xBFF8 -}; - -enum { - SIFIVE_CLINT_TIMEBASE_FREQ = 10000000 -}; - -#endif -- cgit v1.2.3-55-g7522 From 84fcf3c15111de9f0c72efbb6bc0def264555c46 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 3 Sep 2020 18:40:17 +0800 Subject: hw/riscv: Move sifive_plic model to hw/intc This is an effort to clean up the hw/riscv directory. Ideally it should only contain the RISC-V SoC / machine codes plus generic codes. Let's move sifive_plic model to hw/intc directory. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1599129623-68957-7-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/intc/Kconfig | 3 + hw/intc/meson.build | 1 + hw/intc/sifive_plic.c | 524 +++++++++++++++++++++++++++++++++++++++++ hw/intc/sifive_plic.h | 81 +++++++ hw/riscv/Kconfig | 5 + hw/riscv/meson.build | 1 - hw/riscv/microchip_pfsoc.c | 2 +- hw/riscv/sifive_e.c | 2 +- hw/riscv/sifive_plic.c | 524 ----------------------------------------- hw/riscv/sifive_u.c | 2 +- hw/riscv/virt.c | 2 +- include/hw/riscv/sifive_plic.h | 81 ------- 12 files changed, 618 insertions(+), 610 deletions(-) create mode 100644 hw/intc/sifive_plic.c create mode 100644 hw/intc/sifive_plic.h delete mode 100644 hw/riscv/sifive_plic.c delete mode 100644 include/hw/riscv/sifive_plic.h (limited to 'hw/riscv/virt.c') diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index f499d0f8df..d07954086a 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -70,3 +70,6 @@ config LOONGSON_LIOINTC config SIFIVE_CLINT bool + +config SIFIVE_PLIC + bool diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 1e20daab77..3f82cc230a 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -48,6 +48,7 @@ specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c')) specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c')) specific_ss.add(when: 'CONFIG_SH4', if_true: files('sh_intc.c')) specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c')) +specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c')) specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c')) specific_ss.add(when: 'CONFIG_XICS_KVM', if_true: files('xics_kvm.c')) specific_ss.add(when: 'CONFIG_XICS_SPAPR', if_true: files('xics_spapr.c')) diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c new file mode 100644 index 0000000000..af611f8db8 --- /dev/null +++ b/hw/intc/sifive_plic.c @@ -0,0 +1,524 @@ +/* + * SiFive PLIC (Platform Level Interrupt Controller) + * + * Copyright (c) 2017 SiFive, Inc. + * + * This provides a parameterizable interrupt controller based on SiFive's PLIC. + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "hw/sysbus.h" +#include "hw/pci/msi.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "hw/intc/sifive_plic.h" +#include "target/riscv/cpu.h" +#include "sysemu/sysemu.h" + +#define RISCV_DEBUG_PLIC 0 + +static PLICMode char_to_mode(char c) +{ + switch (c) { + case 'U': return PLICMode_U; + case 'S': return PLICMode_S; + case 'H': return PLICMode_H; + case 'M': return PLICMode_M; + default: + error_report("plic: invalid mode '%c'", c); + exit(1); + } +} + +static char mode_to_char(PLICMode m) +{ + switch (m) { + case PLICMode_U: return 'U'; + case PLICMode_S: return 'S'; + case PLICMode_H: return 'H'; + case PLICMode_M: return 'M'; + default: return '?'; + } +} + +static void sifive_plic_print_state(SiFivePLICState *plic) +{ + int i; + int addrid; + + /* pending */ + qemu_log("pending : "); + for (i = plic->bitfield_words - 1; i >= 0; i--) { + qemu_log("%08x", plic->pending[i]); + } + qemu_log("\n"); + + /* pending */ + qemu_log("claimed : "); + for (i = plic->bitfield_words - 1; i >= 0; i--) { + qemu_log("%08x", plic->claimed[i]); + } + qemu_log("\n"); + + for (addrid = 0; addrid < plic->num_addrs; addrid++) { + qemu_log("hart%d-%c enable: ", + plic->addr_config[addrid].hartid, + mode_to_char(plic->addr_config[addrid].mode)); + for (i = plic->bitfield_words - 1; i >= 0; i--) { + qemu_log("%08x", plic->enable[addrid * plic->bitfield_words + i]); + } + qemu_log("\n"); + } +} + +static uint32_t atomic_set_masked(uint32_t *a, uint32_t mask, uint32_t value) +{ + uint32_t old, new, cmp = atomic_read(a); + + do { + old = cmp; + new = (old & ~mask) | (value & mask); + cmp = atomic_cmpxchg(a, old, new); + } while (old != cmp); + + return old; +} + +static void sifive_plic_set_pending(SiFivePLICState *plic, int irq, bool level) +{ + atomic_set_masked(&plic->pending[irq >> 5], 1 << (irq & 31), -!!level); +} + +static void sifive_plic_set_claimed(SiFivePLICState *plic, int irq, bool level) +{ + atomic_set_masked(&plic->claimed[irq >> 5], 1 << (irq & 31), -!!level); +} + +static int sifive_plic_irqs_pending(SiFivePLICState *plic, uint32_t addrid) +{ + int i, j; + for (i = 0; i < plic->bitfield_words; i++) { + uint32_t pending_enabled_not_claimed = + (plic->pending[i] & ~plic->claimed[i]) & + plic->enable[addrid * plic->bitfield_words + i]; + if (!pending_enabled_not_claimed) { + continue; + } + for (j = 0; j < 32; j++) { + int irq = (i << 5) + j; + uint32_t prio = plic->source_priority[irq]; + int enabled = pending_enabled_not_claimed & (1 << j); + if (enabled && prio > plic->target_priority[addrid]) { + return 1; + } + } + } + return 0; +} + +static void sifive_plic_update(SiFivePLICState *plic) +{ + int addrid; + + /* raise irq on harts where this irq is enabled */ + for (addrid = 0; addrid < plic->num_addrs; addrid++) { + uint32_t hartid = plic->addr_config[addrid].hartid; + PLICMode mode = plic->addr_config[addrid].mode; + CPUState *cpu = qemu_get_cpu(hartid); + CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + if (!env) { + continue; + } + int level = sifive_plic_irqs_pending(plic, addrid); + switch (mode) { + case PLICMode_M: + riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level)); + break; + case PLICMode_S: + riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level)); + break; + default: + break; + } + } + + if (RISCV_DEBUG_PLIC) { + sifive_plic_print_state(plic); + } +} + +static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid) +{ + int i, j; + uint32_t max_irq = 0; + uint32_t max_prio = plic->target_priority[addrid]; + + for (i = 0; i < plic->bitfield_words; i++) { + uint32_t pending_enabled_not_claimed = + (plic->pending[i] & ~plic->claimed[i]) & + plic->enable[addrid * plic->bitfield_words + i]; + if (!pending_enabled_not_claimed) { + continue; + } + for (j = 0; j < 32; j++) { + int irq = (i << 5) + j; + uint32_t prio = plic->source_priority[irq]; + int enabled = pending_enabled_not_claimed & (1 << j); + if (enabled && prio > max_prio) { + max_irq = irq; + max_prio = prio; + } + } + } + + if (max_irq) { + sifive_plic_set_pending(plic, max_irq, false); + sifive_plic_set_claimed(plic, max_irq, true); + } + return max_irq; +} + +static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) +{ + SiFivePLICState *plic = opaque; + + /* writes must be 4 byte words */ + if ((addr & 0x3) != 0) { + goto err; + } + + if (addr >= plic->priority_base && /* 4 bytes per source */ + addr < plic->priority_base + (plic->num_sources << 2)) + { + uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: read priority: irq=%d priority=%d\n", + irq, plic->source_priority[irq]); + } + return plic->source_priority[irq]; + } else if (addr >= plic->pending_base && /* 1 bit per source */ + addr < plic->pending_base + (plic->num_sources >> 3)) + { + uint32_t word = (addr - plic->pending_base) >> 2; + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: read pending: word=%d value=%d\n", + word, plic->pending[word]); + } + return plic->pending[word]; + } else if (addr >= plic->enable_base && /* 1 bit per source */ + addr < plic->enable_base + plic->num_addrs * plic->enable_stride) + { + uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride; + uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2; + if (wordid < plic->bitfield_words) { + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: read enable: hart%d-%c word=%d value=%x\n", + plic->addr_config[addrid].hartid, + mode_to_char(plic->addr_config[addrid].mode), wordid, + plic->enable[addrid * plic->bitfield_words + wordid]); + } + return plic->enable[addrid * plic->bitfield_words + wordid]; + } + } else if (addr >= plic->context_base && /* 1 bit per source */ + addr < plic->context_base + plic->num_addrs * plic->context_stride) + { + uint32_t addrid = (addr - plic->context_base) / plic->context_stride; + uint32_t contextid = (addr & (plic->context_stride - 1)); + if (contextid == 0) { + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: read priority: hart%d-%c priority=%x\n", + plic->addr_config[addrid].hartid, + mode_to_char(plic->addr_config[addrid].mode), + plic->target_priority[addrid]); + } + return plic->target_priority[addrid]; + } else if (contextid == 4) { + uint32_t value = sifive_plic_claim(plic, addrid); + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: read claim: hart%d-%c irq=%x\n", + plic->addr_config[addrid].hartid, + mode_to_char(plic->addr_config[addrid].mode), + value); + } + sifive_plic_update(plic); + return value; + } + } + +err: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid register read 0x%" HWADDR_PRIx "\n", + __func__, addr); + return 0; +} + +static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + SiFivePLICState *plic = opaque; + + /* writes must be 4 byte words */ + if ((addr & 0x3) != 0) { + goto err; + } + + if (addr >= plic->priority_base && /* 4 bytes per source */ + addr < plic->priority_base + (plic->num_sources << 2)) + { + uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; + plic->source_priority[irq] = value & 7; + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: write priority: irq=%d priority=%d\n", + irq, plic->source_priority[irq]); + } + sifive_plic_update(plic); + return; + } else if (addr >= plic->pending_base && /* 1 bit per source */ + addr < plic->pending_base + (plic->num_sources >> 3)) + { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid pending write: 0x%" HWADDR_PRIx "", + __func__, addr); + return; + } else if (addr >= plic->enable_base && /* 1 bit per source */ + addr < plic->enable_base + plic->num_addrs * plic->enable_stride) + { + uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride; + uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2; + if (wordid < plic->bitfield_words) { + plic->enable[addrid * plic->bitfield_words + wordid] = value; + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: write enable: hart%d-%c word=%d value=%x\n", + plic->addr_config[addrid].hartid, + mode_to_char(plic->addr_config[addrid].mode), wordid, + plic->enable[addrid * plic->bitfield_words + wordid]); + } + return; + } + } else if (addr >= plic->context_base && /* 4 bytes per reg */ + addr < plic->context_base + plic->num_addrs * plic->context_stride) + { + uint32_t addrid = (addr - plic->context_base) / plic->context_stride; + uint32_t contextid = (addr & (plic->context_stride - 1)); + if (contextid == 0) { + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: write priority: hart%d-%c priority=%x\n", + plic->addr_config[addrid].hartid, + mode_to_char(plic->addr_config[addrid].mode), + plic->target_priority[addrid]); + } + if (value <= plic->num_priorities) { + plic->target_priority[addrid] = value; + sifive_plic_update(plic); + } + return; + } else if (contextid == 4) { + if (RISCV_DEBUG_PLIC) { + qemu_log("plic: write claim: hart%d-%c irq=%x\n", + plic->addr_config[addrid].hartid, + mode_to_char(plic->addr_config[addrid].mode), + (uint32_t)value); + } + if (value < plic->num_sources) { + sifive_plic_set_claimed(plic, value, false); + sifive_plic_update(plic); + } + return; + } + } + +err: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid register write 0x%" HWADDR_PRIx "\n", + __func__, addr); +} + +static const MemoryRegionOps sifive_plic_ops = { + .read = sifive_plic_read, + .write = sifive_plic_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static Property sifive_plic_properties[] = { + DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config), + DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0), + DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0), + DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0), + DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0), + DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0), + DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0), + DEFINE_PROP_UINT32("enable-stride", SiFivePLICState, enable_stride, 0), + DEFINE_PROP_UINT32("context-base", SiFivePLICState, context_base, 0), + DEFINE_PROP_UINT32("context-stride", SiFivePLICState, context_stride, 0), + DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +/* + * parse PLIC hart/mode address offset config + * + * "M" 1 hart with M mode + * "MS,MS" 2 harts, 0-1 with M and S mode + * "M,MS,MS,MS,MS" 5 harts, 0 with M mode, 1-5 with M and S mode + */ +static void parse_hart_config(SiFivePLICState *plic) +{ + int addrid, hartid, modes; + const char *p; + char c; + + /* count and validate hart/mode combinations */ + addrid = 0, hartid = 0, modes = 0; + p = plic->hart_config; + while ((c = *p++)) { + if (c == ',') { + addrid += ctpop8(modes); + modes = 0; + hartid++; + } else { + int m = 1 << char_to_mode(c); + if (modes == (modes | m)) { + error_report("plic: duplicate mode '%c' in config: %s", + c, plic->hart_config); + exit(1); + } + modes |= m; + } + } + if (modes) { + addrid += ctpop8(modes); + } + hartid++; + + plic->num_addrs = addrid; + plic->num_harts = hartid; + + /* store hart/mode combinations */ + plic->addr_config = g_new(PLICAddr, plic->num_addrs); + addrid = 0, hartid = plic->hartid_base; + p = plic->hart_config; + while ((c = *p++)) { + if (c == ',') { + hartid++; + } else { + plic->addr_config[addrid].addrid = addrid; + plic->addr_config[addrid].hartid = hartid; + plic->addr_config[addrid].mode = char_to_mode(c); + addrid++; + } + } +} + +static void sifive_plic_irq_request(void *opaque, int irq, int level) +{ + SiFivePLICState *plic = opaque; + if (RISCV_DEBUG_PLIC) { + qemu_log("sifive_plic_irq_request: irq=%d level=%d\n", irq, level); + } + sifive_plic_set_pending(plic, irq, level > 0); + sifive_plic_update(plic); +} + +static void sifive_plic_realize(DeviceState *dev, Error **errp) +{ + SiFivePLICState *plic = SIFIVE_PLIC(dev); + int i; + + memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic, + TYPE_SIFIVE_PLIC, plic->aperture_size); + parse_hart_config(plic); + plic->bitfield_words = (plic->num_sources + 31) >> 5; + plic->source_priority = g_new0(uint32_t, plic->num_sources); + plic->target_priority = g_new(uint32_t, plic->num_addrs); + plic->pending = g_new0(uint32_t, plic->bitfield_words); + plic->claimed = g_new0(uint32_t, plic->bitfield_words); + plic->enable = g_new0(uint32_t, plic->bitfield_words * plic->num_addrs); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio); + qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources); + + /* We can't allow the supervisor to control SEIP as this would allow the + * supervisor to clear a pending external interrupt which will result in + * lost a interrupt in the case a PLIC is attached. The SEIP bit must be + * hardware controlled when a PLIC is attached. + */ + for (i = 0; i < plic->num_harts; i++) { + RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(plic->hartid_base + i)); + if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { + error_report("SEIP already claimed"); + exit(1); + } + } + + msi_nonbroken = true; +} + +static void sifive_plic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, sifive_plic_properties); + dc->realize = sifive_plic_realize; +} + +static const TypeInfo sifive_plic_info = { + .name = TYPE_SIFIVE_PLIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFivePLICState), + .class_init = sifive_plic_class_init, +}; + +static void sifive_plic_register_types(void) +{ + type_register_static(&sifive_plic_info); +} + +type_init(sifive_plic_register_types) + +/* + * Create PLIC device. + */ +DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, + uint32_t hartid_base, uint32_t num_sources, + uint32_t num_priorities, uint32_t priority_base, + uint32_t pending_base, uint32_t enable_base, + uint32_t enable_stride, uint32_t context_base, + uint32_t context_stride, uint32_t aperture_size) +{ + DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC); + assert(enable_stride == (enable_stride & -enable_stride)); + assert(context_stride == (context_stride & -context_stride)); + qdev_prop_set_string(dev, "hart-config", hart_config); + qdev_prop_set_uint32(dev, "hartid-base", hartid_base); + qdev_prop_set_uint32(dev, "num-sources", num_sources); + qdev_prop_set_uint32(dev, "num-priorities", num_priorities); + qdev_prop_set_uint32(dev, "priority-base", priority_base); + qdev_prop_set_uint32(dev, "pending-base", pending_base); + qdev_prop_set_uint32(dev, "enable-base", enable_base); + qdev_prop_set_uint32(dev, "enable-stride", enable_stride); + qdev_prop_set_uint32(dev, "context-base", context_base); + qdev_prop_set_uint32(dev, "context-stride", context_stride); + qdev_prop_set_uint32(dev, "aperture-size", aperture_size); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); + return dev; +} diff --git a/hw/intc/sifive_plic.h b/hw/intc/sifive_plic.h new file mode 100644 index 0000000000..ace76d0f1b --- /dev/null +++ b/hw/intc/sifive_plic.h @@ -0,0 +1,81 @@ +/* + * SiFive PLIC (Platform Level Interrupt Controller) interface + * + * Copyright (c) 2017 SiFive, Inc. + * + * This provides a RISC-V PLIC device + * + * 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 . + */ + +#ifndef HW_SIFIVE_PLIC_H +#define HW_SIFIVE_PLIC_H + +#include "hw/sysbus.h" + +#define TYPE_SIFIVE_PLIC "riscv.sifive.plic" + +#define SIFIVE_PLIC(obj) \ + OBJECT_CHECK(SiFivePLICState, (obj), TYPE_SIFIVE_PLIC) + +typedef enum PLICMode { + PLICMode_U, + PLICMode_S, + PLICMode_H, + PLICMode_M +} PLICMode; + +typedef struct PLICAddr { + uint32_t addrid; + uint32_t hartid; + PLICMode mode; +} PLICAddr; + +typedef struct SiFivePLICState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion mmio; + uint32_t num_addrs; + uint32_t num_harts; + uint32_t bitfield_words; + PLICAddr *addr_config; + uint32_t *source_priority; + uint32_t *target_priority; + uint32_t *pending; + uint32_t *claimed; + uint32_t *enable; + + /* config */ + char *hart_config; + uint32_t hartid_base; + uint32_t num_sources; + uint32_t num_priorities; + uint32_t priority_base; + uint32_t pending_base; + uint32_t enable_base; + uint32_t enable_stride; + uint32_t context_base; + uint32_t context_stride; + uint32_t aperture_size; +} SiFivePLICState; + +DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, + uint32_t hartid_base, uint32_t num_sources, + uint32_t num_priorities, uint32_t priority_base, + uint32_t pending_base, uint32_t enable_base, + uint32_t enable_stride, uint32_t context_base, + uint32_t context_stride, uint32_t aperture_size); + +#endif diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index f8bb7e7a05..23b7027e11 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -17,6 +17,7 @@ config SIFIVE_E select SIFIVE select SIFIVE_CLINT select SIFIVE_GPIO + select SIFIVE_PLIC select SIFIVE_E_PRCI select UNIMP @@ -28,6 +29,7 @@ config SIFIVE_U select SIFIVE_CLINT select SIFIVE_GPIO select SIFIVE_PDMA + select SIFIVE_PLIC select SIFIVE_U_OTP select SIFIVE_U_PRCI select UNIMP @@ -38,6 +40,7 @@ config SPIKE select HTIF select SIFIVE select SIFIVE_CLINT + select SIFIVE_PLIC config OPENTITAN bool @@ -58,6 +61,7 @@ config RISCV_VIRT select PFLASH_CFI01 select SIFIVE select SIFIVE_CLINT + select SIFIVE_PLIC config MICROCHIP_PFSOC bool @@ -67,4 +71,5 @@ config MICROCHIP_PFSOC select UNIMP select MCHP_PFSOC_MMUART select SIFIVE_PDMA + select SIFIVE_PLIC select CADENCE_SDHCI diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index d0b4cafaec..df3f89d062 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -4,7 +4,6 @@ riscv_ss.add(files('numa.c')) riscv_ss.add(when: 'CONFIG_HART', if_true: files('riscv_hart.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) -riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_plic.c')) riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_test.c')) riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_uart.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c')) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 131eea1ef3..4627179cd3 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -48,9 +48,9 @@ #include "hw/misc/unimp.h" #include "hw/riscv/boot.h" #include "hw/riscv/riscv_hart.h" -#include "hw/riscv/sifive_plic.h" #include "hw/riscv/microchip_pfsoc.h" #include "hw/intc/sifive_clint.h" +#include "hw/intc/sifive_plic.h" #include "sysemu/sysemu.h" /* diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 3bdb16e697..0ddcf1508d 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -39,11 +39,11 @@ #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_uart.h" #include "hw/riscv/sifive_e.h" #include "hw/riscv/boot.h" #include "hw/intc/sifive_clint.h" +#include "hw/intc/sifive_plic.h" #include "hw/misc/sifive_e_prci.h" #include "chardev/char.h" #include "sysemu/arch_init.h" diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c deleted file mode 100644 index 11ef147606..0000000000 --- a/hw/riscv/sifive_plic.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - * SiFive PLIC (Platform Level Interrupt Controller) - * - * Copyright (c) 2017 SiFive, Inc. - * - * This provides a parameterizable interrupt controller based on SiFive's PLIC. - * - * 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 . - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "qemu/error-report.h" -#include "hw/sysbus.h" -#include "hw/pci/msi.h" -#include "hw/boards.h" -#include "hw/qdev-properties.h" -#include "target/riscv/cpu.h" -#include "sysemu/sysemu.h" -#include "hw/riscv/sifive_plic.h" - -#define RISCV_DEBUG_PLIC 0 - -static PLICMode char_to_mode(char c) -{ - switch (c) { - case 'U': return PLICMode_U; - case 'S': return PLICMode_S; - case 'H': return PLICMode_H; - case 'M': return PLICMode_M; - default: - error_report("plic: invalid mode '%c'", c); - exit(1); - } -} - -static char mode_to_char(PLICMode m) -{ - switch (m) { - case PLICMode_U: return 'U'; - case PLICMode_S: return 'S'; - case PLICMode_H: return 'H'; - case PLICMode_M: return 'M'; - default: return '?'; - } -} - -static void sifive_plic_print_state(SiFivePLICState *plic) -{ - int i; - int addrid; - - /* pending */ - qemu_log("pending : "); - for (i = plic->bitfield_words - 1; i >= 0; i--) { - qemu_log("%08x", plic->pending[i]); - } - qemu_log("\n"); - - /* pending */ - qemu_log("claimed : "); - for (i = plic->bitfield_words - 1; i >= 0; i--) { - qemu_log("%08x", plic->claimed[i]); - } - qemu_log("\n"); - - for (addrid = 0; addrid < plic->num_addrs; addrid++) { - qemu_log("hart%d-%c enable: ", - plic->addr_config[addrid].hartid, - mode_to_char(plic->addr_config[addrid].mode)); - for (i = plic->bitfield_words - 1; i >= 0; i--) { - qemu_log("%08x", plic->enable[addrid * plic->bitfield_words + i]); - } - qemu_log("\n"); - } -} - -static uint32_t atomic_set_masked(uint32_t *a, uint32_t mask, uint32_t value) -{ - uint32_t old, new, cmp = atomic_read(a); - - do { - old = cmp; - new = (old & ~mask) | (value & mask); - cmp = atomic_cmpxchg(a, old, new); - } while (old != cmp); - - return old; -} - -static void sifive_plic_set_pending(SiFivePLICState *plic, int irq, bool level) -{ - atomic_set_masked(&plic->pending[irq >> 5], 1 << (irq & 31), -!!level); -} - -static void sifive_plic_set_claimed(SiFivePLICState *plic, int irq, bool level) -{ - atomic_set_masked(&plic->claimed[irq >> 5], 1 << (irq & 31), -!!level); -} - -static int sifive_plic_irqs_pending(SiFivePLICState *plic, uint32_t addrid) -{ - int i, j; - for (i = 0; i < plic->bitfield_words; i++) { - uint32_t pending_enabled_not_claimed = - (plic->pending[i] & ~plic->claimed[i]) & - plic->enable[addrid * plic->bitfield_words + i]; - if (!pending_enabled_not_claimed) { - continue; - } - for (j = 0; j < 32; j++) { - int irq = (i << 5) + j; - uint32_t prio = plic->source_priority[irq]; - int enabled = pending_enabled_not_claimed & (1 << j); - if (enabled && prio > plic->target_priority[addrid]) { - return 1; - } - } - } - return 0; -} - -static void sifive_plic_update(SiFivePLICState *plic) -{ - int addrid; - - /* raise irq on harts where this irq is enabled */ - for (addrid = 0; addrid < plic->num_addrs; addrid++) { - uint32_t hartid = plic->addr_config[addrid].hartid; - PLICMode mode = plic->addr_config[addrid].mode; - CPUState *cpu = qemu_get_cpu(hartid); - CPURISCVState *env = cpu ? cpu->env_ptr : NULL; - if (!env) { - continue; - } - int level = sifive_plic_irqs_pending(plic, addrid); - switch (mode) { - case PLICMode_M: - riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level)); - break; - case PLICMode_S: - riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level)); - break; - default: - break; - } - } - - if (RISCV_DEBUG_PLIC) { - sifive_plic_print_state(plic); - } -} - -static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid) -{ - int i, j; - uint32_t max_irq = 0; - uint32_t max_prio = plic->target_priority[addrid]; - - for (i = 0; i < plic->bitfield_words; i++) { - uint32_t pending_enabled_not_claimed = - (plic->pending[i] & ~plic->claimed[i]) & - plic->enable[addrid * plic->bitfield_words + i]; - if (!pending_enabled_not_claimed) { - continue; - } - for (j = 0; j < 32; j++) { - int irq = (i << 5) + j; - uint32_t prio = plic->source_priority[irq]; - int enabled = pending_enabled_not_claimed & (1 << j); - if (enabled && prio > max_prio) { - max_irq = irq; - max_prio = prio; - } - } - } - - if (max_irq) { - sifive_plic_set_pending(plic, max_irq, false); - sifive_plic_set_claimed(plic, max_irq, true); - } - return max_irq; -} - -static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) -{ - SiFivePLICState *plic = opaque; - - /* writes must be 4 byte words */ - if ((addr & 0x3) != 0) { - goto err; - } - - if (addr >= plic->priority_base && /* 4 bytes per source */ - addr < plic->priority_base + (plic->num_sources << 2)) - { - uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: read priority: irq=%d priority=%d\n", - irq, plic->source_priority[irq]); - } - return plic->source_priority[irq]; - } else if (addr >= plic->pending_base && /* 1 bit per source */ - addr < plic->pending_base + (plic->num_sources >> 3)) - { - uint32_t word = (addr - plic->pending_base) >> 2; - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: read pending: word=%d value=%d\n", - word, plic->pending[word]); - } - return plic->pending[word]; - } else if (addr >= plic->enable_base && /* 1 bit per source */ - addr < plic->enable_base + plic->num_addrs * plic->enable_stride) - { - uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride; - uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2; - if (wordid < plic->bitfield_words) { - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: read enable: hart%d-%c word=%d value=%x\n", - plic->addr_config[addrid].hartid, - mode_to_char(plic->addr_config[addrid].mode), wordid, - plic->enable[addrid * plic->bitfield_words + wordid]); - } - return plic->enable[addrid * plic->bitfield_words + wordid]; - } - } else if (addr >= plic->context_base && /* 1 bit per source */ - addr < plic->context_base + plic->num_addrs * plic->context_stride) - { - uint32_t addrid = (addr - plic->context_base) / plic->context_stride; - uint32_t contextid = (addr & (plic->context_stride - 1)); - if (contextid == 0) { - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: read priority: hart%d-%c priority=%x\n", - plic->addr_config[addrid].hartid, - mode_to_char(plic->addr_config[addrid].mode), - plic->target_priority[addrid]); - } - return plic->target_priority[addrid]; - } else if (contextid == 4) { - uint32_t value = sifive_plic_claim(plic, addrid); - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: read claim: hart%d-%c irq=%x\n", - plic->addr_config[addrid].hartid, - mode_to_char(plic->addr_config[addrid].mode), - value); - } - sifive_plic_update(plic); - return value; - } - } - -err: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Invalid register read 0x%" HWADDR_PRIx "\n", - __func__, addr); - return 0; -} - -static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - SiFivePLICState *plic = opaque; - - /* writes must be 4 byte words */ - if ((addr & 0x3) != 0) { - goto err; - } - - if (addr >= plic->priority_base && /* 4 bytes per source */ - addr < plic->priority_base + (plic->num_sources << 2)) - { - uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; - plic->source_priority[irq] = value & 7; - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: write priority: irq=%d priority=%d\n", - irq, plic->source_priority[irq]); - } - sifive_plic_update(plic); - return; - } else if (addr >= plic->pending_base && /* 1 bit per source */ - addr < plic->pending_base + (plic->num_sources >> 3)) - { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid pending write: 0x%" HWADDR_PRIx "", - __func__, addr); - return; - } else if (addr >= plic->enable_base && /* 1 bit per source */ - addr < plic->enable_base + plic->num_addrs * plic->enable_stride) - { - uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride; - uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2; - if (wordid < plic->bitfield_words) { - plic->enable[addrid * plic->bitfield_words + wordid] = value; - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: write enable: hart%d-%c word=%d value=%x\n", - plic->addr_config[addrid].hartid, - mode_to_char(plic->addr_config[addrid].mode), wordid, - plic->enable[addrid * plic->bitfield_words + wordid]); - } - return; - } - } else if (addr >= plic->context_base && /* 4 bytes per reg */ - addr < plic->context_base + plic->num_addrs * plic->context_stride) - { - uint32_t addrid = (addr - plic->context_base) / plic->context_stride; - uint32_t contextid = (addr & (plic->context_stride - 1)); - if (contextid == 0) { - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: write priority: hart%d-%c priority=%x\n", - plic->addr_config[addrid].hartid, - mode_to_char(plic->addr_config[addrid].mode), - plic->target_priority[addrid]); - } - if (value <= plic->num_priorities) { - plic->target_priority[addrid] = value; - sifive_plic_update(plic); - } - return; - } else if (contextid == 4) { - if (RISCV_DEBUG_PLIC) { - qemu_log("plic: write claim: hart%d-%c irq=%x\n", - plic->addr_config[addrid].hartid, - mode_to_char(plic->addr_config[addrid].mode), - (uint32_t)value); - } - if (value < plic->num_sources) { - sifive_plic_set_claimed(plic, value, false); - sifive_plic_update(plic); - } - return; - } - } - -err: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Invalid register write 0x%" HWADDR_PRIx "\n", - __func__, addr); -} - -static const MemoryRegionOps sifive_plic_ops = { - .read = sifive_plic_read, - .write = sifive_plic_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static Property sifive_plic_properties[] = { - DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config), - DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0), - DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0), - DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0), - DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0), - DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0), - DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0), - DEFINE_PROP_UINT32("enable-stride", SiFivePLICState, enable_stride, 0), - DEFINE_PROP_UINT32("context-base", SiFivePLICState, context_base, 0), - DEFINE_PROP_UINT32("context-stride", SiFivePLICState, context_stride, 0), - DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -/* - * parse PLIC hart/mode address offset config - * - * "M" 1 hart with M mode - * "MS,MS" 2 harts, 0-1 with M and S mode - * "M,MS,MS,MS,MS" 5 harts, 0 with M mode, 1-5 with M and S mode - */ -static void parse_hart_config(SiFivePLICState *plic) -{ - int addrid, hartid, modes; - const char *p; - char c; - - /* count and validate hart/mode combinations */ - addrid = 0, hartid = 0, modes = 0; - p = plic->hart_config; - while ((c = *p++)) { - if (c == ',') { - addrid += ctpop8(modes); - modes = 0; - hartid++; - } else { - int m = 1 << char_to_mode(c); - if (modes == (modes | m)) { - error_report("plic: duplicate mode '%c' in config: %s", - c, plic->hart_config); - exit(1); - } - modes |= m; - } - } - if (modes) { - addrid += ctpop8(modes); - } - hartid++; - - plic->num_addrs = addrid; - plic->num_harts = hartid; - - /* store hart/mode combinations */ - plic->addr_config = g_new(PLICAddr, plic->num_addrs); - addrid = 0, hartid = plic->hartid_base; - p = plic->hart_config; - while ((c = *p++)) { - if (c == ',') { - hartid++; - } else { - plic->addr_config[addrid].addrid = addrid; - plic->addr_config[addrid].hartid = hartid; - plic->addr_config[addrid].mode = char_to_mode(c); - addrid++; - } - } -} - -static void sifive_plic_irq_request(void *opaque, int irq, int level) -{ - SiFivePLICState *plic = opaque; - if (RISCV_DEBUG_PLIC) { - qemu_log("sifive_plic_irq_request: irq=%d level=%d\n", irq, level); - } - sifive_plic_set_pending(plic, irq, level > 0); - sifive_plic_update(plic); -} - -static void sifive_plic_realize(DeviceState *dev, Error **errp) -{ - SiFivePLICState *plic = SIFIVE_PLIC(dev); - int i; - - memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic, - TYPE_SIFIVE_PLIC, plic->aperture_size); - parse_hart_config(plic); - plic->bitfield_words = (plic->num_sources + 31) >> 5; - plic->source_priority = g_new0(uint32_t, plic->num_sources); - plic->target_priority = g_new(uint32_t, plic->num_addrs); - plic->pending = g_new0(uint32_t, plic->bitfield_words); - plic->claimed = g_new0(uint32_t, plic->bitfield_words); - plic->enable = g_new0(uint32_t, plic->bitfield_words * plic->num_addrs); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio); - qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources); - - /* We can't allow the supervisor to control SEIP as this would allow the - * supervisor to clear a pending external interrupt which will result in - * lost a interrupt in the case a PLIC is attached. The SEIP bit must be - * hardware controlled when a PLIC is attached. - */ - for (i = 0; i < plic->num_harts; i++) { - RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(plic->hartid_base + i)); - if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { - error_report("SEIP already claimed"); - exit(1); - } - } - - msi_nonbroken = true; -} - -static void sifive_plic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - device_class_set_props(dc, sifive_plic_properties); - dc->realize = sifive_plic_realize; -} - -static const TypeInfo sifive_plic_info = { - .name = TYPE_SIFIVE_PLIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SiFivePLICState), - .class_init = sifive_plic_class_init, -}; - -static void sifive_plic_register_types(void) -{ - type_register_static(&sifive_plic_info); -} - -type_init(sifive_plic_register_types) - -/* - * Create PLIC device. - */ -DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, - uint32_t hartid_base, uint32_t num_sources, - uint32_t num_priorities, uint32_t priority_base, - uint32_t pending_base, uint32_t enable_base, - uint32_t enable_stride, uint32_t context_base, - uint32_t context_stride, uint32_t aperture_size) -{ - DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC); - assert(enable_stride == (enable_stride & -enable_stride)); - assert(context_stride == (context_stride & -context_stride)); - qdev_prop_set_string(dev, "hart-config", hart_config); - qdev_prop_set_uint32(dev, "hartid-base", hartid_base); - qdev_prop_set_uint32(dev, "num-sources", num_sources); - qdev_prop_set_uint32(dev, "num-priorities", num_priorities); - qdev_prop_set_uint32(dev, "priority-base", priority_base); - qdev_prop_set_uint32(dev, "pending-base", pending_base); - qdev_prop_set_uint32(dev, "enable-base", enable_base); - qdev_prop_set_uint32(dev, "enable-stride", enable_stride); - qdev_prop_set_uint32(dev, "context-base", context_base); - qdev_prop_set_uint32(dev, "context-stride", context_stride); - qdev_prop_set_uint32(dev, "aperture-size", aperture_size); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); - return dev; -} diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7187d1ad17..faca2e829e 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -46,11 +46,11 @@ #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_uart.h" #include "hw/riscv/sifive_u.h" #include "hw/riscv/boot.h" #include "hw/intc/sifive_clint.h" +#include "hw/intc/sifive_plic.h" #include "chardev/char.h" #include "net/eth.h" #include "sysemu/arch_init.h" diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index bce2020d02..0caab8e050 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -30,12 +30,12 @@ #include "hw/char/serial.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" -#include "hw/riscv/sifive_plic.h" #include "hw/riscv/sifive_test.h" #include "hw/riscv/virt.h" #include "hw/riscv/boot.h" #include "hw/riscv/numa.h" #include "hw/intc/sifive_clint.h" +#include "hw/intc/sifive_plic.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" diff --git a/include/hw/riscv/sifive_plic.h b/include/hw/riscv/sifive_plic.h deleted file mode 100644 index ace76d0f1b..0000000000 --- a/include/hw/riscv/sifive_plic.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SiFive PLIC (Platform Level Interrupt Controller) interface - * - * Copyright (c) 2017 SiFive, Inc. - * - * This provides a RISC-V PLIC device - * - * 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 . - */ - -#ifndef HW_SIFIVE_PLIC_H -#define HW_SIFIVE_PLIC_H - -#include "hw/sysbus.h" - -#define TYPE_SIFIVE_PLIC "riscv.sifive.plic" - -#define SIFIVE_PLIC(obj) \ - OBJECT_CHECK(SiFivePLICState, (obj), TYPE_SIFIVE_PLIC) - -typedef enum PLICMode { - PLICMode_U, - PLICMode_S, - PLICMode_H, - PLICMode_M -} PLICMode; - -typedef struct PLICAddr { - uint32_t addrid; - uint32_t hartid; - PLICMode mode; -} PLICAddr; - -typedef struct SiFivePLICState { - /*< private >*/ - SysBusDevice parent_obj; - - /*< public >*/ - MemoryRegion mmio; - uint32_t num_addrs; - uint32_t num_harts; - uint32_t bitfield_words; - PLICAddr *addr_config; - uint32_t *source_priority; - uint32_t *target_priority; - uint32_t *pending; - uint32_t *claimed; - uint32_t *enable; - - /* config */ - char *hart_config; - uint32_t hartid_base; - uint32_t num_sources; - uint32_t num_priorities; - uint32_t priority_base; - uint32_t pending_base; - uint32_t enable_base; - uint32_t enable_stride; - uint32_t context_base; - uint32_t context_stride; - uint32_t aperture_size; -} SiFivePLICState; - -DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, - uint32_t hartid_base, uint32_t num_sources, - uint32_t num_priorities, uint32_t priority_base, - uint32_t pending_base, uint32_t enable_base, - uint32_t enable_stride, uint32_t context_base, - uint32_t context_stride, uint32_t aperture_size); - -#endif -- cgit v1.2.3-55-g7522 From a4b84608ba0eecce1d4858181457dc26582e6d28 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 3 Sep 2020 18:40:20 +0800 Subject: hw/riscv: Move sifive_test model to hw/misc This is an effort to clean up the hw/riscv directory. Ideally it should only contain the RISC-V SoC / machine codes plus generic codes. Let's move sifive_test model to hw/misc directory. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1599129623-68957-10-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/misc/Kconfig | 3 ++ hw/misc/meson.build | 1 + hw/misc/sifive_test.c | 100 +++++++++++++++++++++++++++++++++++++++++ hw/riscv/Kconfig | 1 + hw/riscv/meson.build | 1 - hw/riscv/sifive_test.c | 100 ----------------------------------------- hw/riscv/virt.c | 2 +- include/hw/misc/sifive_test.h | 45 +++++++++++++++++++ include/hw/riscv/sifive_test.h | 45 ------------------- 9 files changed, 151 insertions(+), 147 deletions(-) create mode 100644 hw/misc/sifive_test.c delete mode 100644 hw/riscv/sifive_test.c create mode 100644 include/hw/misc/sifive_test.h delete mode 100644 include/hw/riscv/sifive_test.h (limited to 'hw/riscv/virt.c') diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index fa3d0f4723..3185456110 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -134,6 +134,9 @@ config MAC_VIA config AVR_POWER bool +config SIFIVE_TEST + bool + config SIFIVE_E_PRCI bool diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 018a88c670..bd24132757 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -22,6 +22,7 @@ softmmu_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c')) softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) # RISC-V devices +softmmu_ss.add(when: 'CONFIG_SIFIVE_TEST', if_true: files('sifive_test.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c')) diff --git a/hw/misc/sifive_test.c b/hw/misc/sifive_test.c new file mode 100644 index 0000000000..2deb2072cc --- /dev/null +++ b/hw/misc/sifive_test.c @@ -0,0 +1,100 @@ +/* + * QEMU SiFive Test Finisher + * + * Copyright (c) 2018 SiFive, Inc. + * + * Test finisher memory mapped device used to exit simulation + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "sysemu/runstate.h" +#include "hw/hw.h" +#include "hw/misc/sifive_test.h" + +static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size) +{ + return 0; +} + +static void sifive_test_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + if (addr == 0) { + int status = val64 & 0xffff; + int code = (val64 >> 16) & 0xffff; + switch (status) { + case FINISHER_FAIL: + exit(code); + case FINISHER_PASS: + exit(0); + case FINISHER_RESET: + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + default: + break; + } + } + 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 = { + .read = sifive_test_read, + .write = sifive_test_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 2, + .max_access_size = 4 + } +}; + +static void sifive_test_init(Object *obj) +{ + SiFiveTestState *s = SIFIVE_TEST(obj); + + memory_region_init_io(&s->mmio, obj, &sifive_test_ops, s, + TYPE_SIFIVE_TEST, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static const TypeInfo sifive_test_info = { + .name = TYPE_SIFIVE_TEST, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveTestState), + .instance_init = sifive_test_init, +}; + +static void sifive_test_register_types(void) +{ + type_register_static(&sifive_test_info); +} + +type_init(sifive_test_register_types) + + +/* + * Create Test device. + */ +DeviceState *sifive_test_create(hwaddr addr) +{ + DeviceState *dev = qdev_new(TYPE_SIFIVE_TEST); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); + return dev; +} diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index a0461578a6..8e0710001b 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -61,6 +61,7 @@ config RISCV_VIRT select SIFIVE select SIFIVE_CLINT select SIFIVE_PLIC + select SIFIVE_TEST config MICROCHIP_PFSOC bool diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 967572d4f6..f762623288 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -4,7 +4,6 @@ riscv_ss.add(files('numa.c')) riscv_ss.add(when: 'CONFIG_HART', if_true: files('riscv_hart.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) -riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_test.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) diff --git a/hw/riscv/sifive_test.c b/hw/riscv/sifive_test.c deleted file mode 100644 index 8c70dd69df..0000000000 --- a/hw/riscv/sifive_test.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * QEMU SiFive Test Finisher - * - * Copyright (c) 2018 SiFive, Inc. - * - * Test finisher memory mapped device used to exit simulation - * - * 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 . - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qapi/error.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "sysemu/runstate.h" -#include "hw/hw.h" -#include "hw/riscv/sifive_test.h" - -static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size) -{ - return 0; -} - -static void sifive_test_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - if (addr == 0) { - int status = val64 & 0xffff; - int code = (val64 >> 16) & 0xffff; - switch (status) { - case FINISHER_FAIL: - exit(code); - case FINISHER_PASS: - exit(0); - case FINISHER_RESET: - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - return; - default: - break; - } - } - 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 = { - .read = sifive_test_read, - .write = sifive_test_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 2, - .max_access_size = 4 - } -}; - -static void sifive_test_init(Object *obj) -{ - SiFiveTestState *s = SIFIVE_TEST(obj); - - memory_region_init_io(&s->mmio, obj, &sifive_test_ops, s, - TYPE_SIFIVE_TEST, 0x1000); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); -} - -static const TypeInfo sifive_test_info = { - .name = TYPE_SIFIVE_TEST, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SiFiveTestState), - .instance_init = sifive_test_init, -}; - -static void sifive_test_register_types(void) -{ - type_register_static(&sifive_test_info); -} - -type_init(sifive_test_register_types) - - -/* - * Create Test device. - */ -DeviceState *sifive_test_create(hwaddr addr) -{ - DeviceState *dev = qdev_new(TYPE_SIFIVE_TEST); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); - return dev; -} diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 0caab8e050..41bd2f38ba 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -30,12 +30,12 @@ #include "hw/char/serial.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" -#include "hw/riscv/sifive_test.h" #include "hw/riscv/virt.h" #include "hw/riscv/boot.h" #include "hw/riscv/numa.h" #include "hw/intc/sifive_clint.h" #include "hw/intc/sifive_plic.h" +#include "hw/misc/sifive_test.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" diff --git a/include/hw/misc/sifive_test.h b/include/hw/misc/sifive_test.h new file mode 100644 index 0000000000..1ec416ac1b --- /dev/null +++ b/include/hw/misc/sifive_test.h @@ -0,0 +1,45 @@ +/* + * QEMU Test Finisher interface + * + * Copyright (c) 2018 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 . + */ + +#ifndef HW_SIFIVE_TEST_H +#define HW_SIFIVE_TEST_H + +#include "hw/sysbus.h" + +#define TYPE_SIFIVE_TEST "riscv.sifive.test" + +#define SIFIVE_TEST(obj) \ + OBJECT_CHECK(SiFiveTestState, (obj), TYPE_SIFIVE_TEST) + +typedef struct SiFiveTestState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion mmio; +} SiFiveTestState; + +enum { + FINISHER_FAIL = 0x3333, + FINISHER_PASS = 0x5555, + FINISHER_RESET = 0x7777 +}; + +DeviceState *sifive_test_create(hwaddr addr); + +#endif diff --git a/include/hw/riscv/sifive_test.h b/include/hw/riscv/sifive_test.h deleted file mode 100644 index 1ec416ac1b..0000000000 --- a/include/hw/riscv/sifive_test.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * QEMU Test Finisher interface - * - * Copyright (c) 2018 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 . - */ - -#ifndef HW_SIFIVE_TEST_H -#define HW_SIFIVE_TEST_H - -#include "hw/sysbus.h" - -#define TYPE_SIFIVE_TEST "riscv.sifive.test" - -#define SIFIVE_TEST(obj) \ - OBJECT_CHECK(SiFiveTestState, (obj), TYPE_SIFIVE_TEST) - -typedef struct SiFiveTestState { - /*< private >*/ - SysBusDevice parent_obj; - - /*< public >*/ - MemoryRegion mmio; -} SiFiveTestState; - -enum { - FINISHER_FAIL = 0x3333, - FINISHER_PASS = 0x5555, - FINISHER_RESET = 0x7777 -}; - -DeviceState *sifive_test_create(hwaddr addr); - -#endif -- cgit v1.2.3-55-g7522