Add the minimal topology required for e-trace support in the virt machine, e.g. each CPU will have a single trace encoder, and each trace encoder will communicate to a single associated trace ram sink.
At this moment we're not going to support more complex topologies with trace funnels and so on. Signed-off-by: Daniel Henrique Barboza <[email protected]> --- hw/riscv/virt.c | 81 ++++++++++++++++++++++++++++++++++++++ include/hw/riscv/virt.h | 2 + target/riscv/cpu.h | 9 +++++ target/riscv/tcg/tcg-cpu.c | 5 +++ 4 files changed, 97 insertions(+) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index d4b501802f..d47b295f0c 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -60,6 +60,8 @@ #include "qapi/qapi-visit-common.h" #include "hw/virtio/virtio-iommu.h" #include "hw/uefi/var-service-api.h" +#include "hw/riscv/trace-encoder.h" +#include "hw/riscv/trace-ram-sink.h" #include "aia.h" @@ -83,6 +85,17 @@ static bool virt_aclint_allowed(void) return tcg_enabled() || qtest_enabled(); } +#define TR_DEV_REGMAP_SIZE 0x1000 +/* For VIRT_CPUS_MAX = 512: TRACE_DEV_REG_MAX = 0x200000 */ +#define TRACE_DEV_REG_MAX (TR_DEV_REGMAP_SIZE * VIRT_CPUS_MAX) + +/* + * 64k for the RAM Sink that includes the 4k (0x1000) + * for regs, for each possible CPU. For 512 max CPUs, + * total size = 0x2000000. + */ +#define TRACE_RAM_SINK_SIZE (1UL << 16) + static const MemMapEntry virt_memmap[] = { [VIRT_DEBUG] = { 0x0, 0x100 }, [VIRT_MROM] = { 0x1000, 0xf000 }, @@ -92,7 +105,9 @@ static const MemMapEntry virt_memmap[] = { [VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 }, [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, [VIRT_IOMMU_SYS] = { 0x3010000, 0x1000 }, + [VIRT_TR_ENCODERS] = { 0x3020000, TRACE_DEV_REG_MAX }, [VIRT_PLATFORM_BUS] = { 0x4000000, 0x2000000 }, + [VIRT_TR_RAM_SINKS] = { 0x6000000, TRACE_RAM_SINK_SIZE * VIRT_CPUS_MAX }, [VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) }, [VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) }, [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) }, @@ -710,6 +725,68 @@ static void virt_machine_done(Notifier *notifier, void *data) } } +/* + * Must be called after 'soc' realize since it + * uses CPU objs. + */ +static void virt_init_socket_trace_hw(RISCVVirtState *s, int socket_num) +{ + int hartid_base = s->soc[socket_num].hartid_base; + + for (int cpu = 0; cpu < s->soc[socket_num].num_harts; cpu++) { + RISCVCPU *cpu_ptr = &s->soc[socket_num].harts[cpu]; + DeviceState *trencoder, *ram_sink; + uint64_t trencoder_addr, ram_sink_addr, smem_addr; + uint32_t smem_size = TRACE_RAM_SINK_SIZE - TR_DEV_REGMAP_SIZE; + int cpu_id = hartid_base + cpu; + + ram_sink = qdev_new(TYPE_TRACE_RAM_SINK); + + ram_sink_addr = virt_memmap[VIRT_TR_RAM_SINKS].base + + TRACE_RAM_SINK_SIZE * cpu_id; + /* smem is located right after ram sink base */ + smem_addr = ram_sink_addr + TR_DEV_REGMAP_SIZE; + + object_property_set_uint(OBJECT(ram_sink), "baseaddr", + ram_sink_addr, &error_fatal); + object_property_set_uint(OBJECT(ram_sink), "smemaddr", + smem_addr, &error_fatal); + object_property_set_uint(OBJECT(ram_sink), "smemsize", + smem_size, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ram_sink), &error_fatal); + + /* + * We can't do object_property_set_link() because we're + * coming after cpu.realize() (the riscv_hart obj creates + * the CPU objs in its realize() since it has no init). + * We need changes in how riscv_hart works to use + * set_link() and to not manually realize the trace + * encoder. + * + * For now do everything manually. + */ + trencoder = qdev_new(TYPE_TRACE_ENCODER); + cpu_ptr->trencoder = OBJECT(trencoder); + + trencoder_addr = virt_memmap[VIRT_TR_ENCODERS].base + + TR_DEV_REGMAP_SIZE * cpu_id; + + object_property_set_link(OBJECT(trencoder), "cpu", + OBJECT(cpu_ptr), &error_fatal); + object_property_set_int(OBJECT(trencoder), "cpu-id", cpu_id, + &error_fatal); + object_property_set_uint(OBJECT(trencoder), "baseaddr", + trencoder_addr, &error_fatal); + object_property_set_uint(OBJECT(trencoder), "dest-baseaddr", + ram_sink_addr, &error_fatal); + object_property_set_uint(OBJECT(trencoder), "ramsink-ramstart", + smem_addr, &error_fatal); + object_property_set_uint(OBJECT(trencoder), "ramsink-ramlimit", + smem_addr + smem_size, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(trencoder), &error_fatal); + } +} + static void virt_machine_init(MachineState *machine) { RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); @@ -765,6 +842,10 @@ static void virt_machine_init(MachineState *machine) hart_count, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal); + if (tcg_enabled()) { + virt_init_socket_trace_hw(s, i); + } + if (virt_aclint_allowed() && s->have_aclint) { if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { /* Per-socket ACLINT MTIMER */ diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index e516898f9a..f3744f48c2 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -91,6 +91,8 @@ enum { VIRT_PLATFORM_BUS, VIRT_PCIE_ECAM, VIRT_IOMMU_SYS, + VIRT_TR_ENCODERS, + VIRT_TR_RAM_SINKS, }; enum { diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index b65d631994..e2ded4c257 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -593,6 +593,15 @@ struct ArchCPU { GHashTable *misa_ext_user_opts; GHashTable *multi_ext_user_opts; const GPtrArray *decoders; + +#ifndef CONFIG_USER_ONLY + /* + * Associated Trace Encoder. It will not be NULL if + * we're running with TCG and initialized manually by + * the board. + */ + Object *trencoder; +#endif }; typedef struct RISCVCSR RISCVCSR; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index e07ca95e49..6e74d6a4de 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -39,6 +39,7 @@ #include "exec/icount.h" #include "target/riscv/tcg/debug.h" #include "target/riscv/tcg/csr.h" +#include "hw/riscv/trace-encoder.h" #endif static GHashTable *multi_ext_implied_rules; @@ -1366,6 +1367,10 @@ static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) if (riscv_has_ext(env, RVH)) { env->mideleg = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP | MIP_SGEIP; } + + if (cpu->trencoder) { + qdev_realize(DEVICE(cpu->trencoder), NULL, &error_fatal); + } #endif return true; -- 2.43.0
