Re: [PATCH v7] ui/cocoa: Use NSWindow's ability to resize

2023-12-18 Thread Akihiko Odaki

On 2023/12/17 18:46, Rene Engel wrote:


--- Ursprüngliche Nachricht ---
Von: Akihiko Odaki 
Datum: 17.12.2023 07:25:52
An: Peter Maydell ,  Philippe Mathieu-Daudé ,  Gerd 
Hoffmann ,  Marc-André Lureau ,  Marek Glogowski 

Betreff: [PATCH v7] ui/cocoa: Use NSWindow's ability to resize

Tested-by: Rene Engel 

This patch now works with the "option zoom-to-fit=on/off" thank you very much.

But there is severe mouse lag within Cocoa output in full screen. You can 
reproduce the problem by using the mouse very slowly inside the machine where 
the mouse pointer no longer moves (guest). This issue only occurs with Cocoa 
edition SDL/GTK works without mouse lag within the machine.


I can't reproduce the issue. Is it a regression caused by this change or 
an existing bug?




Re: [PATCH 1/1] target/riscv: SMBIOS support for RISC-V virt machine

2023-12-18 Thread Sunil V L
Hi Heinrich,

Thanks for the patch!.

On Mon, Dec 18, 2023 at 08:40:18AM +0100, Heinrich Schuchardt wrote:
> Generate SMBIOS tables for the RISC-V mach-virt.
> Add CONFIG_SMBIOS=y to the RISC-V default config.
> 
> The implementation is based on the corresponding ARM and Loongson code.
> 
> With the patch the following firmware tables are provided:
> 
> etc/smbios/smbios-anchor
> etc/smbios/smbios-tables
> 
> Booting Ubuntu 23.10 via EDK II allowed displaying the SMBIOS table using
> the dmidecode command:
> 
> Handle 0x0100, DMI type 1, 27 bytes
> System Information
> Manufacturer: QEMU
> Product Name: QEMU Virtual Machine
> Version: virt
> ...
> 
> Signed-off-by: Heinrich Schuchardt 
> ---
>  hw/riscv/Kconfig |  1 +
>  hw/riscv/virt.c  | 36 
>  2 files changed, 37 insertions(+)
> 
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index b6a5eb4452..1e11ac9432 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -41,6 +41,7 @@ config RISCV_VIRT
>  select RISCV_IMSIC
>  select SIFIVE_PLIC
>  select SIFIVE_TEST
> +select SMBIOS
>  select VIRTIO_MMIO
>  select FW_CFG_DMA
>  select PLATFORM_BUS
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index d2eac24156..6c27cb5330 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -36,6 +36,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
>  #include "kvm/kvm_riscv.h"
> +#include "hw/firmware/smbios.h"
>  #include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/riscv_aplic.h"
>  #include "hw/intc/riscv_imsic.h"
> @@ -1249,6 +1250,39 @@ static void create_platform_bus(RISCVVirtState *s, 
> DeviceState *irqchip)
>  sysbus_mmio_get_region(sysbus, 0));
>  }
>  
> +static void virt_build_smbios(RISCVVirtState *s)
> +{
Can we avoid duplicating this function which exists in other
architectures? 

Thanks,
Sunil



[PATCH 1/1] target/riscv/kvm.c: remove group setting of KVM AIA if the machine only has 1 socket

2023-12-18 Thread Yong-Xuan Wang
The emulated AIA within the Linux kernel restores the HART index
of the IMSICs according to the configured AIA settings. During
this process, the group setting is used only when the machine
partitions harts into groups. It's unnecessary to set the group
configuration if the machine has only one socket, as its address
space might not contain the group shift.

Signed-off-by: Yong-Xuan Wang 
Reviewed-by: Jim Shu 
---
 target/riscv/kvm/kvm-cpu.c | 31 +--
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 62a1e51f0a2e..6494597157b8 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1387,21 +1387,24 @@ void kvm_riscv_aia_create(MachineState *machine, 
uint64_t group_shift,
 exit(1);
 }
 
-socket_bits = find_last_bit(&socket_count, BITS_PER_LONG) + 1;
-ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
-KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS,
-&socket_bits, true, NULL);
-if (ret < 0) {
-error_report("KVM AIA: failed to set group_bits");
-exit(1);
-}
 
-ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
-KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT,
-&group_shift, true, NULL);
-if (ret < 0) {
-error_report("KVM AIA: failed to set group_shift");
-exit(1);
+if (socket_count > 1) {
+socket_bits = find_last_bit(&socket_count, BITS_PER_LONG) + 1;
+ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
+KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS,
+&socket_bits, true, NULL);
+if (ret < 0) {
+error_report("KVM AIA: failed to set group_bits");
+exit(1);
+}
+
+ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
+KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT,
+&group_shift, true, NULL);
+if (ret < 0) {
+error_report("KVM AIA: failed to set group_shift");
+exit(1);
+}
 }
 
 guest_bits = guest_num == 0 ? 0 :
-- 
2.17.1




[PATCH 1/1] hw/riscv/virt.c: fix the interrupts-extended property format of PLIC

2023-12-18 Thread Yong-Xuan Wang
The interrupts-extended property of PLIC only has 2 * hart number
fields when KVM enabled, copy 4 * hart number fields to fdt will
expose some uninitialized value.

In this patch, I also refactor the code about the setting of
interrupts-extended property of PLIC for improved readability.

Signed-off-by: Yong-Xuan Wang 
Reviewed-by: Jim Shu 
---
 hw/riscv/virt.c | 47 +++
 1 file changed, 27 insertions(+), 20 deletions(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index d2eac2415619..e42baf82cab6 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -460,24 +460,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
 "sifive,plic-1.0.0", "riscv,plic0"
 };
 
-if (kvm_enabled()) {
-plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
-} else {
-plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
-}
-
-for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
-if (kvm_enabled()) {
-plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
-plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT);
-} else {
-plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
-plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
-plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
-plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
-}
-}
-
 plic_phandles[socket] = (*phandle)++;
 plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
 plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
@@ -490,8 +472,33 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
   (char **)&plic_compat,
   ARRAY_SIZE(plic_compat));
 qemu_fdt_setprop(ms->fdt, plic_name, "interrupt-controller", NULL, 0);
-qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended",
-plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
+
+if (kvm_enabled()) {
+plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
+
+for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT);
+}
+
+qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended",
+ plic_cells,
+ s->soc[socket].num_harts * sizeof(uint32_t) * 2);
+   } else {
+plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
+
+for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
+plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
+plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
+plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
+}
+
+qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended",
+ plic_cells,
+ s->soc[socket].num_harts * sizeof(uint32_t) * 4);
+}
+
 qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg",
 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
 qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev",
-- 
2.17.1




[PATCH v2 01/17] hw/loongarch: Move boot fucntions to boot.c

2023-12-18 Thread Song Gao
Move some boot functions to boot.c and struct
loongarch_boot_info into struct LoongArchMachineState.

Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 127 
 hw/loongarch/meson.build|   1 +
 hw/loongarch/virt.c | 118 ++---
 include/hw/loongarch/boot.h |  21 ++
 include/hw/loongarch/virt.h |   2 +
 5 files changed, 155 insertions(+), 114 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
new file mode 100644
index 00..9f25ea5847
--- /dev/null
+++ b/hw/loongarch/boot.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch boot helper functions.
+ *
+ * Copyright (c) 2023 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "target/loongarch/cpu.h"
+#include "hw/loongarch/virt.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "qemu/error-report.h"
+#include "sysemu/reset.h"
+
+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
+{
+return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
+}
+
+static int64_t load_kernel_info(struct loongarch_boot_info *info)
+{
+uint64_t kernel_entry, kernel_low, kernel_high;
+ssize_t kernel_size;
+
+kernel_size = load_elf(info->kernel_filename, NULL,
+   cpu_loongarch_virt_to_phys, NULL,
+   &kernel_entry, &kernel_low,
+   &kernel_high, NULL, 0,
+   EM_LOONGARCH, 1, 0);
+
+if (kernel_size < 0) {
+error_report("could not load kernel '%s': %s",
+ info->kernel_filename,
+ load_elf_strerror(kernel_size));
+exit(1);
+}
+return kernel_entry;
+}
+
+static void reset_load_elf(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+CPULoongArchState *env = &cpu->env;
+
+cpu_reset(CPU(cpu));
+if (env->load_elf) {
+cpu_set_pc(CPU(cpu), env->elf_address);
+}
+}
+
+static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info,
+   FWCfgState *fw_cfg)
+{
+/*
+ * Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ false);
+
+if (info->initrd_filename) {
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+}
+
+if (info->kernel_cmdline) {
+fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+   strlen(info->kernel_cmdline) + 1);
+fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+  info->kernel_cmdline);
+}
+}
+
+static void loongarch_firmware_boot(LoongArchMachineState *lams,
+struct loongarch_boot_info *info)
+{
+fw_cfg_add_kernel_info(info, lams->fw_cfg);
+}
+
+static void loongarch_direct_kernel_boot(LoongArchMachineState *lams,
+ struct loongarch_boot_info *info)
+{
+MachineState *machine = MACHINE(lams);
+int64_t kernel_addr = 0;
+LoongArchCPU *lacpu;
+int i;
+
+if (info->kernel_filename) {
+kernel_addr = load_kernel_info(info);
+} else {
+error_report("Need kernel filename\n");
+exit(1);
+}
+
+for (i = 0; i < machine->smp.cpus; i++) {
+lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
+lacpu->env.load_elf = true;
+lacpu->env.elf_address = kernel_addr;
+}
+}
+
+void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
+{
+LoongArchMachineState *lams = LOONGARCH_MACHINE(ms);
+int i;
+
+/* register reset function */
+for (i = 0; i < ms->smp.cpus; i++) {
+qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(i)));
+}
+
+info->kernel_filename = ms->kernel_filename;
+info->kernel_cmdline = ms->kernel_cmdline;
+info->initrd_filename = ms->initrd_filename;
+
+if (lams->bios_loaded) {
+loongarch_firmware_boot(lams, info);
+} else {
+loongarch_direct_kernel_boot(lams, info);
+}
+}
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index c0421502ab..d306d82c2e 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,6 +1,7 @@
 loongarch_ss = ss.source_set()
 loongarch_ss.add(files(
 'fw_cfg.c',
+'boot.c',
 ))
 loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: [files('virt.c'), 
fdt])
 loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'))
diff --git a/hw/loongarch/virt.c b/hw/loonga

[PATCH v2 07/17] hw/loongarch: Init efi_initrd table

2023-12-18 Thread Song Gao
Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 29 +++--
 include/hw/loongarch/boot.h |  9 +
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 5d963176bd..1600ae6e55 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -14,11 +14,15 @@
 #include "qemu/error-report.h"
 #include "sysemu/reset.h"
 
+ram_addr_t initrd_offset;
+uint64_t initrd_size;
+
 enum {
 SLAVE_BOOT,
 EFI_SYSTAB,
 EFI_TABLES,
 EFI_MEMMAP,
+EFI_INITRD,
 };
 
 static const MemMapEntry loader_rommap[] = {
@@ -26,6 +30,7 @@ static const MemMapEntry loader_rommap[] = {
 [EFI_SYSTAB] = {0xf20, 0x1},
 [EFI_TABLES] = {0xf30, 0x1},
 [EFI_MEMMAP] = {0xf40, 0x1},
+[EFI_INITRD] = {0xf50, 0x1},
 };
 
 static unsigned int slave_boot_code[] = {
@@ -117,6 +122,26 @@ static void init_efi_boot_memmap(struct efi_system_table 
*systab)
 g_free(boot_memmap);
 }
 
+static void init_efi_initrd_table(struct efi_system_table *systab)
+{
+efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
+struct efi_initrd *initrd_table  = 
g_malloc0(loader_rommap[EFI_INITRD].size);
+
+initrd_table->base = initrd_offset;
+initrd_table->size = initrd_size;
+
+rom_add_blob_fixed("initrd_tbl_rom", initrd_table,
+   loader_rommap[EFI_INITRD].size,
+   loader_rommap[EFI_INITRD].base);
+
+/* efi_configuration_table 2 */
+guidcpy(&systab->tables[1].guid, &tbl_guid);
+systab->tables[1].table = (void *)loader_rommap[EFI_INITRD].base;
+systab->nr_tables = 2;
+
+g_free(initrd_table);
+}
+
 static void init_systab(struct loongarch_boot_info *info)
 {
 struct efi_system_table *systab;
@@ -134,6 +159,7 @@ static void init_systab(struct loongarch_boot_info *info)
 systab->tables = efi_tables;
 
 init_efi_boot_memmap(systab);
+init_efi_initrd_table(systab);
 
 rom_add_blob_fixed("tables_rom", efi_tables,
loader_rommap[EFI_TABLES].size,
@@ -173,8 +199,7 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
-ram_addr_t initrd_offset;
+uint64_t kernel_entry, kernel_low, kernel_high;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index bef9ab659e..e482b829f7 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -32,6 +32,10 @@ typedef struct {
 EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
  0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 
+#define LINUX_EFI_INITRD_MEDIA_GUID \
+EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
+ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -85,6 +89,11 @@ struct efi_boot_memmap {
 efi_memory_desc_t map[32];
 };
 
+struct efi_initrd {
+uint64_t base;
+uint64_t size;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PATCH v2 05/17] hw/loongarch: Init efi_system_table

2023-12-18 Thread Song Gao
Add init_systab and set boot_info->a2

Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 39 +
 include/hw/loongarch/boot.h | 50 +
 2 files changed, 89 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 076e795714..7d043fd718 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -16,10 +16,14 @@
 
 enum {
 SLAVE_BOOT,
+EFI_SYSTAB,
+EFI_TABLES,
 };
 
 static const MemMapEntry loader_rommap[] = {
 [SLAVE_BOOT] = {0xf10, 0x1},
+[EFI_SYSTAB] = {0xf20, 0x1},
+[EFI_TABLES] = {0xf30, 0x1},
 };
 
 static unsigned int slave_boot_code[] = {
@@ -70,6 +74,39 @@ static unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $r0,$r1,0   */
 };
 
+static void init_systab(struct loongarch_boot_info *info)
+{
+struct efi_system_table *systab;
+struct efi_configuration_table *efi_tables;
+systab = g_malloc0(loader_rommap[EFI_SYSTAB].size);
+efi_tables = g_malloc0(loader_rommap[EFI_TABLES].size);
+
+systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
+systab->hdr.revision = EFI_SPECIFICATION_VERSION;
+systab->hdr.revision = sizeof(struct efi_system_table),
+systab->fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8;
+systab->runtime = 0;
+systab->boottime = 0;
+systab->nr_tables = 0;
+systab->tables = efi_tables;
+
+rom_add_blob_fixed("tables_rom", efi_tables,
+   loader_rommap[EFI_TABLES].size,
+   loader_rommap[EFI_TABLES].base);
+
+systab->tables = (struct efi_configuration_table *)
+ loader_rommap[EFI_TABLES].base;
+
+rom_add_blob_fixed("systab_rom", systab,
+   loader_rommap[EFI_SYSTAB].size,
+   loader_rommap[EFI_SYSTAB].base);
+
+info->a2 = loader_rommap[EFI_SYSTAB].base;
+
+g_free(systab);
+g_free(efi_tables);
+}
+
 static int init_cmdline(struct loongarch_boot_info *info)
 {
 hwaddr cmdline_addr;
@@ -134,6 +171,7 @@ static int64_t load_kernel_info(struct loongarch_boot_info 
*info)
 }
 
 init_cmdline(info);
+init_systab(info);
 
 return kernel_entry;
 }
@@ -148,6 +186,7 @@ static void reset_load_elf(void *opaque)
if (cpu == LOONGARCH_CPU(first_cpu)) {
 env->gpr[4] = env->boot_info->a0;
 env->gpr[5] = env->boot_info->a1;
+env->gpr[6] = env->boot_info->a2;
 }
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 3275c1e295..4ee116b25d 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -8,6 +8,56 @@
 #ifndef HW_LOONGARCH_BOOT_H
 #define HW_LOONGARCH_BOOT_H
 
+/* UEFI 2.10 */
+#define EFI_SYSTEM_TABLE_SIGNATURE   0x5453595320494249
+#define EFI_2_100_SYSTEM_TABLE_REVISION  ((2<<16) | (100))
+#define EFI_SPECIFICATION_VERSIONEFI_SYSTEM_TABLE_REVISION
+#define EFI_SYSTEM_TABLE_REVISIONEFI_2_100_SYSTEM_TABLE_REVISION
+
+#define FW_VERSION 0x1
+#define FW_PATCHLEVEL 0x0
+
+#define EFI_MAX_CONFIGURATION_TABLES 16
+
+typedef struct {
+uint8_t b[16];
+} efi_guid_t __attribute__((aligned(8)));
+
+struct efi_config_table {
+efi_guid_t guid;
+uint64_t *ptr;
+const char name[16];
+};
+
+typedef struct {
+uint64_t signature;
+uint32_t revision;
+uint32_t headersize;
+uint32_t crc32;
+uint32_t reserved;
+} efi_table_hdr_t;
+
+struct efi_configuration_table {
+efi_guid_t guid;
+void *table;
+};
+
+struct efi_system_table {
+efi_table_hdr_t hdr;
+uint64_t fw_vendor;/* physical addr of CHAR16 vendor string */
+uint32_t fw_revision;
+uint64_t con_in_handle;
+uint64_t *con_in;
+uint64_t con_out_handle;
+uint64_t *con_out;
+uint64_t stderr_handle;
+uint64_t stderr;
+uint64_t *runtime;
+uint64_t *boottime;
+uint64_t nr_tables;
+struct efi_configuration_table *tables;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PATCH v2 09/17] hw/loongarch: Fix fdt memory node wrong 'reg'

2023-12-18 Thread Song Gao
The right fdt memory node like [1], not [2]

  [1]
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00 0x1000>;
};
  [2]
memory@0 {
device_type = "memory";
reg = <0x02 0x00 0x02 0x1000>;
};

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c45e724961..eaa0824f73 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -290,7 +290,7 @@ static void fdt_add_memory_node(MachineState *ms,
 char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
 
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size);
 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
 
 if (ms->numa_state && ms->numa_state->num_nodes) {
-- 
2.25.1




[PATCH v2 06/17] hw/loongarch: Init efi_boot_memmap table

2023-12-18 Thread Song Gao
Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 45 +
 hw/loongarch/virt.c | 11 ++---
 include/hw/loongarch/boot.h | 27 ++
 include/hw/loongarch/virt.h | 10 +
 4 files changed, 84 insertions(+), 9 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 7d043fd718..5d963176bd 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -18,12 +18,14 @@ enum {
 SLAVE_BOOT,
 EFI_SYSTAB,
 EFI_TABLES,
+EFI_MEMMAP,
 };
 
 static const MemMapEntry loader_rommap[] = {
 [SLAVE_BOOT] = {0xf10, 0x1},
 [EFI_SYSTAB] = {0xf20, 0x1},
 [EFI_TABLES] = {0xf30, 0x1},
+[EFI_MEMMAP] = {0xf40, 0x1},
 };
 
 static unsigned int slave_boot_code[] = {
@@ -74,6 +76,47 @@ static unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $r0,$r1,0   */
 };
 
+static inline void *guidcpy(void *dst, const void *src)
+{
+return memcpy(dst, src, sizeof(efi_guid_t));
+}
+
+static void init_efi_boot_memmap(struct efi_system_table *systab)
+{
+unsigned i;
+struct efi_boot_memmap *boot_memmap;
+efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
+
+boot_memmap = g_malloc0(sizeof(struct efi_boot_memmap) +
+sizeof(efi_memory_desc_t) * 32);
+if (!boot_memmap) {
+error_report("init_boot_memmap :can not malloc memory\n");
+exit(1);
+}
+boot_memmap->desc_size = sizeof(efi_memory_desc_t);
+boot_memmap->desc_ver = 1;
+boot_memmap->map_size = 0;
+
+efi_memory_desc_t *map;
+for (i = 0; i < memmap_entries; i++) {
+map = (void *)boot_memmap + sizeof(*map);
+map[i].type = memmap_table[i].type;
+map[i].phys_addr = memmap_table[i].address;
+map[i].num_pages = memmap_table[i].length >> 16; /* 64KB align*/
+}
+
+rom_add_blob_fixed("memmap_rom", boot_memmap,
+   loader_rommap[EFI_MEMMAP].size,
+   loader_rommap[EFI_MEMMAP].base);
+
+/* efi_configuration_table 1 */
+guidcpy(&systab->tables[0].guid, &tbl_guid);
+systab->tables[0].table = (void *)loader_rommap[EFI_MEMMAP].base;
+systab->nr_tables = 1;
+
+g_free(boot_memmap);
+}
+
 static void init_systab(struct loongarch_boot_info *info)
 {
 struct efi_system_table *systab;
@@ -90,6 +133,8 @@ static void init_systab(struct loongarch_boot_info *info)
 systab->nr_tables = 0;
 systab->tables = efi_tables;
 
+init_efi_boot_memmap(systab);
+
 rom_add_blob_fixed("tables_rom", efi_tables,
loader_rommap[EFI_TABLES].size,
loader_rommap[EFI_TABLES].base);
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 3e27d72f55..c45e724961 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -342,15 +342,8 @@ static void virt_powerdown_req(Notifier *notifier, void 
*opaque)
 acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
 }
 
-struct memmap_entry {
-uint64_t address;
-uint64_t length;
-uint32_t type;
-uint32_t reserved;
-};
-
-static struct memmap_entry *memmap_table;
-static unsigned memmap_entries;
+struct memmap_entry *memmap_table;
+unsigned memmap_entries;
 
 static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
 {
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 4ee116b25d..bef9ab659e 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -23,6 +23,15 @@ typedef struct {
 uint8_t b[16];
 } efi_guid_t __attribute__((aligned(8)));
 
+#define EFI_GUID(a, b, c, d...) (efi_guid_t){ {
\
+(a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, 
\
+(b) & 0xff, ((b) >> 8) & 0xff, 
\
+(c) & 0xff, ((c) >> 8) & 0xff, d } }
+
+#define LINUX_EFI_BOOT_MEMMAP_GUID \
+EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
+ 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -58,6 +67,24 @@ struct efi_system_table {
 struct efi_configuration_table *tables;
 };
 
+typedef struct {
+uint32_t type;
+uint32_t pad;
+uint64_t phys_addr;
+uint64_t virt_addr;
+uint64_t num_pages;
+uint64_t attribute;
+} efi_memory_desc_t;
+
+struct efi_boot_memmap {
+uint64_t map_size;
+uint64_t desc_size;
+uint32_t desc_ver;
+uint64_t map_key;
+uint64_t buff_size;
+efi_memory_desc_t map[32];
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index d21de2cef4..aef4cd05b1 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -33,6 +33,16 @@
 
 #define COMMAND_LINE_SIZE   512
 
+extern struct memmap_entry *memmap_table;
+extern unsign

[PATCH v2 16/17] hw/loongarch: Add cells missing from uart node

2023-12-18 Thread Song Gao
uart node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 02a3af3b5e..e1a6ec86c8 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -209,7 +209,8 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_uart_node(LoongArchMachineState *lams)
+static void fdt_add_uart_node(LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_UART_BASE;
@@ -222,6 +223,10 @@ static void fdt_add_uart_node(LoongArchMachineState *lams)
 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
 qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 1);
 qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -593,7 +598,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
-fdt_add_uart_node(lams);
+fdt_add_uart_node(lams, pch_pic_phandle);
 
 /* Network init */
 for (i = 0; i < nb_nics; i++) {
-- 
2.25.1




[PATCH v2 13/17] hw/loongarch: fdt adds pch_msi Controller

2023-12-18 Thread Song Gao
fdt adds pch msi controller, we use 'loongson,pch-msi-1.0'.

See:
  drivers/irqchip/irq-loongson-pch-msi.c
Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c| 33 -
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 166e3f1892..859f17c2f6 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -150,6 +150,34 @@ static void fdt_add_pch_pic_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_msi_node(LoongArchMachineState *lams,
+ uint32_t *extioic_phandle,
+ uint32_t *pch_msi_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
+hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
+
+*pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-msi-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
+   0, pch_msi_base,
+   0, pch_msi_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *extioic_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
+  VIRT_PCH_PIC_IRQ_NUM);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
+  EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -560,7 +588,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, extioiic_phandle, pch_pic_phandle;
+uint32_t cpuintc_phandle, extioiic_phandle, pch_pic_phandle, 
pch_msi_phandle;
 
 extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
@@ -671,6 +699,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
   qdev_get_gpio_in(extioi, i + start));
 }
 
+/* Add PCH MSI node */
+fdt_add_pch_msi_node(lams, &extioiic_phandle, &pch_msi_phandle);
+
 loongarch_devices_init(pch_pic, lams);
 }
 
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index fe260f0183..cd7c9ec7bc 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -25,6 +25,7 @@
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
 #define VIRT_PCH_REG_SIZE0x400
+#define VIRT_PCH_MSI_SIZE0x8
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PATCH v2 15/17] hw/loongarch: fdt remove unused irqchip node

2023-12-18 Thread Song Gao
Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 31 +--
 1 file changed, 1 insertion(+), 30 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 74cac07e8a..02a3af3b5e 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -410,34 +410,6 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
-static void fdt_add_irqchip_node(LoongArchMachineState *lams)
-{
-MachineState *ms = MACHINE(lams);
-char *nodename;
-uint32_t irqchip_phandle;
-
-irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt);
-qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle);
-
-nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE);
-qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3);
-qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2);
-qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0);
-
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
-"loongarch,ls7a");
-
-qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, VIRT_IOAPIC_REG_BASE,
- 2, PCH_PIC_ROUTE_ENTRY_OFFSET);
-
-qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle);
-g_free(nodename);
-}
-
 static void fdt_add_memory_node(MachineState *ms,
 uint64_t base, uint64_t size, int node_id)
 {
@@ -918,8 +890,7 @@ static void loongarch_init(MachineState *machine)
 
 /* Initialize the IO interrupt subsystem */
 loongarch_irq_init(lams);
-fdt_add_irqchip_node(lams);
-platform_bus_add_all_fdt_nodes(machine->fdt, "/intc",
+platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
VIRT_PLATFORM_BUS_BASEADDRESS,
VIRT_PLATFORM_BUS_SIZE,
VIRT_PLATFORM_BUS_IRQ);
-- 
2.25.1




[PATCH v2 04/17] hw/loongarch: Add slave cpu boot_code

2023-12-18 Thread Song Gao
Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 65 -
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 4bfe24274a..076e795714 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -14,6 +14,62 @@
 #include "qemu/error-report.h"
 #include "sysemu/reset.h"
 
+enum {
+SLAVE_BOOT,
+};
+
+static const MemMapEntry loader_rommap[] = {
+[SLAVE_BOOT] = {0xf10, 0x1},
+};
+
+static unsigned int slave_boot_code[] = {
+  /* Configure reset ebase. */
+0x0400302c,   /* csrwr  $r12,0xc*/
+
+  /* Disable interrupt. */
+0x0380100c,   /* ori$r12,$r0,0x4*/
+0x04000180,   /* csrxchg$r0,$r12,0x0*/
+
+  /* Clear mailbox. */
+0x142d,   /* lu12i.w$r13,1(0x1) */
+0x038081ad,   /* ori$r13,$r13,0x20  */
+0x06481da0,   /* iocsrwr.d  $r0,$r13*/
+
+  /* Enable IPI interrupt.  */
+0x142c,   /* lu12i.w$r12,1(0x1) */
+0x0400118c,   /* csrxchg$r12,$r12,0x4   */
+0x02fffc0c,   /* addi.d $r12,$r0,-1(0xfff)  */
+0x142d,   /* lu12i.w$r13,1(0x1) */
+0x038011ad,   /* ori$r13,$r13,0x4   */
+0x064819ac,   /* iocsrwr.w  $r12,$r13   */
+0x142d,   /* lu12i.w$r13,1(0x1) */
+0x038081ad,   /* ori$r13,$r13,0x20  */
+
+  /* Wait for wakeup  <.L11>:   */
+0x06488000,   /* idle   0x0 */
+0x0340,   /* andi   $r0,$r0,0x0 */
+0x064809ac,   /* iocsrrd.w  $r12,$r13   */
+0x43fff59f,   /* beqz   $r12,-12(0x74) # 48 <.L11> */
+
+  /* Read and clear IPI interrupt.  */
+0x142d,   /* lu12i.w$r13,1(0x1) */
+0x064809ac,   /* iocsrrd.w  $r12,$r13   */
+0x142d,   /* lu12i.w$r13,1(0x1) */
+0x038031ad,   /* ori$r13,$r13,0xc   */
+0x064819ac,   /* iocsrwr.w  $r12,$r13   */
+
+  /* Disable  IPI interrupt.*/
+0x142c,   /* lu12i.w$r12,1(0x1) */
+0x04001180,   /* csrxchg$r0,$r12,0x4*/
+
+  /* Read mail buf and jump to specified entry */
+0x142d,   /* lu12i.w$r13,1(0x1) */
+0x038081ad,   /* ori$r13,$r13,0x20  */
+0x06480dac,   /* iocsrrd.d  $r12,$r13   */
+0x00150181,   /* move   $r1,$r12*/
+0x4c20,   /* jirl   $r0,$r1,0   */
+};
+
 static int init_cmdline(struct loongarch_boot_info *info)
 {
 hwaddr cmdline_addr;
@@ -145,10 +201,17 @@ static void 
loongarch_direct_kernel_boot(LoongArchMachineState *lams,
 exit(1);
 }
 
+rom_add_blob_fixed("slave_boot", slave_boot_code, sizeof(slave_boot_code),
+   loader_rommap[SLAVE_BOOT].base);
+
 for (i = 0; i < machine->smp.cpus; i++) {
 lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
 lacpu->env.load_elf = true;
-lacpu->env.elf_address = kernel_addr;
+if (i == 0) {
+lacpu->env.elf_address = kernel_addr;
+} else {
+lacpu->env.elf_address = loader_rommap[SLAVE_BOOT].base;
+}
 lacpu->env.boot_info = info;
 }
 }
-- 
2.25.1




[PATCH v2 14/17] hw/loongarch: fdt adds pcie irq_map node

2023-12-18 Thread Song Gao
Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 73 ++---
 1 file changed, 69 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 859f17c2f6..74cac07e8a 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -316,7 +316,62 @@ static void fdt_add_fw_cfg_node(const 
LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_pcie_node(const LoongArchMachineState *lams)
+static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams,
+  char *nodename,
+  uint32_t *pch_pic_phandle)
+{
+int pin, dev;
+uint32_t irq_map_stride = 0;
+uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {};
+uint32_t *irq_map = full_irq_map;
+const MachineState *ms = MACHINE(lams);
+
+/* This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+
+for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+int devfn = dev * 0x8;
+
+for (pin = 0; pin  < GPEX_NUM_IRQS; pin++) {
+int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+int i = 0;
+
+/* Fill PCI address cells */
+irq_map[i] = cpu_to_be32(devfn << 8);
+i += 3;
+
+/* Fill PCI Interrupt cells */
+irq_map[i] = cpu_to_be32(pin + 1);
+i += 1;
+
+/* Fill interrupt controller phandle and cells */
+irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
+irq_map[i++] = cpu_to_be32(irq_nr);
+
+if (!irq_map_stride) {
+irq_map_stride = i;
+}
+irq_map += irq_map_stride;
+}
+}
+
+
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
+ GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ irq_map_stride * sizeof(uint32_t));
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
+static void fdt_add_pcie_node(const LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle,
+  uint32_t *pch_msi_phandle)
 {
 char *nodename;
 hwaddr base_mmio = VIRT_PCI_MEM_BASE;
@@ -347,6 +402,11 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams)
  2, base_pio, 2, size_pio,
  1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
  2, base_mmio, 2, size_mmio);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
+   0, *pch_msi_phandle, 0, 0x1);
+
+fdt_add_pcie_irq_map_node(lams, nodename, pch_pic_phandle);
+
 g_free(nodename);
 }
 
@@ -505,7 +565,10 @@ static DeviceState *create_platform_bus(DeviceState 
*pch_pic)
 return dev;
 }
 
-static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState 
*lams)
+static void loongarch_devices_init(DeviceState *pch_pic,
+   LoongArchMachineState *lams,
+   uint32_t *pch_pic_phandle,
+   uint32_t *pch_msi_phandle)
 {
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 DeviceState *gpex_dev;
@@ -551,6 +614,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, 
LoongArchMachineState *
 gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
 }
 
+/* Add pcie node */
+fdt_add_pcie_node(lams, pch_pic_phandle, pch_msi_phandle);
+
 serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
@@ -702,7 +768,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 /* Add PCH MSI node */
 fdt_add_pch_msi_node(lams, &extioiic_phandle, &pch_msi_phandle);
 
-loongarch_devices_init(pch_pic, lams);
+loongarch_devices_init(pch_pic, lams, &pch_pic_phandle, &pch_msi_phandle);
 }
 
 static void loongarch_firmware_init(LoongArchMachineState *lams)
@@ -863,7 +929,6 @@ static void loongarch_init(MachineState *machine)
 lams->powerdown_notifier.notify = virt_powerdown_req;
 qemu_register_powerdown_notifier(&lams->powerdown_notifier);
 
-fdt_add_pcie_node(lams);
 /*
  * Since lowmem region starts from 0 and Linux kernel legacy start address
  * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
-- 
2.25.1




[PATCH v2 03/17] hw/loongarch: Add init_cmdline

2023-12-18 Thread Song Gao
Add init_cmline and set boot_info->a0, a1

Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 21 +
 include/hw/loongarch/virt.h |  2 ++
 target/loongarch/cpu.h  |  2 ++
 3 files changed, 25 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 2be6dfb037..4bfe24274a 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -14,6 +14,20 @@
 #include "qemu/error-report.h"
 #include "sysemu/reset.h"
 
+static int init_cmdline(struct loongarch_boot_info *info)
+{
+hwaddr cmdline_addr;
+cmdline_addr = 0xff0ULL;
+
+pstrcpy_targphys("cmdline", 0xff0ULL,
+ COMMAND_LINE_SIZE, info->kernel_cmdline);
+
+info->a0 = 1;
+info->a1 = cmdline_addr;
+
+return 0;
+}
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -63,6 +77,8 @@ static int64_t load_kernel_info(struct loongarch_boot_info 
*info)
 exit(1);
 }
 
+init_cmdline(info);
+
 return kernel_entry;
 }
 
@@ -73,6 +89,10 @@ static void reset_load_elf(void *opaque)
 
 cpu_reset(CPU(cpu));
 if (env->load_elf) {
+   if (cpu == LOONGARCH_CPU(first_cpu)) {
+env->gpr[4] = env->boot_info->a0;
+env->gpr[5] = env->boot_info->a1;
+}
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
 }
@@ -129,6 +149,7 @@ static void 
loongarch_direct_kernel_boot(LoongArchMachineState *lams,
 lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
 lacpu->env.load_elf = true;
 lacpu->env.elf_address = kernel_addr;
+lacpu->env.boot_info = info;
 }
 }
 
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index e4126dd0e7..d21de2cef4 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -31,6 +31,8 @@
 #define VIRT_GED_MEM_ADDR   (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN)
 #define VIRT_GED_REG_ADDR   (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN)
 
+#define COMMAND_LINE_SIZE   512
+
 struct LoongArchMachineState {
 /*< private >*/
 MachineState parent_obj;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 00d1fba597..c7c695138e 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -362,6 +362,8 @@ typedef struct CPUArchState {
 uint64_t elf_address;
 /* Store ipistate to access from this struct */
 DeviceState *ipistate;
+
+struct loongarch_boot_info *boot_info;
 #endif
 } CPULoongArchState;
 
