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 | 77 ++++++++++++++++++++++++++++++++++++++ include/hw/riscv/virt.h | 2 + target/riscv/cpu.h | 9 +++++ target/riscv/tcg/tcg-cpu.c | 5 +++ 4 files changed, 93 insertions(+) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 17909206c7..b1a4d63efd 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -58,6 +58,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" /* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */ static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type) @@ -79,6 +81,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 }, @@ -88,7 +101,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) }, @@ -1525,6 +1540,64 @@ 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) +{ + 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; + + ram_sink = qdev_new(TYPE_TRACE_RAM_SINK); + + ram_sink_addr = virt_memmap[VIRT_TR_RAM_SINKS].base + + TRACE_RAM_SINK_SIZE * cpu; + /* 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; + + object_property_set_link(OBJECT(trencoder), "cpu", + OBJECT(cpu_ptr), &error_fatal); + object_property_set_int(OBJECT(trencoder), "cpu-id", cpu, &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); @@ -1580,6 +1653,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 7b4c2c8b7d..e2aa6fbbcd 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -88,6 +88,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 36e7f10037..12251e4d94 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -553,6 +553,15 @@ struct ArchCPU { /* Mapping of events to counters */ GHashTable *pmu_event_ctr_map; 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 d3968251fa..a381ee2840 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -37,6 +37,7 @@ #include "hw/boards.h" #include "system/tcg.h" #include "exec/icount.h" +#include "hw/riscv/trace-encoder.h" #endif /* Hash that stores user set extensions */ @@ -1297,6 +1298,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.51.1
