@@ -116,6 +116,9 @@ struct arm_boot_info {
*/
bool secure_board_setup;
+ /* If set, all ram objects have tag memory objects. */
+ bool tag_memory;
+
arm_endianness endianness;
};
@@ -792,6 +792,10 @@ struct ARMCPU {
/* MemoryRegion to use for secure physical accesses */
MemoryRegion *secure_memory;
+ /* MemoryRegion to use for allocation tag accesses */
+ MemoryRegion *tag_memory;
+ MemoryRegion *secure_tag_memory;
+
/* For v8M, pointer to the IDAU interface provided by board/SoC */
Object *idau;
@@ -2985,6 +2989,8 @@ typedef enum ARMMMUIdxBit {
typedef enum ARMASIdx {
ARMASIdx_NS = 0,
ARMASIdx_S = 1,
+ ARMASIdx_TagNS = 2,
+ ARMASIdx_TagS = 3,
} ARMASIdx;
/* Return the Exception Level targeted by debug exceptions. */
@@ -427,7 +427,7 @@ static void set_kernel_args_old(const struct arm_boot_info *info,
static int fdt_add_memory_node(void *fdt, uint32_t acells, hwaddr mem_base,
uint32_t scells, hwaddr mem_len,
- int numa_node_id)
+ int numa_node_id, bool tag_memory)
{
char *nodename;
int ret;
@@ -446,6 +446,10 @@ static int fdt_add_memory_node(void *fdt, uint32_t acells, hwaddr mem_base,
ret = qemu_fdt_setprop_cell(fdt, nodename,
"numa-node-id", numa_node_id);
}
+ if (tag_memory) {
+ qemu_fdt_setprop(fdt, nodename, "arm,armv8.5-memtag", "", 0);
+ }
+
out:
g_free(nodename);
return ret;
@@ -534,6 +538,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
hwaddr mem_base, mem_len;
char **node_path;
Error *err = NULL;
+ bool tag_memory;
if (binfo->dtb_filename) {
char *filename;
@@ -599,12 +604,13 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
}
g_strfreev(node_path);
+ tag_memory = binfo->tag_memory;
if (ms->numa_state != NULL && ms->numa_state->num_nodes > 0) {
mem_base = binfo->loader_start;
for (i = 0; i < ms->numa_state->num_nodes; i++) {
mem_len = ms->numa_state->nodes[i].node_mem;
rc = fdt_add_memory_node(fdt, acells, mem_base,
- scells, mem_len, i);
+ scells, mem_len, i, tag_memory);
if (rc < 0) {
fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
mem_base);
@@ -615,7 +621,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
}
} else {
rc = fdt_add_memory_node(fdt, acells, binfo->loader_start,
- scells, binfo->ram_size, -1);
+ scells, binfo->ram_size, -1, tag_memory);
if (rc < 0) {
fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
binfo->loader_start);
@@ -1390,8 +1390,19 @@ static void create_platform_bus(VirtMachineState *vms)
sysbus_mmio_get_region(s, 0));
}
+static void create_tag_ram(MemoryRegion *tag_sysmem,
+ hwaddr base, hwaddr size,
+ const char *name)
+{
+ MemoryRegion *tagram = g_new(MemoryRegion, 1);
+
+ memory_region_init_ram(tagram, NULL, name, size / 32, &error_fatal);
+ memory_region_add_subregion(tag_sysmem, base / 32, tagram);
+}
+
static void create_secure_ram(VirtMachineState *vms,
- MemoryRegion *secure_sysmem)
+ MemoryRegion *secure_sysmem,
+ MemoryRegion *secure_tag_sysmem)
{
MemoryRegion *secram = g_new(MemoryRegion, 1);
char *nodename;
@@ -1409,6 +1420,11 @@ static void create_secure_ram(VirtMachineState *vms,
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
+ if (secure_tag_sysmem) {
+ create_tag_ram(secure_tag_sysmem, base, size, "mach-virt.secure-tag");
+ qemu_fdt_setprop(vms->fdt, nodename, "arm,armv8.5-memtag", "", 0);
+ }
+
g_free(nodename);
}
@@ -1665,6 +1681,8 @@ static void machvirt_init(MachineState *machine)
const CPUArchIdList *possible_cpus;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *secure_sysmem = NULL;
+ MemoryRegion *tag_sysmem = NULL;
+ MemoryRegion *secure_tag_sysmem = NULL;
int n, virt_max_cpus;
bool firmware_loaded;
bool aarch64 = true;
@@ -1819,6 +1837,36 @@ static void machvirt_init(MachineState *machine)
"secure-memory", &error_abort);
}
+ /*
+ * The cpu adds the property if and only if MemTag is supported.
+ * If it is, we must allocate the ram to back that up.
+ */
+ if (object_property_find(cpuobj, "tag-memory", NULL)) {
+ if (!tag_sysmem) {
+ vms->bootinfo.tag_memory = true;
+ tag_sysmem = g_new(MemoryRegion, 1);
+ memory_region_init(tag_sysmem, OBJECT(machine),
+ "tag-memory", UINT64_MAX / 32);
+
+ if (vms->secure) {
+ secure_tag_sysmem = g_new(MemoryRegion, 1);
+ memory_region_init(secure_tag_sysmem, OBJECT(machine),
+ "secure-tag-memory", UINT64_MAX / 32);
+
+ /* As with ram, secure-tag takes precedence over tag. */
+ memory_region_add_subregion_overlap(secure_tag_sysmem, 0,
+ tag_sysmem, -1);
+ }
+ }
+
+ object_property_set_link(cpuobj, OBJECT(tag_sysmem),
+ "tag-memory", &error_abort);
+ if (vms->secure) {
+ object_property_set_link(cpuobj, OBJECT(secure_tag_sysmem),
+ "secure-tag-memory", &error_abort);
+ }
+ }
+
qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
object_unref(cpuobj);
}
@@ -1857,10 +1905,15 @@ static void machvirt_init(MachineState *machine)
create_uart(vms, VIRT_UART, sysmem, serial_hd(0));
if (vms->secure) {
- create_secure_ram(vms, secure_sysmem);
+ create_secure_ram(vms, secure_sysmem, secure_tag_sysmem);
create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1));
}
+ if (tag_sysmem) {
+ create_tag_ram(tag_sysmem, vms->memmap[VIRT_MEM].base,
+ machine->ram_size, "mach-virt.tag");
+ }
+
vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64);
create_rtc(vms);
@@ -1249,6 +1249,25 @@ void arm_cpu_post_init(Object *obj)
if (kvm_enabled()) {
kvm_arm_add_vcpu_properties(obj);
}
+
+#ifndef CONFIG_USER_ONLY
+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) &&
+ cpu_isar_feature(aa64_mte, cpu)) {
+ object_property_add_link(obj, "tag-memory",
+ TYPE_MEMORY_REGION,
+ (Object **)&cpu->tag_memory,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
+ object_property_add_link(obj, "secure-tag-memory",
+ TYPE_MEMORY_REGION,
+ (Object **)&cpu->secure_tag_memory,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+ }
+#endif
}
static void arm_cpu_finalizefn(Object *obj)
@@ -1739,17 +1758,43 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
MachineState *ms = MACHINE(qdev_get_machine());
unsigned int smp_cpus = ms->smp.cpus;
- if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ /*
+ * We must set cs->num_ases to the final value before
+ * the first call to cpu_address_space_init.
+ */
+ if (cpu->tag_memory != NULL) {
+ cs->num_ases = 4;
+ } else if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
cs->num_ases = 2;
+ } else {
+ cs->num_ases = 1;
+ }
+ if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
if (!cpu->secure_memory) {
cpu->secure_memory = cs->memory;
}
cpu_address_space_init(cs, ARMASIdx_S, "cpu-secure-memory",
cpu->secure_memory);
- } else {
- cs->num_ases = 1;
}
+
+ if (cpu->tag_memory != NULL) {
+ cpu_address_space_init(cs, ARMASIdx_TagNS, "cpu-tag-memory",
+ cpu->tag_memory);
+ if (cpu->has_el3) {
+ cpu_address_space_init(cs, ARMASIdx_TagS, "cpu-tag-memory",
+ cpu->secure_tag_memory);
+ }
+ } else if (cpu_isar_feature(aa64_mte, cpu)) {
+ /*
+ * Since there is no tag memory, we can't meaningfully support MTE
+ * to its fullest. To avoid problems later, when we would come to
+ * use the tag memory, downgrade support to insns only.
+ */
+ cpu->isar.id_aa64pfr1 =
+ FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 1);
+ }
+
cpu_address_space_init(cs, ARMASIdx_NS, "cpu-memory", cs->memory);
/* No core_count specified, default to smp_cpus. */
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- v5: Assign cs->num_ases to the final value first. Downgrade to ID_AA64PFR1.MTE=1 if tag memory is not available. v6: Add secure tag memory for EL3. v8: Add arm,armv8.5-memtag. --- include/hw/arm/boot.h | 3 +++ target/arm/cpu.h | 6 +++++ hw/arm/boot.c | 12 ++++++--- hw/arm/virt.c | 57 +++++++++++++++++++++++++++++++++++++++++-- target/arm/cpu.c | 51 +++++++++++++++++++++++++++++++++++--- 5 files changed, 121 insertions(+), 8 deletions(-) -- 2.25.1