-- 
2.25.1




[PATCH v2 00/17] Add boot LoongArch elf kernel with FDT

2023-12-18 Thread Song Gao
Hi, All

We already support boot efi kernel with bios, but not support boot elf kernel.
This series adds boot elf kernel with FDT.

'LoongArch supports ACPI and FDT. The information that needs to be passed
 to the kernel includes the memmap, the initrd, the command line, optionally
 the ACPI/FDT tables, and so on'  see [1].

Patch 2-8 : Create efi system table, and three efi configuration table
boot_memmap, initd, FDT.
Patch 9-17 : Fixes FDT problems.

Test:
  - Start kernel
See [2] start_kernel.sh
  - Start qcow2 
See [2] start_qcow2.sh

V2:
  - FDT pcie node adds cells 'msi-map';
 

[1]: 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/arch/loongarch/booting.rst?h=v6.7-rc4

[2]: https://github.com/gaosong-loongson/loongarch-binary/releases

Please review!

Thanks.
Song Gao

Song Gao (17):
  hw/loongarch: Move boot fucntions to boot.c
  hw/loongarch: Add load initrd
  hw/loongarch: Add init_cmdline
  hw/loongarch: Add slave cpu boot_code
  hw/loongarch: Init efi_system_table
  hw/loongarch: Init efi_boot_memmap table
  hw/loongarch: Init efi_initrd table
  hw/loongarch: Init efi_fdt table
  hw/loongarch: Fix fdt memory node wrong 'reg'
  hw/loongarch: fdt adds cpu interrupt controller node
  hw/loongarch: fdt adds Extend I/O Interrupt Controller
  hw/loongarch: fdt adds pch_pic Controller
  hw/loongarch: fdt adds pch_msi Controller
  hw/loongarch: fdt adds pcie irq_map node
  hw/loongarch: fdt remove unused irqchip node
  hw/loongarch: Add cells missing from uart node
  hw/loongarch: Add cells missing from rtc node

 hw/loongarch/boot.c| 358 
 hw/loongarch/meson.build   |   1 +
 hw/loongarch/virt.c| 360 -
 include/hw/intc/loongarch_extioi.h |   1 +
 include/hw/loongarch/boot.h| 111 +
 include/hw/loongarch/virt.h|  14 ++
 include/hw/pci-host/ls7a.h |   2 +
 target/loongarch/cpu.h |   2 +
 8 files changed, 688 insertions(+), 161 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h

-- 
2.25.1




[PATCH v2 10/17] hw/loongarch: fdt adds cpu interrupt controller node

2023-12-18 Thread Song Gao
fdt adds cpu interrupt controller node,
we use 'loongson,cpu-interrupt-controller'.

See:
  drivers/irqchip/irq-loongarch-cpu.c

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index eaa0824f73..d251674090 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -81,7 +81,23 @@ static void virt_flash_map(LoongArchMachineState *lams,
 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
 memory_region_add_subregion(sysmem, base,
 sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 
0));
+}
+
+static void fdt_add_cpuic_node(LoongArchMachineState *lams,
+   uint32_t *cpuintc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
 
+*cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/cpuic");
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,cpu-interrupt-controller");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+g_free(nodename);
 }
 
 static void fdt_add_flash_node(LoongArchMachineState *lams)
@@ -494,6 +510,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
+uint32_t cpuintc_phandle;
 
 extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
@@ -519,6 +536,10 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
  * | UARTs  | | Devices | | Devices |
  * ++ +-+ +-+
  */
+
+/* Add cpu interrupt-controller */
+fdt_add_cpuic_node(lams, &cpuintc_phandle);
+
 for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
 cpu_state = qemu_get_cpu(cpu);
 cpudev = DEVICE(cpu_state);
-- 
2.25.1




[PATCH v2 02/17] hw/loongarch: Add load initrd

2023-12-18 Thread Song Gao
we load initrd ramdisk after kernel_high address

Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 29 -
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 9f25ea5847..2be6dfb037 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -21,7 +21,8 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high;
+uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
+ram_addr_t initrd_offset;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
@@ -36,6 +37,32 @@ static int64_t load_kernel_info(struct loongarch_boot_info 
*info)
  load_elf_strerror(kernel_size));
 exit(1);
 }
+
+if (info->initrd_filename) {
+initrd_size = get_image_size(info->initrd_filename);
+if (initrd_size > 0) {
+initrd_offset = ROUND_UP(kernel_high, 64 * KiB);
+
+if (initrd_offset + initrd_size > info->ram_size) {
+error_report("memory too small for initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+
+initrd_size = load_image_targphys(info->initrd_filename, 
initrd_offset,
+  info->ram_size - initrd_offset);
+}
+
+if (initrd_size == (target_ulong)-1) {
+error_report("could not load initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+} else {
+error_report("Need initrd!");
+exit(1);
+}
+
 return kernel_entry;
 }
 
-- 
2.25.1




[PATCH v2 11/17] hw/loongarch: fdt adds Extend I/O Interrupt Controller

2023-12-18 Thread Song Gao
fdt adds Extend I/O Interrupt Controller,
we use 'loongson,ls2k2000-eiointc'.

See:
  drivers/irqchip/irq-loongson-eiointc.c

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c| 30 +-
 include/hw/intc/loongarch_extioi.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index d251674090..7534e42309 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -100,6 +100,31 @@ static void fdt_add_cpuic_node(LoongArchMachineState *lams,
 g_free(nodename);
 }
 
+static void fdt_add_extioiic_node(LoongArchMachineState *lams,
+  uint32_t *cpuintc_phandle,
+  uint32_t *extioic_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr extioi_base = APIC_BASE;
+hwaddr extioi_size = EXTIOI_SIZE;
+
+*extioic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/extioiic@%" PRIx64, extioi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *extioic_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls2k2000-eiointc");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *cpuintc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
+   extioi_base, 0x0, extioi_size);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -510,7 +535,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle;
+uint32_t cpuintc_phandle, extioiic_phandle;
 
 extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
@@ -582,6 +607,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 }
 }
 
+/* Add Extend I/O Interrupt Controller node */
+fdt_add_extioiic_node(lams, &cpuintc_phandle, &extioiic_phandle);
+
 pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
 num = VIRT_PCH_PIC_IRQ_NUM;
 qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index fbdef9a7b3..5012584f50 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -39,6 +39,7 @@
 #define EXTIOI_COREISR_END   (0xB20 - APIC_OFFSET)
 #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET)
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
+#define EXTIOI_SIZE  0x800
 
 #define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
 OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
-- 
2.25.1




[PATCH v2 12/17] hw/loongarch: fdt adds pch_pic Controller

2023-12-18 Thread Song Gao
fdt adds pch pic controller, we use 'loongson,pch-pic-1.0'

See:
  drivers/irqchip/irq-loongson-pch-pic.c

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c| 30 +-
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 7534e42309..166e3f1892 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -125,6 +125,31 @@ static void fdt_add_extioiic_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_pic_node(LoongArchMachineState *lams,
+ uint32_t *extioic_phandle,
+ uint32_t *pch_pic_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
+hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
+
+*pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt,  nodename, "phandle", *pch_pic_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-pic-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
+   pch_pic_base, 0, pch_pic_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *extioic_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -535,7 +560,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, extioiic_phandle;
+uint32_t cpuintc_phandle, extioiic_phandle, pch_pic_phandle;
 
 extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
@@ -629,6 +654,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
 }
 
+/* Add PCH PIC node */
+fdt_add_pch_pic_node(lams, &extioiic_phandle, &pch_pic_phandle);
+
 pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
 start   =  num;
 num = EXTIOI_IRQS - start;
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index e753449593..fe260f0183 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -24,6 +24,7 @@
 #define VIRT_PCH_REG_BASE0x1000UL
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
+#define VIRT_PCH_REG_SIZE0x400
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PATCH v2 17/17] hw/loongarch: Add cells missing from rtc node

2023-12-18 Thread Song Gao
rtc node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e1a6ec86c8..c122d86048 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -195,7 +195,8 @@ static void fdt_add_flash_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_rtc_node(LoongArchMachineState *lams)
+static void fdt_add_rtc_node(LoongArchMachineState *lams,
+ uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_RTC_REG_BASE;
@@ -204,8 +205,13 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 
 nodename = g_strdup_printf("/rtc@%" PRIx64, base);
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 
"loongson,ls7a-rtc");
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls7a-rtc");
 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -613,7 +619,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
 sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE,
  qdev_get_gpio_in(pch_pic,
  VIRT_RTC_IRQ - VIRT_GSI_BASE));
-fdt_add_rtc_node(lams);
+fdt_add_rtc_node(lams, pch_pic_phandle);
 
 /* acpi ged */
 lams->acpi_ged = create_acpi_ged(pch_pic, lams);
-- 
2.25.1




[PATCH v2 08/17] hw/loongarch: Init efi_fdt table

2023-12-18 Thread Song Gao
Signed-off-by: Song Gao 
---
 hw/loongarch/boot.c | 11 +++
 include/hw/loongarch/boot.h |  4 
 2 files changed, 15 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 1600ae6e55..8c28a0ef6f 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -142,6 +142,16 @@ static void init_efi_initrd_table(struct efi_system_table 
*systab)
 g_free(initrd_table);
 }
 
+static void init_efi_fdt_table(struct efi_system_table *systab)
+{
+efi_guid_t tbl_guid = DEVICE_TREE_GUID;
+
+/* efi_configuration_table 3 */
+guidcpy(&systab->tables[2].guid, &tbl_guid);
+systab->tables[2].table = (void *)0x10; /* fdt_base 1MiB */
+systab->nr_tables = 3;
+}
+
 static void init_systab(struct loongarch_boot_info *info)
 {
 struct efi_system_table *systab;
@@ -160,6 +170,7 @@ static void init_systab(struct loongarch_boot_info *info)
 
 init_efi_boot_memmap(systab);
 init_efi_initrd_table(systab);
+init_efi_fdt_table(systab);
 
 rom_add_blob_fixed("tables_rom", efi_tables,
loader_rommap[EFI_TABLES].size,
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index e482b829f7..ce1cd51c01 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -36,6 +36,10 @@ typedef struct {
 EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
  0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
 
+#define DEVICE_TREE_GUID \
+EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5,  0x83, 0x0b, \
+ 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
-- 
2.25.1




[PATCH qemu v3 3/3] hw/arm: Connect STM32L4x5 EXTI to STM32L4x5 SoC

2023-12-18 Thread ~inesvarhol
From: Inès Varhol 

Signed-off-by: Arnaud Minier 
Signed-off-by: Inès Varhol 
---
 hw/arm/Kconfig |  1 +
 hw/arm/stm32l4x5_soc.c | 56 --
 include/hw/arm/stm32l4x5_soc.h |  3 ++
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 7520dc5cc0..9c9d5bb541 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -458,6 +458,7 @@ config STM32L4X5_SOC
 bool
 select ARM_V7M
 select OR_IRQ
+select STM32L4X5_EXTI
 
 config XLNX_ZYNQMP_ARM
 bool
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
index f476878b2c..b07593730f 100644
--- a/hw/arm/stm32l4x5_soc.c
+++ b/hw/arm/stm32l4x5_soc.c
@@ -45,10 +45,51 @@
 #define SRAM2_BASE_ADDRESS 0x1000
 #define SRAM2_SIZE (32 * KiB)
 
+#define EXTI_ADDR 0x40010400
+
+#define NUM_EXTI_IRQ 40
+/* Match exti line connections with their CPU IRQ number */
+/* See Vector Table (Reference Manual p.396) */
+static const int exti_irq[NUM_EXTI_IRQ] = {
+6,  /* GPIO[0] */
+7,  /* GPIO[1] */
+8,  /* GPIO[2] */
+9,  /* GPIO[3] */
+10, /* GPIO[4] */
+23, 23, 23, 23, 23, /* GPIO[5..9]  */
+40, 40, 40, 40, 40, 40, /* GPIO[10..15]*/
+1,  /* PVD */
+67, /* OTG_FS_WKUP, Direct */
+41, /* RTC_ALARM   */
+2,  /* RTC_TAMP_STAMP2/CSS_LSE */
+3,  /* RTC wakeup timer*/
+63, /* COMP1   */
+63, /* COMP2   */
+31, /* I2C1 wakeup, Direct */
+33, /* I2C2 wakeup, Direct */
+72, /* I2C3 wakeup, Direct */
+37, /* USART1 wakeup, Direct   */
+38, /* USART2 wakeup, Direct   */
+39, /* USART3 wakeup, Direct   */
+52, /* UART4 wakeup, Direct*/
+53, /* UART4 wakeup, Direct*/
+70, /* LPUART1 wakeup, Direct  */
+65, /* LPTIM1, Direct  */
+66, /* LPTIM2, Direct  */
+76, /* SWPMI1 wakeup, Direct   */
+1,  /* PVM1 wakeup */
+1,  /* PVM2 wakeup */
+1,  /* PVM3 wakeup */
+1,  /* PVM4 wakeup */
+78  /* LCD wakeup, Direct  */
+};
+
 static void stm32l4x5_soc_initfn(Object *obj)
 {
 Stm32l4x5SocState *s = STM32L4X5_SOC(obj);
 
+object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI);
+
 s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
 s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
 }
@@ -59,7 +100,9 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, 
Error **errp)
 Stm32l4x5SocState *s = STM32L4X5_SOC(dev_soc);
 const Stm32l4x5SocClass *sc = STM32L4X5_SOC_GET_CLASS(dev_soc);
 MemoryRegion *system_memory = get_system_memory();
-DeviceState *armv7m;
+DeviceState *dev, *armv7m;
+SysBusDevice *busdev;
+int i;
 
 /*
  * We use s->refclk internally and only define it with qdev_init_clock_in()
@@ -124,6 +167,16 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, 
Error **errp)
 return;
 }
 
+dev = DEVICE(&s->exti);
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->exti), errp)) {
+return;
+}
+busdev = SYS_BUS_DEVICE(dev);
+sysbus_mmio_map(busdev, 0, EXTI_ADDR);
+for (i = 0; i < NUM_EXTI_IRQ; i++) {
+sysbus_connect_irq(busdev, i, qdev_get_gpio_in(armv7m, exti_irq[i]));
+}
+
 /* APB1 BUS */
 create_unimplemented_device("TIM2",  0x4000, 0x400);
 create_unimplemented_device("TIM3",  0x4400, 0x400);
@@ -164,7 +217,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, 
Error **errp)
 create_unimplemented_device("SYSCFG",0x4001, 0x30);
 create_unimplemented_device("VREFBUF",   0x40010030, 0x1D0);
 create_unimplemented_device("COMP",  0x40010200, 0x200);
-create_unimplemented_device("EXTI",  0x40010400, 0x400);
 /* RESERVED:0x40010800, 0x1400 */
 create_unimplemented_device("FIREWALL",  0x40011C00, 0x400);
 /* RESERVED:0x40012000, 0x800 */
diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h
index 564201fee5..ac47158596 100644
--- a/include/hw/arm/stm32l4x5_soc.h
+++ b/include/hw/arm/stm32l4x5_soc.h
@@ -37,6 +37,7 @@
 #include "qemu/units.h"
 #include "hw/qdev-core.h"
 #include 

[PATCH qemu v3 1/3] hw/misc: Implement STM32L4x5 EXTI

2023-12-18 Thread ~inesvarhol
From: Inès Varhol 

Although very similar to the STM32F4xx EXTI, STM32L4x5 EXTI generates
more than 32 event/interrupt requests and thus uses more registers
than STM32F4xx EXTI which generates 23 event/interrupt requests.

Signed-off-by: Arnaud Minier 
Signed-off-by: Inès Varhol 
---
 hw/misc/Kconfig  |   3 +
 hw/misc/meson.build  |   1 +
 hw/misc/stm32l4x5_exti.c | 289 +++
 hw/misc/trace-events |   5 +
 include/hw/misc/stm32l4x5_exti.h |  51 ++
 5 files changed, 349 insertions(+)
 create mode 100644 hw/misc/stm32l4x5_exti.c
 create mode 100644 include/hw/misc/stm32l4x5_exti.h

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index cc8a8c1418..3efe3dc2cc 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -87,6 +87,9 @@ config STM32F4XX_SYSCFG
 config STM32F4XX_EXTI
 bool
 
+config STM32L4X5_EXTI
+bool
+
 config MIPS_ITU
 bool
 
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 36c20d5637..16db6e228d 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -110,6 +110,7 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL_TRNG', if_true: 
files(
 system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: 
files('stm32f2xx_syscfg.c'))
 system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: 
files('stm32f4xx_syscfg.c'))
 system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: 
files('stm32f4xx_exti.c'))
+system_ss.add(when: 'CONFIG_STM32L4X5_EXTI', if_true: 
files('stm32l4x5_exti.c'))
 system_ss.add(when: 'CONFIG_MPS2_FPGAIO', if_true: files('mps2-fpgaio.c'))
 system_ss.add(when: 'CONFIG_MPS2_SCC', if_true: files('mps2-scc.c'))
 
