[RFC PATCH 5/7] hw/arm/virt: Add machine option 'mec'

Gustavo Romero posted 7 patches 2 weeks, 4 days ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>
[RFC PATCH 5/7] hw/arm/virt: Add machine option 'mec'
Posted by Gustavo Romero 2 weeks, 4 days ago
Add new machine option 'mec' that enables and sets the memory used by
FEAT_MEC.

Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>
---
 hw/arm/virt.c         | 76 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/virt.h |  1 +
 2 files changed, 77 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index cab2e21e8a..7d127a4205 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1762,6 +1762,27 @@ static void create_tag_ram(MemoryRegion *tag_sysmem,
     memory_region_add_subregion(tag_sysmem, base / 32, tagram);
 }
 
+static void create_mec_ram(MemoryRegion *tag_sysmem,
+                           hwaddr base, hwaddr size,
+                           const char *name)
+{
+    memory_region_init_ram(tag_sysmem, NULL, name, size / 32, &error_fatal);
+}
+
+static void create_mec_ram_fake_page(MemoryRegion *mr, uint64_t size, const char *name)
+{
+    assert(is_power_of_2(size) );
+    assert(size >= sizeof(uint32_t));
+
+    uint32_t *ptr = g_malloc(size);
+
+    for (int i = 0; i < size / sizeof(uint32_t); i++) {
+        ptr[i] = 0xDEADBEEF;
+    }
+
+    memory_region_init_ram_ptr(mr, NULL, name, size, ptr);
+}
+
 static void create_secure_ram(VirtMachineState *vms,
                               MemoryRegion *secure_sysmem,
                               MemoryRegion *secure_tag_sysmem)
@@ -2267,6 +2288,8 @@ static void machvirt_init(MachineState *machine)
     MemoryRegion *secure_sysmem = NULL;
     MemoryRegion *tag_sysmem = NULL;
     MemoryRegion *secure_tag_sysmem = NULL;
+    MemoryRegion *pseudo_encrypted_page = NULL;
+    MemoryRegion *tuple_memory = NULL;
     int n, virt_max_cpus;
     bool firmware_loaded;
     bool aarch64 = true;
@@ -2495,6 +2518,28 @@ static void machvirt_init(MachineState *machine)
             }
         }
 
+        if (vms->mec) {
+            if (tcg_enabled()) {
+                if (tuple_memory == NULL) {
+                    /* XXX(gromero): Add object_property_find(cpuobj, "tuple-memory", ...) here. */
+
+                    tuple_memory = g_new(MemoryRegion, 1);
+                    memory_region_init(tuple_memory, OBJECT(machine), "mec", UINT64_MAX / 32);
+
+                    pseudo_encrypted_page = g_new(MemoryRegion, 1);
+                    memory_region_init(pseudo_encrypted_page, OBJECT(machine), "mec-page", 4 * 1024 /* 4 KiB */);
+                }
+
+                object_property_set_link(cpuobj, "mec",  OBJECT(tuple_memory), &error_abort);
+                object_property_set_link(cpuobj, "mec-page",  OBJECT(pseudo_encrypted_page), &error_abort);
+
+                } else {
+                    /* Check for other accels here. */
+                    error_report("MEC requested, but not supported");
+                    exit(1);
+                }
+        }
+
         qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
         object_unref(cpuobj);
     }
@@ -2561,6 +2606,14 @@ static void machvirt_init(MachineState *machine)
                        machine->ram_size, "mach-virt.tag");
     }
 
+    if (tuple_memory) {
+        create_mec_ram(tuple_memory, vms->memmap[VIRT_MEM].base, machine->ram_size, "tuple-memory");
+    }
+
+    if(pseudo_encrypted_page) {
+       create_mec_ram_fake_page(pseudo_encrypted_page, 4 * 1024, "mec-fake-page");
+    }
+
     vms->highmem_ecam &= (!firmware_loaded || aarch64);
 
     create_rtc(vms);
@@ -2966,6 +3019,20 @@ static void virt_set_mte(Object *obj, bool value, Error **errp)
     vms->mte = value;
 }
 
