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 <dbarboza@ventanamicro.com>
---
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