diff --git a/hw/misc/stm32l4x5_exti.c b/hw/misc/stm32l4x5_exti.c
new file mode 100644
index 00..9037740161
--- /dev/null
+++ b/hw/misc/stm32l4x5_exti.c
@@ -0,0 +1,289 @@
+/*
+ * STM32L4x5 EXTI (Extended interrupts and events controller)
+ *
+ * Copyright (c) 2023 Arnaud Minier 
+ * Copyright (c) 2023 Samuel Tardieu 
+ * Copyright (c) 2023 Inès Varhol 
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This work is based on the stm32f4xx_exti by Alistair Francis.
+ * Original code is licensed under the MIT License:
+ *
+ * Copyright (c) 2014 Alistair Francis 
+ */
+
+/*
+ * The reference used is the STMicroElectronics RM0351 Reference manual
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
+ * 
https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32l4x5_exti.h"
+
+#define EXTI_IMR1   0x00
+#define EXTI_EMR1   0x04
+#define EXTI_RTSR1  0x08
+#define EXTI_FTSR1  0x0C
+#define EXTI_SWIER1 0x10
+#define EXTI_PR10x14
+#define EXTI_IMR2   0x20
+#define EXTI_EMR2   0x24
+#define EXTI_RTSR2  0x28
+#define EXTI_FTSR2  0x2C
+#define EXTI_SWIER2 0x30
+#define EXTI_PR20x34
+
+#define EXTI_NUM_GPIO_EVENT_IN_LINES 16
+
+/* 0b_1010__ */
+#define DIRECT_LINE_MASK1 0xFF82
+/* 0b___1111 */
+#define DIRECT_LINE_MASK2 0x0087
+/* 0b___ */
+#define RESERVED_BITS_MASK2 0xFF00
+
+/* 0b___0000 */
+#define ACTIVABLE_MASK2 (~DIRECT_LINE_MASK2 & ~RESERVED_BITS_MASK2)
+
+static void stm32l4x5_exti_reset_hold(Object *obj)
+{
+Stm32l4x5ExtiState *s = STM32L4X5_EXTI(obj);
+
+s->imr[0] = DIRECT_LINE_MASK1;
+s->emr[0] = 0x;
+s->rtsr[0] = 0x;
+s->ftsr[0] = 0x;
+s->swier[0] = 0x;
+s->pr[0] = 0x;
+
+s->imr[1] = DIRECT_LINE_MASK2;
+s->emr[1] = 0x;
+s->rtsr[1] = 0x;
+s->ftsr[1] = 0x;
+s->swier[1] = 0x;
+s->pr[1] = 0x;
+}
+
+static void stm32l4x5_exti_set_irq(void *opaque, int irq, int level)
+{
+Stm32l4x5ExtiState *s = opaque;
+const unsigned n = irq >= 32;
+const int oirq = irq;
+
+trace_stm32l4x5_exti_set_irq(irq, level);
+
+if (irq >= 32) {
+/* Shift the value to enable access in x2 registers. */
+irq -= 32;
+}
+
+/* If the interrupt is masked, pr won't be raised */
+if (!((1 << irq) & s->imr[n])) {
+return;
+}
+
+if (((1 << irq) & s->rtsr[n]) && level) {
+/* Rising Edge */
+s->pr[n] |= 1 << irq;
+}
+
+if (((1 << irq) & s->ftsr[n]) && !level) {
+/* Falling Edge */
+s->pr[n] |= 1 << irq;
+}
+
+qemu_irq_pulse(s->irq[oirq]);
+}
+
+static uint64_t stm32l4x5_exti_read(void *opaque, hwaddr addr,
+unsigned int size)
+{
+Stm32l4x5ExtiState *s = opaque;
+uint32_t r = 0;
+const unsigned n = addr >= EXTI_IMR2;
+
+switch (addr) {
+case EXTI_IMR1:
+case EXTI_IMR2:
+

[PATCH qemu v3 2/3] tests/qtest: Add STM32L4x5 EXTI QTest testcase

2023-12-18 Thread ~inesvarhol
From: Inès Varhol 

Signed-off-by: Arnaud Minier 
Signed-off-by: Inès Varhol 
---
 tests/qtest/meson.build   |   5 +
 tests/qtest/stm32l4x5_exti-test.c | 485 ++
 2 files changed, 490 insertions(+)
 create mode 100644 tests/qtest/stm32l4x5_exti-test.c

diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 47dabf91d0..d5126f4d86 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -194,6 +194,10 @@ qtests_aspeed = \
   ['aspeed_hace-test',
'aspeed_smc-test',
'aspeed_gpio-test']
+
+qtests_stm32l4x5 = \
+  ['stm32l4x5_exti-test']
+
 qtests_arm = \
   (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
   (config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? 
['cmsdk-apb-dualtimer-test'] : []) + \
@@ -207,6 +211,7 @@ qtests_arm = \
   (config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : 
[]) + \
   (config_all_devices.has_key('CONFIG_VEXPRESS') ? ['test-arm-mptimer'] : []) 
+ \
   (config_all_devices.has_key('CONFIG_MICROBIT') ? ['microbit-test'] : []) + \
+  (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') ? qtests_stm32l4x5 : []) 
+ \
   ['arm-cpu-features',
'boot-serial-test']
 
diff --git a/tests/qtest/stm32l4x5_exti-test.c 
b/tests/qtest/stm32l4x5_exti-test.c
new file mode 100644
index 00..e105b3dea3
--- /dev/null
+++ b/tests/qtest/stm32l4x5_exti-test.c
@@ -0,0 +1,485 @@
+/*
+ * QTest testcase for STM32L4x5_EXTI
+ *
+ * Copyright (c) 2023 Arnaud Minier 
+ * Copyright (c) 2023 Inès Varhol 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+#define EXTI_BASE_ADDR 0x40010400
+#define EXTI_IMR1 0x00
+#define EXTI_EMR1 0x04
+#define EXTI_RTSR1 0x08
+#define EXTI_FTSR1 0x0C
+#define EXTI_SWIER1 0x10
+#define EXTI_PR1 0x14
+#define EXTI_IMR2 0x20
+#define EXTI_EMR2 0x24
+#define EXTI_RTSR2 0x28
+#define EXTI_FTSR2 0x2C
+#define EXTI_SWIER2 0x30
+#define EXTI_PR2 0x34
+
+#define NVIC_ISER 0xE000E100
+#define NVIC_ISPR 0xE000E200
+#define NVIC_ICPR 0xE000E280
+
+#define EXTI0_IRQ 6
+#define EXTI1_IRQ 7
+#define EXTI35_IRQ 1
+
+static void enable_nvic_irq(unsigned int n)
+{
+writel(NVIC_ISER, 1 << n);
+}
+
+static void unpend_nvic_irq(unsigned int n)
+{
+writel(NVIC_ICPR, 1 << n);
+}
+
+static bool check_nvic_pending(unsigned int n)
+{
+return readl(NVIC_ISPR) & (1 << n);
+}
+
+static void exti_writel(unsigned int offset, uint32_t value)
+{
+writel(EXTI_BASE_ADDR + offset, value);
+}
+
+static uint32_t exti_readl(unsigned int offset)
+{
+return readl(EXTI_BASE_ADDR + offset);
+}
+
+static void test_reg_write_read(void)
+{
+/* Test that non-reserved bits in xMR and xTSR can be set and cleared */
+
+exti_writel(EXTI_IMR1, 0x);
+uint32_t imr1 = exti_readl(EXTI_IMR1);
+g_assert_cmpuint(imr1, ==, 0x);
+exti_writel(EXTI_IMR1, 0x);
+imr1 = exti_readl(EXTI_IMR1);
+g_assert_cmpuint(imr1, ==, 0x);
+
+exti_writel(EXTI_EMR1, 0x);
+uint32_t emr1 = exti_readl(EXTI_EMR1);
+g_assert_cmpuint(emr1, ==, 0x);
+exti_writel(EXTI_EMR1, 0x);
+emr1 = exti_readl(EXTI_EMR1);
+g_assert_cmpuint(emr1, ==, 0x);
+
+exti_writel(EXTI_RTSR1, 0x);
+uint32_t rtsr1 = exti_readl(EXTI_RTSR1);
+g_assert_cmpuint(rtsr1, ==, 0x007D);
+exti_writel(EXTI_RTSR1, 0x);
+rtsr1 = exti_readl(EXTI_RTSR1);
+g_assert_cmpuint(rtsr1, ==, 0x);
+
+exti_writel(EXTI_FTSR1, 0x);
+uint32_t ftsr1 = exti_readl(EXTI_FTSR1);
+g_assert_cmpuint(ftsr1, ==, 0x007D);
+exti_writel(EXTI_FTSR1, 0x);
+ftsr1 = exti_readl(EXTI_FTSR1);
+g_assert_cmpuint(ftsr1, ==, 0x);
+
+exti_writel(EXTI_IMR2, 0x);
+uint32_t imr2 = exti_readl(EXTI_IMR2);
+g_assert_cmpuint(imr2, ==, 0x00FF);
+exti_writel(EXTI_IMR2, 0x);
+imr2 = exti_readl(EXTI_IMR2);
+g_assert_cmpuint(imr2, ==, 0x);
+
+exti_writel(EXTI_EMR2, 0x);
+uint32_t emr2 = exti_readl(EXTI_EMR2);
+g_assert_cmpuint(emr2, ==, 0x00FF);
+exti_writel(EXTI_EMR2, 0x);
+emr2 = exti_readl(EXTI_EMR2);
+g_assert_cmpuint(emr2, ==, 0x);
+
+exti_writel(EXTI_RTSR2, 0x);
+uint32_t rtsr2 = exti_readl(EXTI_RTSR2);
+g_assert_cmpuint(rtsr2, ==, 0x0078);
+exti_writel(EXTI_RTSR2, 0x);
+rtsr2 = exti_readl(EXTI_RTSR2);
+g_assert_cmpuint(rtsr2, ==, 0x);
+
+exti_writel(EXTI_FTSR2, 0x);
+uint32_t ftsr2 = exti_readl(EXTI_FTSR2);
+g_assert_cmpuint(ftsr2, ==, 0x0078);
+exti_writel(EXTI_FTSR2, 0x);
+ftsr2 = exti_readl(EXTI_FTSR2);
+g_assert_cmpuint(ftsr2, ==, 0x);
+}
+
+static void test_direct_lines_write(void)
+{
+/* Test that direct lines reserved bits are

[PATCH qemu v3 0/3] Add device STM32L4x5 EXTI

2023-12-18 Thread ~inesvarhol
Changes from non-RFC v2 to non-RFC v3:
- corrected the license

Changes from non-RFC v1 to non-RFC v2:
- correct the commit messages
- remove a misleading comment

Changes from v3 to non-RFC v1:
- separating the patch in 3 commits
- justifying in the commit message why we implement a new
model instead of changing the existing stm32f4xx_exti
- changed irq_raise to irq_pulse in register SWIERx write (in
stm32l4x5_exti_write)
to be consistent with the irq_pulse in stm32l4x5_exti_set_irq (and also
both these interrupts
are edge-triggered)
- changed the license to GPL

Changes from v2 to v3:
- adding more tests writing/reading in exti registers
- adding tests checking that interrupt work by reading NVIC registers
- correcting exti_write in SWIER (so it sets an irq only when a bit goes
from '0' to '1')
- correcting exti_set_irq (so it never writes in PR when the relevant
bit in IMR is '0')

Changes from v1 to v2:
- use arrays to deduplicate code and logic
- move internal constant EXTI_NUM_GPIO_EVENT_IN_LINES from the header
to the .c file
- Improve copyright headers
- replace static const with #define
- use the DEFINE_TYPES macro
- fill the impl and valid field of the exti's MemoryRegionOps
- fix invalid test caused by a last minute change

Based-on: <170256739558.25729.1405311371647046456...@git.sr.ht>
([PATCH qemu v3 0/2] hw/arm: Add minimal support for the B-L475E-IOT01A
board)

Inès Varhol (3):
  hw/misc: Implement STM32L4x5 EXTI
  tests/qtest: Add STM32L4x5 EXTI QTest testcase
  hw/arm: Connect STM32L4x5 EXTI to STM32L4x5 SoC

 hw/arm/Kconfig|   1 +
 hw/arm/stm32l4x5_soc.c|  56 +++-
 hw/misc/Kconfig   |   3 +
 hw/misc/meson.build   |   1 +
 hw/misc/stm32l4x5_exti.c  | 289 ++
 hw/misc/trace-events  |   5 +
 include/hw/arm/stm32l4x5_soc.h|   3 +
 include/hw/misc/stm32l4x5_exti.h  |  51 
 tests/qtest/meson.build   |   5 +
 tests/qtest/stm32l4x5_exti-test.c | 485 ++
 10 files changed, 897 insertions(+), 2 deletions(-)
 create mode 100644 hw/misc/stm32l4x5_exti.c
 create mode 100644 include/hw/misc/stm32l4x5_exti.h
 create mode 100644 tests/qtest/stm32l4x5_exti-test.c

-- 
2.38.5



Re: [PATCH 1/1] target/riscv: SMBIOS support for RISC-V virt machine

2023-12-18 Thread Heinrich Schuchardt

On 12/18/23 09:49, Sunil V L wrote:

Hi Heinrich,

Thanks for the patch!.

On Mon, Dec 18, 2023 at 08:40:18AM +0100, Heinrich Schuchardt wrote:

Generate SMBIOS tables for the RISC-V mach-virt.
Add CONFIG_SMBIOS=y to the RISC-V default config.

The implementation is based on the corresponding ARM and Loongson code.

With the patch the following firmware tables are provided:

 etc/smbios/smbios-anchor
 etc/smbios/smbios-tables

Booting Ubuntu 23.10 via EDK II allowed displaying the SMBIOS table using
the dmidecode command:

 Handle 0x0100, DMI type 1, 27 bytes
 System Information
 Manufacturer: QEMU
 Product Name: QEMU Virtual Machine
 Version: virt
 ...

Signed-off-by: Heinrich Schuchardt 
---
  hw/riscv/Kconfig |  1 +
  hw/riscv/virt.c  | 36 
  2 files changed, 37 insertions(+)

diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index b6a5eb4452..1e11ac9432 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -41,6 +41,7 @@ config RISCV_VIRT
  select RISCV_IMSIC
  select SIFIVE_PLIC
  select SIFIVE_TEST
+select SMBIOS
  select VIRTIO_MMIO
  select FW_CFG_DMA
  select PLATFORM_BUS
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index d2eac24156..6c27cb5330 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -36,6 +36,7 @@
  #include "hw/riscv/boot.h"
  #include "hw/riscv/numa.h"
  #include "kvm/kvm_riscv.h"
+#include "hw/firmware/smbios.h"
  #include "hw/intc/riscv_aclint.h"
  #include "hw/intc/riscv_aplic.h"
  #include "hw/intc/riscv_imsic.h"
@@ -1249,6 +1250,39 @@ static void create_platform_bus(RISCVVirtState *s, 
DeviceState *irqchip)
  sysbus_mmio_get_region(sysbus, 0));
  }
  
+static void virt_build_smbios(RISCVVirtState *s)

+{

Can we avoid duplicating this function which exists in other
architectures?



Every architecture uses it own structures (e.g. RISCVVirtState) and 
constants (e.g VIRT_DRAM). As long as this is not addressed we will have 
to live with this piece of code duplication.


After this patch is accepted we will have to work on improving SMBIOS 
3.7.0 compliance:


* Table 22
* * field Processor Family should contain a RISC-V specfic value. Maybe 
derived from TARGET_RISCV##.
* * field Processor ID should contain the value of mvendorid of hart 0 
(i.e. cpu->cfg.mvendorid).


* Table 44

The required contents of this table are provided in 
https://github.com/riscv/riscv-smbios .


Best regards

Heinrich



Re: [RFC PATCH] hw/arm: Prefer arm_feature() over object_property_find()

2023-12-18 Thread Peter Maydell
On Mon, 18 Dec 2023 at 07:26, Markus Armbruster  wrote:
>
> Peter Maydell  writes:
>
> > On Thu, 14 Dec 2023 at 17:14, Philippe Mathieu-Daudé  
> > wrote:
> >>
> >> QOM properties are added on the ARM vCPU object when a
> >> feature is present. Rather than checking the property
> >> is present, check the feature.
> >>
> >> Suggested-by: Markus Armbruster 
> >> Signed-off-by: Philippe Mathieu-Daudé 
> >> ---
> >> RFC: If there is no objection on this patch, I can split
> >>  as a per-feature series if necessary.
> >>
> >> Based-on: <20231123143813.42632-1-phi...@linaro.org>
> >>   "hw: Simplify accesses to CPUState::'start-powered-off' property"
> >
> > I'm not a super-fan of board-level code looking inside
> > the QOM object with direct use of arm_feature() when
> > it doesn't have to. What's wrong with asking whether
> > the property exists before trying to set it?
>
> I'm not a fan of using QOM instead of the native C interface.
>
> The native C interface is CPUArmState method arm_feature().

But we don't in most of these cases really want to know "is this
a CPU with feature foo?". What we're asking is "does this
QOM property exist so it won't blow up if I set/get it?".

> Attempts to use it on anything but a CPUArmState * will be caught by the
> compiler.  object_property_find() will happily take any Object.
>
> Likewise, typos in its second argument will be caught by the compiler.
> object_property_find() will happily return NULL then.
>
>
> I also don't like adding QOM properties to instances.
> arm_cpu_post_init() seems to do that.  I feel it's best to stick to
> class properties whenever practical.

I agree, and the Arm CPU is a bit of an outlier in what it's
doing, for reasons that are largely I think historical. I'd
be happy to review patches that change these to class properties
where applicable, but I suspect that might be tricky...

thanks
-- PMM



Re: [PATCH 2/2] hw/usb/hcd-xhci.c: allow unaligned access to Capability Registers

2023-12-18 Thread Tomoyuki Hirose
On Tue, Dec 12, 2023 at 7:26 PM Peter Maydell  wrote:
>
> On Tue, 12 Dec 2023 at 01:43, Tomoyuki Hirose
>  wrote:
> >
> > Thanks for comment.
> >
> > On Mon, Dec 11, 2023 at 10:57 PM Peter Maydell  
> > wrote:
> > > We should definitely look at fixing the unaligned access
> > > stuff, but the linked bug report is not trying to do an
> > > unaligned access -- it wants to do a 2-byte read from offset 2,
> > > which is aligned. The capability registers in the xHCI spec
> > > are also all at offsets and sizes that mean that a natural
> > > read of them is not unaligned.
> >
> > Shouldn't I link this bug report?
> > Or is it not appropriate to allow unaligned access?
>
> The bug report is definitely relevant. But depending
> on how tricky the unaligned access handling turns out to
> be to get right, we might be able to fix the bug by
> permitting aligned-but-not-4-bytes accesses. (I'm
> a bit surprised that doesn't work already, in fact:
> we use it in other devices.)
>
> thanks
> -- PMM

Thank you for answering my question.
The unaligned access handling of my patch is not so tricky.
If the access is unaligned, just correct the access size
and address and read the value as before.
Also, it is allowed by the specifications, and byte access
was possible even on real devices.

Regards,
Tomoyuki HIROSE



Re: [RFC PATCH] hw/arm: Prefer arm_feature() over object_property_find()

2023-12-18 Thread Peter Maydell
On Thu, 14 Dec 2023 at 17:14, Philippe Mathieu-Daudé  wrote:
>
> QOM properties are added on the ARM vCPU object when a
> feature is present. Rather than checking the property
> is present, check the feature.
>
> Suggested-by: Markus Armbruster 
> Signed-off-by: Philippe Mathieu-Daudé 
> ---
> RFC: If there is no objection on this patch, I can split
>  as a per-feature series if necessary.
>
> Based-on: <20231123143813.42632-1-phi...@linaro.org>
>   "hw: Simplify accesses to CPUState::'start-powered-off' property"
> ---
>  hw/arm/armv7m.c   | 21 -
>  hw/arm/exynos4210.c   |  4 ++--
>  hw/arm/highbank.c |  3 ++-
>  hw/arm/integratorcp.c |  5 ++---
>  hw/arm/realview.c |  2 +-
>  hw/arm/sbsa-ref.c |  3 ++-
>  hw/arm/versatilepb.c  |  5 ++---
>  hw/arm/vexpress.c |  6 --
>  hw/arm/virt.c | 27 +++
>  hw/arm/xilinx_zynq.c  |  2 +-
>  hw/cpu/a15mpcore.c| 17 +++--
>  hw/cpu/a9mpcore.c |  6 +++---
>  12 files changed, 57 insertions(+), 44 deletions(-)
>
> diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
> index 3a6d72b0f3..932061c11a 100644
> --- a/hw/arm/armv7m.c
> +++ b/hw/arm/armv7m.c
> @@ -302,28 +302,29 @@ static void armv7m_realize(DeviceState *dev, Error 
> **errp)
>
>  object_property_set_link(OBJECT(s->cpu), "memory", OBJECT(&s->container),
>   &error_abort);
> -if (object_property_find(OBJECT(s->cpu), "idau")) {
> +if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) {
>  object_property_set_link(OBJECT(s->cpu), "idau", s->idau,
>   &error_abort);
> -}
> -if (object_property_find(OBJECT(s->cpu), "init-svtor")) {
>  if (!object_property_set_uint(OBJECT(s->cpu), "init-svtor",
>s->init_svtor, errp)) {
>  return;
>  }
>  }
> -if (object_property_find(OBJECT(s->cpu), "init-nsvtor")) {
> +if (arm_feature(&s->cpu->env, ARM_FEATURE_M)) {

This doesn't make sense as a check -- we shouldn't be able to get
here if the CPU isn't M-profile.

>  if (!object_property_set_uint(OBJECT(s->cpu), "init-nsvtor",
>s->init_nsvtor, errp)) {
>  return;
>  }
>  }
> -if (object_property_find(OBJECT(s->cpu), "vfp")) {
> -if (!object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, errp)) {
> -return;
> +if (arm_feature(&s->cpu->env, ARM_FEATURE_AARCH64)) {

Similarly this can't possibly be an AArch64 CPU, so this is
not the correct condition to check.

> +if (cpu_isar_feature(aa64_fp_simd, s->cpu)) {
> +if (!object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, 
> errp)) {
> +return;
> +}
>  }
>  }
> -if (object_property_find(OBJECT(s->cpu), "dsp")) {
> +if (arm_feature(&s->cpu->env, ARM_FEATURE_M) &&
> +arm_feature(&s->cpu->env, ARM_FEATURE_THUMB_DSP)) {
>  if (!object_property_set_bool(OBJECT(s->cpu), "dsp", s->dsp, errp)) {

Another unnecessary "is this M-profile?" check. This also is
introducing a point of potential future failure because now
we have the condition for "do we have a dsp property" in two
places: in the CPU object where we add it, and then again here
when we set it. Now they can get out of sync.

Most of the others are similar. There might be places where we're
using the "does property X check" to do something more than just
guard "now set property X"; those are probably worth looking at
to see if they should be checking something else.

thanks
-- PMM



Re: [PATCH 12/12] hw/isa/vt82c686: Implement relocation of SuperI/O functions

2023-12-18 Thread Bernhard Beschow



Am 17. Dezember 2023 15:40:58 UTC schrieb BALATON Zoltan :
>On Sun, 17 Dec 2023, Bernhard Beschow wrote:
>> The VIA south bridges are able to relocate and enable or disable their 
>> SuperI/O
>> functions. So far this is hardcoded such that all functions are always 
>> enabled
>> and are located at fixed addresses.
>> 
>> Some PC BIOSes seem to probe for I/O occupancy before activating such a 
>> function
>> and issue an error in case of a conflict. Since the functions are enabled on
>> reset, conflicts are always detected. Prevent that by implementing 
>> relocation of
>> the SuperI/O functions.
>> 
>> Note that the reset I/O region of VT8231's serial port changes from
>> 0x2f8/enabled to 0x3f8/disabled. The ROM of the Pegasos II machine can 
>> handle it
>> since it enables and relocates the I/O region accordingly.
>
>"... but we need to do that when running without firmware which this patch 
>does." or something like that is missing here to complete the sentence.

I'll mention this in the next iteration.

> I think this part changing pegasos2.c could be split off in its own patch 
> coming before this one. Poking those registers before they are implemented is 
> harmless (the ROM does that already) but would make two simpler patches 
> instead of one doing two things.

Will do. I considered this but went with the combined approach for compactness.

>
>This is a welcome change but since vt82c686 uses isa-superio I wonder if it 
>there could be a way to add functions to isa-superio.c to set these base 
>addresses and enable/disable deivces in runtime instead of poking the 
>internals od superio in vt82c686.c? That looks to me a more object oriented 
>approach. Or going further with that maybe the fdc and serial device objects 
>should have methods to set their base that then either superio or vt82c686 
>could then use without peeking them or exposing the device sturctures.

Let's focus on this topic in the other thread.

Best regards,
Bernhard

>
>Regards,
>BALATON Zoltan
>
>> Signed-off-by: Bernhard Beschow 
>> ---
>> hw/isa/vt82c686.c | 140 --
>> hw/ppc/pegasos2.c |  15 +
>> 2 files changed, 124 insertions(+), 31 deletions(-)
>> 
>> diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
>> index 9c2333a277..8fbc016755 100644
>> --- a/hw/isa/vt82c686.c
>> +++ b/hw/isa/vt82c686.c
>> @@ -15,6 +15,9 @@
>> 
>> #include "qemu/osdep.h"
>> #include "hw/isa/vt82c686.h"
>> +#include "hw/block/fdc-isa.h"
>> +#include "hw/char/parallel-isa.h"
>> +#include "hw/char/serial-isa.h"
>> #include "hw/pci/pci.h"
>> #include "hw/qdev-properties.h"
>> #include "hw/ide/pci.h"
>> @@ -343,6 +346,46 @@ static const TypeInfo via_superio_info = {
>> 
>> #define TYPE_VT82C686B_SUPERIO "vt82c686b-superio"
>> 
>> +static void vt82c686b_superio_update(ViaSuperIOState *s)
>> +{
>> +FDCtrlISABus *fd = ISA_FDC(s->superio.floppy);
>> +ISASerialState *ss1 = ISA_SERIAL(s->superio.serial[0]);
>> +ISASerialState *ss2 = ISA_SERIAL(s->superio.serial[1]);
>> +ISAParallelState *ps = ISA_PARALLEL(s->superio.parallel[0]);
>> +
>> +portio_list_set_enabled(&ps->state.portio_list, (s->regs[0xe2] & 0x3) 
>> != 3);
>> +memory_region_set_enabled(&ss1->state.io, s->regs[0xe2] & BIT(2));
>> +memory_region_set_enabled(&ss2->state.io, s->regs[0xe2] & BIT(3));
>> +portio_list_set_enabled(&fd->state.portio_list, s->regs[0xe2] & BIT(4));
>> +
>> +fd->iobase = (s->regs[0xe3] & 0xfc) << 2;
>> +portio_list_set_address(&fd->state.portio_list, fd->iobase);
>> +
>> +ps->iobase = s->regs[0xe6] << 2;
>> +portio_list_set_address(&ps->state.portio_list, ps->iobase);
>> +
>> +ss1->iobase = (s->regs[0xe7] & 0xfe) << 2;
>> +memory_region_set_address(&ss1->state.io, ss1->iobase);
>> +
>> +ss2->iobase = (s->regs[0xe8] & 0xfe) << 2;
>> +memory_region_set_address(&ss2->state.io, ss2->iobase);
>> +}
>> +
>> +static int vmstate_vt82c686b_superio_post_load(void *opaque, int version_id)
>> +{
>> +ViaSuperIOState *s = opaque;
>> +
>> +vt82c686b_superio_update(s);
>> +
>> +return 0;
>> +}
>> +
>> +static const VMStateDescription vmstate_vt82c686b_superio = {
>> +.name = "vt82c686b_superio",
>> +.version_id = 1,
>> +.post_load = vmstate_vt82c686b_superio_post_load,
>> +};
>> +
>> static void vt82c686b_superio_cfg_write(void *opaque, hwaddr addr,
>> uint64_t data, unsigned size)
>> {
>> @@ -368,7 +411,11 @@ static void vt82c686b_superio_cfg_write(void *opaque, 
>> hwaddr addr,
>> case 0xfd ... 0xff:
>> /* ignore write to read only registers */
>> return;
>> -/* case 0xe6 ... 0xe8: Should set base port of parallel and serial */
>> +case 0xe2 ... 0xe3:
>> +case 0xe6 ... 0xe8:
>> +sc->regs[idx] = data;
>> +vt82c686b_superio_update(sc);
>> +return;
>> default:
>> qemu_log_mask(LOG_UNIMP,
>>   "via_superio_cfg: unimplemented registe

[PATCH v2] qemu_init: increase NOFILE soft limit on POSIX

2023-12-18 Thread Fiona Ebner
In many configurations, e.g. multiple vNICs with multiple queues or
with many Ceph OSDs, the default soft limit of 1024 is not enough.
QEMU is supposed to work fine with file descriptors >= 1024 and does
not use select() on POSIX. Bump the soft limit to the allowed hard
limit to avoid issues with the aforementioned configurations.

Of course the limit could be raised from the outside, but the man page
of systemd.exec states about 'LimitNOFILE=':

> Don't use.
> [...]
> Typically applications should increase their soft limit to the hard
> limit on their own, if they are OK with working with file
> descriptors above 1023,

If the soft limit is already the same as the hard limit, avoid the
superfluous setrlimit call. This can avoid a warning with a strict
seccomp filter blocking setrlimit if NOFILE was already raised before
executing QEMU.

Buglink: https://bugzilla.proxmox.com/show_bug.cgi?id=4507
Signed-off-by: Fiona Ebner 
---

Changes in v2:
* avoid the redundant setrlimit call when cur == max

 include/sysemu/os-posix.h |  1 +
 include/sysemu/os-win32.h |  5 +
 os-posix.c| 22 ++
 system/vl.c   |  2 ++
 4 files changed, 30 insertions(+)

diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h
index dff32ae185..b881ac6c6f 100644
--- a/include/sysemu/os-posix.h
+++ b/include/sysemu/os-posix.h
@@ -51,6 +51,7 @@ bool is_daemonized(void);
 void os_daemonize(void);
 bool os_set_runas(const char *user_id);
 void os_set_chroot(const char *path);
+void os_setup_limits(void);
 void os_setup_post(void);
 int os_mlock(void);
 
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index 1047d260cb..106f155037 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -128,6 +128,11 @@ static inline int os_mlock(void)
 return -ENOSYS;
 }
 
+void os_setup_limits(void)
+{
+return;
+}
+
 #define fsync _commit
 
 #if !defined(lseek)
diff --git a/os-posix.c b/os-posix.c
index 52ef6990ff..a4284e2c07 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -24,6 +24,7 @@
  */
 
 #include "qemu/osdep.h"
+#include 
 #include 
 #include 
 #include 
@@ -256,6 +257,27 @@ void os_daemonize(void)
 }
 }
 
+void os_setup_limits(void)
+{
+struct rlimit nofile;
+
+if (getrlimit(RLIMIT_NOFILE, &nofile) < 0) {
+warn_report("unable to query NOFILE limit: %s", strerror(errno));
+return;
+}
+
+if (nofile.rlim_cur == nofile.rlim_max) {
+return;
+}
+
+nofile.rlim_cur = nofile.rlim_max;
+
+if (setrlimit(RLIMIT_NOFILE, &nofile) < 0) {
+warn_report("unable to set NOFILE limit: %s", strerror(errno));
+return;
+}
+}
+
 void os_setup_post(void)
 {
 int fd = 0;
diff --git a/system/vl.c b/system/vl.c
index 2bcd9efb9a..6f42f37200 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -2774,6 +2774,8 @@ void qemu_init(int argc, char **argv)
 error_init(argv[0]);
 qemu_init_exec_dir(argv[0]);
 
+os_setup_limits();
+
 qemu_init_arch_modules();
 
 qemu_init_subsystems();
-- 
2.39.2





Re: [PATCH v2 0/4] scsi: eliminate AioContext lock

2023-12-18 Thread Kevin Wolf
[ Cc: qemu-block ]

Am 04.12.2023 um 17:42 hat Stefan Hajnoczi geschrieben:
> v2:
> - Reschedule BH in new AioContext if change is detected [Kevin]
> - Drop stray "remember" in Patch 2's commit description [Eric]
> 
> The SCSI subsystem uses the AioContext lock to protect internal state. This is
> necessary because the main loop and the IOThread can access SCSI state in
> parallel. This inter-thread access happens during scsi_device_purge_requests()
> and scsi_dma_restart_cb().
> 
> This patch series modifies the code so SCSI state is only accessed from the
> IOThread that is executing requests. Once this has been achieved the 
> AioContext
> lock is no longer necessary.
> 
> Note that a few aio_context_acquire()/aio_context_release() calls still remain
> after this series. They surround API calls that invoke AIO_WAIT_WHILE() and
> therefore still rely on the AioContext lock for now.
> 
> Stefan Hajnoczi (4):
>   scsi: only access SCSIDevice->requests from one thread
>   virtio-scsi: don't lock AioContext around
> virtio_queue_aio_attach_host_notifier()
>   scsi: don't lock AioContext in I/O code path
>   dma-helpers: don't lock AioContext in dma_blk_cb()

Thanks, applied to the block branch.

Kevin




Re: [PATCH v3] hw/usb: fix xhci port notify

2023-12-18 Thread Nikita Ostrenkov
ping
https://patchew.org/QEMU/20231117173916.3658-1-n.ostren...@gmail.com/

пт, 17 нояб. 2023 г., 20:39 Nikita Ostrenkov :

> From MCF5253 Reference manual
> https://www.nxp.com/docs/en/reference-manual/MCF5253RM.pdf
>
> Host mode: Port Change Detect. The controller sets this bit to a one when
> on any port a Connect Status occurs, a PortEnable/Disable Change occurs, an
> Over Current Change occurs, or the Force Port Resume bit is set as
> theresult of a J-K transition on the suspended port.
>
> Signed-off-by: Nikita Ostrenkov 
> ---
>  hw/usb/hcd-xhci.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
> index 4b60114207..1b2f4ac721 100644
> --- a/hw/usb/hcd-xhci.c
> +++ b/hw/usb/hcd-xhci.c
> @@ -2627,6 +2627,7 @@ static void xhci_port_notify(XHCIPort *port,
> uint32_t bits)
>  if (!xhci_running(port->xhci)) {
>  return;
>  }
> +port->xhci->usbsts |= USBSTS_PCD;
>  xhci_event(port->xhci, &ev, 0);
>  }
>
> --
> 2.34.1
>
>


Re: [PATCH 04/12] hw/block/fdc: Expose internal header

2023-12-18 Thread BALATON Zoltan

On Sun, 17 Dec 2023, Bernhard Beschow wrote:

Am 17. Dezember 2023 15:47:33 UTC schrieb BALATON Zoltan :

On Sun, 17 Dec 2023, Bernhard Beschow wrote:

Exposing the internal header allows for exposing struct FDCtrlISABus which is
encuraged by qdev guidelines.


Hopefully the guidelines don't encourage this as object orientation indeed 
encourages object encapsulation so only the object itseld should poke its 
internals and other objects should use methods the change object state. In QOM 
some object states were exposed in public headers to allow embedding those 
objects in other objects becuase C needs the struct size to allow that. This 
was to simplify memory management so the embedded objects don't need to be 
tracked and freed but would be created and freed with the other object 
embedding it but this does not mean the other object should poke into these 
object or that this is a general guideline to expose internal object state. I'd 
say the exposed objects are an exception instead of recommended guideline and 
only allowed for objects that need to be embeded in others but generally object 
encapsulation would be better to preserve where possible. This patch exposes 
objects so others can poke into them which would make those other objects depe

ndent on the implementation of these objects making these harder to chnage in 
the future so a better way may be to add methods to fdc and serial to allow 
changing their base address and map/unmap their ports and keep their internals 
unexposed.


Each ISADevice sub class would need concenience methods as well as each 
state class. This series touches three of each: fdc, parallel, serial. 
And each of those need two convenience methods: set_enabled() and 
set_address(). This would add another 12 functions on top of the current 
ones.


If all ISA devices need this then these should really be methods of 
ISADevice but since that's just an empty wrapper over devices each of 
which handles its own ports, the ISADevice does not know about those and 
since each device may have different ports and not all of them uses portio 
lists for this, moving port handling to ISADevice might be too big 
refactoring to do for this. Keeping these functions with the superio 
component devices so their implementation is kept private still worth it 
in my opinion so even if that adds 2 functions to superio component 
devices (which is not all ISA devices just a limited set) seems to be a 
better approach to me than breaking encapsulation of objects. These are 
simple access methods for internal object state which are common in object 
otiented programming.


Then ISASuperIODevice would require at least 6 more such methods (not 
counting the unneeded ones for IDE which might be desirable for 
consistency). So in the end we'd have at least 18 more methods. Is this 
really worth it?


We may do without these if we say superio is just a container of 
components so don't add forwarding methods but we can call the accessor 
methods of component objects from vt82c686.c. That's still better than 
reaching into object internals from foreign objects.


Regards,
BALATON Zoltan

I didn't feel very comfortable going this route, so ended up with the 
current solution poking the states directly. I'm open to different 
approaches including the one above but I'd really like to know the 
opinion of the maintainers, too.


Best regards,
Bernhard



Regards,
BALATON Zoltan


Signed-off-by: Bernhard Beschow 
---
MAINTAINERS   | 2 +-
hw/block/fdc-internal.h => include/hw/block/fdc.h | 4 ++--
hw/block/fdc-isa.c| 2 +-
hw/block/fdc-sysbus.c | 2 +-
hw/block/fdc.c| 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
rename hw/block/fdc-internal.h => include/hw/block/fdc.h (98%)

diff --git a/MAINTAINERS b/MAINTAINERS
index b4718fcf59..939f518701 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1945,9 +1945,9 @@ M: John Snow 
L: qemu-bl...@nongnu.org
S: Odd Fixes
F: hw/block/fdc.c
-F: hw/block/fdc-internal.h
F: hw/block/fdc-isa.c
F: hw/block/fdc-sysbus.c
+F: include/hw/block/fdc.h
F: include/hw/block/fdc-isa.h
F: tests/qtest/fdc-test.c
T: git https://gitlab.com/jsnow/qemu.git ide
diff --git a/hw/block/fdc-internal.h b/include/hw/block/fdc.h
similarity index 98%
rename from hw/block/fdc-internal.h
rename to include/hw/block/fdc.h
index 1728231a26..acca7e0d0e 100644
--- a/hw/block/fdc-internal.h
+++ b/include/hw/block/fdc.h
@@ -22,8 +22,8 @@
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
-#ifndef HW_BLOCK_FDC_INTERNAL_H
-#define HW_BLOCK_FDC_INTERNAL_H
+#ifndef HW_BLOCK_FDC_H
+#define HW_BLOCK_FDC_H

#include "exec/memory.h"
#include "exec/ioport.h"
diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c
index 6387dc94fa..7058d4118f 100644
--- a/hw/block/fdc-isa.c
+++ b/hw/block/fdc-isa.c
@@ -39,6 +39,7 @@
#include "hw/qdev-properti

Re: [v2 3/4] crypto: Support generic LUKS encryption

2023-12-18 Thread Daniel P . Berrangé
On Thu, Dec 07, 2023 at 12:37:44AM +0800, Hyman Huang wrote:
> By enhancing the LUKS driver, it is possible to enable
> the detachable LUKS header and, as a result, achieve
> general encryption for any disk format that QEMU has
> supported.
> 
> Take the qcow2 as an example, the usage of the generic
> LUKS encryption as follows:
> 
> 1. add a protocol blockdev node of data disk
> $ virsh qemu-monitor-command vm '{"execute":"blockdev-add",
> > "arguments":{"node-name":"libvirt-1-storage", "driver":"file",
> > "filename":"/path/to/test_disk.qcow2"}}'
> 
> 2. add a protocol blockdev node of LUKS header as above.
> $ virsh qemu-monitor-command vm '{"execute":"blockdev-add",
> > "arguments":{"node-name":"libvirt-2-storage", "driver":"file",
> > "filename": "/path/to/cipher.gluks" }}'
> 
> 3. add the secret for decrypting the cipher stored in LUKS
>header above
> $ virsh qemu-monitor-command vm '{"execute":"object-add",
> > "arguments":{"qom-type":"secret", "id":
> > "libvirt-2-storage-secret0", "data":"abc123"}}'
> 
> 4. add the qcow2-drived blockdev format node
> $ virsh qemu-monitor-command vm '{"execute":"blockdev-add",
> > "arguments":{"node-name":"libvirt-1-format", "driver":"qcow2",
> > "file":"libvirt-1-storage"}}'
> 
> 5. add the luks-drived blockdev to link the qcow2 disk with
>LUKS header by specifying the field "header"
> $ virsh qemu-monitor-command vm '{"execute":"blockdev-add",
> > "arguments":{"node-name":"libvirt-2-format", "driver":"luks",
> > "file":"libvirt-1-format", "header":"libvirt-2-storage",
> > "key-secret":"libvirt-2-format-secret0"}}'
> 
> 6. add the virtio-blk device finally
> $ virsh qemu-monitor-command vm '{"execute":"device_add",
> > "arguments": {"num-queues":"1", "driver":"virtio-blk-pci",
> > "drive": "libvirt-2-format", "id":"virtio-disk2"}}'
> 
> The generic LUKS encryption method of starting a virtual
> machine (VM) is somewhat similar to hot-plug in that both
> maintaining the same json command while the starting VM
> changes the "blockdev-add/device_add" parameters to
> "blockdev/device".
> 
> Signed-off-by: Hyman Huang 
> ---
>  block/crypto.c | 38 +-
>  1 file changed, 37 insertions(+), 1 deletion(-)
> 
> diff --git a/block/crypto.c b/block/crypto.c
> index f82b13d32b..7d70349463 100644
> --- a/block/crypto.c
> +++ b/block/crypto.c
> @@ -40,6 +40,7 @@ struct BlockCrypto {
>  QCryptoBlock *block;
>  bool updating_keys;
>  BdrvChild *header;  /* Reference to the detached LUKS header */
> +bool detached_mode; /* If true, LUKS plays a detached header role */
>  };
>  
>  
> @@ -64,12 +65,16 @@ static int block_crypto_read_func(QCryptoBlock *block,
>Error **errp)
>  {
>  BlockDriverState *bs = opaque;
> +BlockCrypto *crypto = bs->opaque;
>  ssize_t ret;
>  
>  GLOBAL_STATE_CODE();
>  GRAPH_RDLOCK_GUARD_MAINLOOP();
>  
> -ret = bdrv_pread(bs->file, offset, buflen, buf, 0);
> +if (crypto->detached_mode)
> +ret = bdrv_pread(crypto->header, offset, buflen, buf, 0);
> +else
> +ret = bdrv_pread(bs->file, offset, buflen, buf, 0);

This can be simplified to:

ret = bdrv_pread(bs->header ? bs->header : file, offset, buflen, buf, 0);

>  if (ret < 0) {
>  error_setg_errno(errp, -ret, "Could not read encryption header");
>  return ret;
> @@ -269,6 +274,8 @@ static int block_crypto_open_generic(QCryptoBlockFormat 
> format,
>  QCryptoBlockOpenOptions *open_opts = NULL;
>  unsigned int cflags = 0;
>  QDict *cryptoopts = NULL;
> +const char *header_bdref =
> +qdict_get_try_str(options, "header");
>  
>  GLOBAL_STATE_CODE();
>  
> @@ -277,6 +284,16 @@ static int block_crypto_open_generic(QCryptoBlockFormat 
> format,
>  return ret;
>  }
>  
> +if (header_bdref) {
> +crypto->detached_mode = true;

Drop this flag since it has no benefit.

> +crypto->header = bdrv_open_child(NULL, options, "header", bs,
> + &child_of_bds, BDRV_CHILD_METADATA,
> + false, errp);
> +if (!crypto->header) {
> +return -EINVAL;
> +}
> +}
> +
>  GRAPH_RDLOCK_GUARD_MAINLOOP();
>  
>  bs->supported_write_flags = BDRV_REQ_FUA &
> @@ -312,6 +329,14 @@ static int block_crypto_open_generic(QCryptoBlockFormat 
> format,
>  goto cleanup;
>  }
>  
> +if (crypto->detached_mode) {

  if (crypto->header != NULL)

> +/*
> + * Set payload offset to zero as the file bdref has no LUKS
> + * header under detached mode.
> + */
> +qcrypto_block_set_payload_offset(crypto->block, 0);

The LUKS header stores the payload offset.  If someone creates the LUKS
volume with a detached header, they may still choose to put the payload
at a non-zero offset.

So AFAICT, we should always honour the payload offset from the header,
even when detached.   

[PATCH qemu v2 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase

2023-12-18 Thread ~inesvarhol
From: Inès Varhol 

Acked-by: Alistair Francis 

Signed-off-by: Arnaud Minier 
Signed-off-by: Inès Varhol 
---
 tests/qtest/meson.build |   3 +-
 tests/qtest/stm32l4x5_syscfg-test.c | 408 
 2 files changed, 410 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/stm32l4x5_syscfg-test.c

diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index d5126f4d86..a2213d60b3 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -196,7 +196,8 @@ qtests_aspeed = \
'aspeed_gpio-test']
 
 qtests_stm32l4x5 = \
-  ['stm32l4x5_exti-test']
+  ['stm32l4x5_exti-test',
+   'stm32l4x5_syscfg-test']
 
 qtests_arm = \
   (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
diff --git a/tests/qtest/stm32l4x5_syscfg-test.c 
b/tests/qtest/stm32l4x5_syscfg-test.c
new file mode 100644
index 00..3edd13b222
--- /dev/null
+++ b/tests/qtest/stm32l4x5_syscfg-test.c
@@ -0,0 +1,408 @@
+/*
+ * QTest testcase for STM32L4x5_SYSCFG
+ *
+ * Copyright (c) 2023 Arnaud Minier 
+ * Copyright (c) 2023 Inès Varhol 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+#define SYSCFG_BASE_ADDR 0x4001
+#define SYSCFG_MEMRMP 0x00
+#define SYSCFG_CFGR1 0x04
+#define SYSCFG_EXTICR1 0x08
+#define SYSCFG_EXTICR2 0x0C
+#define SYSCFG_EXTICR3 0x10
+#define SYSCFG_EXTICR4 0x14
+#define SYSCFG_SCSR 0x18
+#define SYSCFG_CFGR2 0x1C
+#define SYSCFG_SWPR 0x20
+#define SYSCFG_SKR 0x24
+#define SYSCFG_SWPR2 0x28
+#define INVALID_ADDR 0x2C
+
+#define EXTI_BASE_ADDR 0x40010400
+#define EXTI_IMR1 0x00
+#define EXTI_RTSR1 0x08
+#define EXTI_FTSR1 0x0C
+
+static void syscfg_writel(unsigned int offset, uint32_t value)
+{
+writel(SYSCFG_BASE_ADDR + offset, value);
+}
+
+static uint32_t syscfg_readl(unsigned int offset)
+{
+return readl(SYSCFG_BASE_ADDR + offset);
+}
+
+static void exti_writel(unsigned int offset, uint32_t value)
+{
+writel(EXTI_BASE_ADDR + offset, value);
+}
+
+static void system_reset(void)
+{
+QDict *response;
+response = qtest_qmp(global_qtest, "{'execute': 'system_reset'}");
+g_assert(qdict_haskey(response, "return"));
+qobject_unref(response);
+}
+
+static void test_reset(void)
+{
+/*
+ * Test that registers are initialized at the correct values
+ */
+const uint32_t memrmp = syscfg_readl(SYSCFG_MEMRMP);
+g_assert_cmpuint(memrmp, ==, 0x);
+
+const uint32_t cfgr1 = syscfg_readl(SYSCFG_CFGR1);
+g_assert_cmpuint(cfgr1, ==, 0x7C01);
+
+const uint32_t exticr1 = syscfg_readl(SYSCFG_EXTICR1);
+g_assert_cmpuint(exticr1, ==, 0x);
+
+const uint32_t exticr2 = syscfg_readl(SYSCFG_EXTICR2);
+g_assert_cmpuint(exticr2, ==, 0x);
+
+const uint32_t exticr3 = syscfg_readl(SYSCFG_EXTICR3);
+g_assert_cmpuint(exticr3, ==, 0x);
+
+const uint32_t exticr4 = syscfg_readl(SYSCFG_EXTICR4);
+g_assert_cmpuint(exticr4, ==, 0x);
+
+const uint32_t scsr = syscfg_readl(SYSCFG_SCSR);
+g_assert_cmpuint(scsr, ==, 0x);
+
+const uint32_t cfgr2 = syscfg_readl(SYSCFG_CFGR2);
+g_assert_cmpuint(cfgr2, ==, 0x);
+
+const uint32_t swpr = syscfg_readl(SYSCFG_SWPR);
+g_assert_cmpuint(swpr, ==, 0x);
+
+const uint32_t skr = syscfg_readl(SYSCFG_SKR);
+g_assert_cmpuint(skr, ==, 0x);
+
+const uint32_t swpr2 = syscfg_readl(SYSCFG_SWPR2);
+g_assert_cmpuint(swpr2, ==, 0x);
+}
+
+static void test_reserved_bits(void)
+{
+/*
+ * Test that reserved bits stay at reset value
+ * (which is 0 for all of them) by writing '1'
+ * in all reserved bits (keeping reset value for
+ * other bits) and checking that the
+ * register is still at reset value
+ */
+syscfg_writel(SYSCFG_MEMRMP, 0xFEF8);
+const uint32_t memrmp = syscfg_readl(SYSCFG_MEMRMP);
+g_assert_cmpuint(memrmp, ==, 0x);
+
+syscfg_writel(SYSCFG_CFGR1, 0x7F00FEFF);
+const uint32_t cfgr1 = syscfg_readl(SYSCFG_CFGR1);
+g_assert_cmpuint(cfgr1, ==, 0x7C01);
+
+syscfg_writel(SYSCFG_EXTICR1, 0x);
+const uint32_t exticr1 = syscfg_readl(SYSCFG_EXTICR1);
+g_assert_cmpuint(exticr1, ==, 0x);
+
+syscfg_writel(SYSCFG_EXTICR2, 0x);
+const uint32_t exticr2 = syscfg_readl(SYSCFG_EXTICR2);
+g_assert_cmpuint(exticr2, ==, 0x);
+
+syscfg_writel(SYSCFG_EXTICR3, 0x);
+const uint32_t exticr3 = syscfg_readl(SYSCFG_EXTICR3);
+g_assert_cmpuint(exticr3, ==, 0x);
+
+syscfg_writel(SYSCFG_EXTICR4, 0x);
+const uint32_t exticr4 = syscfg_readl(SYSCFG_EXTICR4);
+g_assert_cmpuint(exticr4, ==, 0x);
+
+syscfg_writel(SYSCFG_SKR, 0xFF00);
+const uint32_t skr = syscfg_readl(SYSCFG_SKR);
+g_assert_cmpuint(skr, ==, 0x);
+}
+
+static void test

[PATCH qemu v2 3/3] hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC

2023-12-18 Thread ~inesvarhol
From: Inès Varhol 

The SYSCFG input GPIOs aren't connected yet. When the STM32L4x5 GPIO
device will be implemented, its output GPIOs will be connected to the
SYSCFG input GPIOs.

Signed-off-by: Arnaud Minier 
Signed-off-by: Inès Varhol 
---
 hw/arm/Kconfig |  1 +
 hw/arm/stm32l4x5_soc.c | 23 ++-
 include/hw/arm/stm32l4x5_soc.h |  2 ++
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 9c9d5bb541..e7c9470d59 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -458,6 +458,7 @@ config STM32L4X5_SOC
 bool
 select ARM_V7M
 select OR_IRQ
+select STM32L4X5_SYSCFG
 select STM32L4X5_EXTI
 
 config XLNX_ZYNQMP_ARM
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
index b07593730f..45f5c2156c 100644
--- a/hw/arm/stm32l4x5_soc.c
+++ b/hw/arm/stm32l4x5_soc.c
@@ -46,6 +46,7 @@
 #define SRAM2_SIZE (32 * KiB)
 
 #define EXTI_ADDR 0x40010400
+#define SYSCFG_ADDR 0x4001
 
 #define NUM_EXTI_IRQ 40
 /* Match exti line connections with their CPU IRQ number */
@@ -90,6 +91,8 @@ static void stm32l4x5_soc_initfn(Object *obj)
 
 object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI);
 
+object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG);
+
 s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
 s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
 }
@@ -167,6 +170,20 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, 
Error **errp)
 return;
 }
 
+/* System configuration controller */
+dev = DEVICE(&s->syscfg);
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), errp)) {
+return;
+}
+busdev = SYS_BUS_DEVICE(dev);
+sysbus_mmio_map(busdev, 0, SYSCFG_ADDR);
+/*
+ * TODO: when the GPIO device is implemented, connect it
+ * to SYCFG using `qdev_connect_gpio_out`, NUM_GPIOS and
+ * GPIO_NUM_PINS.
+ */
+
+/* EXTI device */
 dev = DEVICE(&s->exti);
 if (!sysbus_realize(SYS_BUS_DEVICE(&s->exti), errp)) {
 return;
@@ -177,6 +194,11 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, 
Error **errp)
 sysbus_connect_irq(busdev, i, qdev_get_gpio_in(armv7m, exti_irq[i]));
 }
 
+for (i = 0; i < 16; i++) {
+qdev_connect_gpio_out(DEVICE(&s->syscfg), i,
+  qdev_get_gpio_in(dev, i));
+}
+
 /* APB1 BUS */
 create_unimplemented_device("TIM2",  0x4000, 0x400);
 create_unimplemented_device("TIM3",  0x4400, 0x400);
@@ -214,7 +236,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, 
Error **errp)
 /* RESERVED:0x40009800, 0x6800 */
 
 /* APB2 BUS */
-create_unimplemented_device("SYSCFG",0x4001, 0x30);
 create_unimplemented_device("VREFBUF",   0x40010030, 0x1D0);
 create_unimplemented_device("COMP",  0x40010200, 0x200);
 /* RESERVED:0x40010800, 0x1400 */
diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h
index ac47158596..230348f847 100644
--- a/include/hw/arm/stm32l4x5_soc.h
+++ b/include/hw/arm/stm32l4x5_soc.h
@@ -37,6 +37,7 @@
 #include "qemu/units.h"
 #include "hw/qdev-core.h"
 #include "hw/arm/armv7m.h"