+static bool virt_get_mec(Object *obj, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+
+    return vms->mec;
+}
+
+static void virt_set_mec(Object *obj, bool value, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+
+    vms->mec = value;
+}
+
 static char *virt_get_gic_version(Object *obj, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -3602,6 +3669,12 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
                                           "guest CPU which implements the ARM "
                                           "Memory Tagging Extension");
 
+    object_class_property_add_bool(oc, "mec", virt_get_mec, virt_set_mec);
+    object_class_property_set_description(oc, "mec",
+		                          "Set on/off to enable/disable emulating a"
+					  "guest CPU which implements the ARM"
+					  "Memory Encryption Extention");
+
     object_class_property_add_bool(oc, "its", virt_get_its,
                                    virt_set_its);
     object_class_property_set_description(oc, "its",
@@ -3686,6 +3759,9 @@ static void virt_instance_init(Object *obj)
     /* MTE is disabled by default.  */
     vms->mte = false;
 
+    /* FEAT_MEC is disabled by default. */
+    vms->mec = false;
+
     /* Supply kaslr-seed and rng-seed by default */
     vms->dtb_randomness = true;
 
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index dba8ac7f2f..4e49eb1d13 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -154,6 +154,7 @@ struct VirtMachineState {
     bool virt;
     bool ras;
     bool mte;
+    bool mec;
     bool dtb_randomness;
     bool second_ns_uart_present;
     OnOffAuto acpi;
-- 
2.34.1
Re: [RFC PATCH 5/7] hw/arm/virt: Add machine option 'mec'
Posted by Richard Henderson 1 week, 3 days ago
On 3/19/26 12:23, Gustavo Romero wrote:
> Add new machine option 'mec' that enables and sets the memory used by
> FEAT_MEC.
> 
> Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>
> ---
>   hw/arm/virt.c         | 76 +++++++++++++++++++++++++++++++++++++++++++
>   include/hw/arm/virt.h |  1 +
>   2 files changed, 77 insertions(+)
> 
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index cab2e21e8a..7d127a4205 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -1762,6 +1762,27 @@ static void create_tag_ram(MemoryRegion *tag_sysmem,
>       memory_region_add_subregion(tag_sysmem, base / 32, tagram);
>   }
>   
> +static void create_mec_ram(MemoryRegion *tag_sysmem,
> +                           hwaddr base, hwaddr size,
> +                           const char *name)
> +{
> +    memory_region_init_ram(tag_sysmem, NULL, name, size / 32, &error_fatal);
> +}

The "32" divisor in create_tag_ram is "2 * TAG_GRANULE", but due to placement that 
constant isn't actually visible in virt.c.  That could certainly be fixed.

Here, you want "size / TARGET_PAGE_SIZE * sizeof(mec data)", so that you store 1 "mec 
data" per page.  (IIRC the mecid is 8 bits?)

> @@ -2495,6 +2518,28 @@ static void machvirt_init(MachineState *machine)
>               }
>           }
>   
> +        if (vms->mec) {
> +            if (tcg_enabled()) {
> +                if (tuple_memory == NULL) {
> +                    /* XXX(gromero): Add object_property_find(cpuobj, "tuple-memory", ...) here. */
> +
> +                    tuple_memory = g_new(MemoryRegion, 1);
> +                    memory_region_init(tuple_memory, OBJECT(machine), "mec", UINT64_MAX / 32);

What is UINT64_MAX / 32?
Tuple memory should be tied to ram, so this should be the size of ram.

> +					  "Memory Encryption Extention");

Extension.


r~
Re: [RFC PATCH 5/7] hw/arm/virt: Add machine option 'mec'
Posted by Jonathan Cameron via qemu development 2 weeks, 4 days ago
On Wed, 18 Mar 2026 23:23:33 -0300
Gustavo Romero <gustavo.romero@linaro.org> wrote:

> Add new machine option 'mec' that enables and sets the memory used by
> FEAT_MEC.
> 
> Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>

Drive by comments only. I'm curious enough to read the patches
but no idea if this is how people would like to see this implemented!

Jonathan

>  static void create_secure_ram(VirtMachineState *vms,
>                                MemoryRegion *secure_sysmem,
>                                MemoryRegion *secure_tag_sysmem)
> @@ -2267,6 +2288,8 @@ static void machvirt_init(MachineState *machine)
>      MemoryRegion *secure_sysmem = NULL;
>      MemoryRegion *tag_sysmem = NULL;
>      MemoryRegion *secure_tag_sysmem = NULL;
> +    MemoryRegion *pseudo_encrypted_page = NULL;
> +    MemoryRegion *tuple_memory = NULL;
>      int n, virt_max_cpus;
>      bool firmware_loaded;
>      bool aarch64 = true;
> @@ -2495,6 +2518,28 @@ static void machvirt_init(MachineState *machine)
>              }
>          }
>  
> +        if (vms->mec) {
> +            if (tcg_enabled()) {
> +                if (tuple_memory == NULL) {
> +                    /* XXX(gromero): Add object_property_find(cpuobj, "tuple-memory", ...) here. */
> +
> +                    tuple_memory = g_new(MemoryRegion, 1);
> +                    memory_region_init(tuple_memory, OBJECT(machine), "mec", UINT64_MAX / 32);
> +
> +                    pseudo_encrypted_page = g_new(MemoryRegion, 1);
> +                    memory_region_init(pseudo_encrypted_page, OBJECT(machine), "mec-page", 4 * 1024 /* 4 KiB */);
> +                }
> +
> +                object_property_set_link(cpuobj, "mec",  OBJECT(tuple_memory), &error_abort);
> +                object_property_set_link(cpuobj, "mec-page",  OBJECT(pseudo_encrypted_page), &error_abort);
Trivial but some bonus spaces.

> +
> +                } else {

Indent seems off. 

> +                    /* Check for other accels here. */
> +                    error_report("MEC requested, but not supported");
> +                    exit(1);
> +                }
> +        }
> +
>          qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
>          object_unref(cpuobj);
>      }
Re: [RFC PATCH 5/7] hw/arm/virt: Add machine option 'mec'
Posted by Gustavo Romero 2 weeks, 3 days ago
Hi Jonathan,