+#include "hw/misc/stm32l4x5_syscfg.h"
 #include "hw/misc/stm32l4x5_exti.h"
 #include "qom/object.h"
 
@@ -52,6 +53,7 @@ struct Stm32l4x5SocState {
 ARMv7MState armv7m;
 
 Stm32l4x5ExtiState exti;
+Stm32l4x5SyscfgState syscfg;
 
 MemoryRegion sram1;
 MemoryRegion sram2;
-- 
2.38.5



[PATCH qemu v2 1/3] hw/misc: Implement STM32L4x5 SYSCFG

2023-12-18 Thread ~inesvarhol
From: Inès Varhol 

Signed-off-by: Arnaud Minier 
Signed-off-by: Inès Varhol 
---
 hw/misc/Kconfig|   3 +
 hw/misc/meson.build|   1 +
 hw/misc/stm32l4x5_syscfg.c | 265 +
 hw/misc/trace-events   |   6 +
 include/hw/misc/stm32l4x5_syscfg.h |  54 ++
 5 files changed, 329 insertions(+)
 create mode 100644 hw/misc/stm32l4x5_syscfg.c
 create mode 100644 include/hw/misc/stm32l4x5_syscfg.h

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 3efe3dc2cc..4fc6b29b43 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -90,6 +90,9 @@ config STM32F4XX_EXTI
 config STM32L4X5_EXTI
 bool
 
+config STM32L4X5_SYSCFG
+bool
+
 config MIPS_ITU
 bool
 
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 16db6e228d..2ca2ce4b62 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -111,6 +111,7 @@ system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: 
files('stm32f2xx_syscfg.
 system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: 
files('stm32f4xx_syscfg.c'))
 system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: 
files('stm32f4xx_exti.c'))
 system_ss.add(when: 'CONFIG_STM32L4X5_EXTI', if_true: 
files('stm32l4x5_exti.c'))
+system_ss.add(when: 'CONFIG_STM32L4X5_SYSCFG', if_true: 
files('stm32l4x5_syscfg.c'))
 system_ss.add(when: 'CONFIG_MPS2_FPGAIO', if_true: files('mps2-fpgaio.c'))
 system_ss.add(when: 'CONFIG_MPS2_SCC', if_true: files('mps2-scc.c'))
 
diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
new file mode 100644
index 00..3af6bd7942
--- /dev/null
+++ b/hw/misc/stm32l4x5_syscfg.c
@@ -0,0 +1,265 @@
+/*
+ * STM32L4x5 SYSCFG (System Configuration Controller)
+ *
+ * Copyright (c) 2023 Arnaud Minier 
+ * Copyright (c) 2023 Inès Varhol 
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This work is based on the stm32f4xx_syscfg by Alistair Francis.
+ * Original code is licensed under the MIT License:
+ *
+ * Copyright (c) 2014 Alistair Francis 
+ */
+
+/*
+ * The reference used is the STMicroElectronics RM0351 Reference manual
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
+ * 
https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32l4x5_syscfg.h"
+
+#define SYSCFG_MEMRMP 0x00
+#define SYSCFG_CFGR1 0x04
+#define SYSCFG_EXTICR1 0x08
+#define SYSCFG_EXTICR2 0x0C
+#define SYSCFG_EXTICR3 0x10
+#define SYSCFG_EXTICR4 0x14
+#define SYSCFG_SCSR 0x18
+#define SYSCFG_CFGR2 0x1C
+#define SYSCFG_SWPR 0x20
+#define SYSCFG_SKR 0x24
+#define SYSCFG_SWPR2 0x28
+
+/* __0001_0111 */
+#define ACTIVABLE_BITS_MEMRP 0x0107
+
+/* 1100__0001_ */
+#define ACTIVABLE_BITS_CFGR1 0xFCFF0100
+/* ___0001 */
+#define FIREWALL_DISABLE_CFGR1 0x0001
+
+/* ___ */
+#define ACTIVABLE_BITS_EXTICR 0x
+
+/* ___0011 */
+/* #define ACTIVABLE_BITS_SCSR 0x0003 */
+
+/* ___ */
+#define ECC_LOCK_CFGR2 0x000F
+/* __0001_ */
+#define SRAM2_PARITY_ERROR_FLAG_CFGR2 0x0100
+
+/* ___ */
+#define ACTIVABLE_BITS_SKR 0x00FF
+
+static void stm32l4x5_syscfg_hold_reset(Object *obj)
+{
+Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj);
+
+s->memrmp = 0x;
+s->cfgr1 = 0x7C01;
+s->exticr[0] = 0x;
+s->exticr[1] = 0x;
+s->exticr[2] = 0x;
+s->exticr[3] = 0x;
+s->scsr = 0x;
+s->cfgr2 = 0x;
+s->swpr = 0x;
+s->skr = 0x;
+s->swpr2 = 0x;
+}
+
+static void stm32l4x5_syscfg_set_irq(void *opaque, int irq, int level)
+{
+Stm32l4x5SyscfgState *s = opaque;
+uint8_t gpio = irq / GPIO_NUM_PINS;
+g_assert(gpio < NUM_GPIOS);
+
+int line = irq % GPIO_NUM_PINS;
+int exticr_reg = line / 4;
+int startbit = (irq % 4) * 4;
+
+trace_stm32l4x5_syscfg_set_irq(gpio, line, level);
+
+if (extract32(s->exticr[exticr_reg], startbit, 4) == gpio) {
+trace_stm32l4x5_syscfg_pulse_exti(line);
+qemu_set_irq(s->gpio_out[line], level);
+   }
+}
+
+static uint64_t stm32l4x5_syscfg_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+Stm32l4x5SyscfgState *s = opaque;
+
+trace_stm32l4x5_syscfg_read(addr);
+
+switch (addr) {
+case SYSCFG_MEMRMP:
+return s->memrmp;
+case SYSCFG_CFGR1:
+return s->cfgr1;
+case SYSCFG_EXTICR1...SYSCFG_EXTICR4:
+return s->exticr[(addr - SYSCFG_EXTICR1) / 4];
+case SYSCFG_SCSR:
+return s->

Re: [v2 1/4] crypto: Introduce option and structure for detached LUKS header

2023-12-18 Thread Daniel P . Berrangé
On Thu, Dec 07, 2023 at 12:37:42AM +0800, Hyman Huang wrote:
> Add the "header" option for the LUKS format. This field would be
> used to identify the blockdev's position where a detachable LUKS
> header is stored.
> 
> In addition, introduce header field in struct BlockCrypto
> 
> Signed-off-by: Hyman Huang 
> ---
>  block/crypto.c   | 1 +
>  qapi/block-core.json | 6 +-
>  2 files changed, 6 insertions(+), 1 deletion(-)

Reviewed-by: Daniel P. Berrangé 


With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [v2 2/4] crypto: Introduce payload offset set function

2023-12-18 Thread Daniel P . Berrangé
On Thu, Dec 07, 2023 at 12:37:43AM +0800, Hyman Huang wrote:
> Signed-off-by: Hyman Huang 
> ---
>  crypto/block.c | 4 
>  include/crypto/block.h | 1 +
>  2 files changed, 5 insertions(+)

Reviewed-by: Daniel P. Berrangé 

however, based on my comment in patch #3, I'm not convinced this method
is needed

> 
> diff --git a/crypto/block.c b/crypto/block.c
> index 7bb4b74a37..3dcf22a69f 100644
> --- a/crypto/block.c
> +++ b/crypto/block.c
> @@ -319,6 +319,10 @@ QCryptoHashAlgorithm 
> qcrypto_block_get_kdf_hash(QCryptoBlock *block)
>  return block->kdfhash;
>  }
>  
> +void qcrypto_block_set_payload_offset(QCryptoBlock *block, uint64_t offset)
> +{
> +block->payload_offset = offset;
> +}
>  
>  uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
>  {
> diff --git a/include/crypto/block.h b/include/crypto/block.h
> index 4f63a37872..b47a90c529 100644
> --- a/include/crypto/block.h
> +++ b/include/crypto/block.h
> @@ -312,4 +312,5 @@ void qcrypto_block_free(QCryptoBlock *block);
>  
>  G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlock, qcrypto_block_free)
>  
> +void qcrypto_block_set_payload_offset(QCryptoBlock *block, uint64_t offset);
>  #endif /* QCRYPTO_BLOCK_H */
> -- 
> 2.39.1
> 

With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




[PATCH qemu v2 0/3] Add device STM32L4x5 SYSCFG

2023-12-18 Thread ~inesvarhol
Hello Alistair, thank you for your comments.

Changes from v1 to v2:
- explain in 3rd commit why SYSCFG input GPIOs aren't connected and add
a TODO comment in stm32l4x5_soc.c
- use macros `NUM_GPIOS` and `GPIO_NUM_PINS` in
`stm32l4x5_syscfg_set_irq`
- rename STM32L4XX to STM32L4X5, Stm32l4xx to Stm32l4x5
(the SYSCFG implementation is only valid for STM32L4x5 and STM32L4x6
but not for STM32L41xx/42xx/43xx/44xx)
- refactor STM32L4x5SyscfgState to Stm32l4x5SyscfgState to be
consistent with other peripherals

Based-on: <170289109015.23396.942818131520623439...@git.sr.ht>
([PATCH qemu v3 0/3] Add device STM32L4x5 EXTI)

Signed-off-by: Arnaud Minier 
Signed-off-by: Inès Varhol 

Inès Varhol (3):
  hw/misc: Implement STM32L4x5 SYSCFG
  tests/qtest: Add STM32L4x5 SYSCFG QTest testcase
  hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC

 hw/arm/Kconfig  |   1 +
 hw/arm/stm32l4x5_soc.c  |  23 +-
 hw/misc/Kconfig |   3 +
 hw/misc/meson.build |   1 +
 hw/misc/stm32l4x5_syscfg.c  | 265 ++
 hw/misc/trace-events|   6 +
 include/hw/arm/stm32l4x5_soc.h  |   2 +
 include/hw/misc/stm32l4x5_syscfg.h  |  54 
 tests/qtest/meson.build |   3 +-
 tests/qtest/stm32l4x5_syscfg-test.c | 408 
 10 files changed, 764 insertions(+), 2 deletions(-)
 create mode 100644 hw/misc/stm32l4x5_syscfg.c
 create mode 100644 include/hw/misc/stm32l4x5_syscfg.h
 create mode 100644 tests/qtest/stm32l4x5_syscfg-test.c

-- 
2.38.5



Re: [PATCH v7] ui/cocoa: Use NSWindow's ability to resize

2023-12-18 Thread BALATON Zoltan

On Mon, 18 Dec 2023, Akihiko Odaki wrote:

On 2023/12/17 20:39, BALATON Zoltan wrote:

On Sun, 17 Dec 2023, Akihiko Odaki wrote:

This change brings two new features:
- The window will be resizable if "Zoom To Fit" is eanbled
- The window can be made full screen by clicking full screen button
 provided by the platform. (The left-top green button.)

Signed-off-by: Akihiko Odaki 
Tested-by: Rene Engel 
---
V5 -> V6:
 Rebased.
---
Changes in v7:
- Fixed zoom-to-fit option. (Marek Glogowski)
- Link to v6: 
https://lore.kernel.org/r/20231211-cocoa-v6-1-49f3be019...@daynix.com

---
ui/cocoa.m | 542 
+

1 file changed, 258 insertions(+), 284 deletions(-)


Is ir possible to break this patch up into smaller ones for easier review? 
E.g. separate patch moving mouse event handling out of handleEventLocked, 
replacing stretch_video flag with NSWindowStyleMaskResizable and whatever 
else can be done as independent steps? Not sure if that's possible or needs 
the whole chnage at once but this patch seems to be too big. Some more 
comments below.


I split it into three patches with v8, but most changes are still in one 
patch because they depend on the change to unify the full screen window and 
normal window and vice-versa.


It still helps to remove unrelated changes from the big patch so it's 
more obvious what's needed for that change and thus easier to review.


[...]

@@ -513,36 +504,43 @@ - (void) drawRect:(NSRect) rect
    }
}

-- (void) setContentDimensions
+- (NSSize) fixZoomedFullScreenSize:(NSSize)proposedSize
{
-    COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
+    NSSize size;

-    if (isFullscreen) {
-    cdx = [[NSScreen mainScreen] frame].size.width / 
(float)screen.width;
-    cdy = [[NSScreen mainScreen] frame].size.height / 
(float)screen.height;

+    size.width = (CGFloat)screen.width * proposedSize.height;
+    size.height = (CGFloat)screen.height * proposedSize.width;


One of these will be overwritten in the next if below so maybe drop this 
init and do the calculation in the if legs which is then also clearer to 
show that this would scale one of these with screen.width/screen.height or 
the inverse of that.


This also removes stretch_video flag and the calculation to preserve aspect 
ratio. Is that correct? Would it now distort the image when zooming to full 
screen if guest resolution is not the same as host screen? Is that how 
zoom-to-fit should work? At leest with -display sdl going to full screen 
guest screen is zoomed preserving aspect ratio but maybe sdl does not have 
zoom-to-fit option. I don't know how it works with other displays such as 
gtk.


The purpose of this method is to fix the aspect ratio for zoom-to-fit by 
shrinking width or height. It operates in the three steps:

1. Compute the values necessary either for shrinking width or height.
2. Decide which of width or height to shrink.
3. Compute the final values.


Wouldn't it be simpler to do in two steps:
1. Decide what needs to be scaled
2. Do the computation accordingly
I.e.

if (size.width < size.height) {
    size.width = proposedSize.height * (CGFloat)screen.width / screen.height;
    size.height = proposedSize.height;
} else {
    size.width = proposedSize.width;
    size.height = proposedSize.width * (CGFloat)screen.height / screen.width;
}

Seems to me more explicit than doing the scale factor calculation split in 
two lines that's harder to follow. I had to think about what that does 
while this shows it clearer. If you prefer shorter lines you could also 
init size = proposedSize and then scale either width or height afterwards 
which would still be clearer than your way I think.


Regaards,
BALATON Zoltan

Re: [v2 4/4] block: Support detached LUKS header creation for blockdev-create

2023-12-18 Thread Daniel P . Berrangé
On Thu, Dec 07, 2023 at 12:37:45AM +0800, Hyman Huang wrote:
> Provide the "detached-mode" option for detached LUKS header
> formatting.
> 
> To format the LUKS header on the pre-creating disk, example
> as follows:
> 
> 1. add a protocol blockdev node of LUKS header
> $ virsh qemu-monitor-command vm '{"execute":"blockdev-add",
> > "arguments":{"node-name":"libvirt-1-storage", "driver":"file",
> > "filename":"/path/to/cipher.gluks" }}'
> 
> 2. add the secret for encrypting the cipher stored in LUKS
>header above
> $ virsh qemu-monitor-command vm '{"execute":"object-add",
> > "arguments":{"qom-type": "secret", "id":
> > "libvirt-1-storage-secret0", "data": "abc123"}}'
> 
> 3. format the disk node
> $ virsh qemu-monitor-command vm '{"execute":"blockdev-create",
> > "arguments":{"job-id":"job0", "options":{"driver":"luks",
> > "size":0, "file":"libvirt-1-storage", "detached-mode":true,
> > "cipher-alg":"aes-256",
> > "key-secret":"libvirt-3-storage-encryption-secret0"}}}'
> 
> Signed-off-by: Hyman Huang 
> ---
>  block/crypto.c   | 8 +++-
>  qapi/block-core.json | 5 -
>  2 files changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/block/crypto.c b/block/crypto.c
> index 7d70349463..e77c49bd0c 100644
> --- a/block/crypto.c
> +++ b/block/crypto.c
> @@ -667,10 +667,12 @@ block_crypto_co_create_luks(BlockdevCreateOptions 
> *create_options, Error **errp)
>  BlockDriverState *bs = NULL;
>  QCryptoBlockCreateOptions create_opts;
>  PreallocMode preallocation = PREALLOC_MODE_OFF;
> +int64_t size;
>  int ret;
>  
>  assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
>  luks_opts = &create_options->u.luks;
> +size = luks_opts->size;
>  
>  bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp);
>  if (bs == NULL) {
> @@ -686,7 +688,11 @@ block_crypto_co_create_luks(BlockdevCreateOptions 
> *create_options, Error **errp)
>  preallocation = luks_opts->preallocation;
>  }
>  
> -ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
> +if (luks_opts->detached_mode) {
> +size = 0;
> +}
> +
> +ret = block_crypto_co_create_generic(bs, size, &create_opts,
>   preallocation, errp);
>  if (ret < 0) {
>  goto fail;
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 10be08d08f..1e7a7e1b05 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -4952,13 +4952,16 @@
>  # @preallocation: Preallocation mode for the new image (since: 4.2)
>  # (default: off; allowed values: off, metadata, falloc, full)
>  #
> +# @detached-mode: create a detached LUKS header. (since 9.0)
> +#
>  # Since: 2.12
>  ##
>  { 'struct': 'BlockdevCreateOptionsLUKS',
>'base': 'QCryptoBlockCreateOptionsLUKS',
>'data': { 'file': 'BlockdevRef',
>  'size': 'size',
> -'*preallocation':   'PreallocMode' } }
> +'*preallocation':   'PreallocMode',
> +'*detached-mode':   'bool'}}

Using a bool flag here is insufficiently flexible. We need to be able to
honour preallocation of the payload device, while using a separate
header.

You need to make the existing 'file' optional, while also adding an
extra optional 'header' field. ie

  { 'struct': 'BlockdevCreateOptionsLUKS',
'base': 'QCryptoBlockCreateOptionsLUKS',
'data': { '*file':'BlockdevRef',
  '*header':  'BlockdevRef',
  'size': 'size',
  '*preallocation':   'PreallocMode' } }


If 'preallocation' is requested, then we must enforce that 'file' is
non-NULL in the code.

With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [v2 0/4] Support generic Luks encryption

2023-12-18 Thread Daniel P . Berrangé
On Thu, Dec 07, 2023 at 12:37:41AM +0800, Hyman Huang wrote:
> v2:
> - Simplify the design by reusing the LUKS driver to implement
>   the generic Luks encryption, thank Daniel for the insightful 
>   advice.
> - rebase on master. 
> 

> Hyman Huang (4):
>   crypto: Introduce option and structure for detached LUKS header
>   crypto: Introduce payload offset set function
>   crypto: Support generic LUKS encryption
>   block: Support detached LUKS header creation for blockdev-create
> 
>  block/crypto.c | 47 --
>  crypto/block.c |  4 
>  include/crypto/block.h |  1 +
>  qapi/block-core.json   | 11 --
>  4 files changed, 59 insertions(+), 4 deletions(-)

Could you add a scenario tests/qemu-iotests/tests/luks-detached-header
to provide coverage of this method feature.

With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




[PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM

2023-12-18 Thread Peter Maydell
FEAT_NV2 requires that when HCR_EL2.{NV,NV2} == 0b11 then accesses by
EL1 to certain system registers are redirected to RAM.  The full list
of affected registers is in the table in rule R_CSRPQ in the Arm ARM.
The registers may be normally accessible at EL1 (like ACTLR_EL1), or
normally UNDEF at EL1 (like HCR_EL2).  Some registers redirect to RAM
only when HCR_EL2.NV1 is 0, and some only when HCR_EL2.NV1 is 1;
others trap in both cases.

Add the infrastructure for identifying which registers should be
redirected and turning them into memory accesses.

This code does not set the correct syndrome or arrange for the
exception to be taken to the correct target EL if the access via
VNCR_EL2 faults; we will do that in the next commit.

Subsequent commits will mark up the relevant regdefs to set their
nv2_redirect_offset, and if relevant one of the two flags which
indicates that the redirect happens only for a particular value of
HCR_EL2.NV1.

Signed-off-by: Peter Maydell 
---
 target/arm/cpregs.h| 12 +++
 target/arm/cpu.h   |  4 +++
 target/arm/tcg/translate.h |  6 
 target/arm/tcg/hflags.c|  6 
 target/arm/tcg/translate-a64.c | 58 ++
 5 files changed, 86 insertions(+)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index cb795bed75b..b6fdd0f3eb4 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -826,6 +826,11 @@ typedef void CPResetFn(CPUARMState *env, const 
ARMCPRegInfo *opaque);
 
 #define CP_ANY 0xff
 
+/* Flags in the high bits of nv2_redirect_offset */
+#define NV2_REDIR_NV1 0x4000 /* Only redirect when HCR_EL2.NV1 == 1 */
+#define NV2_REDIR_NO_NV1 0x8000 /* Only redirect when HCR_EL2.NV1 == 0 */
+#define NV2_REDIR_FLAG_MASK 0xc000
+
 /* Definition of an ARM coprocessor register */
 struct ARMCPRegInfo {
 /* Name of register (useful mainly for debugging, need not be unique) */
@@ -867,6 +872,13 @@ struct ARMCPRegInfo {
  * value encodes both the trap register and bit within it.
  */
 FGTBit fgt;
+
+/*
+ * Offset from VNCR_EL2 when FEAT_NV2 redirects access to memory;
+ * may include an NV2_REDIR_* flag.
+ */
+uint32_t nv2_redirect_offset;
+
 /*
  * The opaque pointer passed to define_arm_cp_regs_with_opaque() when
  * this register was defined: can be used to hand data through to the
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e60b4f34fe4..bc4fa95ea35 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3244,6 +3244,10 @@ FIELD(TBFLAG_A64, ATA0, 31, 1)
 FIELD(TBFLAG_A64, NV, 32, 1)
 FIELD(TBFLAG_A64, NV1, 33, 1)
 FIELD(TBFLAG_A64, NV2, 34, 1)
+/* Set if FEAT_NV2 RAM accesses use the EL2&0 translation regime */
+FIELD(TBFLAG_A64, NV2_MEM_E20, 35, 1)
+/* Set if FEAT_NV2 RAM accesses are big-endian */
+FIELD(TBFLAG_A64, NV2_MEM_BE, 36, 1)
 
 /*
  * Helpers for using the above. Note that only the A64 accessors use
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 9e13c4ef7b6..93be745cf33 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -150,6 +150,10 @@ typedef struct DisasContext {
 bool nv1;
 /* True if NV enabled and HCR_EL2.NV2 is set */
 bool nv2;
+/* True if NV2 enabled and NV2 RAM accesses use EL2&0 translation regime */
+bool nv2_mem_e20;
+/* True if NV2 enabled and NV2 RAM accesses are big-endian */
+bool nv2_mem_be;
 /*
  * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
  *  < 0, set by the current instruction.
@@ -165,6 +169,8 @@ typedef struct DisasContext {
 int c15_cpar;
 /* TCG op of the current insn_start.  */
 TCGOp *insn_start;
+/* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */
+uint32_t nv2_redirect_offset;
 } DisasContext;
 
 typedef struct DisasCompare {
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index d2b352663e8..8e5d35d9227 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -307,6 +307,12 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, 
int el, int fp_el,
 }
 if (hcr & HCR_NV2) {
 DP_TBFLAG_A64(flags, NV2, 1);
+if (hcr & HCR_E2H) {
+DP_TBFLAG_A64(flags, NV2_MEM_E20, 1);
+}
+if (env->cp15.sctlr_el[2] & SCTLR_EE) {
+DP_TBFLAG_A64(flags, NV2_MEM_BE, 1);
+}
 }
 }
 
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 6909c9df30d..128bff4b445 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2134,6 +2134,7 @@ static void handle_sys(DisasContext *s, bool isread,
 bool nv_trap_to_el2 = false;
 bool nv_redirect_reg = false;
 bool skip_fp_access_checks = false;
+bool nv2_mem_redirect = false;
 TCGv_ptr tcg_ri = NULL;
 TCGv_i64 tcg_rt;
 uint32_t syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, 
isread);
@@ -2166,6 +216

[PATCH 10/35] target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0

2023-12-18 Thread Peter Maydell
The alias registers like SCTLR_EL12 only exist when HCR_EL2.E2H
is 1; they should UNDEF otherwise. We weren't implementing this.
Add an intercept of the accessfn for these aliases, and implement
the UNDEF check.

Signed-off-by: Peter Maydell 
---
 target/arm/cpregs.h |  3 ++-
 target/arm/helper.c | 16 
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index f1293d16c07..e748d184cb6 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -937,7 +937,7 @@ struct ARMCPRegInfo {
 CPResetFn *resetfn;
 
 /*
- * "Original" writefn and readfn.
+ * "Original" readfn, writefn, accessfn.
  * For ARMv8.1-VHE register aliases, we overwrite the read/write
  * accessor functions of various EL1/EL0 to perform the runtime
  * check for which sysreg should actually be modified, and then
@@ -948,6 +948,7 @@ struct ARMCPRegInfo {
  */
 CPReadFn *orig_readfn;
 CPWriteFn *orig_writefn;
+CPAccessFn *orig_accessfn;
 };
 
 /*
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c6f069b74cd..e90eb5e16f3 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6519,6 +6519,20 @@ static void el2_e2h_e12_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 return ri->orig_writefn(env, ri->opaque, value);
 }
 
+static CPAccessResult el2_e2h_e12_access(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+/* FOO_EL12 aliases only exist when E2H is 1; otherwise they UNDEF */
+if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
+return CP_ACCESS_TRAP_UNCATEGORIZED;
+}
+if (ri->orig_accessfn) {
+return ri->orig_accessfn(env, ri->opaque, isread);
+}
+return CP_ACCESS_OK;
+}
+
 static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
 {
 struct E2HAlias {
@@ -6632,6 +6646,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU 
*cpu)
 new_reg->opaque = src_reg;
 new_reg->orig_readfn = src_reg->readfn ?: raw_read;
 new_reg->orig_writefn = src_reg->writefn ?: raw_write;
+new_reg->orig_accessfn = src_reg->accessfn;
 if (!new_reg->raw_readfn) {
 new_reg->raw_readfn = raw_read;
 }
@@ -6640,6 +6655,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU 
*cpu)
 }
 new_reg->readfn = el2_e2h_e12_read;
 new_reg->writefn = el2_e2h_e12_write;
+new_reg->accessfn = el2_e2h_e12_access;
 
 ok = g_hash_table_insert(cpu->cp_regs,
  (gpointer)(uintptr_t)a->new_key, new_reg);
-- 
2.34.1




[PATCH 05/35] target/arm: Implement HCR_EL2.AT handling

2023-12-18 Thread Peter Maydell
The FEAT_NV HCR_EL2.AT bit enables trapping of some address
translation instructions from EL1 to EL2.  Implement this behaviour.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 21 +++--
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index ca8de414bdb..f1c7fbf319c 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3687,6 +3687,15 @@ static CPAccessResult at_s1e2_access(CPUARMState *env, 
const ARMCPRegInfo *ri,
 return at_e012_access(env, ri, isread);
 }
 
+static CPAccessResult at_s1e01_access(CPUARMState *env, const ARMCPRegInfo *ri,
+  bool isread)
+{
+if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_AT)) {
+return CP_ACCESS_TRAP_EL2;
+}
+return at_e012_access(env, ri, isread);
+}
+
 static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
 uint64_t value)
 {
@@ -5552,22 +5561,22 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
   .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0,
   .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
   .fgt = FGT_ATS1E1R,
-  .accessfn = at_e012_access, .writefn = ats_write64 },
+  .accessfn = at_s1e01_access, .writefn = ats_write64 },
 { .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64,
   .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1,
   .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
   .fgt = FGT_ATS1E1W,
-  .accessfn = at_e012_access, .writefn = ats_write64 },
+  .accessfn = at_s1e01_access, .writefn = ats_write64 },
 { .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64,
   .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2,
   .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
   .fgt = FGT_ATS1E0R,
-  .accessfn = at_e012_access, .writefn = ats_write64 },
+  .accessfn = at_s1e01_access, .writefn = ats_write64 },
 { .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64,
   .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3,
   .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
   .fgt = FGT_ATS1E0W,
-  .accessfn = at_e012_access, .writefn = ats_write64 },
+  .accessfn = at_s1e01_access, .writefn = ats_write64 },
 { .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64,
   .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4,
   .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
@@ -8145,12 +8154,12 @@ static const ARMCPRegInfo ats1e1_reginfo[] = {
   .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0,
   .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
   .fgt = FGT_ATS1E1RP,
-  .accessfn = at_e012_access, .writefn = ats_write64 },
+  .accessfn = at_s1e01_access, .writefn = ats_write64 },
 { .name = "AT_S1E1WP", .state = ARM_CP_STATE_AA64,
   .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
   .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
   .fgt = FGT_ATS1E1WP,
-  .accessfn = at_e012_access, .writefn = ats_write64 },
+  .accessfn = at_s1e01_access, .writefn = ats_write64 },
 };
 
 static const ARMCPRegInfo ats1cp_reginfo[] = {
-- 
2.34.1




[PATCH 12/35] target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check

2023-12-18 Thread Peter Maydell
In handle_sys() we don't do the check for whether the register is
marked as needing an FPU/SVE/SME access check until after we've
handled the special cases covered by ARM_CP_SPECIAL_MASK.  This is
conceptually the wrong way around, because if for example we happen
to implement an FPU-access-checked register as ARM_CP_NOP, we should
do the access check first.

Move the access checks up so they are with all the other access
checks, not sandwiched between the special-case read/write handling
and the normal-case read/write handling. This doesn't change
behaviour at the moment, because we happen not to define any
cpregs with both ARM_CPU_{FPU,SVE,SME} and one of the cases
dealt with by ARM_CP_SPECIAL_MASK.

Moving this code also means we have the correct place to put the
FEAT_NV/FEAT_NV2 access handling, which should come after the access
checks and before we try to do any read/write action.

Signed-off-by: Peter Maydell 
---
 target/arm/tcg/translate-a64.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 00d12e148ca..2d26cb6210f 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2189,6 +2189,14 @@ static void handle_sys(DisasContext *s, bool isread,
 gen_a64_update_pc(s, 0);
 }
 
+if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
+return;
+} else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
+return;
+} else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
+return;
+}
+
 /* Handle special cases first */
 switch (ri->type & ARM_CP_SPECIAL_MASK) {
 case 0:
@@ -2267,13 +2275,6 @@ static void handle_sys(DisasContext *s, bool isread,
 default:
 g_assert_not_reached();
 }
-if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
-return;
-} else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
-return;
-} else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
-return;
-}
 
 if (ri->type & ARM_CP_IO) {
 /* I/O operations must end the TB here (whether read or write) */
-- 
2.34.1




[PATCH 15/35] target/arm: Set SPSR_EL1.M correctly when nested virt is enabled

2023-12-18 Thread Peter Maydell
FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,0} and an exception
is taken from EL1 to EL1 then the reported EL in SPSR_EL1.M should be
EL2, not EL1.  Implement this behaviour.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 44005665d12..220ee64df0d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11327,6 +11327,12 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
 old_mode = pstate_read(env);
 aarch64_save_sp(env, arm_current_el(env));
 env->elr_el[new_el] = env->pc;
+
+if (cur_el == 1 && new_el == 1 &&
+((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) {
+/* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */
+old_mode = deposit32(old_mode, 2, 2, 2);
+}
 } else {
 old_mode = cpsr_read_for_spsr_elx(env);
 env->elr_el[new_el] = env->regs[15];
-- 
2.34.1




[PATCH 00/35] target/arm: Implement emulation of nested virtualization

2023-12-18 Thread Peter Maydell
This patchset adds support for emulating the Arm architectural features
FEAT_NV and FEAT_NV2 which allow nested virtualization, i.e. where a
hypervisor can run a guest which thinks it is running at EL2.

Nominally FEAT_NV is sufficient for this and FEAT_NV2 merely improves
the performance in the nested-virt setup, but in practice hypervisors
such as KVM are going to require FEAT_NV2 and not bother to support
the FEAT_NV-only case, so I have implemented them one after the other
in this single patchset.

The feature is essentially a collection of changes that allow the
hypervisor to lie to the guest so that it thinks it is running in EL2
when it's really at EL1. The best summary of what all the changes are
is in section D8.11 "Nested virtualization" in the Arm ARM, but the
short summary is:
 * EL2 system registers etc trap to EL2 rather than UNDEFing
 * ERET traps to EL2
 * the CurrentEL register reports "EL2" when NV is enabled
 * on exception entry, SPSR_EL1.M may report "EL2" as the EL the
   exception was taken from
 * when HCR_EL1.NV1 is also set, then there are some extra tweaks
   (NV1 == 1 means "guest thinks it is running with HCR_EL2.E2H == 0")
 * some AT S1 address translation insns can be trapped to EL2
and FEAT_NV2 adds:
 * accesses to some system registers are transformed into memory
   accesses instead of trapping to EL2
 * accesses to a few EL2 system registers are redirected to the
   equivalent EL1 registers

This patchset is sufficient that you can run an L0 guest kernel that
has support for FEAT_NV/FEAT_NV2 in its KVM code, and then
inside that start a nested L1 guest that thinks it has EL2 access,
and then run an inner-nested L2 guest under that that can get
to running userspace code. To do that you'll need some not-yet-upstream
patches for both Linux and kvmtool:

https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/nv-6.8-nv2-only
https://gitlab.arm.com/linux-arm/kvmtool/-/commits/nv-v6.6

You'll also want to turn off SVE and SME emulation in QEMU
(-cpu max,sve=off,sme=off) because at the moment the KVM patchset
doesn't handle SVE and nested-virt together (the other option
is to hack kvmtool to make it not ask for both at once, but this
is easier).

(kvmtool is needed here to run the L1 because QEMU itself as a VMM
doesn't yet support asking KVM for an EL2 guest.)

The first three patches in the series aren't strictly part of FEAT_NV:
 * patch 1 is already reviewed; I put it here to avoid having
   to deal with textual conflicts between it and this series
 * patch 2 sets CTR_EL0.{IDC,DIC} for '-cpu max', which is a good
   idea anyway and also works around what Marc Z and I think is
   a KVM bug that otherwise causes boot of the L2 kernel to hang
 * patch 3 is a GIC bug which is not FEAT_NV specific but for
   some reason only manifests when booting an L1 kernel under NV

thanks
-- PMM

Peter Maydell (35):
  target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only
  target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU
  hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers
  target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV
  target/arm: Implement HCR_EL2.AT handling
  target/arm: Enable trapping of ERET for FEAT_NV
  target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set
  target/arm: Allow use of upper 32 bits of TBFLAG_A64
  target/arm: Record correct opcode fields in cpreg for E2H aliases
  target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0
  target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses
  target/arm: Move FPU/SVE/SME access checks up above
ARM_CP_SPECIAL_MASK check
  target/arm: Trap sysreg accesses for FEAT_NV
  target/arm: Make NV reads of CurrentEL return EL2
  target/arm: Set SPSR_EL1.M correctly when nested virt is enabled
  target/arm: Trap registers when HCR_EL2.{NV,NV1} == {1,1}
  target/arm: Always use arm_pan_enabled() when checking if PAN is
enabled
  target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV,NV1} == {1,1}
  target/arm: Treat LDTR* and STTR* as LDR/STR when NV,NV1 is 1,1
  target/arm: Handle FEAT_NV page table attribute changes
  target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs
  target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits
  target/arm: Implement VNCR_EL2 register
  target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2
  target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2,
FAR_EL2
  target/arm: Implement FEAT_NV2 redirection of sysregs to RAM
  target/arm: Report VNCR_EL2 based faults correctly
  target/arm: Mark up VNCR offsets (offsets 0x0..0xff)
  target/arm: Mark up VNCR offsets (offsets 0x100..0x160)
  target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8)
  target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC)
  hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers
  target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps
  target/arm: Enhance CPU_LOG_INT

[PATCH 30/35] target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8)

2023-12-18 Thread Peter Maydell
Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM.  This commit covers offsets 0x168 to 0x1f8.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 78c3c3ebd8d..6c33619d646 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3175,6 +3175,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1,
   .type = ARM_CP_IO, .access = PL0_RW,
   .accessfn = gt_ptimer_access,
+  .nv2_redirect_offset = 0x180 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
   .resetvalue = 0,
   .readfn = gt_phys_redir_ctl_read, .raw_readfn = raw_read,
@@ -3192,6 +3193,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1,
   .type = ARM_CP_IO, .access = PL0_RW,
   .accessfn = gt_vtimer_access,
+  .nv2_redirect_offset = 0x170 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
   .resetvalue = 0,
   .readfn = gt_virt_redir_ctl_read, .raw_readfn = raw_read,
@@ -3271,6 +3273,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2,
   .access = PL0_RW,
   .type = ARM_CP_IO,
+  .nv2_redirect_offset = 0x178 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
   .resetvalue = 0, .accessfn = gt_ptimer_access,
   .readfn = gt_phys_redir_cval_read, .raw_readfn = raw_read,
@@ -3288,6 +3291,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2,
   .access = PL0_RW,
   .type = ARM_CP_IO,
+  .nv2_redirect_offset = 0x168 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
   .resetvalue = 0, .accessfn = gt_vtimer_access,
   .readfn = gt_virt_redir_cval_read, .raw_readfn = raw_read,
@@ -7036,6 +7040,7 @@ static void zcr_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 static const ARMCPRegInfo zcr_reginfo[] = {
 { .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0,
+  .nv2_redirect_offset = 0x1e0 | NV2_REDIR_NV1,
   .access = PL1_RW, .type = ARM_CP_SVE,
   .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]),
   .writefn = zcr_write, .raw_writefn = raw_write },
@@ -7177,6 +7182,7 @@ static const ARMCPRegInfo sme_reginfo[] = {
   .writefn = svcr_write, .raw_writefn = raw_write },
 { .name = "SMCR_EL1", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 6,
+  .nv2_redirect_offset = 0x1f0 | NV2_REDIR_NV1,
   .access = PL1_RW, .type = ARM_CP_SME,
   .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[1]),
   .writefn = smcr_write, .raw_writefn = raw_write },
@@ -7210,6 +7216,7 @@ static const ARMCPRegInfo sme_reginfo[] = {
   .type = ARM_CP_CONST, .resetvalue = 0 },
 { .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5,
+  .nv2_redirect_offset = 0x1f8,
   .access = PL2_RW, .accessfn = access_smprimap,
   .type = ARM_CP_CONST, .resetvalue = 0 },
 };
@@ -7924,6 +7931,7 @@ static const ARMCPRegInfo mte_reginfo[] = {
 { .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tfsr_el1,
+  .nv2_redirect_offset = 0x190 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
 { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
   .type = ARM_CP_NV2_REDIRECT,
@@ -8098,6 +8106,7 @@ static const ARMCPRegInfo scxtnum_reginfo[] = {
   .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7,
   .access = PL1_RW, .accessfn = access_scxtnum_el1,
   .fgt = FGT_SCXTNUM_EL1,
+  .nv2_redirect_offset = 0x188 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) },
 { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7,
@@ -8122,22 +8131,27 @@ static CPAccessResult access_fgt(CPUARMState *env, 
const ARMCPRegInfo *ri,
 static const ARMCPRegInfo fgt_reginfo[] = {
 { .name = "HFGRTR_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4,
+  .nv2_redirect_offset = 0x1b8,
   .access = PL2_RW, .accessfn = access_fgt,
   .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_HFGRTR]) },
 { .name = "HFGWTR_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 5,
+  .nv2_redirect_offset = 0x1c0,
   .access 

[PATCH 34/35] target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry

2023-12-18 Thread Peter Maydell
We already print various lines of information when we take an
exception, including the ELR and (if relevant) the FAR. Now
that FEAT_NV means that we might report something other than
the old PSTATE to the guest as the SPSR, it's worth logging
this as well.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index c72ce4aee09..b8604f39169 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11493,6 +11493,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
 }
 env->banked_spsr[aarch64_banked_spsr_index(new_el)] = old_mode;
 
+qemu_log_mask(CPU_LOG_INT, "...with SPSR 0x%x\n", old_mode);
 qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n",
   env->elr_el[new_el]);
 
-- 
2.34.1




[PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly

2023-12-18 Thread Peter Maydell
If FEAT_NV2 redirects a system register access to a memory offset
from VNCR_EL2, that access might fault.  In this case we need to
report the correct syndrome information:
 * Data Abort, from same-EL
 * no ISS information
 * the VNCR bit (bit 13) is set

and the exception must be taken to EL2.

Save an appropriate syndrome template when generating code; we can
then use that to:
 * select the right target EL
 * reconstitute a correct final syndrome for the data abort
 * report the right syndrome if we take a FEAT_RME granule protection
   fault on the VNCR-based write

Note that because VNCR is bit 13, we must start keeping bit 13 in
template syndromes, by adjusting ARM_INSN_START_WORD2_SHIFT.

Signed-off-by: Peter Maydell 
---
 target/arm/cpu.h   |  4 ++--
 target/arm/syndrome.h  | 20 
 target/arm/tcg/tlb_helper.c| 27 +--
 target/arm/tcg/translate-a64.c |  4 
 4 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index bc4fa95ea35..da640949518 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -120,12 +120,12 @@ enum {
 #define TARGET_INSN_START_EXTRA_WORDS 2
 
 /* The 2nd extra word holding syndrome info for data aborts does not use
- * the upper 6 bits nor the lower 14 bits. We mask and shift it down to
+ * the upper 6 bits nor the lower 13 bits. We mask and shift it down to
  * help the sleb128 encoder do a better job.
  * When restoring the CPU state, we shift it back up.
  */
 #define ARM_INSN_START_WORD2_MASK ((1 << 26) - 1)
-#define ARM_INSN_START_WORD2_SHIFT 14
+#define ARM_INSN_START_WORD2_SHIFT 13
 
 /* We currently assume float and double are IEEE single and double
precision respectively.
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 95454b5b3bb..1a49767479f 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -86,6 +86,9 @@ typedef enum {
 #define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
 #define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
 
+/* In the Data Abort syndrome */
+#define ARM_EL_VNCR (1 << 13)
+
 static inline uint32_t syn_get_ec(uint32_t syn)
 {
 return syn >> ARM_EL_EC_SHIFT;
@@ -256,13 +259,12 @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int 
rm)
 (cv << 24) | (cond << 20) | rm;
 }
 
-static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc,
+static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,
int cm, int s1ptw, int wnr, int fsc)
 {
-/* TODO: FEAT_NV2 adds VNCR */
 return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21)
-| (ind << 20) | (gpcsc << 14) | (cm << 8) | (s1ptw << 7)
-| (wnr << 6) | fsc;
+| (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8)
+| (s1ptw << 7) | (wnr << 6) | fsc;
 }
 
 static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
@@ -295,6 +297,16 @@ static inline uint32_t syn_data_abort_with_iss(int same_el,
| (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
 }
 
+/*
+ * Faults due to FEAT_NV2 VNCR_EL2-based accesses report as same-EL
+ * Data Aborts with the VNCR bit set.
+ */
+static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc)
+{
+return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (1 << ARM_EL_EC_SHIFT)
+| ARM_EL_IL | ARM_EL_VNCR | (wnr << 6) | fsc;
+}
+
 static inline uint32_t syn_swstep(int same_el, int isv, int ex)
 {
 return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
index 4fdd85359e1..dd5de74ffb7 100644
--- a/target/arm/tcg/tlb_helper.c
+++ b/target/arm/tcg/tlb_helper.c
@@ -50,7 +50,15 @@ static inline uint32_t merge_syn_data_abort(uint32_t 
template_syn,
  * ST64BV, or ST64BV0 insns report syndrome info even for stage-1
  * faults and regardless of the target EL.
  */
-if (!(template_syn & ARM_EL_ISV) || target_el != 2
+if (template_syn & ARM_EL_VNCR) {
+/*
+ * FEAT_NV2 faults on accesses via VNCR_EL2 are a special case:
+ * they are always reported as "same EL", even though we are going
+ * from EL1 to EL2.
+ */
+assert(!fi->stage2);
+syn = syn_data_abort_vncr(fi->ea, is_write, fsc);
+} else if (!(template_syn & ARM_EL_ISV) || target_el != 2
 || fi->s1ptw || !fi->stage2) {
 syn = syn_data_abort_no_iss(same_el, 0,
 fi->ea, 0, fi->s1ptw, is_write, fsc);
@@ -169,6 +177,20 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr,
 int current_el = arm_current_el(env);
 bool same_el;
 uint32_t syn, exc, fsr, fsc;
+/*
+ * We know this must be a data or insn abort, and that
+ * env->exception.syndrome contains the template syndrome set
+ * up at translate time. So we can check only the VNCR bit
+ * (and indeed syndrome does not have the EC field in it,
+ * because w

[PATCH 06/35] target/arm: Enable trapping of ERET for FEAT_NV

2023-12-18 Thread Peter Maydell
When FEAT_NV is turned on via the HCR_EL2.NV bit, ERET instructions
are trapped, with the same syndrome information as for the existing
FEAT_FGT fine-grained trap (in the pseudocode this is handled in
AArch64.CheckForEretTrap()).

Rename the DisasContext and tbflag bits to reflect that they are
no longer exclusively for FGT traps, and set the tbflag bit when
FEAT_NV is enabled as well as when the FGT is enabled.

Signed-off-by: Peter Maydell 
---
 target/arm/cpu.h   |  2 +-
 target/arm/tcg/translate.h |  4 ++--
 target/arm/tcg/hflags.c| 11 ++-
 target/arm/tcg/translate-a64.c |  6 +++---
 4 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index a0282e0d281..167b3759ac9 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3235,7 +3235,7 @@ FIELD(TBFLAG_A64, PSTATE_ZA, 23, 1)
 FIELD(TBFLAG_A64, SVL, 24, 4)
 /* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */
 FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1)
-FIELD(TBFLAG_A64, FGT_ERET, 29, 1)
+FIELD(TBFLAG_A64, TRAP_ERET, 29, 1)
 FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
 
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 3c3bb3431ad..8c84377003c 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -138,10 +138,10 @@ typedef struct DisasContext {
 bool mve_no_pred;
 /* True if fine-grained traps are active */
 bool fgt_active;
-/* True if fine-grained trap on ERET is enabled */
-bool fgt_eret;
 /* True if fine-grained trap on SVC is enabled */
 bool fgt_svc;
+/* True if a trap on ERET is enabled (FGT or NV) */
+bool trap_eret;
 /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */
 bool naa;
 /*
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index a6ebd7571a3..560fb7964ab 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -169,6 +169,7 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, 
int el, int fp_el,
 CPUARMTBFlags flags = {};
 ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);
 uint64_t tcr = regime_tcr(env, mmu_idx);
+uint64_t hcr = arm_hcr_el2_eff(env);
 uint64_t sctlr;
 int tbii, tbid;
 
@@ -285,13 +286,21 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, 
int el, int fp_el,
 if (arm_fgt_active(env, el)) {
 DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1);
 if (FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, ERET)) {
-DP_TBFLAG_A64(flags, FGT_ERET, 1);
+DP_TBFLAG_A64(flags, TRAP_ERET, 1);
 }
 if (fgt_svc(env, el)) {
 DP_TBFLAG_ANY(flags, FGT_SVC, 1);
 }
 }
 
+/*
+ * ERET can also be trapped for FEAT_NV. arm_hcr_el2_eff() takes care
+ * of "is EL2 enabled" and the NV bit can only be set if FEAT_NV is 
present.
+ */
+if (el == 1 && (hcr & HCR_NV)) {
+DP_TBFLAG_A64(flags, TRAP_ERET, 1);
+}
+
 if (cpu_isar_feature(aa64_mte, env_archcpu(env))) {
 /*
  * Set MTE_ACTIVE if any access may be Checked, and leave clear
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index a2e49c39f9f..00d12e148ca 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -1605,7 +1605,7 @@ static bool trans_ERET(DisasContext *s, arg_ERET *a)
 if (s->current_el == 0) {
 return false;
 }
-if (s->fgt_eret) {
+if (s->trap_eret) {
 gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(0), 2);
 return true;
 }
@@ -1632,7 +1632,7 @@ static bool trans_ERETA(DisasContext *s, arg_reta *a)
 return false;
 }
 /* The FGT trap takes precedence over an auth trap. */
-if (s->fgt_eret) {
+if (s->trap_eret) {
 gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(a->m ? 3 : 2), 2);
 return true;
 }
@@ -13979,7 +13979,7 @@ static void 
aarch64_tr_init_disas_context(DisasContextBase *dcbase,
 dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
 dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE);
 dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC);
-dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET);
+dc->trap_eret = EX_TBFLAG_A64(tb_flags, TRAP_ERET);
 dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
 dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL);
 dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16;
-- 
2.34.1




[PATCH 32/35] hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers

2023-12-18 Thread Peter Maydell
Mark up the cpreginfo structs for the GIC CPU registers to indicate
the offsets from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ
in the Arm ARM.

Signed-off-by: Peter Maydell 
---
 hw/intc/arm_gicv3_cpuif.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 258dee1b808..96539cdbe9a 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -2684,6 +2684,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
 { .name = "ICH_AP0R0_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 0,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x480,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2691,6 +2692,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
 { .name = "ICH_AP1R0_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 0,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x4a0,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2698,6 +2700,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
 { .name = "ICH_HCR_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 0,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x4c0,
   .access = PL2_RW,
   .readfn = ich_hcr_read,
   .writefn = ich_hcr_write,
@@ -2729,6 +2732,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
 { .name = "ICH_VMCR_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 7,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x4c8,
   .access = PL2_RW,
   .readfn = ich_vmcr_read,
   .writefn = ich_vmcr_write,
@@ -2739,6 +2743,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] 
= {
 { .name = "ICH_AP0R1_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 1,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x488,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2746,6 +2751,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] 
= {
 { .name = "ICH_AP1R1_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 1,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x4a8,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2756,6 +2762,7 @@ static const ARMCPRegInfo 
gicv3_cpuif_ich_apxr23_reginfo[] = {
 { .name = "ICH_AP0R2_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 2,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x490,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2763,6 +2770,7 @@ static const ARMCPRegInfo 
gicv3_cpuif_ich_apxr23_reginfo[] = {
 { .name = "ICH_AP0R3_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 3,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x498,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2770,6 +2778,7 @@ static const ARMCPRegInfo 
gicv3_cpuif_ich_apxr23_reginfo[] = {
 { .name = "ICH_AP1R2_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 2,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x4b0,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2777,6 +2786,7 @@ static const ARMCPRegInfo 
gicv3_cpuif_ich_apxr23_reginfo[] = {
 { .name = "ICH_AP1R3_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 3,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x4b8,
   .access = PL2_RW,
   .readfn = ich_ap_read,
   .writefn = ich_ap_write,
@@ -2898,6 +2908,7 @@ void gicv3_init_cpuif(GICv3State *s)
   .opc0 = 3, .opc1 = 4, .crn = 12,
   .crm = 12 + (j >> 3), .opc2 = j & 7,
   .type = ARM_CP_IO | ARM_CP_NO_RAW,
+  .nv2_redirect_offset = 0x400 + 8 * j,
   .access = PL2_RW,
   .readfn = ich_lr_read,
   .writefn = ich_lr_write,
-- 
2.34.1




[PATCH 03/35] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers

2023-12-18 Thread Peter Maydell
The hypervisor can deliver (virtual) LPIs to a guest by setting up a
list register to have an intid which is an LPI.  The GIC has to treat
these a little differently to standard interrupt IDs, because LPIs
have no Active state, and so the guest will only EOI them, it will
not also deactivate them.  So icv_eoir_write() must do two things:

 * if the LPI ID is not in any list register, we drop the
   priority but do not increment the EOI count
 * if the LPI ID is in a list register, we immediately deactivate
   it, regardless of the split-drop-and-deactivate control

This can be seen in the VirtualWriteEOIR0() and VirtualWriteEOIR1()
pseudocode in the GICv3 architecture specification.

Without this fix, potentially a hypervisor guest might stall because
LPIs get stuck in a bogus Active+Pending state.

Cc: qemu-sta...@nongnu.org
Signed-off-by: Peter Maydell 
---
Weirdly, I only saw this being a problem when the hypervisor guest
was an EL2-enabled one under my FEAT_NV/FEAT_NV2 implementation.
But there's nothing FEAT_NV specific about the bug.
---
 hw/intc/arm_gicv3_cpuif.c | 17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index ab1a00508e6..258dee1b808 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -1434,16 +1434,25 @@ static void icv_eoir_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 idx = icv_find_active(cs, irq);
 
 if (idx < 0) {
-/* No valid list register corresponding to EOI ID */
-icv_increment_eoicount(cs);
+/*
+ * No valid list register corresponding to EOI ID; if this is a vLPI
+ * not in the list regs then do nothing; otherwise increment EOI count
+ */
+if (irq < GICV3_LPI_INTID_START) {
+icv_increment_eoicount(cs);
+}
 } else {
 uint64_t lr = cs->ich_lr_el2[idx];
 int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
 int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp);
 
 if (thisgrp == grp && lr_gprio == dropprio) {
-if (!icv_eoi_split(env, cs)) {
-/* Priority drop and deactivate not split: deactivate irq now 
*/
+if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) {
+/*
+ * Priority drop and deactivate not split: deactivate irq now.
+ * LPIs always get their active state cleared immediately
+ * because no separate deactivate is expected.
+ */
 icv_deactivate_irq(cs, idx);
 }
 }
-- 
2.34.1




[PATCH 18/35] target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1}

2023-12-18 Thread Peter Maydell
For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled
even when the PSTATE.PAN bit is set. Implement this by having
arm_pan_enabled() return false in this situation.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 4b0e46cfaae..28448624c36 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -266,6 +266,9 @@ void init_cpreg_list(ARMCPU *cpu)
 static bool arm_pan_enabled(CPUARMState *env)
 {
 if (is_a64(env)) {
+if ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == (HCR_NV | HCR_NV1)) 
{
+return false;
+}
 return env->pstate & PSTATE_PAN;
 } else {
 return env->uncached_cpsr & CPSR_PAN;
-- 
2.34.1




[PATCH 16/35] target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1}

2023-12-18 Thread Peter Maydell
When HCR_EL2.{NV,NV1} is {1,1} we must trap five extra registers to
EL2: VBAR_EL1, ELR_EL1, SPSR_EL1, SCXTNUM_EL1 and TFSR_EL1.
Implement these traps.

This trap does not apply when FEAT_NV2 is implemented and enabled;
include the check that HCR_EL2.NV2 is 0 here, to save us having
to come back and add it later.

Signed-off-by: Peter Maydell 
---
I have mostly implemented FEAT_NV2 after FEAT_NV, but in
this particular case it seemed cleaner to include the NV2
bit check from the start.
---
 target/arm/helper.c | 44 
 1 file changed, 40 insertions(+), 4 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 220ee64df0d..3270fb11049 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5339,6 +5339,19 @@ static void mdcr_el2_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 }
 }
 
+static CPAccessResult access_nv1(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+if (arm_current_el(env) == 1) {
+uint64_t hcr_nv = arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1 | HCR_NV2);
+
+if (hcr_nv == (HCR_NV | HCR_NV1)) {
+return CP_ACCESS_TRAP_EL2;
+}
+}
+return CP_ACCESS_OK;
+}
+
 #ifdef CONFIG_USER_ONLY
 /*
  * `IC IVAU` is handled to improve compatibility with JITs that dual-map their
@@ -5687,12 +5700,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
 { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64,
   .type = ARM_CP_ALIAS,
   .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
-  .access = PL1_RW,
+  .access = PL1_RW, .accessfn = access_nv1,
   .fieldoffset = offsetof(CPUARMState, elr_el[1]) },
 { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
   .type = ARM_CP_ALIAS,
   .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
-  .access = PL1_RW,
+  .access = PL1_RW, .accessfn = access_nv1,
   .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) },
 /*
  * We rely on the access checks not allowing the guest to write to the
@@ -7807,6 +7820,16 @@ static CPAccessResult access_mte(CPUARMState *env, const 
ARMCPRegInfo *ri,
 }
 return CP_ACCESS_OK;
 }
+static CPAccessResult access_tfsr_el1(CPUARMState *env, const ARMCPRegInfo *ri,
+  bool isread)
+{
+CPAccessResult nv1 = access_nv1(env, ri, isread);
+
+if (nv1 != CP_ACCESS_OK) {
+return nv1;
+}
+return access_mte(env, ri, isread);
+}
 
 static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri,
   bool isread)
@@ -7852,7 +7875,7 @@ static const ARMCPRegInfo mte_reginfo[] = {
   .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[0]) },
 { .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0,
-  .access = PL1_RW, .accessfn = access_mte,
+  .access = PL1_RW, .accessfn = access_tfsr_el1,
   .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
 { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0,
@@ -8004,6 +8027,18 @@ static CPAccessResult access_scxtnum(CPUARMState *env, 
const ARMCPRegInfo *ri,
 return CP_ACCESS_OK;
 }
 
+static CPAccessResult access_scxtnum_el1(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+CPAccessResult nv1 = access_nv1(env, ri, isread);
+
+if (nv1 != CP_ACCESS_OK) {
+return nv1;
+}
+return access_scxtnum(env, ri, isread);
+}
+
 static const ARMCPRegInfo scxtnum_reginfo[] = {
 { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7,
@@ -8012,7 +8047,7 @@ static const ARMCPRegInfo scxtnum_reginfo[] = {
   .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) },
 { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7,
-  .access = PL1_RW, .accessfn = access_scxtnum,
+  .access = PL1_RW, .accessfn = access_scxtnum_el1,
   .fgt = FGT_SCXTNUM_EL1,
   .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) },
 { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64,
@@ -9394,6 +9429,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
   .access = PL1_RW, .writefn = vbar_write,
+  .accessfn = access_nv1,
   .fgt = FGT_VBAR_EL1,
   .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s),
  offsetof(CPUARMState, cp15.vbar_ns) },
-- 
2.34.1




[PATCH 01/35] target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only

2023-12-18 Thread Peter Maydell
The system registers DBGVCR32_EL2, FPEXC32_EL2, DACR32_EL2 and
IFSR32_EL2 are present only to allow an AArch64 EL2 or EL3 to read
and write the contents of an AArch32-only system register.  The
architecture requires that they are present only when EL1 can be
AArch32, but we implement them unconditionally. This was OK when
all our CPUs supported AArch32 EL1, but we have quite a lot of
CPU models now which only support AArch64 at EL1:
 a64fx
 cortex-a76
 cortex-a710
 neoverse-n1
 neoverse-n2
 neoverse-v1

Only define these registers for CPUs which allow AArch32 EL1.

Signed-off-by: Peter Maydell 
Reviewed-by: Richard Henderson 
---
 target/arm/debug_helper.c | 23 +++
 target/arm/helper.c   | 35 +--
 2 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index cbfba532f50..83d2619080f 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -1026,14 +1026,6 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
   .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tda,
   .type = ARM_CP_NOP },
-/*
- * Dummy DBGVCR32_EL2 (which is only for a 64-bit hypervisor
- * to save and restore a 32-bit guest's DBGVCR)
- */
-{ .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
-  .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
-  .access = PL2_RW, .accessfn = access_tda,
-  .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
 /*
  * Dummy MDCCINT_EL1, since we don't implement the Debug Communications
  * Channel but Linux may try to access this register. The 32-bit
@@ -1062,6 +1054,18 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
   .fieldoffset = offsetof(CPUARMState, cp15.dbgclaim) },
 };
 
+/* These are present only when EL1 supports AArch32 */
+static const ARMCPRegInfo debug_aa32_el1_reginfo[] = {
+/*
+ * Dummy DBGVCR32_EL2 (which is only for a 64-bit hypervisor
+ * to save and restore a 32-bit guest's DBGVCR)
+ */
+{ .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
+  .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
+  .access = PL2_RW, .accessfn = access_tda,
+  .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
+};
+
 static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
 /* 64 bit access versions of the (dummy) debug registers */
 { .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0,
@@ -1207,6 +1211,9 @@ void define_debug_regs(ARMCPU *cpu)
 assert(ctx_cmps <= brps);
 
 define_arm_cp_regs(cpu, debug_cp_reginfo);
+if (cpu_isar_feature(aa64_aa32_el1, cpu)) {
+define_arm_cp_regs(cpu, debug_aa32_el1_reginfo);
+}
 
 if (arm_feature(&cpu->env, ARM_FEATURE_LPAE)) {
 define_arm_cp_regs(cpu, debug_lpae_cp_reginfo);
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 2746d3fdac8..39830c7f948 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5698,20 +5698,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0,
   .type = ARM_CP_NO_RAW,
   .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write },
-{ .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64,
-  .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0,
-  .access = PL2_RW,
-  .type = ARM_CP_ALIAS | ARM_CP_FPU | ARM_CP_EL3_NO_EL2_KEEP,
-  .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]) },
-{ .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64,
-  .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0,
-  .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP,
-  .writefn = dacr_write, .raw_writefn = raw_write,
-  .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) },
-{ .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64,
-  .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1,
-  .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP,
-  .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) },
 { .name = "SPSR_IRQ", .state = ARM_CP_STATE_AA64,
   .type = ARM_CP_ALIAS,
   .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 0,
@@ -5746,6 +5732,24 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
   .fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) },
 };
 
+/* These are present only when EL1 supports AArch32 */
+static const ARMCPRegInfo v8_aa32_el1_reginfo[] = {
+{ .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64,
+  .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0,
+  .access = PL2_RW,
+  .type = ARM_CP_ALIAS | ARM_CP_FPU | ARM_CP_EL3_NO_EL2_KEEP,
+  .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]) },
+{ .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64,
+  .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0,
+  .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP,
+  .writefn = dacr_write, .raw_write

[PATCH 02/35] target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU

2023-12-18 Thread Peter Maydell
The CTR_EL0 register has some bits which allow the implementation to
tell the guest that it does not need to do cache maintenance for
data-to-instruction coherence and instruction-to-data coherence.
QEMU doesn't emulate caches and so our cache maintenance insns are
all NOPs.

We already have some models of specific CPUs where we set these bits
(e.g.  the Neoverse V1), but the 'max' CPU still uses the settings it
inherits from Cortex-A57.  Set the bits for 'max' as well, so the
guest doesn't need to do unnecessary work.

Signed-off-by: Peter Maydell 
---
This is worthwhile anyway; it also works around what Marc Z
and I think is a KVM bug where booting the L2 guest hangs
if L0 thinks it needs to do cache maintenance ops, when
running all this under QEMU's FEAT_NV/FEAT_NV2 emulation.
---
 target/arm/tcg/cpu64.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index fcda99e1583..40e7a45166f 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1105,6 +1105,16 @@ void aarch64_max_tcg_initfn(Object *obj)
 u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0);
 cpu->clidr = u;
 
+/*
+ * Set CTR_EL0.DIC and IDC to tell the guest it doesnt' need to
+ * do any cache maintenance for data-to-instruction or
+ * instruction-to-guest coherence. (Our cache ops are nops.)
+ */
+t = cpu->ctr;
+t = FIELD_DP64(t, CTR_EL0, IDC, 1);
+t = FIELD_DP64(t, CTR_EL0, DIC, 1);
+cpu->ctr = t;
+
 t = cpu->isar.id_aa64isar0;
 t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2);  /* FEAT_PMULL */
 t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */
-- 
2.34.1




[PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160)

2023-12-18 Thread Peter Maydell
Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM.  This commit covers offsets 0x100 to 0x160.

Many (but not all) of the registers in this range have _EL12 aliases,
and the slot in memory is shared between the _EL12 version of the
register and the _EL1 version.  Where we programmatically generate
the regdef for the _EL12 register, arrange that its
nv2_redirect_offset is set up correctly to do this.

Signed-off-by: Peter Maydell 
---
 target/arm/debug_helper.c |  1 +
 target/arm/helper.c   | 22 ++
 2 files changed, 23 insertions(+)

diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index b39144d5b93..7d856acddf2 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -960,6 +960,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
   .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
   .access = PL1_RW, .accessfn = access_tda,
   .fgt = FGT_MDSCR_EL1,
+  .nv2_redirect_offset = 0x158,
   .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
   .resetvalue = 0 },
 /*
diff --git a/target/arm/helper.c b/target/arm/helper.c
index ff7f90fa4af..78c3c3ebd8d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -647,6 +647,7 @@ static const ARMCPRegInfo cp_reginfo[] = {
   .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_CONTEXTIDR_EL1,
+  .nv2_redirect_offset = 0x108 | NV2_REDIR_NV1,
   .secure = ARM_CP_SECSTATE_NS,
   .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]),
   .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, 
},
@@ -883,6 +884,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
 { .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
   .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access,
   .fgt = FGT_CPACR_EL1,
+  .nv2_redirect_offset = 0x100 | NV2_REDIR_NV1,
   .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1),
   .resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read },
 };
@@ -2234,11 +2236,13 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_AFSR0_EL1,
+  .nv2_redirect_offset = 0x128 | NV2_REDIR_NV1,
   .type = ARM_CP_CONST, .resetvalue = 0 },
 { .name = "AFSR1_EL1", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 1,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_AFSR1_EL1,
+  .nv2_redirect_offset = 0x130 | NV2_REDIR_NV1,
   .type = ARM_CP_CONST, .resetvalue = 0 },
 /*
  * MAIR can just read-as-written because we don't implement caches
@@ -2248,6 +2252,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_MAIR_EL1,
+  .nv2_redirect_offset = 0x140 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]),
   .resetvalue = 0 },
 { .name = "MAIR_EL3", .state = ARM_CP_STATE_AA64,
@@ -4271,6 +4276,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
   .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_ESR_EL1,
+  .nv2_redirect_offset = 0x138 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, },
 { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
@@ -4290,6 +4296,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
   .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_TCR_EL1,
+  .nv2_redirect_offset = 0x120 | NV2_REDIR_NV1,
   .writefn = vmsa_tcr_el12_write,
   .raw_writefn = raw_write,
   .resetvalue = 0,
@@ -4529,6 +4536,7 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
   .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_AMAIR_EL1,
+  .nv2_redirect_offset = 0x148 | NV2_REDIR_NV1,
   .type = ARM_CP_CONST, .resetvalue = 0 },
 /* AMAIR1 is mapped to AMAIR_EL1[63:32] */
 { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1,
@@ -5718,6 +5726,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
   .type = ARM_CP_ALIAS,
   .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_nv1,
+  .nv2_redirect_offset = 0x160 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) },
 /*
  * We rely on the access checks not allowing the guest to write to the
@@ 

[PATCH 20/35] target/arm: Handle FEAT_NV page table attribute changes

2023-12-18 Thread Peter Maydell
FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,1} the handling
of some of the page table attribute bits changes for the EL1&0
translation regime:

 * for block and page descriptors:
  - bit [54] holds PXN, not UXN
  - bit [53] is RES0, and the effective value of UXN is 0
  - bit [6], AP[1], is treated as 0
 * for table descriptors, when hierarchical permissions are enabled:
  - bit [60] holds PXNTable, not UXNTable
  - bit [59] is RES0
  - bit [61], APTable[0] is treated as 0

Implement these changes to the page table attribute handling.

Signed-off-by: Peter Maydell 
---
 target/arm/ptw.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 1762b058aec..cab30f0bf46 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -1581,6 +1581,12 @@ static bool lpae_block_desc_valid(ARMCPU *cpu, bool ds,
 }
 }
 
+static bool nv_nv1_enabled(CPUARMState *env, S1Translate *ptw)
+{
+uint64_t hcr = arm_hcr_el2_eff_secstate(env, ptw->in_space);
+return (hcr & (HCR_NV | HCR_NV1)) == (HCR_NV | HCR_NV1);
+}
+
 /**
  * get_phys_addr_lpae: perform one stage of page table walk, LPAE format
  *
@@ -1989,6 +1995,21 @@ static bool get_phys_addr_lpae(CPUARMState *env, 
S1Translate *ptw,
 xn = extract64(attrs, 54, 1);
 pxn = extract64(attrs, 53, 1);
 
+if (el == 1 && nv_nv1_enabled(env, ptw)) {
+/*
+ * With FEAT_NV, when HCR_EL2.{NV,NV1} == {1,1}, the block/page
+ * descriptor bit 54 holds PXN, 53 is RES0, and the effective value
+ * of UXN is 0. Similarly for bits 59 and 60 in table descriptors
+ * (which we have already folded into bits 53 and 54 of attrs).
+ * AP[1] (descriptor bit 6, our ap bit 0) is treated as 0.
+ * Similarly, APTable[0] from the table descriptor is treated as 0;
+ * we already folded this into AP[1] and squashing that to 0 does
+ * the right thing.
+ */
+pxn = xn;
+xn = 0;
+ap &= ~1;
+}
 /*
  * Note that we modified ptw->in_space earlier for NSTable, but
  * result->f.attrs retains a copy of the original security space.
-- 
2.34.1




[PATCH 11/35] target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses

2023-12-18 Thread Peter Maydell
FEAT_NV and FEAT_NV2 will allow EL1 to attempt to access cpregs that
only exist at EL2. This means we're going to want to run their
accessfns when the CPU is at EL1. In almost all cases, the behaviour
we want is "the accessfn returns OK if at EL1".

Mostly the accessfn already does the right thing; in a few cases we
need to explicitly check that the EL is not 1 before applying various
trap controls, or split out an accessfn used both for an _EL1 and an
_EL2 register into two so we can handle the FEAT_NV case correctly
for the _EL2 register.

There are two registers where we want the accessfn to trap for
a FEAT_NV EL1 access: VSTTBR_EL2 and VSTCR_EL2 should UNDEF
an access from NonSecure EL1, not trap to EL2 under FEAT_NV.
The way we have written sel2_access() already results in this
behaviour.

We can identify the registers we care about here because they
all have opc1 == 4 or 5.

Signed-off-by: Peter Maydell 
---
 target/arm/debug_helper.c | 12 +++-
 target/arm/helper.c   | 65 ++-
 2 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index 83d2619080f..b39144d5b93 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -844,6 +844,16 @@ static CPAccessResult access_tda(CPUARMState *env, const 
ARMCPRegInfo *ri,
 return CP_ACCESS_OK;
 }
 
+static CPAccessResult access_dbgvcr32(CPUARMState *env, const ARMCPRegInfo *ri,
+  bool isread)
+{
+/* MCDR_EL3.TDMA doesn't apply for FEAT_NV traps */
+if (arm_current_el(env) == 2 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
+return CP_ACCESS_TRAP_EL3;
+}
+return CP_ACCESS_OK;
+}
+
 /*
  * Check for traps to Debug Comms Channel registers. If FEAT_FGT
  * is implemented then these are controlled by MDCR_EL2.TDCC for
@@ -1062,7 +1072,7 @@ static const ARMCPRegInfo debug_aa32_el1_reginfo[] = {
  */
 { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
-  .access = PL2_RW, .accessfn = access_tda,
+  .access = PL2_RW, .accessfn = access_dbgvcr32,
   .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
 };
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index e90eb5e16f3..44005665d12 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3308,6 +3308,11 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
 static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
  bool isread)
 {
+if (arm_current_el(env) == 1) {
+/* This must be a FEAT_NV access */
+/* TODO: FEAT_ECV will need to check CNTHCTL_EL2 here */
+return CP_ACCESS_OK;
+}
 if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
 return CP_ACCESS_TRAP;
 }
@@ -5998,7 +6003,7 @@ static void hcrx_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri,
   bool isread)
 {
-if (arm_current_el(env) < 3
+if (arm_current_el(env) == 2
 && arm_feature(env, ARM_FEATURE_EL3)
 && !(env->cp15.scr_el3 & SCR_HXEN)) {
 return CP_ACCESS_TRAP_EL3;
@@ -6523,6 +6528,15 @@ static CPAccessResult el2_e2h_e12_access(CPUARMState 
*env,
  const ARMCPRegInfo *ri,
  bool isread)
 {
+if (arm_current_el(env) == 1) {
+/*
+ * This must be a FEAT_NV access (will either trap or redirect
+ * to memory). None of the registers with _EL12 aliases want to
+ * apply their trap controls for this kind of access, so don't
+ * call the orig_accessfn or do the "UNDEF when E2H is 0" check.
+ */
+return CP_ACCESS_OK;
+}
 /* FOO_EL12 aliases only exist when E2H is 1; otherwise they UNDEF */
 if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
 return CP_ACCESS_TRAP_UNCATEGORIZED;
@@ -6999,10 +7013,21 @@ static CPAccessResult access_tpidr2(CPUARMState *env, 
const ARMCPRegInfo *ri,
 return CP_ACCESS_OK;
 }
 
-static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri,
- bool isread)
+static CPAccessResult access_smprimap(CPUARMState *env, const ARMCPRegInfo *ri,
+  bool isread)
+{
+/* If EL1 this is a FEAT_NV access and CPTR_EL3.ESM doesn't apply */
+if (arm_current_el(env) == 2
+&& arm_feature(env, ARM_FEATURE_EL3)
+&& !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) {
+return CP_ACCESS_TRAP_EL3;
+}
+return CP_ACCESS_OK;
+}
+
+static CPAccessResult access_smpri(CPUARMState *env, const ARMCPRegInfo *ri,
+   bool isread)
 {
-/* TODO: FEAT_FGT for SMPRI_EL1 but not SMPRIMAP_EL2 */
 if (arm_current_el(env) < 3
 && arm_feature(env, ARM_FEATURE_EL3)
 && !F

[PATCH 13/35] target/arm: Trap sysreg accesses for FEAT_NV

2023-12-18 Thread Peter Maydell
For FEAT_NV, accesses to system registers and instructions from EL1
which would normally UNDEF there but which work in EL2 need to
instead be trapped to EL2. Detect this both for "we know this will
UNDEF at translate time" and "we found this UNDEFs at runtime", and
make the affected registers trap to EL2 instead.

The Arm ARM defines the set of registers that should trap in terms
of their names; for our implementation this would be both awkward
and inefficent as a test, so we instead trap based on the opc1
field of the sysreg. The regularity of the architectural choice
of encodings for sysregs means that in practice this captures
exactly the correct set of registers.

Regardless of how we try to define the registers this trapping
applies to, there's going to be a certain possibility of breakage
if new architectural features introduce new registers that don't
follow the current rules (FEAT_MEC is one example already visible
in the released sysreg XML, though not yet in the Arm ARM). This
approach seems to me to be straightforward and likely to require
a minimum of manual overrides.

Signed-off-by: Peter Maydell 
---
 target/arm/cpregs.h| 34 +++
 target/arm/cpu.h   |  1 +
 target/arm/tcg/translate.h |  2 ++
 target/arm/tcg/hflags.c|  1 +
 target/arm/tcg/translate-a64.c | 49 +++---
 5 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index e748d184cb6..3c5f1b48879 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -1080,4 +1080,38 @@ void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu);
 
 CPAccessResult access_tvm_trvm(CPUARMState *, const ARMCPRegInfo *, bool);
 
+/**
+ * arm_cpreg_trap_in_nv: Return true if cpreg traps in nested virtualization
+ *
+ * Return true if this cpreg is one which should be trapped to EL2 if
+ * it is executed at EL1 when nested virtualization is enabled via HCR_EL2.NV.
+ */
+static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
+{
+/*
+ * The Arm ARM defines the registers to be trapped in terms of
+ * their names (I_TZTZL). However the underlying principle is "if
+ * it would UNDEF at EL1 but work at EL2 then it should trap", and
+ * the way the encoding of sysregs and system instructions is done
+ * means that the right set of registers is exactly those where
+ * the opc1 field is 4 or 5. (You can see this also in the assert
+ * we do that the opc1 field and the permissions mask line up in
+ * define_one_arm_cp_reg_with_opaque().)
+ * Checking the opc1 field is easier for us and avoids the problem
+ * that we do not consistently use the right architectural names
+ * for all sysregs, since we treat the name field as largely for debug.
+ *
+ * However we do this check, it is going to be at least potentially
+ * fragile to future new sysregs, but this seems the least likely
+ * to break.
+ *
+ * In particular, note that the released sysreg XML defines that
+ * the FEAT_MEC sysregs and instructions do not follow this FEAT_NV
+ * trapping rule, so we will need to add an ARM_CP_* flag to indicate
+ * "register does not trap on NV" to handle those if/when we implement
+ * FEAT_MEC.
+ */
+return ri->opc1 == 4 || ri->opc1 == 5;
+}
+
 #endif /* TARGET_ARM_CPREGS_H */
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 91157db85ae..0ec67847181 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3238,6 +3238,7 @@ FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1)
 FIELD(TBFLAG_A64, TRAP_ERET, 29, 1)
 FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
+FIELD(TBFLAG_A64, NV, 32, 1)
 
 /*
  * Helpers for using the above. Note that only the A64 accessors use
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 8c84377003c..63e075bce3a 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -144,6 +144,8 @@ typedef struct DisasContext {
 bool trap_eret;
 /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */
 bool naa;
+/* True if FEAT_NV HCR_EL2.NV is enabled */
+bool nv;
 /*
  * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
  *  < 0, set by the current instruction.
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index 560fb7964ab..f33c0a12741 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -299,6 +299,7 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, 
int el, int fp_el,
  */
 if (el == 1 && (hcr & HCR_NV)) {
 DP_TBFLAG_A64(flags, TRAP_ERET, 1);
+DP_TBFLAG_A64(flags, NV, 1);
 }
 
 if (cpu_isar_feature(aa64_mte, env_archcpu(env))) {
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 2d26cb6210f..d060e24356d 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2131,16 +2131,17 @@ static void handle_sys(

[PATCH 25/35] target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2

2023-12-18 Thread Peter Maydell
Under FEAT_NV2, when HCR_EL2.{NV,NV2} == 0b11 at EL1, accesses to the
registers SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 and TFSR_EL2 (which
would UNDEF without FEAT_NV or FEAT_NV2) should instead access the
equivalent EL1 registers SPSR_EL1, ELR_EL1, ESR_EL1, FAR_EL1 and
TFSR_EL1.

Because there are only five registers involved and the encoding for
the EL1 register is identical to that of the EL2 register except
that opc1 is 0, we handle this by finding the EL1 register in the
hash table and using it instead.

Note that traps that apply to direct accesses to the EL1 register,
such as active fine-grained traps or other trap bits, do not trigger
when it is accessed via the EL2 encoding in this way.  However, some
traps that are defined by the EL2 register may apply.  We therefore
call the EL2 register's accessfn first.  The only one of the five
which has such traps is TFSR_EL2: make sure its accessfn correctly
handles both FEAT_NV (where we trap to EL2 without checking ATA bits)
and FEAT_NV2 (where we check ATA bits and then redirect to TFSR_EL1).

(We don't need the NV1 tbflag bit until the next patch, but we
introduce it here to avoid putting the NV, NV1, NV2 bits in an
odd order.)

Signed-off-by: Peter Maydell 
---
 target/arm/cpregs.h|  5 +
 target/arm/cpu.h   |  2 ++
 target/arm/tcg/translate.h |  4 
 target/arm/helper.c| 13 +
 target/arm/tcg/hflags.c|  6 ++
 target/arm/tcg/translate-a64.c | 33 -
 6 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 3c5f1b48879..cb795bed75b 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -118,6 +118,11 @@ enum {
  * ARM pseudocode function CheckSMEAccess().
  */
 ARM_CP_SME   = 1 << 19,
+/*
+ * Flag: one of the four EL2 registers which redirect to the
+ * equivalent EL1 register when FEAT_NV2 is enabled.
+ */
+ARM_CP_NV2_REDIRECT  = 1 << 20,
 };
 
 /*
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 9df8fc08d79..e60b4f34fe4 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3242,6 +3242,8 @@ FIELD(TBFLAG_A64, TRAP_ERET, 29, 1)
 FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
 FIELD(TBFLAG_A64, NV, 32, 1)
+FIELD(TBFLAG_A64, NV1, 33, 1)
+FIELD(TBFLAG_A64, NV2, 34, 1)
 
 /*
  * Helpers for using the above. Note that only the A64 accessors use
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 63e075bce3a..9e13c4ef7b6 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -146,6 +146,10 @@ typedef struct DisasContext {
 bool naa;
 /* True if FEAT_NV HCR_EL2.NV is enabled */
 bool nv;
+/* True if NV enabled and HCR_EL2.NV1 is set */
+bool nv1;
+/* True if NV enabled and HCR_EL2.NV2 is set */
+bool nv2;
 /*
  * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
  *  < 0, set by the current instruction.
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 38e16c2f8a5..61aac61bcc4 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6119,14 +6119,16 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 7,
   .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
 { .name = "ELR_EL2", .state = ARM_CP_STATE_AA64,
-  .type = ARM_CP_ALIAS,
+  .type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT,
   .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
   .access = PL2_RW,
   .fieldoffset = offsetof(CPUARMState, elr_el[2]) },
 { .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH,
+  .type = ARM_CP_NV2_REDIRECT,
   .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0,
   .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) },
 { .name = "FAR_EL2", .state = ARM_CP_STATE_BOTH,
+  .type = ARM_CP_NV2_REDIRECT,
   .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0,
   .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) },
 { .name = "HIFAR", .state = ARM_CP_STATE_AA32,
@@ -6135,7 +6137,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
   .access = PL2_RW,
   .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[2]) },
 { .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
-  .type = ARM_CP_ALIAS,
+  .type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT,
   .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
   .access = PL2_RW,
   .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_HYP]) },
@@ -7852,11 +7854,13 @@ static CPAccessResult access_tfsr_el2(CPUARMState *env, 
const ARMCPRegInfo *ri,
 /*
  * TFSR_EL2: similar to generic access_mte(), but we need to
  * account for FEAT_NV. At EL1 this must be a FEAT_NV access;
- * we will trap to EL2 and the HCR/SCR traps do not apply.
+ * if NV2 is enabled then we will redirect this to TFSR_EL1
+   

[PATCH 33/35] target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps

2023-12-18 Thread Peter Maydell
When interpreting CPU dumps where FEAT_NV and FEAT_NV2 are in use,
it's helpful to include the values of HCR_EL2.{NV,NV1,NV2} in the CPU
dump format, as a way of distinguishing when we are in EL1 as part of
executing guest-EL2 and when we are just in normal EL1.

Add the bits to the end of the log line that shows PSTATE and similar
information:

PSTATE=03c9  EL2h  BTYPE=0 NV NV2

Signed-off-by: Peter Maydell 
---
 target/arm/cpu.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index da0c02f850b..d1d592609eb 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1059,6 +1059,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, 
int flags)
 uint32_t psr = pstate_read(env);
 int i, j;
 int el = arm_current_el(env);
+uint64_t hcr = arm_hcr_el2_eff(env);
 const char *ns_status;
 bool sve;
 
@@ -1096,6 +1097,10 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE 
*f, int flags)
 if (cpu_isar_feature(aa64_bti, cpu)) {
 qemu_fprintf(f, "  BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
 }
+qemu_fprintf(f, "%s%s%s",
+ (hcr & HCR_NV) ? " NV" : "",
+ (hcr & HCR_NV1) ? " NV1" : "",
+ (hcr & HCR_NV2) ? " NV2" : "");
 if (!(flags & CPU_DUMP_FPU)) {
 qemu_fprintf(f, "\n");
 return;
-- 
2.34.1




[PATCH 19/35] target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1

2023-12-18 Thread Peter Maydell
FEAT_NV requires (per I_JKLJK) that when HCR_EL2.{NV,NV1} is {1,1} the
unprivileged-access instructions LDTR, STTR etc behave as normal
loads and stores. Implement the check that handles this.

Signed-off-by: Peter Maydell 
---
 target/arm/tcg/hflags.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index f33c0a12741..8f254bf9ccb 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -261,8 +261,10 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, 
int el, int fp_el,
 switch (mmu_idx) {
 case ARMMMUIdx_E10_1:
 case ARMMMUIdx_E10_1_PAN:
-/* TODO: ARMv8.3-NV */
-DP_TBFLAG_A64(flags, UNPRIV, 1);
+/* FEAT_NV: NV,NV1 == 1,1 means we don't do UNPRIV accesses */
+if ((hcr & (HCR_NV | HCR_NV1)) != (HCR_NV | HCR_NV1)) {
+DP_TBFLAG_A64(flags, UNPRIV, 1);
+}
 break;
 case ARMMMUIdx_E20_2:
 case ARMMMUIdx_E20_2_PAN:
-- 
2.34.1




[PATCH 04/35] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV

2023-12-18 Thread Peter Maydell
FEAT_NV defines three new bits in HCR_EL2: NV, NV1 and AT.  When the
feature is enabled, allow these bits to be written, and flush the
TLBs for the bits which affect page table interpretation.

Signed-off-by: Peter Maydell 
---
 target/arm/cpu-features.h | 5 +
 target/arm/helper.c   | 6 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 954d3582685..3a43c328d9e 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -839,6 +839,11 @@ static inline bool isar_feature_aa64_e0pd(const 
ARMISARegisters *id)
 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, E0PD) != 0;
 }
 
+static inline bool isar_feature_aa64_nv(const ARMISARegisters *id)
+{
+return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0;
+}
+
 static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
 {
 return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 &&
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 39830c7f948..ca8de414bdb 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5799,6 +5799,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t 
value, uint64_t valid_mask)
 if (cpu_isar_feature(aa64_rme, cpu)) {
 valid_mask |= HCR_GPF;
 }
+if (cpu_isar_feature(aa64_nv, cpu)) {
+valid_mask |= HCR_NV | HCR_NV1 | HCR_AT;
+}
 }
 
 if (cpu_isar_feature(any_evt, cpu)) {
@@ -5817,9 +5820,10 @@ static void do_hcr_write(CPUARMState *env, uint64_t 
value, uint64_t valid_mask)
  * HCR_DC disables stage1 and enables stage2 translation
  * HCR_DCT enables tagging on (disabled) stage1 translation
  * HCR_FWB changes the interpretation of stage2 descriptor bits
+ * HCR_NV and HCR_NV1 affect interpretation of descriptor bits
  */
 if ((env->cp15.hcr_el2 ^ value) &
-(HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB)) {
+(HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB | HCR_NV | HCR_NV1)) {
 tlb_flush(CPU(cpu));
 }
 env->cp15.hcr_el2 = value;
-- 
2.34.1




[PATCH 09/35] target/arm: Record correct opcode fields in cpreg for E2H aliases

2023-12-18 Thread Peter Maydell
For FEAT_VHE, we define a set of register aliases, so that for instance:
 * the SCTLR_EL1 either accesses the real SCTLR_EL1, or (if E2H is 1)
   SCTLR_EL2
 * a new SCTLR_EL12 register accesses SCTLR_EL1 if E2H is 1

However when we create the 'new_reg' cpreg struct for the SCTLR_EL12
register, we duplicate the information in the SCTLR_EL1 cpreg, which
means the opcode fields are those of SCTLR_EL1, not SCTLR_EL12.  This
is a problem for code which looks at the cpreg opcode fields to
determine behaviour (e.g.  in access_check_cp_reg()). In practice
the current checks we do there don't intersect with the *_EL12
registers, but for FEAT_NV this will become a problem.

Write the correct values from the encoding into the new_reg struct.
This restores the invariant that the cpreg that you get back
from the hashtable has opcode fields that match the key you used
to retrieve it.

When we call the readfn or writefn for the target register, we
pass it the cpreg struct for that target register, not the one
for the alias, in case the readfn/writefn want to look at the
opcode fields to determine behaviour. This means we need to
interpose custom read/writefns for the e12 aliases.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 35 +++
 1 file changed, 35 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index f1c7fbf319c..c6f069b74cd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6506,6 +6506,19 @@ static void el2_e2h_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 writefn(env, ri, value);
 }
 
+static uint64_t el2_e2h_e12_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+/* Pass the EL1 register accessor its ri, not the EL12 alias ri */
+return ri->orig_readfn(env, ri->opaque);
+}
+
+static void el2_e2h_e12_write(CPUARMState *env, const ARMCPRegInfo *ri,
+  uint64_t value)
+{
+/* Pass the EL1 register accessor its ri, not the EL12 alias ri */
+return ri->orig_writefn(env, ri->opaque, value);
+}
+
 static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
 {
 struct E2HAlias {
@@ -6605,6 +6618,28 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU 
*cpu)
 new_reg->type |= ARM_CP_ALIAS;
 /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place.  */
 new_reg->access &= PL2_RW | PL3_RW;
+/* The new_reg op fields are as per new_key, not the target reg */
+new_reg->crn = (a->new_key & CP_REG_ARM64_SYSREG_CRN_MASK)
+>> CP_REG_ARM64_SYSREG_CRN_SHIFT;
+new_reg->crm = (a->new_key & CP_REG_ARM64_SYSREG_CRM_MASK)
+>> CP_REG_ARM64_SYSREG_CRM_SHIFT;
+new_reg->opc0 = (a->new_key & CP_REG_ARM64_SYSREG_OP0_MASK)
+>> CP_REG_ARM64_SYSREG_OP0_SHIFT;
+new_reg->opc1 = (a->new_key & CP_REG_ARM64_SYSREG_OP1_MASK)
+>> CP_REG_ARM64_SYSREG_OP1_SHIFT;
+new_reg->opc2 = (a->new_key & CP_REG_ARM64_SYSREG_OP2_MASK)
+>> CP_REG_ARM64_SYSREG_OP2_SHIFT;
+new_reg->opaque = src_reg;
+new_reg->orig_readfn = src_reg->readfn ?: raw_read;
+new_reg->orig_writefn = src_reg->writefn ?: raw_write;
+if (!new_reg->raw_readfn) {
+new_reg->raw_readfn = raw_read;
+}
+if (!new_reg->raw_writefn) {
+new_reg->raw_writefn = raw_write;
+}
+new_reg->readfn = el2_e2h_e12_read;
+new_reg->writefn = el2_e2h_e12_write;
 
 ok = g_hash_table_insert(cpu->cp_regs,
  (gpointer)(uintptr_t)a->new_key, new_reg);
-- 
2.34.1




[PATCH 22/35] target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits

2023-12-18 Thread Peter Maydell
FEAT_NV2 defines another new bit in HCR_EL2: NV2. When the
feature is enabled, allow this bit to be written in HCR_EL2.

Signed-off-by: Peter Maydell 
---
 target/arm/cpu-features.h | 5 +
 target/arm/helper.c   | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 3a43c328d9e..7a590c824cf 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -844,6 +844,11 @@ static inline bool isar_feature_aa64_nv(const 
ARMISARegisters *id)
 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0;
 }
 
+static inline bool isar_feature_aa64_nv2(const ARMISARegisters *id)
+{
+return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) >= 2;
+}
+
 static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
 {
 return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 &&
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 28448624c36..afed58b6f7f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5841,6 +5841,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t 
value, uint64_t valid_mask)
 if (cpu_isar_feature(aa64_nv, cpu)) {
 valid_mask |= HCR_NV | HCR_NV1 | HCR_AT;
 }
+if (cpu_isar_feature(aa64_nv2, cpu)) {
+valid_mask |= HCR_NV2;
+}
 }
 
 if (cpu_isar_feature(any_evt, cpu)) {
-- 
2.34.1




[PATCH 23/35] target/arm: Implement VNCR_EL2 register

2023-12-18 Thread Peter Maydell
For FEAT_NV2, a new system register VNCR_EL2 holds the base
address of the memory which nested-guest system register
accesses are redirected to. Implement this register.

Signed-off-by: Peter Maydell 
---
 target/arm/cpu.h|  3 +++
 target/arm/helper.c | 26 ++
 2 files changed, 29 insertions(+)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 0ec67847181..9df8fc08d79 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -547,6 +547,9 @@ typedef struct CPUArchState {
 uint64_t gpccr_el3;
 uint64_t gptbr_el3;
 uint64_t mfar_el3;
+
+/* NV2 register */
+uint64_t vncr_el2;
 } cp15;
 
 struct {
diff --git a/target/arm/helper.c b/target/arm/helper.c
index afed58b6f7f..45444360f95 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8107,6 +8107,28 @@ static const ARMCPRegInfo fgt_reginfo[] = {
   .access = PL2_RW, .accessfn = access_fgt,
   .fieldoffset = offsetof(CPUARMState, cp15.fgt_exec[FGTREG_HFGITR]) },
 };
+
+static void vncr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+   uint64_t value)
+{
+/*
+ * Clear the RES0 bottom 12 bits; this means at runtime we can guarantee
+ * that VNCR_EL2 + offset is 64-bit aligned. We don't need to do anything
+ * about the RESS bits at the top -- we choose the "generate an EL2
+ * translation abort on use" CONSTRAINED UNPREDICTABLE option (i.e. let
+ * the ptw.c code detect the resulting invalid address).
+ */
+env->cp15.vncr_el2 = value & ~0xfffULL;
+}
+
+static const ARMCPRegInfo nv2_reginfo[] = {
+{ .name = "VNCR_EL2", .state = ARM_CP_STATE_AA64,
+  .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 2, .opc2 = 0,
+  .access = PL2_RW,
+  .writefn = vncr_write,
+  .fieldoffset = offsetof(CPUARMState, cp15.vncr_el2) },
+};
+
 #endif /* TARGET_AARCH64 */
 
 static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -9590,6 +9612,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 define_arm_cp_regs(cpu, rme_mte_reginfo);
 }
 }