On 3/19/26 06:46, Jonathan Cameron wrote:
> On Wed, 18 Mar 2026 23:23:33 -0300
> Gustavo Romero <gustavo.romero@linaro.org> wrote:
> 
>> Add new machine option 'mec' that enables and sets the memory used by
>> FEAT_MEC.
>>
>> Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>
> 
> Drive by comments only. I'm curious enough to read the patches
> but no idea if this is how people would like to see this implemented!

Thanks for taking a look at it and for you comments.

In which sense do you mean exactly? Do mind to elaborate a bit more on 
it? If it's about the whole implementation, would it be about not
really encrypting data or something else? Please help me to understand it :)

I'm not sure if you're talking about just this patch or the whole 
FEAT_MEC design.


Cheers,
Gustavo

> Jonathan
> 
>>   static void create_secure_ram(VirtMachineState *vms,
>>                                 MemoryRegion *secure_sysmem,
>>                                 MemoryRegion *secure_tag_sysmem)
>> @@ -2267,6 +2288,8 @@ static void machvirt_init(MachineState *machine)
>>       MemoryRegion *secure_sysmem = NULL;
>>       MemoryRegion *tag_sysmem = NULL;
>>       MemoryRegion *secure_tag_sysmem = NULL;
>> +    MemoryRegion *pseudo_encrypted_page = NULL;
>> +    MemoryRegion *tuple_memory = NULL;
>>       int n, virt_max_cpus;
>>       bool firmware_loaded;
>>       bool aarch64 = true;
>> @@ -2495,6 +2518,28 @@ static void machvirt_init(MachineState *machine)
>>               }
>>           }
>>   
>> +        if (vms->mec) {
>> +            if (tcg_enabled()) {
>> +                if (tuple_memory == NULL) {
>> +                    /* XXX(gromero): Add object_property_find(cpuobj, "tuple-memory", ...) here. */
>> +
>> +                    tuple_memory = g_new(MemoryRegion, 1);
>> +                    memory_region_init(tuple_memory, OBJECT(machine), "mec", UINT64_MAX / 32);
>> +
>> +                    pseudo_encrypted_page = g_new(MemoryRegion, 1);
>> +                    memory_region_init(pseudo_encrypted_page, OBJECT(machine), "mec-page", 4 * 1024 /* 4 KiB */);
>> +                }
>> +
>> +                object_property_set_link(cpuobj, "mec",  OBJECT(tuple_memory), &error_abort);
>> +                object_property_set_link(cpuobj, "mec-page",  OBJECT(pseudo_encrypted_page), &error_abort);
> Trivial but some bonus spaces.
> 
>> +
>> +                } else {
> 
> Indent seems off.
> 
>> +                    /* Check for other accels here. */
>> +                    error_report("MEC requested, but not supported");
>> +                    exit(1);
>> +                }
>> +        }
>> +
>>           qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
>>           object_unref(cpuobj);
>>       }
> 
>
Re: [RFC PATCH 5/7] hw/arm/virt: Add machine option 'mec'
Posted by Jonathan Cameron via qemu development 2 weeks, 3 days ago
On Thu, 19 Mar 2026 14:27:57 -0300
Gustavo Romero <gustavo.romero@linaro.org> wrote:

> Hi Jonathan,
> 
> On 3/19/26 06:46, Jonathan Cameron wrote:
> > On Wed, 18 Mar 2026 23:23:33 -0300
> > Gustavo Romero <gustavo.romero@linaro.org> wrote:
> >   
> >> Add new machine option 'mec' that enables and sets the memory used by
> >> FEAT_MEC.
> >>
> >> Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>  
> > 
> > Drive by comments only. I'm curious enough to read the patches
> > but no idea if this is how people would like to see this implemented!  
> 
> Thanks for taking a look at it and for you comments.
> 
> In which sense do you mean exactly? Do mind to elaborate a bit more on 
> it? If it's about the whole implementation, would it be about not
> really encrypting data or something else? Please help me to understand it :)
> 
> I'm not sure if you're talking about just this patch or the whole 
> FEAT_MEC design.

I was failing to express that this is fine for me but out of my area of expertise
wrt to QEMU so would leave the questions of 'is this the best way to do it?'
for others!

> 
> 
> Cheers,
> Gustavo
> 
> > Jonathan
> >   
> >>   static void create_secure_ram(VirtMachineState *vms,
> >>                                 MemoryRegion *secure_sysmem,
> >>                                 MemoryRegion *secure_tag_sysmem)
> >> @@ -2267,6 +2288,8 @@ static void machvirt_init(MachineState *machine)
> >>       MemoryRegion *secure_sysmem = NULL;
> >>       MemoryRegion *tag_sysmem = NULL;
> >>       MemoryRegion *secure_tag_sysmem = NULL;
> >> +    MemoryRegion *pseudo_encrypted_page = NULL;
> >> +    MemoryRegion *tuple_memory = NULL;
> >>       int n, virt_max_cpus;
> >>       bool firmware_loaded;
> >>       bool aarch64 = true;
> >> @@ -2495,6 +2518,28 @@ static void machvirt_init(MachineState *machine)
> >>               }
> >>           }
> >>   
> >> +        if (vms->mec) {
> >> +            if (tcg_enabled()) {
> >> +                if (tuple_memory == NULL) {
> >> +                    /* XXX(gromero): Add object_property_find(cpuobj, "tuple-memory", ...) here. */
> >> +
> >> +                    tuple_memory = g_new(MemoryRegion, 1);
> >> +                    memory_region_init(tuple_memory, OBJECT(machine), "mec", UINT64_MAX / 32);
> >> +
> >> +                    pseudo_encrypted_page = g_new(MemoryRegion, 1);
> >> +                    memory_region_init(pseudo_encrypted_page, OBJECT(machine), "mec-page", 4 * 1024 /* 4 KiB */);
> >> +                }
> >> +
> >> +                object_property_set_link(cpuobj, "mec",  OBJECT(tuple_memory), &error_abort);
> >> +                object_property_set_link(cpuobj, "mec-page",  OBJECT(pseudo_encrypted_page), &error_abort);  
> > Trivial but some bonus spaces.
> >   
> >> +
> >> +                } else {  
> > 
> > Indent seems off.
> >   
> >> +                    /* Check for other accels here. */
> >> +                    error_report("MEC requested, but not supported");
> >> +                    exit(1);
> >> +                }
> >> +        }
> >> +
> >>           qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
> >>           object_unref(cpuobj);
> >>       }  
> > 
> >   
> 
>