+
+if (cpu_isar_feature(aa64_nv2, cpu)) {
+define_arm_cp_regs(cpu, nv2_reginfo);
+}
 #endif
 
 if (cpu_isar_feature(any_predinv, cpu)) {
-- 
2.34.1




[PATCH 08/35] target/arm: Allow use of upper 32 bits of TBFLAG_A64

2023-12-18 Thread Peter Maydell
The TBFLAG_A64 TB flag bits go in flags2, which for AArch64 guests
we know is 64 bits. However at the moment we use FIELD_EX32() and
FIELD_DP32() to read and write these bits, which only works for
bits 0 to 31. Since we're about to add a flag that uses bit 32,
switch to FIELD_EX64() and FIELD_DP64() so that this will work.

Signed-off-by: Peter Maydell 
---
 target/arm/cpu.h | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 167b3759ac9..91157db85ae 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3240,12 +3240,14 @@ FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
 
 /*
- * Helpers for using the above.
+ * Helpers for using the above. Note that only the A64 accessors use
+ * FIELD_DP64() and FIELD_EX64(), because in the other cases the flags
+ * word either is or might be 32 bits only.
  */
 #define DP_TBFLAG_ANY(DST, WHICH, VAL) \
 (DST.flags = FIELD_DP32(DST.flags, TBFLAG_ANY, WHICH, VAL))
 #define DP_TBFLAG_A64(DST, WHICH, VAL) \
-(DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A64, WHICH, VAL))
+(DST.flags2 = FIELD_DP64(DST.flags2, TBFLAG_A64, WHICH, VAL))
 #define DP_TBFLAG_A32(DST, WHICH, VAL) \
 (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A32, WHICH, VAL))
 #define DP_TBFLAG_M32(DST, WHICH, VAL) \
@@ -3254,7 +3256,7 @@ FIELD(TBFLAG_A64, ATA0, 31, 1)
 (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_AM32, WHICH, VAL))
 
 #define EX_TBFLAG_ANY(IN, WHICH)   FIELD_EX32(IN.flags, TBFLAG_ANY, WHICH)
-#define EX_TBFLAG_A64(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_A64, WHICH)
+#define EX_TBFLAG_A64(IN, WHICH)   FIELD_EX64(IN.flags2, TBFLAG_A64, WHICH)
 #define EX_TBFLAG_A32(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_A32, WHICH)
 #define EX_TBFLAG_M32(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_M32, WHICH)
 #define EX_TBFLAG_AM32(IN, WHICH)  FIELD_EX32(IN.flags2, TBFLAG_AM32, WHICH)
-- 
2.34.1




[PATCH 28/35] target/arm: Mark up VNCR offsets (offsets 0x0..0xff)

2023-12-18 Thread Peter Maydell
Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM. This commit covers offsets below 0x100; all of these
registers are redirected to memory regardless of the value of
HCR_EL2.NV1.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 61aac61bcc4..ff7f90fa4af 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6043,6 +6043,7 @@ static const ARMCPRegInfo hcrx_el2_reginfo = {
 .name = "HCRX_EL2", .state = ARM_CP_STATE_AA64,
 .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 2,
 .access = PL2_RW, .writefn = hcrx_write, .accessfn = access_hxen,
+.nv2_redirect_offset = 0xa0,
 .fieldoffset = offsetof(CPUARMState, cp15.hcrx_el2),
 };
 
@@ -6109,6 +6110,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
   .type = ARM_CP_IO,
   .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
   .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
+  .nv2_redirect_offset = 0x78,
   .writefn = hcr_write, .raw_writefn = raw_write },
 { .name = "HCR", .state = ARM_CP_STATE_AA32,
   .type = ARM_CP_ALIAS | ARM_CP_IO,
@@ -6193,6 +6195,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
 { .name = "VTCR_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2,
   .access = PL2_RW,
+  .nv2_redirect_offset = 0x40,
   /* no .writefn needed as this can't cause an ASID change */
   .fieldoffset = offsetof(CPUARMState, cp15.vtcr_el2) },
 { .name = "VTTBR", .state = ARM_CP_STATE_AA32,
@@ -6204,6 +6207,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
 { .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0,
   .access = PL2_RW, .writefn = vttbr_write, .raw_writefn = raw_write,
+  .nv2_redirect_offset = 0x20,
   .fieldoffset = offsetof(CPUARMState, cp15.vttbr_el2) },
 { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
@@ -6212,6 +6216,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
 { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2,
   .access = PL2_RW, .resetvalue = 0,
+  .nv2_redirect_offset = 0x90,
   .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[2]) },
 { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
@@ -6307,6 +6312,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
   .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
   .writefn = gt_cntvoff_write,
+  .nv2_redirect_offset = 0x60,
   .fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
 { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
   .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS | ARM_CP_IO,
@@ -6345,6 +6351,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
 { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH,
   .cp = 15, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3,
   .access = PL2_RW,
+  .nv2_redirect_offset = 0x80,
   .fieldoffset = offsetof(CPUARMState, cp15.hstr_el2) },
 };
 
@@ -6370,10 +6377,12 @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = {
 { .name = "VSTTBR_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 0,
   .access = PL2_RW, .accessfn = sel2_access,
+  .nv2_redirect_offset = 0x30,
   .fieldoffset = offsetof(CPUARMState, cp15.vsttbr_el2) },
 { .name = "VSTCR_EL2", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 2,
   .access = PL2_RW, .accessfn = sel2_access,
+  .nv2_redirect_offset = 0x48,
   .fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) },
 };
 
@@ -8131,6 +8140,7 @@ static const ARMCPRegInfo nv2_reginfo[] = {
   .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 2, .opc2 = 0,
   .access = PL2_RW,
   .writefn = vncr_write,
+  .nv2_redirect_offset = 0xb0,
   .fieldoffset = offsetof(CPUARMState, cp15.vncr_el2) },
 };
 
@@ -8962,6 +8972,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
   .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
   .access = PL2_RW, .resetvalue = cpu->midr,
   .type = ARM_CP_EL3_NO_EL2_C_NZ,
+  .nv2_redirect_offset = 0x88,
   .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) },
 { .name = "VMPIDR", .state = ARM_CP_STATE_AA32,
   .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
@@ -8973,6 +8984,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
   .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
   .access = PL2_RW, .resetvalue = vmpidr_def

[PATCH 31/35] target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC)

2023-12-18 Thread Peter Maydell
Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM.  This covers all the remaining offsets at 0x200 and
above, except for the GIC ICH_* registers.

(Note that because we don't implement FEAT_SPE, FEAT_TRF,
FEAT_MPAM, FEAT_BRBE or FEAT_AMUv1p1 we don't implement any
of the registers that use offsets at 0x800 and above.)

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 6c33619d646..c72ce4aee09 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4271,6 +4271,7 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
   .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_FAR_EL1,
+  .nv2_redirect_offset = 0x220 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
   .resetvalue = 0, },
 };
@@ -4286,6 +4287,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_TTBR0_EL1,
+  .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1,
   .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
   .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
  offsetof(CPUARMState, cp15.ttbr0_ns) } },
@@ -4293,6 +4295,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
   .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1,
   .access = PL1_RW, .accessfn = access_tvm_trvm,
   .fgt = FGT_TTBR1_EL1,
+  .nv2_redirect_offset = 0x210 | NV2_REDIR_NV1,
   .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
   .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
  offsetof(CPUARMState, cp15.ttbr1_ns) } },
@@ -5725,6 +5728,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
   .type = ARM_CP_ALIAS,
   .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
   .access = PL1_RW, .accessfn = access_nv1,
+  .nv2_redirect_offset = 0x230 | NV2_REDIR_NV1,
   .fieldoffset = offsetof(CPUARMState, elr_el[1]) },
 { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
   .type = ARM_CP_ALIAS,
@@ -5744,6 +5748,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
   .fieldoffset = offsetof(CPUARMState, sp_el[0]) },
 { .name = "SP_EL1", .state = ARM_CP_STATE_AA64,
   .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 1, .opc2 = 0,
+  .nv2_redirect_offset = 0x240,
   .access = PL2_RW, .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_KEEP,
   .fieldoffset = offsetof(CPUARMState, sp_el[1]) },
 { .name = "SPSel", .state = ARM_CP_STATE_AA64,
@@ -6866,9 +6871,11 @@ static const ARMCPRegInfo minimal_ras_reginfo[] = {
   .type = ARM_CP_CONST, .resetvalue = 0 },
 { .name = "VDISR_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 1, .opc2 = 1,
+  .nv2_redirect_offset = 0x500,
   .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vdisr_el2) },
 { .name = "VSESR_EL2", .state = ARM_CP_STATE_BOTH,
   .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 3,
+  .nv2_redirect_offset = 0x508,
   .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2) },
 };
 
@@ -9524,6 +9531,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
   .access = PL1_RW, .writefn = vbar_write,
   .accessfn = access_nv1,
   .fgt = FGT_VBAR_EL1,
+  .nv2_redirect_offset = 0x250 | NV2_REDIR_NV1,
   .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s),
  offsetof(CPUARMState, cp15.vbar_ns) },
   .resetvalue = 0 },
-- 
2.34.1




[PATCH 07/35] target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set

2023-12-18 Thread Peter Maydell
The HCR_EL2.TSC trap for trapping EL1 execution of SMC instructions
has a behaviour change for FEAT_NV when EL3 is not implemented:

 * in older architecture versions TSC was required to have no
   effect (i.e. the SMC insn UNDEFs)
 * with FEAT_NV, when HCR_EL2.NV == 1 the trap must apply
   (i.e. SMC traps to EL2, as it already does in all cases when
   EL3 is implemented)
 * in newer architecture versions, the behaviour either without
   FEAT_NV or with FEAT_NV and HCR_EL2.NV == 0 is relaxed to
   an IMPDEF choice between UNDEF and trap-to-EL2 (i.e. it is
   permitted to always honour HCR_EL2.TSC) for AArch64 only

Add the condition to honour the trap bit when HCR_EL2.NV == 1.  We
leave the HCR_EL2.NV == 0 case with the existing (UNDEF) behaviour,
as our IMPDEF choice (both because it avoids a behaviour change
for older CPU models and because we'd have to distinguish AArch32
from AArch64 if we opted to trap to EL2).

Signed-off-by: Peter Maydell 
---
 target/arm/tcg/op_helper.c | 16 +---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index ea08936a852..ae158200c00 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -930,7 +930,14 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
  *
  *  Conduit SMC, valid call  Trap to EL2 PSCI Call
  *  Conduit SMC, inval call  Trap to EL2 Undef insn
- *  Conduit not SMC  Undef insn  Undef insn
+ *  Conduit not SMC  Undef or trap[1]Undef insn
+ *
+ * [1] In this case:
+ *  - if HCR_EL2.NV == 1 we must trap to EL2
+ *  - if HCR_EL2.NV == 0 then newer architecture revisions permit
+ *AArch64 (but not AArch32) to trap to EL2 as an IMPDEF choice
+ *  - otherwise we must UNDEF
+ * We take the IMPDEF choice to always UNDEF if HCR_EL2.NV == 0.
  */
 
 /* On ARMv8 with EL3 AArch64, SMD applies to both S and NS state.
@@ -944,9 +951,12 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
  : smd_flag && !secure;
 
 if (!arm_feature(env, ARM_FEATURE_EL3) &&
+!(arm_hcr_el2_eff(env) & HCR_NV) &&
 cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
-/* If we have no EL3 then SMC always UNDEFs and can't be
- * trapped to EL2. PSCI-via-SMC is a sort of ersatz EL3
+/*
+ * If we have no EL3 then traditionally SMC always UNDEFs and can't be
+ * trapped to EL2. For nested virtualization, SMC can be trapped to
+ * the outer hypervisor. PSCI-via-SMC is a sort of ersatz EL3
  * firmware within QEMU, and we want an EL2 guest to be able
  * to forbid its EL1 from making PSCI calls into QEMU's
  * "firmware" via HCR.TSC, so for these purposes treat
-- 
2.34.1




[PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs

2023-12-18 Thread Peter Maydell
Enable FEAT_NV on the 'max' CPU, and stop filtering it out for the
Neoverse N2 and Neoverse V1 CPUs.  We continue to downgrade FEAT_NV2
support to FEAT_NV for the latter two CPU types.

Signed-off-by: Peter Maydell 
---
 docs/system/arm/emulation.rst | 1 +
 target/arm/cpu.c  | 8 +---
 target/arm/tcg/cpu64.c| 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 0b604f90059..d827b42de79 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -63,6 +63,7 @@ the following architecture extensions:
 - FEAT_MTE (Memory Tagging Extension)
 - FEAT_MTE2 (Memory Tagging Extension)
 - FEAT_MTE3 (MTE Asymmetric Fault Handling)
+- FEAT_NV (Nested Virtualization)
 - FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm)
 - FEAT_PACQARMA3 (Pointer authentication - QARMA3 algorithm)
 - FEAT_PACQARMA5 (Pointer authentication - QARMA5 algorithm)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index efb22a87f9e..da0c02f850b 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2238,9 +2238,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error 
**errp)
 /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */
 cpu->isar.id_aa64pfr0 =
 FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, MPAM, 0);
-/* FEAT_NV (Nested Virtualization) */
-cpu->isar.id_aa64mmfr2 =
-FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 0);
+/* FEAT_NV2 (Enhanced Nested Virtualization support) */
+if (FIELD_EX64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV) > 1) {
+cpu->isar.id_aa64mmfr2 =
+FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 1);
+}
 }
 
 /* MPU can be configured out of a PMSA CPU either by setting has-mpu
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 40e7a45166f..93f040e6e96 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1204,6 +1204,7 @@ void aarch64_max_tcg_initfn(Object *obj)
 t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);  /* FEAT_UAO */
 t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */
 t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1);  /* FEAT_LVA */
+t = FIELD_DP64(t, ID_AA64MMFR2, NV, 1);   /* FEAT_NV */
 t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1);   /* FEAT_TTST */
 t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1);   /* FEAT_LSE2 */
 t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1);  /* FEAT_IDST */
-- 
2.34.1




[PATCH 35/35] target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs

2023-12-18 Thread Peter Maydell
Enable FEAT_NV2 on the 'max' CPU, and stop filtering it out for
the Neoverse N2 and Neoverse V1 CPUs.

Signed-off-by: Peter Maydell 
---
 docs/system/arm/emulation.rst | 1 +
 target/arm/cpu.c  | 5 -
 target/arm/tcg/cpu64.c| 2 +-
 3 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index d827b42de79..f67aea2d836 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -64,6 +64,7 @@ the following architecture extensions:
 - FEAT_MTE2 (Memory Tagging Extension)
 - FEAT_MTE3 (MTE Asymmetric Fault Handling)
 - FEAT_NV (Nested Virtualization)
+- FEAT_NV2 (Enhanced nested virtualization support)
 - FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm)
 - FEAT_PACQARMA3 (Pointer authentication - QARMA3 algorithm)
 - FEAT_PACQARMA5 (Pointer authentication - QARMA5 algorithm)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d1d592609eb..65dc88ba864 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2243,11 +2243,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error 
**errp)
 /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */
 cpu->isar.id_aa64pfr0 =
 FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, MPAM, 0);
-/* FEAT_NV2 (Enhanced Nested Virtualization support) */
-if (FIELD_EX64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV) > 1) {
-cpu->isar.id_aa64mmfr2 =
-FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 1);
-}
 }
 
 /* MPU can be configured out of a PMSA CPU either by setting has-mpu
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 93f040e6e96..5fba2c0f040 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1204,7 +1204,7 @@ void aarch64_max_tcg_initfn(Object *obj)
 t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);  /* FEAT_UAO */
 t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */
 t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1);  /* FEAT_LVA */
-t = FIELD_DP64(t, ID_AA64MMFR2, NV, 1);   /* FEAT_NV */
+t = FIELD_DP64(t, ID_AA64MMFR2, NV, 2);   /* FEAT_NV2 */
 t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1);   /* FEAT_TTST */
 t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1);   /* FEAT_LSE2 */
 t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1);  /* FEAT_IDST */
-- 
2.34.1




[PATCH 14/35] target/arm: Make NV reads of CurrentEL return EL2

2023-12-18 Thread Peter Maydell
FEAT_NV requires that when HCR_EL2.NV is set reads of the CurrentEL
register from EL1 always report EL2 rather than the real EL.
Implement this.

Signed-off-by: Peter Maydell 
---
 target/arm/tcg/translate-a64.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index d060e24356d..6bfc39d8ea7 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2240,12 +2240,17 @@ static void handle_sys(DisasContext *s, bool isread,
 }
 return;
 case ARM_CP_CURRENTEL:
-/* Reads as current EL value from pstate, which is
+{
+/*
+ * Reads as current EL value from pstate, which is
  * guaranteed to be constant by the tb flags.
+ * For nested virt we should report EL2.
  */
+int el = s->nv ? 2 : s->current_el;
 tcg_rt = cpu_reg(s, rt);
-tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
+tcg_gen_movi_i64(tcg_rt, el << 2);
 return;
+}
 case ARM_CP_DC_ZVA:
 /* Writes clear the aligned block of memory which rt points into. */
 if (s->mte_active[0]) {
-- 
2.34.1




[PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2

2023-12-18 Thread Peter Maydell
With FEAT_NV2, the condition for when SPSR_EL1.M should report that
an exception was taken from EL2 changes.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 16 
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 45444360f95..38e16c2f8a5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11405,10 +11405,18 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
 aarch64_save_sp(env, arm_current_el(env));
 env->elr_el[new_el] = env->pc;
 
-if (cur_el == 1 && new_el == 1 &&
-((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) {
-/* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */
-old_mode = deposit32(old_mode, 2, 2, 2);
+if (cur_el == 1 && new_el == 1) {
+uint64_t hcr = arm_hcr_el2_eff(env);
+if ((hcr & (HCR_NV | HCR_NV1 | HCR_NV2)) == HCR_NV ||
+(hcr & (HCR_NV | HCR_NV2)) == (HCR_NV | HCR_NV2)) {
+/*
+ * FEAT_NV, FEAT_NV2 may need to report EL2 in the SPSR
+ * by setting M[3:2] to 0b10.
+ * If NV2 is disabled, change SPSR when NV,NV1 == 1,0 (I_ZJRNN)
+ * If NV2 is enabled, change SPSR when NV is 1 (I_DBTLM)
+ */
+old_mode = deposit32(old_mode, 2, 2, 2);
+}
 }
 } else {
 old_mode = cpsr_read_for_spsr_elx(env);
-- 
2.34.1




[PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled

2023-12-18 Thread Peter Maydell
Currently the code in target/arm/helper.c mostly checks the PAN bits
in env->pstate or env->uncached_cpsr directly when it wants to know
if PAN is enabled, because in most callsites we know whether we are
in AArch64 or AArch32. We do have an arm_pan_enabled() function, but
we only use it in a few places where the code might run in either an
AArch32 or AArch64 context.

For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled
even when the PSTATE.PAN bit is set, the "is PAN enabled" test
becomes more complicated. Make all places that check for PAN use
arm_pan_enabled(), so we have a place to put the FEAT_NV test.

Signed-off-by: Peter Maydell 
---
 target/arm/helper.c | 22 +++---
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3270fb11049..4b0e46cfaae 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -263,6 +263,15 @@ void init_cpreg_list(ARMCPU *cpu)
 g_list_free(keys);
 }
 
+static bool arm_pan_enabled(CPUARMState *env)
+{
+if (is_a64(env)) {
+return env->pstate & PSTATE_PAN;
+} else {
+return env->uncached_cpsr & CPSR_PAN;
+}
+}
+
 /*
  * Some registers are not accessible from AArch32 EL3 if SCR.NS == 0.
  */
@@ -3598,7 +3607,7 @@ static void ats_write(CPUARMState *env, const 
ARMCPRegInfo *ri, uint64_t value)
 g_assert(ss != ARMSS_Secure);  /* ARMv8.4-SecEL2 is 64-bit only */
 /* fall through */
 case 1:
-if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) {
+if (ri->crm == 9 && arm_pan_enabled(env)) {
 mmu_idx = ARMMMUIdx_Stage1_E1_PAN;
 } else {
 mmu_idx = ARMMMUIdx_Stage1_E1;
@@ -3714,7 +3723,7 @@ static void ats_write64(CPUARMState *env, const 
ARMCPRegInfo *ri,
 case 0:
 switch (ri->opc1) {
 case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */
-if (ri->crm == 9 && (env->pstate & PSTATE_PAN)) {
+if (ri->crm == 9 && arm_pan_enabled(env)) {
 mmu_idx = regime_e20 ?
   ARMMMUIdx_E20_2_PAN : ARMMMUIdx_Stage1_E1_PAN;
 } else {
@@ -1,15 +12231,6 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState 
*env, bool secstate)
 }
 #endif
 
-static bool arm_pan_enabled(CPUARMState *env)
-{
-if (is_a64(env)) {
-return env->pstate & PSTATE_PAN;
-} else {
-return env->uncached_cpsr & CPSR_PAN;
-}
-}
-
 ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
 {
 ARMMMUIdx idx;
-- 
2.34.1




Re: [RFC 0/3] aio-posix: call ->poll_end() when removing AioHandler

2023-12-18 Thread Fiona Ebner
Am 14.12.23 um 20:53 schrieb Stefan Hajnoczi:
> 
> I will still try the other approach that Hanna and Paolo have suggested.
> It seems more palatable. I will send a v2.
> 

FYI, what I already tried downstream (for VirtIO SCSI):

> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
> index 9c751bf296..a6449b04d0 100644
> --- a/hw/scsi/virtio-scsi.c
> +++ b/hw/scsi/virtio-scsi.c
> @@ -1166,6 +1166,8 @@ static void virtio_scsi_drained_end(SCSIBus *bus)
>  
>  for (uint32_t i = 0; i < total_queues; i++) {
>  VirtQueue *vq = virtio_get_queue(vdev, i);
> +virtio_queue_set_notification(vq, 1);
> +virtio_queue_notify(vdev, i);
>  virtio_queue_aio_attach_host_notifier(vq, s->ctx);
>  }
>  }

But this introduces an issue where e.g. a 'backup' QMP command would put
the iothread into a bad state. After the command, whenever the guest
issues IO, the thread will temporarily spike to using 100% CPU. Using
QMP stop+cont is a way to make it go back to normal.

I think it's because of nested drains, because when additionally
checking that the drain count is zero and only executing the loop then,
that issue doesn't seem to manifest, i.e.:

> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
> index 9c751bf296..d22c586b38 100644
> --- a/hw/scsi/virtio-scsi.c
> +++ b/hw/scsi/virtio-scsi.c
> @@ -1164,9 +1164,13 @@ static void virtio_scsi_drained_end(SCSIBus *bus)
>  return;
>  }
>  
> -for (uint32_t i = 0; i < total_queues; i++) {
> -VirtQueue *vq = virtio_get_queue(vdev, i);
> -virtio_queue_aio_attach_host_notifier(vq, s->ctx);
> +if (s->bus.drain_count == 0) {
> +for (uint32_t i = 0; i < total_queues; i++) {
> +VirtQueue *vq = virtio_get_queue(vdev, i);
> +virtio_queue_set_notification(vq, 1);
> +virtio_queue_notify(vdev, i);
> +virtio_queue_aio_attach_host_notifier(vq, s->ctx);
> +}
>  }
>  }
>  

Best Regards,
Fiona




[PATCH v13 04/26] target/riscv: add rv64i CPU

2023-12-18 Thread Daniel Henrique Barboza
We don't have any form of a 'bare bones' CPU. rv64, our default CPUs,
comes with a lot of defaults. This is fine for most regular uses but
it's not suitable when more control of what is actually loaded in the
CPU is required.

A bare-bones CPU would be annoying to deal with if not by profile
support, a way to load a multitude of extensions with a single flag.
Profile support is going to be implemented shortly, so let's add a CPU
for it.

The new 'rv64i' CPU will have only RVI loaded. It is inspired in the
profile specification that dictates, for RVA22U64 [1]:

"RVA22U64 Mandatory Base
 RV64I is the mandatory base ISA for RVA22U64"

And so it seems that RV64I is the mandatory base ISA for all profiles
listed in [1], making it an ideal CPU to use with profile support.

rv64i is a CPU of type TYPE_RISCV_BARE_CPU. It has a mix of features
from pre-existent CPUs:

- it allows extensions to be enabled, like generic CPUs;
- it will not inherit extension defaults, like vendor CPUs.

This is the minimum extension set to boot OpenSBI and buildroot using
rv64i:

./build/qemu-system-riscv64 -nographic -M virt \
-cpu rv64i,sv39=true,g=true,c=true,s=true,u=true

Our minimal riscv,isa in this case will be:

 # cat /proc/device-tree/cpus/cpu@0/riscv,isa
rv64imafdc_zicntr_zicsr_zifencei_zihpm_zca_zcd#

[1] https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu-qom.h |  2 ++
 target/riscv/cpu.c | 46 ++
 2 files changed, 48 insertions(+)

diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index ca7dd509e3..4d1aa54311 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -24,6 +24,7 @@
 #define TYPE_RISCV_CPU "riscv-cpu"
 #define TYPE_RISCV_DYNAMIC_CPU "riscv-dynamic-cpu"
 #define TYPE_RISCV_VENDOR_CPU "riscv-vendor-cpu"
+#define TYPE_RISCV_BARE_CPU "riscv-bare-cpu"
 
 #define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU
 #define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX)
@@ -33,6 +34,7 @@
 #define TYPE_RISCV_CPU_BASE32   RISCV_CPU_TYPE_NAME("rv32")
 #define TYPE_RISCV_CPU_BASE64   RISCV_CPU_TYPE_NAME("rv64")
 #define TYPE_RISCV_CPU_BASE128  RISCV_CPU_TYPE_NAME("x-rv128")
+#define TYPE_RISCV_CPU_RV64IRISCV_CPU_TYPE_NAME("rv64i")
 #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex")
 #define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c")
 #define TYPE_RISCV_CPU_SIFIVE_E31   RISCV_CPU_TYPE_NAME("sifive-e31")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index bb91bcacee..34102f6869 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -370,6 +370,17 @@ static void set_satp_mode_max_supported(RISCVCPU *cpu,
 /* Set the satp mode to the max supported */
 static void set_satp_mode_default_map(RISCVCPU *cpu)
 {
+/*
+ * Bare CPUs do not default to the max available.
+ * Users must set a valid satp_mode in the command
+ * line.
+ */
+if (object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_BARE_CPU) != NULL) {
+warn_report("No satp mode set. Defaulting to 'bare'");
+cpu->cfg.satp_mode.map = (1 << VM_1_10_MBARE);
+return;
+}
+
 cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported;
 }
 #endif
@@ -552,6 +563,28 @@ static void rv128_base_cpu_init(Object *obj)
 set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
 #endif
 }
+
+static void rv64i_bare_cpu_init(Object *obj)
+{
+CPURISCVState *env = &RISCV_CPU(obj)->env;
+riscv_cpu_set_misa(env, MXL_RV64, RVI);
+
+/* Remove the defaults from the parent class */
+RISCV_CPU(obj)->cfg.ext_zicntr = false;
+RISCV_CPU(obj)->cfg.ext_zihpm = false;
+
+/* Set to QEMU's first supported priv version */
+env->priv_ver = PRIV_VERSION_1_10_0;
+
+/*
+ * Support all available satp_mode settings. The default
+ * value will be set to MBARE if the user doesn't set
+ * satp_mode manually (see set_satp_mode_default()).
+ */
+#ifndef CONFIG_USER_ONLY
+set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV64);
+#endif
+}
 #else
 static void rv32_base_cpu_init(Object *obj)
 {
@@ -1785,6 +1818,13 @@ void riscv_cpu_list(void)
 .instance_init = initfn  \
 }
 
+#define DEFINE_BARE_CPU(type_name, initfn) \
+{  \
+.name = type_name, \
+.parent = TYPE_RISCV_BARE_CPU, \
+.instance_init = initfn\
+}
+
 static const TypeInfo riscv_cpu_type_infos[] = {
 {
 .name = TYPE_RISCV_CPU,
@@ -1807,6 +1847,11 @@ static const TypeInfo riscv_cpu_type_infos[] = {
 .parent = TYPE_RISCV_CPU,
 .abstract = true,
 },
+{
+.name = TYPE_RISCV_BARE_CPU,
+.parent = TYPE_RISCV_CPU,
+.abstract = true,
+},
 DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY,  riscv_any_cpu_init),
 DEFINE_DYNAMI

[PATCH v13 06/26] target/riscv/tcg: add 'zic64b' support

2023-12-18 Thread Daniel Henrique Barboza
zic64b is defined in the RVA22U64 profile [1] as a named feature for
"Cache blocks must be 64 bytes in size, naturally aligned in the address
space". It's a fantasy name for 64 bytes cache blocks. The RVA22U64
profile mandates this feature, meaning that applications using this
profile expects 64 bytes cache blocks.

To make the upcoming RVA22U64 implementation complete, we'll zic64b as
a 'named feature', not a regular extension. This means that:

- it won't be exposed to users;
- it won't be written in riscv,isa.

This will be extended to other named extensions in the future, so we're
creating some common boilerplate for them as well.

zic64b is default to 'true' since we're already using 64 bytes blocks.
If any cache block size (cbo{m,p,z}_blocksize) is changed to something
different than 64, zic64b is set to 'false'.

Our profile implementation will then be able to check the current state
of zic64b and take the appropriate action (e.g. throw a warning).

[1] https://github.com/riscv/riscv-profiles/releases/download/v1.0/profiles.pdf

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu.c |  6 ++
 target/riscv/cpu.h |  1 +
 target/riscv/cpu_cfg.h |  1 +
 target/riscv/tcg/tcg-cpu.c | 26 ++
 4 files changed, 34 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 86e3514cc8..b2e539f807 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1444,6 +1444,12 @@ const RISCVCPUMultiExtConfig 
riscv_cpu_experimental_exts[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+const RISCVCPUMultiExtConfig riscv_cpu_named_features[] = {
+MULTI_EXT_CFG_BOOL("zic64b", zic64b, true),
+
+DEFINE_PROP_END_OF_LIST(),
+};
+
 /* Deprecated entries marked for future removal */
 const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[] = {
 MULTI_EXT_CFG_BOOL("Zifencei", ext_zifencei, true),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index d74b361be6..5fb4ca2324 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -767,6 +767,7 @@ typedef struct RISCVCPUMultiExtConfig {
 extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[];
 extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[];
 extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[];
+extern const RISCVCPUMultiExtConfig riscv_cpu_named_features[];
 extern const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[];
 extern Property riscv_cpu_options[];
 
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index bd2ff87cc8..90f18eb601 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -116,6 +116,7 @@ struct RISCVCPUConfig {
 bool ext_smepmp;
 bool rvv_ta_all_1s;
 bool rvv_ma_all_1s;
+bool zic64b;
 
 uint32_t mvendorid;
 uint64_t marchid;
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index aee98db6f8..3319ba8e4e 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -114,6 +114,19 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
 g_assert_not_reached();
 }
 
+static bool cpu_cfg_offset_is_named_feat(uint32_t ext_offset)
+{
+const RISCVCPUMultiExtConfig *feat;
+
+for (feat = riscv_cpu_named_features; feat->name != NULL; feat++) {
+if (feat->offset == ext_offset) {
+return true;
+}
+}
+
+return false;
+}
+
 static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env,
 uint32_t ext_offset)
 {
@@ -123,6 +136,10 @@ static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env,
 return;
 }
 
+if (cpu_cfg_offset_is_named_feat(ext_offset)) {
+return;
+}
+
 ext_priv_ver = cpu_cfg_ext_get_min_version(ext_offset);
 
 if (env->priv_ver < ext_priv_ver) {
@@ -293,6 +310,13 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU 
*cpu)
 }
 }
 
+static void riscv_cpu_update_named_features(RISCVCPU *cpu)
+{
+cpu->cfg.zic64b = cpu->cfg.cbom_blocksize == 64 &&
+  cpu->cfg.cbop_blocksize == 64 &&
+  cpu->cfg.cboz_blocksize == 64;
+}
+
 /*
  * Check consistency between chosen extensions while setting
  * cpu->cfg accordingly.
@@ -657,6 +681,8 @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error 
**errp)
 return;
 }
 
+riscv_cpu_update_named_features(cpu);
+
 if (cpu->cfg.ext_smepmp && !cpu->cfg.pmp) {
 /*
  * Enhanced PMP should only be available
-- 
2.43.0




[PATCH v13 05/26] target/riscv: add zicbop extension flag

2023-12-18 Thread Daniel Henrique Barboza
QEMU already implements zicbom (Cache Block Management Operations) and
zicboz (Cache Block Zero Operations). Commit 59cb29d6a5 ("target/riscv:
add Zicbop cbo.prefetch{i, r, m} placeholder") added placeholders for
what would be the instructions for zicbop (Cache Block Prefetch
Operations), which are now no-ops.

The RVA22U64 profile mandates zicbop, which means that applications that
run with this profile might expect zicbop to be present in the riscv,isa
DT and might behave badly if it's absent.

Adding zicbop as an extension will make our future RVA22U64
implementation more in line with what userspace expects and, if/when
cache block prefetch operations became relevant to QEMU, we already have
the extension flag to turn then on/off as needed.

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 hw/riscv/virt.c| 5 +
 target/riscv/cpu.c | 3 +++
 target/riscv/cpu_cfg.h | 2 ++
 3 files changed, 10 insertions(+)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index d2eac24156..da650865e5 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -273,6 +273,11 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int 
socket,
   cpu_ptr->cfg.cboz_blocksize);
 }
 
+if (cpu_ptr->cfg.ext_zicbop) {
+qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbop-block-size",
+  cpu_ptr->cfg.cbop_blocksize);
+}
+
 qemu_fdt_setprop_string(ms->fdt, cpu_name, "compatible", "riscv");
 qemu_fdt_setprop_string(ms->fdt, cpu_name, "status", "okay");
 qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg",
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 34102f6869..86e3514cc8 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -78,6 +78,7 @@ const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, 
RVV,
  */
 const RISCVIsaExtData isa_edata_arr[] = {
 ISA_EXT_DATA_ENTRY(zicbom, PRIV_VERSION_1_12_0, ext_zicbom),
+ISA_EXT_DATA_ENTRY(zicbop, PRIV_VERSION_1_12_0, ext_zicbop),
 ISA_EXT_DATA_ENTRY(zicboz, PRIV_VERSION_1_12_0, ext_zicboz),
 ISA_EXT_DATA_ENTRY(zicond, PRIV_VERSION_1_12_0, ext_zicond),
 ISA_EXT_DATA_ENTRY(zicntr, PRIV_VERSION_1_12_0, ext_zicntr),
@@ -1376,6 +1377,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
 MULTI_EXT_CFG_BOOL("zhinxmin", ext_zhinxmin, false),
 
 MULTI_EXT_CFG_BOOL("zicbom", ext_zicbom, true),
+MULTI_EXT_CFG_BOOL("zicbop", ext_zicbop, true),
 MULTI_EXT_CFG_BOOL("zicboz", ext_zicboz, true),
 
 MULTI_EXT_CFG_BOOL("zmmul", ext_zmmul, false),
@@ -1510,6 +1512,7 @@ Property riscv_cpu_options[] = {
 DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
 
 DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64),
+DEFINE_PROP_UINT16("cbop_blocksize", RISCVCPU, cfg.cbop_blocksize, 64),
 DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64),
 
 DEFINE_PROP_END_OF_LIST(),
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index f4605fb190..bd2ff87cc8 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -65,6 +65,7 @@ struct RISCVCPUConfig {
 bool ext_zicntr;
 bool ext_zicsr;
 bool ext_zicbom;
+bool ext_zicbop;
 bool ext_zicboz;
 bool ext_zicond;
 bool ext_zihintntl;
@@ -142,6 +143,7 @@ struct RISCVCPUConfig {
 uint16_t vlen;
 uint16_t elen;
 uint16_t cbom_blocksize;
+uint16_t cbop_blocksize;
 uint16_t cboz_blocksize;
 bool mmu;
 bool pmp;
-- 
2.43.0




[PATCH v13 00/26] riscv: RVA22 profiles support

2023-12-18 Thread Daniel Henrique Barboza
Hi,

This is a merge of the two profile series:

"[PATCH for-9.0 v12 00/18] riscv: rv64i/rva22u64 CPUs, RVA22U64 profile support"
"[PATCH for-9.0 v2 0/8] target/riscv: implement RVA22S64 profile"

I'm sending them together since the second series is dependent on the first.

Quick summary of the major features added:

- A new rv64i CPU type. This is a CPU that has only RVI enabled;

- 'rva22u64' and 'rva22s64' profile flags. They were designed to be used
  with the 'rv64i' CPU but can be used with other generic CPUs like
  rv64;

- Two new profile CPUs: 'rva22u64' and 'rva22s64'. A profile CPU is an
  alias of '-cpu rv64,profile=on' and it's the most convenient way of
  using profiles. E.g to launch an rva22s64 'virt' machine:

  ./qemu-system-riscv64 -M virt -cpu rva22s64  (...)

  To test an application with an rva22u64 profile with linux-user mode:

  ./qemu-riscv64 -cpu rva22u64  (...)


The series can also be fetch via:

https://gitlab.com/danielhb/qemu/-/tree/rva22_v13

Patches rebased on top of Alistair riscv-to-apply.next.

All patches acked.

Daniel Henrique Barboza (26):
  target/riscv: create TYPE_RISCV_VENDOR_CPU
  target/riscv/tcg: do not use "!generic" CPU checks
  target/riscv/tcg: update priv_ver on user_set extensions
  target/riscv: add rv64i CPU
  target/riscv: add zicbop extension flag
  target/riscv/tcg: add 'zic64b' support
  riscv-qmp-cmds.c: expose named features in cpu_model_expansion
  target/riscv: add rva22u64 profile definition
  target/riscv/kvm: add 'rva22u64' flag as unavailable
  target/riscv/tcg: add user flag for profile support
  target/riscv/tcg: add MISA user options hash
  target/riscv/tcg: add riscv_cpu_write_misa_bit()
  target/riscv/tcg: handle profile MISA bits
  target/riscv/tcg: add hash table insert helpers
  target/riscv/tcg: honor user choice for G MISA bits
  target/riscv/tcg: validate profiles during finalize
  riscv-qmp-cmds.c: add profile flags in cpu-model-expansion
  target/riscv: add 'rva22u64' CPU
  target/riscv: implement svade
  target/riscv: add priv ver restriction to profiles
  target/riscv/cpu.c: finalize satp_mode earlier
  target/riscv/cpu.c: add riscv_cpu_is_32bit()
  target/riscv: add satp_mode profile support
  target/riscv: add 'parent' in profile description
  target/riscv: add RVA22S64 profile
  target/riscv: add rva22s64 cpu

 hw/riscv/virt.c   |   5 +
 target/riscv/cpu-qom.h|   5 +
 target/riscv/cpu.c| 201 +--
 target/riscv/cpu.h|  18 ++
 target/riscv/cpu_cfg.h|   4 +
 target/riscv/kvm/kvm-cpu.c|   7 +-
 target/riscv/riscv-qmp-cmds.c |  44 +++-
 target/riscv/tcg/tcg-cpu.c| 450 +++---
 8 files changed, 672 insertions(+), 62 deletions(-)

-- 
2.43.0




[PATCH v13 12/26] target/riscv/tcg: add riscv_cpu_write_misa_bit()

2023-12-18 Thread Daniel Henrique Barboza
We have two instances of the setting/clearing a MISA bit from
env->misa_ext and env->misa_ext_mask pattern. And the next patch will
end up adding one more.

Create a helper to avoid code repetition.

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Alistair Francis 
Reviewed-by: LIU Zhiwei 
Reviewed-by: Andrew Jones 
---
 target/riscv/tcg/tcg-cpu.c | 32 ++--
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 2affc1f771..f8c35ba060 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -42,6 +42,20 @@ static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
  GUINT_TO_POINTER(ext_offset));
 }
 
+static void riscv_cpu_write_misa_bit(RISCVCPU *cpu, uint32_t bit,
+ bool enabled)
+{
+CPURISCVState *env = &cpu->env;
+
+if (enabled) {
+env->misa_ext |= bit;
+env->misa_ext_mask |= bit;
+} else {
+env->misa_ext &= ~bit;
+env->misa_ext_mask &= ~bit;
+}
+}
+
 static void riscv_cpu_synchronize_from_tb(CPUState *cs,
   const TranslationBlock *tb)
 {
@@ -828,13 +842,9 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, 
const char *name,
  */
 env->priv_ver = PRIV_VERSION_1_12_0;
 }
-
-env->misa_ext |= misa_bit;
-env->misa_ext_mask |= misa_bit;
-} else {
-env->misa_ext &= ~misa_bit;
-env->misa_ext_mask &= ~misa_bit;
 }
+
+riscv_cpu_write_misa_bit(cpu, misa_bit, value);
 }
 
 static void cpu_get_misa_ext_cfg(Object *obj, Visitor *v, const char *name,
@@ -878,7 +888,6 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
  */
 static void riscv_cpu_add_misa_properties(Object *cpu_obj)
 {
-CPURISCVState *env = &RISCV_CPU(cpu_obj)->env;
 bool use_def_vals = riscv_cpu_is_generic(cpu_obj);
 int i;
 
@@ -899,13 +908,8 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj)
 NULL, (void *)misa_cfg);
 object_property_set_description(cpu_obj, name, desc);
 if (use_def_vals) {
-if (misa_cfg->enabled) {
-env->misa_ext |= bit;
-env->misa_ext_mask |= bit;
-} else {
-env->misa_ext &= ~bit;
-env->misa_ext_mask &= ~bit;
-}
+riscv_cpu_write_misa_bit(RISCV_CPU(cpu_obj), bit,
+ misa_cfg->enabled);
 }
 }
 }
-- 
2.43.0




[PATCH v13 09/26] target/riscv/kvm: add 'rva22u64' flag as unavailable

2023-12-18 Thread Daniel Henrique Barboza
KVM does not have the means to support enabling the rva22u64 profile.
The main reasons are:

- we're missing support for some mandatory rva22u64 extensions in the
  KVM module;

- we can't make promises about enabling a profile since it all depends
  on host support in the end.

We'll revisit this decision in the future if needed. For now mark the
'rva22u64' profile as unavailable when running a KVM CPU:

$ qemu-system-riscv64 -machine virt,accel=kvm -cpu rv64,rva22u64=true
qemu-system-riscv64: can't apply global rv64-riscv-cpu.rva22u64=true:
'rva22u64' is not available with KVM

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Alistair Francis 
Reviewed-by: LIU Zhiwei 
Reviewed-by: Andrew Jones 
---
 target/riscv/kvm/kvm-cpu.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 62a1e51f0a..ea8b1b1259 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -414,7 +414,7 @@ static void cpu_set_cfg_unavailable(Object *obj, Visitor *v,
 }
 
 if (value) {
-error_setg(errp, "extension %s is not available with KVM",
+error_setg(errp, "'%s' is not available with KVM",
propname);
 }
 }
@@ -495,6 +495,11 @@ static void kvm_riscv_add_cpu_user_properties(Object 
*cpu_obj)
 riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_extensions);
 riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_vendor_exts);
 riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_experimental_exts);
+
+   /* We don't have the needed KVM support for profiles */
+for (i = 0; riscv_profiles[i] != NULL; i++) {
+riscv_cpu_add_kvm_unavail_prop(cpu_obj, riscv_profiles[i]->name);
+}
 }
 
 static int kvm_riscv_get_regs_core(CPUState *cs)
-- 
2.43.0




[PATCH v13 20/26] target/riscv: add priv ver restriction to profiles

2023-12-18 Thread Daniel Henrique Barboza
Some profiles, like RVA22S64, has a priv_spec requirement.

Make this requirement explicit for all profiles. We'll validate this
requirement finalize() time and, in case the user chooses an
incompatible priv_spec while activating a profile, a warning will be
shown.

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu.c |  1 +
 target/riscv/cpu.h |  2 ++
 target/riscv/tcg/tcg-cpu.c | 31 +++
 3 files changed, 34 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a76bc1b86a..1ba85c6d1c 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1537,6 +1537,7 @@ Property riscv_cpu_options[] = {
 static RISCVCPUProfile RVA22U64 = {
 .name = "rva22u64",
 .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU,
+.priv_spec = RISCV_PROFILE_ATTR_UNUSED,
 .ext_offsets = {
 CPU_CFG_OFFSET(ext_zicsr), CPU_CFG_OFFSET(ext_zihintpause),
 CPU_CFG_OFFSET(ext_zba), CPU_CFG_OFFSET(ext_zbb),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5ff629650d..1f34eda1e4 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -81,10 +81,12 @@ typedef struct riscv_cpu_profile {
 uint32_t misa_ext;
 bool enabled;
 bool user_set;
+int priv_spec;
 const int32_t ext_offsets[];
 } RISCVCPUProfile;
 
 #define RISCV_PROFILE_EXT_LIST_END -1
+#define RISCV_PROFILE_ATTR_UNUSED -1
 
 extern RISCVCPUProfile *riscv_profiles[];
 
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index e395e2449e..4d25fc43d2 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -74,6 +74,20 @@ static void riscv_cpu_write_misa_bit(RISCVCPU *cpu, uint32_t 
bit,
 }
 }
 
+static const char *cpu_priv_ver_to_str(int priv_ver)
+{
+switch (priv_ver) {
+case PRIV_VERSION_1_10_0:
+return "v1.10.0";
+case PRIV_VERSION_1_11_0:
+return "v1.11.0";
+case PRIV_VERSION_1_12_0:
+return "v1.12.0";
+}
+
+g_assert_not_reached();
+}
+
 static void riscv_cpu_synchronize_from_tb(CPUState *cs,
   const TranslationBlock *tb)
 {
@@ -755,11 +769,24 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, 
Error **errp)
 static void riscv_cpu_validate_profile(RISCVCPU *cpu,
RISCVCPUProfile *profile)
 {
+CPURISCVState *env = &cpu->env;
 const char *warn_msg = "Profile %s mandates disabled extension %s";
 bool send_warn = profile->user_set && profile->enabled;
 bool profile_impl = true;
 int i;
 
+if (profile->priv_spec != RISCV_PROFILE_ATTR_UNUSED &&
+profile->priv_spec != env->priv_ver) {
+profile_impl = false;
+
+if (send_warn) {
+warn_report("Profile %s requires priv spec %s, "
+"but priv ver %s was set", profile->name,
+cpu_priv_ver_to_str(profile->priv_spec),
+cpu_priv_ver_to_str(env->priv_ver));
+}
+}
+
 for (i = 0; misa_bits[i] != 0; i++) {
 uint32_t bit = misa_bits[i];
 
@@ -1048,6 +1075,10 @@ static void cpu_set_profile(Object *obj, Visitor *v, 
const char *name,
 profile->user_set = true;
 profile->enabled = value;
 
+if (profile->enabled) {
+cpu->env.priv_ver = profile->priv_spec;
+}
+
 for (i = 0; misa_bits[i] != 0; i++) {
 uint32_t bit = misa_bits[i];
 
-- 
2.43.0




[PATCH v13 08/26] target/riscv: add rva22u64 profile definition

2023-12-18 Thread Daniel Henrique Barboza
The rva22U64 profile, described in:

https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva22-profiles

Contains a set of CPU extensions aimed for 64-bit userspace
applications. Enabling this set to be enabled via a single user flag
makes it convenient to enable a predictable set of features for the CPU,
giving users more predicability when running/testing their workloads.

QEMU implements all possible extensions of this profile. All the so
called 'synthetic extensions' described in the profile that are cache
related are ignored/assumed enabled (Za64rs, Zic64b, Ziccif, Ziccrse,
Ziccamoa, Zicclsm) since we do not implement a cache model.

An abstraction called RISCVCPUProfile is created to store the profile.
'ext_offsets' contains mandatory extensions that QEMU supports. Same
thing with the 'misa_ext' mask. Optional extensions must be enabled
manually in the command line if desired.

The design here is to use the common target/riscv/cpu.c file to store
the profile declaration and export it to the accelerator files. Each
accelerator is then responsible to expose it (or not) to users and how
to enable the extensions.

Next patches will implement the profile for TCG and KVM.

Signed-off-by: Daniel Henrique Barboza 
Acked-by: Alistair Francis 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu.c | 32 
 target/riscv/cpu.h | 12 
 2 files changed, 44 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index b2e539f807..b9057c8da2 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1524,6 +1524,38 @@ Property riscv_cpu_options[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+/*
+ * RVA22U64 defines some 'named features' or 'synthetic extensions'
+ * that are cache related: Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa
+ * and Zicclsm. We do not implement caching in QEMU so we'll consider
+ * all these named features as always enabled.
+ *
+ * There's no riscv,isa update for them (nor for zic64b, despite it
+ * having a cfg offset) at this moment.
+ */
+static RISCVCPUProfile RVA22U64 = {
+.name = "rva22u64",
+.misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU,
+.ext_offsets = {
+CPU_CFG_OFFSET(ext_zicsr), CPU_CFG_OFFSET(ext_zihintpause),
+CPU_CFG_OFFSET(ext_zba), CPU_CFG_OFFSET(ext_zbb),
+CPU_CFG_OFFSET(ext_zbs), CPU_CFG_OFFSET(ext_zfhmin),
+CPU_CFG_OFFSET(ext_zkt), CPU_CFG_OFFSET(ext_zicntr),
+CPU_CFG_OFFSET(ext_zihpm), CPU_CFG_OFFSET(ext_zicbom),
+CPU_CFG_OFFSET(ext_zicbop), CPU_CFG_OFFSET(ext_zicboz),
+
+/* mandatory named features for this profile */
+CPU_CFG_OFFSET(zic64b),
+
+RISCV_PROFILE_EXT_LIST_END
+}
+};
+
+RISCVCPUProfile *riscv_profiles[] = {
+&RVA22U64,
+NULL,
+};
+
 static Property riscv_cpu_properties[] = {
 DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true),
 
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5fb4ca2324..5ff629650d 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -76,6 +76,18 @@ const char *riscv_get_misa_ext_description(uint32_t bit);
 
 #define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop)
 
+typedef struct riscv_cpu_profile {
+const char *name;
+uint32_t misa_ext;
+bool enabled;
+bool user_set;
+const int32_t ext_offsets[];
+} RISCVCPUProfile;
+
+#define RISCV_PROFILE_EXT_LIST_END -1
+
+extern RISCVCPUProfile *riscv_profiles[];
+
 /* Privileged specification version */
 enum {
 PRIV_VERSION_1_10_0 = 0,
-- 
2.43.0




[PATCH v13 15/26] target/riscv/tcg: honor user choice for G MISA bits

2023-12-18 Thread Daniel Henrique Barboza
RVG behaves like a profile: a single flag enables a set of bits. Right
now we're considering user choice when handling RVG and zicsr/zifencei
and ignoring user choice on MISA bits.

We'll add user warnings for profiles when the user disables its
mandatory extensions in the next patch. We'll do the same thing with RVG
now to keep consistency between RVG and profile handling.

First and foremost, create a new RVG only helper to avoid clogging
riscv_cpu_validate_set_extensions(). We do not want to annoy users with
RVG warnings like we did in the past (see 9b9741c38f), thus we'll only
warn if RVG was user set and the user disabled a RVG extension in the
command line.

For every RVG MISA bit (IMAFD), zicsr and zifencei, the logic then
becomes:

- if enabled, do nothing;
- if disabled and not user set, enable it;
- if disabled and user set, throw a warning that it's a RVG mandatory
  extension.

This same logic will be used for profiles in the next patch.

Note that this is a behavior change, where we would error out if the
user disabled either zicsr or zifencei. As long as users are explicitly
disabling things in the command line we'll let them have a go at it, at
least in this step. We'll error out later in the validation if needed.

Other notable changes from the previous RVG code:

- use riscv_cpu_write_misa_bit() instead of manually updating both
  env->misa_ext and env->misa_ext_mask;

- set zicsr and zifencei directly. We're already checking if they
  were user set and priv version will never fail for these
  extensions, making cpu_cfg_ext_auto_update() redundant.

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
Reviewed-by: Alistair Francis 
---
 target/riscv/tcg/tcg-cpu.c | 73 +-
 1 file changed, 48 insertions(+), 25 deletions(-)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 01d2cc9f94..c9df783c51 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -42,6 +42,12 @@ static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
  GUINT_TO_POINTER(ext_offset));
 }
 
+static bool cpu_misa_ext_is_user_set(uint32_t misa_bit)
+{
+return g_hash_table_contains(misa_ext_user_opts,
+ GUINT_TO_POINTER(misa_bit));
+}
+
 static void cpu_cfg_ext_add_user_opt(uint32_t ext_offset, bool value)
 {
 g_hash_table_insert(multi_ext_user_opts, GUINT_TO_POINTER(ext_offset),
@@ -357,6 +363,46 @@ static void riscv_cpu_update_named_features(RISCVCPU *cpu)
   cpu->cfg.cboz_blocksize == 64;
 }
 
+static void riscv_cpu_validate_g(RISCVCPU *cpu)
+{
+const char *warn_msg = "RVG mandates disabled extension %s";
+uint32_t g_misa_bits[] = {RVI, RVM, RVA, RVF, RVD};
+bool send_warn = cpu_misa_ext_is_user_set(RVG);
+
+for (int i = 0; i < ARRAY_SIZE(g_misa_bits); i++) {
+uint32_t bit = g_misa_bits[i];
+
+if (riscv_has_ext(&cpu->env, bit)) {
+continue;
+}
+
+if (!cpu_misa_ext_is_user_set(bit)) {
+riscv_cpu_write_misa_bit(cpu, bit, true);
+continue;
+}
+
+if (send_warn) {
+warn_report(warn_msg, riscv_get_misa_ext_name(bit));
+}
+}
+
+if (!cpu->cfg.ext_zicsr) {
+if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zicsr))) {
+cpu->cfg.ext_zicsr = true;
+} else if (send_warn) {
+warn_report(warn_msg, "zicsr");
+}
+}
+
+if (!cpu->cfg.ext_zifencei) {
+if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zifencei))) {
+cpu->cfg.ext_zifencei = true;
+} else if (send_warn) {
+warn_report(warn_msg, "zifencei");
+}
+}
+}
+
 /*
  * Check consistency between chosen extensions while setting
  * cpu->cfg accordingly.
@@ -366,31 +412,8 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, 
Error **errp)
 CPURISCVState *env = &cpu->env;
 Error *local_err = NULL;
 
-/* Do some ISA extension error checking */
-if (riscv_has_ext(env, RVG) &&
-!(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) &&
-  riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) &&
-  riscv_has_ext(env, RVD) &&
-  cpu->cfg.ext_zicsr && cpu->cfg.ext_zifencei)) {
-
-if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zicsr)) &&
-!cpu->cfg.ext_zicsr) {
-error_setg(errp, "RVG requires Zicsr but user set Zicsr to false");
-return;
-}
-
-if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zifencei)) &&
-!cpu->cfg.ext_zifencei) {
-error_setg(errp, "RVG requires Zifencei but user set "
-   "Zifencei to false");
-return;
-}
-
-cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zicsr), true);
-cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zifencei), true);
-
-env->misa_ext |= RVI | RVM | RVA | RVF | RV

[PATCH v13 23/26] target/riscv: add satp_mode profile support

2023-12-18 Thread Daniel Henrique Barboza
'satp_mode' is a requirement for supervisor profiles like RVA22S64.
User-mode/application profiles like RVA22U64 doesn't care.

Add 'satp_mode' to the profile description. If a profile requires it,
set it during cpu_set_profile(). We'll also check it during finalize()
to validate if the running config implements the profile.

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu.c |  1 +
 target/riscv/cpu.h |  1 +
 target/riscv/tcg/tcg-cpu.c | 40 ++
 3 files changed, 42 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 1dea5db52d..6795f5da41 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1543,6 +1543,7 @@ static RISCVCPUProfile RVA22U64 = {
 .name = "rva22u64",
 .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU,
 .priv_spec = RISCV_PROFILE_ATTR_UNUSED,
+.satp_mode = RISCV_PROFILE_ATTR_UNUSED,
 .ext_offsets = {
 CPU_CFG_OFFSET(ext_zicsr), CPU_CFG_OFFSET(ext_zihintpause),
 CPU_CFG_OFFSET(ext_zba), CPU_CFG_OFFSET(ext_zbb),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 485d2da3c2..6c5fceb5f5 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -82,6 +82,7 @@ typedef struct riscv_cpu_profile {
 bool enabled;
 bool user_set;
 int priv_spec;
+int satp_mode;
 const int32_t ext_offsets[];
 } RISCVCPUProfile;
 
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 4d25fc43d2..152f95718b 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -766,6 +766,31 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, 
Error **errp)
 riscv_cpu_disable_priv_spec_isa_exts(cpu);
 }
 
+#ifndef CONFIG_USER_ONLY
+static bool riscv_cpu_validate_profile_satp(RISCVCPU *cpu,
+RISCVCPUProfile *profile,
+bool send_warn)
+{
+int satp_max = satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
+
+if (profile->satp_mode > satp_max) {
+if (send_warn) {
+bool is_32bit = riscv_cpu_is_32bit(cpu);
+const char *req_satp = satp_mode_str(profile->satp_mode, is_32bit);
+const char *cur_satp = satp_mode_str(satp_max, is_32bit);
+
+warn_report("Profile %s requires satp mode %s, "
+"but satp mode %s was set", profile->name,
+req_satp, cur_satp);
+}
+
+return false;
+}
+
+return true;
+}
+#endif
+
 static void riscv_cpu_validate_profile(RISCVCPU *cpu,
RISCVCPUProfile *profile)
 {
@@ -775,6 +800,13 @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu,
 bool profile_impl = true;
 int i;
 
+#ifndef CONFIG_USER_ONLY
+if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) {
+profile_impl = riscv_cpu_validate_profile_satp(cpu, profile,
+   send_warn);
+}
+#endif
+
 if (profile->priv_spec != RISCV_PROFILE_ATTR_UNUSED &&
 profile->priv_spec != env->priv_ver) {
 profile_impl = false;
@@ -1079,6 +,14 @@ static void cpu_set_profile(Object *obj, Visitor *v, 
const char *name,
 cpu->env.priv_ver = profile->priv_spec;
 }
 
+#ifndef CONFIG_USER_ONLY
+if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) {
+const char *satp_prop = satp_mode_str(profile->satp_mode,
+  riscv_cpu_is_32bit(cpu));
+object_property_set_bool(obj, satp_prop, profile->enabled, NULL);
+}
+#endif
+
 for (i = 0; misa_bits[i] != 0; i++) {
 uint32_t bit = misa_bits[i];
 
-- 
2.43.0




[PATCH v13 18/26] target/riscv: add 'rva22u64' CPU

2023-12-18 Thread Daniel Henrique Barboza
This CPU was suggested by Alistair [1] and others during the profile
design discussions. It consists of the bare 'rv64i' CPU with rva22u64
enabled by default, like an alias of '-cpu rv64i,rva22u64=true'.

Users now have an even easier way of consuming this user-mode profile by
doing '-cpu rva22u64'. Extensions can be enabled/disabled at will on top
of it.

We can boot Linux with this "user-mode" CPU by doing:

-cpu rva22u64,sv39=true,s=true,zifencei=true

[1] 
https://lore.kernel.org/qemu-riscv/CAKmqyKP7xzZ9Sx=-lbx2ob0qcfb7z+jo944fq2tq+49mqo0...@mail.gmail.com/

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu-qom.h |  1 +
 target/riscv/cpu.c | 17 +
 target/riscv/tcg/tcg-cpu.c |  9 +
 3 files changed, 27 insertions(+)

diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 4d1aa54311..12fe78fc52 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -35,6 +35,7 @@
 #define TYPE_RISCV_CPU_BASE64   RISCV_CPU_TYPE_NAME("rv64")
 #define TYPE_RISCV_CPU_BASE128  RISCV_CPU_TYPE_NAME("x-rv128")
 #define TYPE_RISCV_CPU_RV64IRISCV_CPU_TYPE_NAME("rv64i")
+#define TYPE_RISCV_CPU_RVA22U64 RISCV_CPU_TYPE_NAME("rva22u64")
 #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex")
 #define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c")
 #define TYPE_RISCV_CPU_SIFIVE_E31   RISCV_CPU_TYPE_NAME("sifive-e31")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index b9057c8da2..a38d78b2d6 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1576,6 +1576,15 @@ static Property riscv_cpu_properties[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+#if defined(TARGET_RISCV64)
+static void rva22u64_profile_cpu_init(Object *obj)
+{
+rv64i_bare_cpu_init(obj);
+
+RVA22U64.enabled = true;
+}
+#endif
+
 static const gchar *riscv_gdb_arch_name(CPUState *cs)
 {
 RISCVCPU *cpu = RISCV_CPU(cs);
@@ -1866,6 +1875,13 @@ void riscv_cpu_list(void)
 .instance_init = initfn\
 }
 
+#define DEFINE_PROFILE_CPU(type_name, initfn) \
+{ \
+.name = type_name,\
+.parent = TYPE_RISCV_BARE_CPU,\
+.instance_init = initfn   \
+}
+
 static const TypeInfo riscv_cpu_type_infos[] = {
 {
 .name = TYPE_RISCV_CPU,
@@ -1910,6 +1926,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
 DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1,   rv64_veyron_v1_cpu_init),
 DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128,  rv128_base_cpu_init),
 DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, rv64i_bare_cpu_init),
+DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, rva22u64_profile_cpu_init),
 #endif
 };
 
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 005d8be26b..04aedf3840 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -1095,6 +1095,15 @@ static void riscv_cpu_add_profiles(Object *cpu_obj)
 object_property_add(cpu_obj, profile->name, "bool",
 cpu_get_profile, cpu_set_profile,
 NULL, (void *)profile);
+
+/*
+ * CPUs might enable a profile right from the start.
+ * Enable its mandatory extensions right away in this
+ * case.
+ */
+if (profile->enabled) {
+object_property_set_bool(cpu_obj, profile->name, true, NULL);
+}
 }
 }
 
-- 
2.43.0




[PATCH v13 14/26] target/riscv/tcg: add hash table insert helpers

2023-12-18 Thread Daniel Henrique Barboza
Previous patches added several g_hash_table_insert() patterns. Add two
helpers, one for each user hash, to make the code cleaner.

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/tcg/tcg-cpu.c | 28 
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index f2e0ce0f3d..01d2cc9f94 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -42,6 +42,18 @@ static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
  GUINT_TO_POINTER(ext_offset));
 }
 
+static void cpu_cfg_ext_add_user_opt(uint32_t ext_offset, bool value)
+{
+g_hash_table_insert(multi_ext_user_opts, GUINT_TO_POINTER(ext_offset),
+(gpointer)value);
+}
+
+static void cpu_misa_ext_add_user_opt(uint32_t bit, bool value)
+{
+g_hash_table_insert(misa_ext_user_opts, GUINT_TO_POINTER(bit),
+(gpointer)value);
+}
+
 static void riscv_cpu_write_misa_bit(RISCVCPU *cpu, uint32_t bit,
  bool enabled)
 {
@@ -817,9 +829,7 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, 
const char *name,
 return;
 }
 
-g_hash_table_insert(misa_ext_user_opts,
-GUINT_TO_POINTER(misa_bit),
-(gpointer)value);
+cpu_misa_ext_add_user_opt(misa_bit, value);
 
 prev_val = env->misa_ext & misa_bit;
 
@@ -956,9 +966,7 @@ static void cpu_set_profile(Object *obj, Visitor *v, const 
char *name,
 continue;
 }
 
-g_hash_table_insert(misa_ext_user_opts,
-GUINT_TO_POINTER(bit),
-(gpointer)value);
+cpu_misa_ext_add_user_opt(bit, profile->enabled);
 riscv_cpu_write_misa_bit(cpu, bit, profile->enabled);
 }
 
@@ -973,9 +981,7 @@ static void cpu_set_profile(Object *obj, Visitor *v, const 
char *name,
 cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset);
 }
 
-g_hash_table_insert(multi_ext_user_opts,
-GUINT_TO_POINTER(ext_offset),
-(gpointer)profile->enabled);
+cpu_cfg_ext_add_user_opt(ext_offset, profile->enabled);
 isa_ext_update_enabled(cpu, ext_offset, profile->enabled);
 }
 }
@@ -1038,9 +1044,7 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor 
*v, const char *name,
 multi_ext_cfg->name, lower);
 }
 
-g_hash_table_insert(multi_ext_user_opts,
-GUINT_TO_POINTER(multi_ext_cfg->offset),
-(gpointer)value);
+cpu_cfg_ext_add_user_opt(multi_ext_cfg->offset, value);
 
 prev_val = isa_ext_is_enabled(cpu, multi_ext_cfg->offset);
 
-- 
2.43.0




[PATCH v13 25/26] target/riscv: add RVA22S64 profile

2023-12-18 Thread Daniel Henrique Barboza
The RVA22S64 profile consists of the following:

- all mandatory extensions of RVA22U64;
- priv spec v1.12.0;
- satp mode sv39;
- Ssccptr, a cache related named feature that we're assuming always
  enable since we don't implement a cache;
- Other named features already implemented: Sstvecd, Sstvala,
  Sscounterenw;
- the new Svade named feature that was recently added.

Most of the work is already done, so this patch is enough to implement
the profile.

After this patch, the 'rva22s64' user flag alone can be used with the
rva64i CPU to boot Linux:

-cpu rv64i,rva22s64=true

This is the /proc/cpuinfo with this profile enabled:

 # cat /proc/cpuinfo
processor   : 0
hart: 0
isa : 
rv64imafdc_zicbom_zicbop_zicboz_zicntr_zicsr_zifencei_zihintpause_zihpm_zfhmin_zca_zcd_zba_zbb_zbs_zkt_svinval_svpbmt
mmu : sv39

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index aa33e7a1cf..f57a9ee298 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1560,8 +1560,40 @@ static RISCVCPUProfile RVA22U64 = {
 }
 };
 
+/*
+ * As with RVA22U64, RVA22S64 also defines 'named features'.
+ *
+ * Cache related features that we consider enabled since we don't
+ * implement cache: Ssccptr
+ *
+ * Other named features that we already implement: Sstvecd, Sstvala,
+ * Sscounterenw
+ *
+ * Named features that we need to enable: svade
+ *
+ * The remaining features/extensions comes from RVA22U64.
+ */
+static RISCVCPUProfile RVA22S64 = {
+.parent = &RVA22U64,
+.name = "rva22s64",
+.misa_ext = RVS,
+.priv_spec = PRIV_VERSION_1_12_0,
+.satp_mode = VM_1_10_SV39,
+.ext_offsets = {
+/* rva22s64 exts */
+CPU_CFG_OFFSET(ext_zifencei), CPU_CFG_OFFSET(ext_svpbmt),
+CPU_CFG_OFFSET(ext_svinval),
+
+/* rva22s64 named features */
+CPU_CFG_OFFSET(svade),
+
+RISCV_PROFILE_EXT_LIST_END
+}
+};
+
 RISCVCPUProfile *riscv_profiles[] = {
 &RVA22U64,
+&RVA22S64,
 NULL,
 };
 
-- 
2.43.0




[PATCH v13 10/26] target/riscv/tcg: add user flag for profile support

2023-12-18 Thread Daniel Henrique Barboza
The TCG emulation implements all the extensions described in the
RVA22U64 profile, both mandatory and optional. The mandatory extensions
will be enabled via the profile flag. We'll leave the optional
extensions to be enabled by hand.

Given that this is the first profile we're implementing in TCG we'll
need some ground work first:

- all profiles declared in riscv_profiles[] will be exposed to users.
TCG is the main accelerator we're considering when adding profile
support in QEMU, so for now it's safe to assume that all profiles in
riscv_profiles[] will be relevant to TCG;

- we'll not support user profile settings for vendor CPUs. The flags
will still be exposed but users won't be able to change them;

- profile support, albeit available for all non-vendor CPUs, will be
based on top of the new 'rv64i' CPU. Setting a profile to 'true' means
enable all mandatory extensions of this profile, setting it to 'false'
will disable all mandatory profile extensions of the CPU, which will
obliterate preset defaults. This is not a problem for a bare CPU like
rv64i but it can allow for silly scenarios when using other CPUs. E.g.
an user can do "-cpu rv64,rva22u64=false" and have a bunch of default
rv64 extensions disabled. The recommended way of using profiles is the
rv64i CPU, but users are free to experiment.

For now we'll handle multi-letter extensions only. MISA extensions need
additional steps that we'll take care later. At this point we can boot a
Linux buildroot using rva22u64 using the following options:

-cpu rv64i,rva22u64=true,sv39=true,g=true,c=true,s=true

Note that being an usermode/application profile we still need to
explicitly set 's=true' to enable Supervisor mode to boot Linux.

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/tcg/tcg-cpu.c | 80 ++
 1 file changed, 80 insertions(+)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 3319ba8e4e..83d4dd00cf 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -127,6 +127,19 @@ static bool cpu_cfg_offset_is_named_feat(uint32_t 
ext_offset)
 return false;
 }
 
+static void riscv_cpu_enable_named_feat(RISCVCPU *cpu, uint32_t feat_offset)
+{
+switch (feat_offset) {
+case CPU_CFG_OFFSET(zic64b):
+cpu->cfg.cbom_blocksize = 64;
+cpu->cfg.cbop_blocksize = 64;
+cpu->cfg.cboz_blocksize = 64;
+break;
+default:
+g_assert_not_reached();
+}
+}
+
 static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env,
 uint32_t ext_offset)
 {
@@ -885,6 +898,71 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj)
 }
 }
 
+static void cpu_set_profile(Object *obj, Visitor *v, const char *name,
+void *opaque, Error **errp)
+{
+RISCVCPUProfile *profile = opaque;
+RISCVCPU *cpu = RISCV_CPU(obj);
+bool value;
+int i, ext_offset;
+
+if (riscv_cpu_is_vendor(obj)) {
+error_setg(errp, "Profile %s is not available for vendor CPUs",
+   profile->name);
+return;
+}
+
+if (cpu->env.misa_mxl != MXL_RV64) {
+error_setg(errp, "Profile %s only available for 64 bit CPUs",
+   profile->name);
+return;
+}
+
+if (!visit_type_bool(v, name, &value, errp)) {
+return;
+}
+
+profile->user_set = true;
+profile->enabled = value;
+
+for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) {
+ext_offset = profile->ext_offsets[i];
+
+if (profile->enabled) {
+if (cpu_cfg_offset_is_named_feat(ext_offset)) {
+riscv_cpu_enable_named_feat(cpu, ext_offset);
+}
+
+cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset);
+}
+
+g_hash_table_insert(multi_ext_user_opts,
+GUINT_TO_POINTER(ext_offset),
+(gpointer)profile->enabled);
+isa_ext_update_enabled(cpu, ext_offset, profile->enabled);
+}
+}
+
+static void cpu_get_profile(Object *obj, Visitor *v, const char *name,
+void *opaque, Error **errp)
+{
+RISCVCPUProfile *profile = opaque;
+bool value = profile->enabled;
+
+visit_type_bool(v, name, &value, errp);
+}
+
+static void riscv_cpu_add_profiles(Object *cpu_obj)
+{
+for (int i = 0; riscv_profiles[i] != NULL; i++) {
+const RISCVCPUProfile *profile = riscv_profiles[i];
+
+object_property_add(cpu_obj, profile->name, "bool",
+cpu_get_profile, cpu_set_profile,
+NULL, (void *)profile);
+}
+}
+
 static bool cpu_ext_is_deprecated(const char *ext_name)
 {
 return isupper(ext_name[0]);
@@ -1012,6 +1090,8 @@ static void riscv_cpu_add_user_properties(Object *obj)
 
 riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_deprecated_exts);
 
+riscv_cpu_add_profiles(obj);
+

[PATCH v13 16/26] target/riscv/tcg: validate profiles during finalize

2023-12-18 Thread Daniel Henrique Barboza
Enabling a profile and then disabling some of its mandatory extensions
is a valid use. It can be useful for debugging and testing. But the
common expected use of enabling a profile is to enable all its mandatory
extensions.

Add an user warning when mandatory extensions from an enabled profile
are disabled in the command line. We're also going to disable the
profile flag in this case since the profile must include all the
mandatory extensions. This flag can be exposed by QMP to indicate the
actual profile state after the CPU is realized.

After this patch, this will throw warnings:

-cpu rv64,rva22u64=true,zihintpause=false,zicbom=false,zicboz=false

qemu-system-riscv64: warning: Profile rva22u64 mandates disabled extension 
zihintpause
qemu-system-riscv64: warning: Profile rva22u64 mandates disabled extension 
zicbom
qemu-system-riscv64: warning: Profile rva22u64 mandates disabled extension 
zicboz

Note that the following will NOT throw warnings because the profile is
being enabled last, hence all its mandatory extensions will be enabled:

-cpu rv64,zihintpause=false,zicbom=false,zicboz=false,rva22u64=true

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/tcg/tcg-cpu.c | 69 ++
 1 file changed, 69 insertions(+)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index c9df783c51..005d8be26b 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -147,6 +147,26 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
 g_assert_not_reached();
 }
 
+static const char *cpu_cfg_ext_get_name(uint32_t ext_offset)
+{
+const RISCVCPUMultiExtConfig *feat;
+const RISCVIsaExtData *edata;
+
+for (edata = isa_edata_arr; edata->name != NULL; edata++) {
+if (edata->ext_enable_offset == ext_offset) {
+return edata->name;
+}
+}
+
+for (feat = riscv_cpu_named_features; feat->name != NULL; feat++) {
+if (feat->offset == ext_offset) {
+return feat->name;
+}
+}
+
+g_assert_not_reached();
+}
+
 static bool cpu_cfg_offset_is_named_feat(uint32_t ext_offset)
 {
 const RISCVCPUMultiExtConfig *feat;
@@ -727,6 +747,54 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, 
Error **errp)
 riscv_cpu_disable_priv_spec_isa_exts(cpu);
 }
 
+static void riscv_cpu_validate_profile(RISCVCPU *cpu,
+   RISCVCPUProfile *profile)
+{
+const char *warn_msg = "Profile %s mandates disabled extension %s";
+bool send_warn = profile->user_set && profile->enabled;
+bool profile_impl = true;
+int i;
+
+for (i = 0; misa_bits[i] != 0; i++) {
+uint32_t bit = misa_bits[i];
+
+if (!(profile->misa_ext & bit)) {
+continue;
+}
+
+if (!riscv_has_ext(&cpu->env, bit)) {
+profile_impl = false;
+
+if (send_warn) {
+warn_report(warn_msg, profile->name,
+riscv_get_misa_ext_name(bit));
+}
+}
+}
+
+for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) {
+int ext_offset = profile->ext_offsets[i];
+
+if (!isa_ext_is_enabled(cpu, ext_offset)) {
+profile_impl = false;
+
+if (send_warn) {
+warn_report(warn_msg, profile->name,
+cpu_cfg_ext_get_name(ext_offset));
+}
+}
+}
+
+profile->enabled = profile_impl;
+}
+
+static void riscv_cpu_validate_profiles(RISCVCPU *cpu)
+{
+for (int i = 0; riscv_profiles[i] != NULL; i++) {
+riscv_cpu_validate_profile(cpu, riscv_profiles[i]);
+}
+}
+
 void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
 {
 CPURISCVState *env = &cpu->env;
@@ -745,6 +813,7 @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error 
**errp)
 }
 
 riscv_cpu_update_named_features(cpu);
+riscv_cpu_validate_profiles(cpu);
 
 if (cpu->cfg.ext_smepmp && !cpu->cfg.pmp) {
 /*
-- 
2.43.0




[PATCH v13 07/26] riscv-qmp-cmds.c: expose named features in cpu_model_expansion

2023-12-18 Thread Daniel Henrique Barboza
Named features (zic64b the sole example at this moment) aren't expose to
users, thus we need another way to expose them.

Go through each named feature, get its boolean value, do the needed
conversions (bool to qbool, qbool to QObject) and add it to output dict.

Another adjustment is needed: named features are evaluated during
finalize(), so riscv_cpu_finalize_features() needs to be mandatory
regardless of whether we have an input dict or not. Otherwise zic64b
will always return 'false', which is incorrect: the default values of
cache blocksizes ([cbom/cbop/cboz]_blocksize) are set to 64, satisfying
the conditions for zic64b.

Here's an API usage example after this patch:

 $ ./build/qemu-system-riscv64 -S -M virt -display none
-qmp tcp:localhost:1234,server,wait=off

 $ ./scripts/qmp/qmp-shell localhost:1234
Welcome to the QMP low-level shell!
Connected to QEMU 8.1.50

(QEMU) query-cpu-model-expansion type=full model={"name":"rv64"}
{"return": {"model":
{"name": "rv64", "props": {... "zic64b": true, ...

zic64b is set to 'true', as expected, since all cache sizes are 64
bytes by default.

If we change one of the cache blocksizes, zic64b is returned as 'false':

(QEMU) query-cpu-model-expansion type=full 
model={"name":"rv64","props":{"cbom_blocksize":128}}
{"return": {"model":
{"name": "rv64", "props": {... "zic64b": false, ...

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/riscv-qmp-cmds.c | 30 +-
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c
index 2f2dbae7c8..5ada279776 100644
--- a/target/riscv/riscv-qmp-cmds.c
+++ b/target/riscv/riscv-qmp-cmds.c
@@ -26,6 +26,7 @@
 
 #include "qapi/error.h"
 #include "qapi/qapi-commands-machine-target.h"
+#include "qapi/qmp/qbool.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qerror.h"
 #include "qapi/qobject-input-visitor.h"
@@ -99,6 +100,22 @@ static void riscv_obj_add_multiext_props(Object *obj, QDict 
*qdict_out,
 }
 }
 
+static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out)
+{
+const RISCVCPUMultiExtConfig *named_cfg;
+RISCVCPU *cpu = RISCV_CPU(obj);
+QObject *value;
+bool flag_val;
+
+for (int i = 0; riscv_cpu_named_features[i].name != NULL; i++) {
+named_cfg = &riscv_cpu_named_features[i];
+flag_val = isa_ext_is_enabled(cpu, named_cfg->offset);
+value = QOBJECT(qbool_from_bool(flag_val));
+
+qdict_put_obj(qdict_out, named_cfg->name, value);
+}
+}
+
 static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
const QDict *qdict_in,
Error **errp)
@@ -129,11 +146,6 @@ static void riscv_cpuobj_validate_qdict_in(Object *obj, 
QObject *props,
 goto err;
 }
 
-riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
-if (local_err) {
-goto err;
-}
-
 visit_end_struct(visitor, NULL);
 
 err:
@@ -191,6 +203,13 @@ CpuModelExpansionInfo 
*qmp_query_cpu_model_expansion(CpuModelExpansionType type,
 }
 }
 
+riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
+if (local_err) {
+error_propagate(errp, local_err);
+object_unref(obj);
+return NULL;
+}
+
 expansion_info = g_new0(CpuModelExpansionInfo, 1);
 expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
 expansion_info->model->name = g_strdup(model->name);
@@ -200,6 +219,7 @@ CpuModelExpansionInfo 
*qmp_query_cpu_model_expansion(CpuModelExpansionType type,
 riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
 riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
 riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
+riscv_obj_add_named_feats_qdict(obj, qdict_out);
 
 /* Add our CPU boolean options too */
 riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
-- 
2.43.0




[PATCH v13 19/26] target/riscv: implement svade

2023-12-18 Thread Daniel Henrique Barboza
'svade' is a RVA22S64 profile requirement, a profile we're going to add
shortly. It is a named feature (i.e. not a formal extension, not defined
in riscv,isa DT at this moment) defined in [1] as:

"Page-fault exceptions are raised when a page is accessed when A bit is
clear, or written when D bit is clear.".

As far as the spec goes, 'svade' is one of the two distinct modes of
handling PTE_A and PTE_D. The other way, i.e. update PTE_A/PTE_D when
they're cleared, is defined by the 'svadu' extension. Checking
cpu_helper.c, get_physical_address(), we can verify that QEMU is
compliant with that: we will update PTE_A/PTE_D if 'svadu' is enabled,
or throw a page-fault exception if 'svadu' isn't enabled.

So, as far as we're concerned, 'svade' translates to 'svadu must be
disabled'.

We'll implement it like 'zic64b': an internal flag that profiles can
enable. The flag will not be exposed to users.

[1] https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu.c | 1 +
 target/riscv/cpu_cfg.h | 1 +
 target/riscv/tcg/tcg-cpu.c | 5 +
 3 files changed, 7 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a38d78b2d6..a76bc1b86a 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1445,6 +1445,7 @@ const RISCVCPUMultiExtConfig 
riscv_cpu_experimental_exts[] = {
 };
 
 const RISCVCPUMultiExtConfig riscv_cpu_named_features[] = {
+MULTI_EXT_CFG_BOOL("svade", svade, true),
 MULTI_EXT_CFG_BOOL("zic64b", zic64b, true),
 
 DEFINE_PROP_END_OF_LIST(),
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index 90f18eb601..46b06db68b 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -116,6 +116,7 @@ struct RISCVCPUConfig {
 bool ext_smepmp;
 bool rvv_ta_all_1s;
 bool rvv_ma_all_1s;
+bool svade;
 bool zic64b;
 
 uint32_t mvendorid;
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 04aedf3840..e395e2449e 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -188,6 +188,9 @@ static void riscv_cpu_enable_named_feat(RISCVCPU *cpu, 
uint32_t feat_offset)
 cpu->cfg.cbop_blocksize = 64;
 cpu->cfg.cboz_blocksize = 64;
 break;
+case CPU_CFG_OFFSET(svade):
+cpu->cfg.ext_svadu = false;
+break;
 default:
 g_assert_not_reached();
 }
@@ -381,6 +384,8 @@ static void riscv_cpu_update_named_features(RISCVCPU *cpu)
 cpu->cfg.zic64b = cpu->cfg.cbom_blocksize == 64 &&
   cpu->cfg.cbop_blocksize == 64 &&
   cpu->cfg.cboz_blocksize == 64;
+
+cpu->cfg.svade = !cpu->cfg.ext_svadu;
 }
 
 static void riscv_cpu_validate_g(RISCVCPU *cpu)
-- 
2.43.0




[PATCH v13 24/26] target/riscv: add 'parent' in profile description

2023-12-18 Thread Daniel Henrique Barboza
Certain S-mode profiles, like RVA22S64 and RVA23S64, mandate all the
mandatory extensions of their respective U-mode profiles. RVA22S64
includes all mandatory extensions of RVA22U64, and the same happens with
RVA23 profiles.

Add a 'parent' field to allow profiles to enable other profiles. This
will allow us to describe S-mode profiles by specifying their parent
U-mode profile, then adding just the S-mode specific extensions.

We're naming the field 'parent' to consider the possibility of other
uses (e.g. a s-mode profile including a previous s-mode profile) in the
future.

Suggested-by: Andrew Jones 
Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Andrew Jones 
---
 target/riscv/cpu.c |  1 +
 target/riscv/cpu.h |  1 +
 target/riscv/tcg/tcg-cpu.c | 14 +-
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6795f5da41..aa33e7a1cf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1540,6 +1540,7 @@ Property riscv_cpu_options[] = {
  * having a cfg offset) at this moment.
  */
 static RISCVCPUProfile RVA22U64 = {
+.parent = NULL,
 .name = "rva22u64",
 .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU,
 .priv_spec = RISCV_PROFILE_ATTR_UNUSED,
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6c5fceb5f5..44fb0a9ca8 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -77,6 +77,7 @@ const char *riscv_get_misa_ext_description(uint32_t bit);
 #define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop)
 
 typedef struct riscv_cpu_profile {
+struct riscv_cpu_profile *parent;
 const char *name;
 uint32_t misa_ext;
 bool enabled;
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 152f95718b..6284d36809 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -797,7 +797,7 @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu,
 CPURISCVState *env = &cpu->env;
 const char *warn_msg = "Profile %s mandates disabled extension %s";
 bool send_warn = profile->user_set && profile->enabled;
-bool profile_impl = true;
+bool parent_enabled, profile_impl = true;
 int i;
 
 #ifndef CONFIG_USER_ONLY
@@ -850,6 +850,13 @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu,
 }
 
 profile->enabled = profile_impl;
+
+if (profile->parent != NULL) {
+parent_enabled = object_property_get_bool(OBJECT(cpu),
+  profile->parent->name,
+  NULL);
+profile->enabled = profile->enabled && parent_enabled;
+}
 }
 
 static void riscv_cpu_validate_profiles(RISCVCPU *cpu)
@@ -1107,6 +1114,11 @@ static void cpu_set_profile(Object *obj, Visitor *v, 
const char *name,
 profile->user_set = true;
 profile->enabled = value;
 
+if (profile->parent != NULL) {
+object_property_set_bool(obj, profile->parent->name,
+ profile->enabled, NULL);
+}
+
 if (profile->enabled) {
 cpu->env.priv_ver = profile->priv_spec;
 }
-- 
2.43.0




  1   2   3   >