Re: [PATCH v2] target/i386: Add kvm_get_one_msr helper

2022-02-11 Thread Yang, Weijiang

Ping...

Does this v2 meet the requirement?

On 1/30/2022 7:07 AM, Yang Weijiang wrote:

When try to get one msr from KVM, I found there's no such kind of
existing interface while kvm_put_one_msr() is there. So here comes
the patch. It'll remove redundant preparation code before finally
call KVM_GET_MSRS IOCTL.

No functional change intended.

v2:
  Per Paolo's suggestion, move the helper before uses to eliminate
  a forward declaration.

base-commit: 48302d4eb628ff0bea4d7e92cbf6b726410eb4c3

Signed-off-by: Yang Weijiang 
---
  target/i386/kvm/kvm.c | 48 ---
  1 file changed, 27 insertions(+), 21 deletions(-)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 2c8feb4a6f..627535395a 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -201,32 +201,45 @@ bool kvm_hv_vpindex_settable(void)
  return hv_vpindex_settable;
  }
  
-static int kvm_get_tsc(CPUState *cs)

+static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value)
  {
-X86CPU *cpu = X86_CPU(cs);
-CPUX86State *env = >env;
+int ret;
  struct {
  struct kvm_msrs info;
  struct kvm_msr_entry entries[1];
-} msr_data = {};
+} msr_data = {
+.info.nmsrs = 1,
+.entries[0].index = index,
+};
+
+ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, _data);
+if (ret < 0) {
+return ret;
+}
+assert(ret == 1);
+*value = msr_data.entries[0].data;
+return ret;
+}
+
+static int kvm_get_tsc(CPUState *cs)
+{
+X86CPU *cpu = X86_CPU(cs);
+CPUX86State *env = >env;
+uint64_t value;
  int ret;
  
  if (env->tsc_valid) {

  return 0;
  }
  
-memset(_data, 0, sizeof(msr_data));

-msr_data.info.nmsrs = 1;
-msr_data.entries[0].index = MSR_IA32_TSC;
  env->tsc_valid = !runstate_is_running();
  
-ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, _data);

+ret = kvm_get_one_msr(cpu, MSR_IA32_TSC, );
  if (ret < 0) {
  return ret;
  }
  
-assert(ret == 1);

-env->tsc = msr_data.entries[0].data;
+env->tsc = value;
  return 0;
  }
  
@@ -1478,21 +1491,14 @@ static int hyperv_init_vcpu(X86CPU *cpu)

   * the kernel doesn't support setting vp_index; assert that its value
   * is in sync
   */
-struct {
-struct kvm_msrs info;
-struct kvm_msr_entry entries[1];
-} msr_data = {
-.info.nmsrs = 1,
-.entries[0].index = HV_X64_MSR_VP_INDEX,
-};
-
-ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, _data);
+uint64_t value;
+
+ret = kvm_get_one_msr(cpu, HV_X64_MSR_VP_INDEX, );
  if (ret < 0) {
  return ret;
  }
-assert(ret == 1);
  
-if (msr_data.entries[0].data != hyperv_vp_index(CPU(cpu))) {

+if (value != hyperv_vp_index(CPU(cpu))) {
  error_report("kernel's vp_index != QEMU's vp_index");
  return -ENXIO;
  }




[PULL 40/40] docs/system: riscv: Update description of CPU

2022-02-11 Thread Alistair Francis
From: Yu Li 

Since the hypervisor extension been non experimental and enabled for
default CPU, the previous command is no longer available and the
option `x-h=true` or `h=true` is also no longer required.

Signed-off-by: Yu Li 
Reviewed-by: Alistair Francis 
Message-Id: <9040401e-8f87-ef4a-d840-6703f08d0...@bytedance.com>
Signed-off-by: Alistair Francis 
---
 docs/system/riscv/virt.rst | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst
index 373645513a..1272b6659e 100644
--- a/docs/system/riscv/virt.rst
+++ b/docs/system/riscv/virt.rst
@@ -23,9 +23,9 @@ The ``virt`` machine supports the following devices:
 * 1 generic PCIe host bridge
 * The fw_cfg device that allows a guest to obtain data from QEMU
 
-Note that the default CPU is a generic RV32GC/RV64GC. Optional extensions
-can be enabled via command line parameters, e.g.: ``-cpu rv64,x-h=true``
-enables the hypervisor extension for RV64.
+The hypervisor extension has been enabled for the default CPU, so virtual
+machines with hypervisor extension can simply be used without explicitly
+declaring.
 
 Hardware configuration information
 --
-- 
2.34.1




[PULL 39/40] target/riscv: add support for svpbmt extension

2022-02-11 Thread Alistair Francis
From: Weiwei Li 

- add PTE_PBMT bits: It uses two PTE bits, but otherwise has no effect on QEMU, 
since QEMU is sequentially consistent and doesn't model PMAs currently
- add PTE_PBMT bit check for inner PTE

Signed-off-by: Weiwei Li 
Signed-off-by: Junqiang Wang 
Reviewed-by: Anup Patel 
Reviewed-by: Alistair Francis 
Message-Id: <20220204022658.18097-6-liwei...@iscas.ac.cn>
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu_bits.h   | 2 ++
 target/riscv/cpu.c| 1 +
 target/riscv/cpu_helper.c | 4 +++-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 37ed4da72c..0fe01d7da5 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -561,7 +561,9 @@ typedef enum {
 #define PTE_A   0x040 /* Accessed */
 #define PTE_D   0x080 /* Dirty */
 #define PTE_SOFT0x300 /* Reserved for Software */
+#define PTE_PBMT0x6000ULL /* Page-based memory types */
 #define PTE_N   0x8000ULL /* NAPOT translation */
+#define PTE_ATTR(PTE_N | PTE_PBMT) /* All attributes bits */
 
 /* Page table PPN shift amount */
 #define PTE_PPN_SHIFT   10
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e5676b40d1..b0a40b83e7 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -776,6 +776,7 @@ static Property riscv_cpu_properties[] = {
 
 DEFINE_PROP_BOOL("svinval", RISCVCPU, cfg.ext_svinval, false),
 DEFINE_PROP_BOOL("svnapot", RISCVCPU, cfg.ext_svnapot, false),
+DEFINE_PROP_BOOL("svpbmt", RISCVCPU, cfg.ext_svpbmt, false),
 
 DEFINE_PROP_BOOL("zba", RISCVCPU, cfg.ext_zba, true),
 DEFINE_PROP_BOOL("zbb", RISCVCPU, cfg.ext_zbb, true),
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 437c9488a6..746335bfd6 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -937,9 +937,11 @@ restart:
 if (!(pte & PTE_V)) {
 /* Invalid PTE */
 return TRANSLATE_FAIL;
+} else if (!cpu->cfg.ext_svpbmt && (pte & PTE_PBMT)) {
+return TRANSLATE_FAIL;
 } else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
 /* Inner PTE, continue walking */
-if (pte & (PTE_D | PTE_A | PTE_U | PTE_N)) {
+if (pte & (PTE_D | PTE_A | PTE_U | PTE_ATTR)) {
 return TRANSLATE_FAIL;
 }
 base = ppn << PGSHIFT;
-- 
2.34.1




[PULL 32/40] hw/riscv: virt: Add optional AIA IMSIC support to virt machine

2022-02-11 Thread Alistair Francis
From: Anup Patel 

We extend virt machine to emulate both AIA IMSIC and AIA APLIC
devices only when "aia=aplic-imsic" parameter is passed along
with machine name in the QEMU command-line. The AIA IMSIC is
only a per-HART MSI controller so we use AIA APLIC in MSI-mode
to forward all wired interrupts as MSIs to the AIA IMSIC.

We also provide "aia-guests=" parameter which can be used
to specify number of VS-level AIA IMSIC Guests MMIO pages for
each HART.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Acked-by: Alistair Francis 
Message-id: 20220204174700.534953-22-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 include/hw/riscv/virt.h |  17 +-
 hw/riscv/virt.c | 440 
 hw/riscv/Kconfig|   1 +
 3 files changed, 374 insertions(+), 84 deletions(-)

diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 47706b456d..d248d0dfa0 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -24,8 +24,10 @@
 #include "hw/block/flash.h"
 #include "qom/object.h"
 
-#define VIRT_CPUS_MAX 32
-#define VIRT_SOCKETS_MAX 8
+#define VIRT_CPUS_MAX_BITS 3
+#define VIRT_CPUS_MAX  (1 << VIRT_CPUS_MAX_BITS)
+#define VIRT_SOCKETS_MAX_BITS  2
+#define VIRT_SOCKETS_MAX   (1 << VIRT_SOCKETS_MAX_BITS)
 
 #define TYPE_RISCV_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
 typedef struct RISCVVirtState RISCVVirtState;
@@ -35,6 +37,7 @@ DECLARE_INSTANCE_CHECKER(RISCVVirtState, RISCV_VIRT_MACHINE,
 typedef enum RISCVVirtAIAType {
 VIRT_AIA_TYPE_NONE = 0,
 VIRT_AIA_TYPE_APLIC,
+VIRT_AIA_TYPE_APLIC_IMSIC,
 } RISCVVirtAIAType;
 
 struct RISCVVirtState {
@@ -50,6 +53,7 @@ struct RISCVVirtState {
 int fdt_size;
 bool have_aclint;
 RISCVVirtAIAType aia_type;
+int aia_guests;
 };
 
 enum {
@@ -65,6 +69,8 @@ enum {
 VIRT_UART0,
 VIRT_VIRTIO,
 VIRT_FW_CFG,
+VIRT_IMSIC_M,
+VIRT_IMSIC_S,
 VIRT_FLASH,
 VIRT_DRAM,
 VIRT_PCIE_MMIO,
@@ -81,8 +87,12 @@ enum {
 VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
 };
 
-#define VIRT_IRQCHIP_NUM_SOURCES 127
+#define VIRT_IRQCHIP_IPI_MSI 1
+#define VIRT_IRQCHIP_NUM_MSIS 255
+#define VIRT_IRQCHIP_NUM_SOURCES VIRTIO_NDEV
 #define VIRT_IRQCHIP_NUM_PRIO_BITS 3
+#define VIRT_IRQCHIP_MAX_GUESTS_BITS 3
+#define VIRT_IRQCHIP_MAX_GUESTS ((1U << VIRT_IRQCHIP_MAX_GUESTS_BITS) - 1U)
 
 #define VIRT_PLIC_PRIORITY_BASE 0x04
 #define VIRT_PLIC_PENDING_BASE 0x1000
@@ -97,6 +107,7 @@ enum {
 #define FDT_PCI_INT_CELLS 1
 #define FDT_PLIC_INT_CELLS1
 #define FDT_APLIC_INT_CELLS   2
+#define FDT_IMSIC_INT_CELLS   0
 #define FDT_MAX_INT_CELLS 2
 #define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
  1 + FDT_MAX_INT_CELLS)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 6b06f79b46..c02710f711 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -34,6 +34,7 @@
 #include "hw/riscv/numa.h"
 #include "hw/intc/riscv_aclint.h"
 #include "hw/intc/riscv_aplic.h"
+#include "hw/intc/riscv_imsic.h"
 #include "hw/intc/sifive_plic.h"
 #include "hw/misc/sifive_test.h"
 #include "chardev/char.h"
@@ -44,6 +45,18 @@
 #include "hw/pci-host/gpex.h"
 #include "hw/display/ramfb.h"
 
+#define VIRT_IMSIC_GROUP_MAX_SIZE  (1U << IMSIC_MMIO_GROUP_MIN_SHIFT)
+#if VIRT_IMSIC_GROUP_MAX_SIZE < \
+IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS)
+#error "Can't accomodate single IMSIC group in address space"
+#endif
+
+#define VIRT_IMSIC_MAX_SIZE(VIRT_SOCKETS_MAX * \
+VIRT_IMSIC_GROUP_MAX_SIZE)
+#if 0x400 < VIRT_IMSIC_MAX_SIZE
+#error "Can't accomodate all IMSIC groups in address space"
+#endif
+
 static const MemMapEntry virt_memmap[] = {
 [VIRT_DEBUG] =   {0x0, 0x100 },
 [VIRT_MROM] ={ 0x1000,0xf000 },
@@ -59,6 +72,8 @@ static const MemMapEntry virt_memmap[] = {
 [VIRT_VIRTIO] =  { 0x10001000,0x1000 },
 [VIRT_FW_CFG] =  { 0x1010,  0x18 },
 [VIRT_FLASH] =   { 0x2000, 0x400 },
+[VIRT_IMSIC_M] = { 0x2400, VIRT_IMSIC_MAX_SIZE },
+[VIRT_IMSIC_S] = { 0x2800, VIRT_IMSIC_MAX_SIZE },
 [VIRT_PCIE_ECAM] =   { 0x3000,0x1000 },
 [VIRT_PCIE_MMIO] =   { 0x4000,0x4000 },
 [VIRT_DRAM] ={ 0x8000,   0x0 },
@@ -310,7 +325,7 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
 {
 int cpu;
 char *name;
-unsigned long addr;
+unsigned long addr, size;
 uint32_t aclint_cells_size;
 uint32_t *aclint_mswi_cells;
 uint32_t *aclint_sswi_cells;
@@ -331,29 +346,38 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
 }
 aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2;
 
-addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
-name = 

[PULL 36/40] target/riscv: add PTE_A/PTE_D/PTE_U bits check for inner PTE

2022-02-11 Thread Alistair Francis
From: Weiwei Li 

For non-leaf PTEs, the D, A, and U bits are reserved for future standard use.

Signed-off-by: Weiwei Li 
Signed-off-by: Junqiang Wang 
Reviewed-by: Anup Patel 
Reviewed-by: Alistair Francis 
Message-Id: <20220204022658.18097-3-liwei...@iscas.ac.cn>
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu_helper.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 7df4569526..25ebc76725 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -937,6 +937,9 @@ restart:
 return TRANSLATE_FAIL;
 } else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
 /* Inner PTE, continue walking */
+if (pte & (PTE_D | PTE_A | PTE_U)) {
+return TRANSLATE_FAIL;
+}
 base = ppn << PGSHIFT;
 } else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) {
 /* Reserved leaf PTE flags: PTE_W */
-- 
2.34.1




[PULL 37/40] target/riscv: add support for svnapot extension

2022-02-11 Thread Alistair Francis
From: Weiwei Li 

- add PTE_N bit
- add PTE_N bit check for inner PTE
- update address translation to support 64KiB continuous region (napot_bits = 4)

Signed-off-by: Weiwei Li 
Signed-off-by: Junqiang Wang 
Reviewed-by: Anup Patel 
Reviewed-by: Alistair Francis 
Message-Id: <20220204022658.18097-4-liwei...@iscas.ac.cn>
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu.c|  2 ++
 target/riscv/cpu_helper.c | 18 +++---
 3 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index b3489cbc10..37ed4da72c 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -561,6 +561,7 @@ typedef enum {
 #define PTE_A   0x040 /* Accessed */
 #define PTE_D   0x080 /* Dirty */
 #define PTE_SOFT0x300 /* Reserved for Software */
+#define PTE_N   0x8000ULL /* NAPOT translation */
 
 /* Page table PPN shift amount */
 #define PTE_PPN_SHIFT   10
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 9dce57a380..fda99c2a81 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -774,6 +774,8 @@ static Property riscv_cpu_properties[] = {
 DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128),
 DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
 
+DEFINE_PROP_BOOL("svnapot", RISCVCPU, cfg.ext_svnapot, false),
+
 DEFINE_PROP_BOOL("zba", RISCVCPU, cfg.ext_zba, true),
 DEFINE_PROP_BOOL("zbb", RISCVCPU, cfg.ext_zbb, true),
 DEFINE_PROP_BOOL("zbc", RISCVCPU, cfg.ext_zbc, true),
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 25ebc76725..437c9488a6 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -753,6 +753,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr 
*physical,
 bool use_background = false;
 hwaddr ppn;
 RISCVCPU *cpu = env_archcpu(env);
+int napot_bits = 0;
+target_ulong napot_mask;
 
 /*
  * Check if we should use the background registers for the two
@@ -937,7 +939,7 @@ restart:
 return TRANSLATE_FAIL;
 } else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
 /* Inner PTE, continue walking */
-if (pte & (PTE_D | PTE_A | PTE_U)) {
+if (pte & (PTE_D | PTE_A | PTE_U | PTE_N)) {
 return TRANSLATE_FAIL;
 }
 base = ppn << PGSHIFT;
@@ -1013,8 +1015,18 @@ restart:
 /* for superpage mappings, make a fake leaf PTE for the TLB's
benefit. */
 target_ulong vpn = addr >> PGSHIFT;
-*physical = ((ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT) |
-(addr & ~TARGET_PAGE_MASK);
+
+if (cpu->cfg.ext_svnapot && (pte & PTE_N)) {
+napot_bits = ctzl(ppn) + 1;
+if ((i != (levels - 1)) || (napot_bits != 4)) {
+return TRANSLATE_FAIL;
+}
+}
+
+napot_mask = (1 << napot_bits) - 1;
+*physical = (((ppn & ~napot_mask) | (vpn & napot_mask) |
+  (vpn & (((target_ulong)1 << ptshift) - 1))
+ ) << PGSHIFT) | (addr & ~TARGET_PAGE_MASK);
 
 /* set permissions on the TLB entry */
 if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) {
-- 
2.34.1




[PULL 35/40] target/riscv: Ignore reserved bits in PTE for RV64

2022-02-11 Thread Alistair Francis
From: Guo Ren 

Highest bits of PTE has been used for svpbmt, ref: [1], [2], so we
need to ignore them. They cannot be a part of ppn.

1: The RISC-V Instruction Set Manual, Volume II: Privileged Architecture
   4.4 Sv39: Page-Based 39-bit Virtual-Memory System
   4.5 Sv48: Page-Based 48-bit Virtual-Memory System

2: https://github.com/riscv/virtual-memory/blob/main/specs/663-Svpbmt-diff.pdf

Signed-off-by: Guo Ren 
Reviewed-by: Liu Zhiwei 
Reviewed-by: Alistair Francis 
Cc: Bin Meng 
Reviewed-by: Alistair Francis 
Message-Id: <20220204022658.18097-2-liwei...@iscas.ac.cn>
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h| 15 +++
 target/riscv/cpu_bits.h   |  3 +++
 target/riscv/cpu_helper.c | 13 -
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7ecb1387dd..cefccb4016 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -359,6 +359,8 @@ struct RISCVCPUConfig {
 bool ext_counters;
 bool ext_ifencei;
 bool ext_icsr;
+bool ext_svnapot;
+bool ext_svpbmt;
 bool ext_zfh;
 bool ext_zfhmin;
 bool ext_zve32f;
@@ -558,6 +560,19 @@ static inline int riscv_cpu_xlen(CPURISCVState *env)
 return 16 << env->xl;
 }
 
+#ifdef TARGET_RISCV32
+#define riscv_cpu_sxl(env)  ((void)(env), MXL_RV32)
+#else
+static inline RISCVMXL riscv_cpu_sxl(CPURISCVState *env)
+{
+#ifdef CONFIG_USER_ONLY
+return env->misa_mxl;
+#else
+return get_field(env->mstatus, MSTATUS64_SXL);
+#endif
+}
+#endif
+
 /*
  * Encode LMUL to lmul as follows:
  * LMULvlmullmul
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 068c4d8034..b3489cbc10 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -565,6 +565,9 @@ typedef enum {
 /* Page table PPN shift amount */
 #define PTE_PPN_SHIFT   10
 
+/* Page table PPN mask */
+#define PTE_PPN_MASK0x3FFC00ULL
+
 /* Leaf page shift amount */
 #define PGSHIFT 12
 
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 430060dcd8..7df4569526 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -751,6 +751,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr 
*physical,
 MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
 int mode = mmu_idx & TB_FLAGS_PRIV_MMU_MASK;
 bool use_background = false;
+hwaddr ppn;
+RISCVCPU *cpu = env_archcpu(env);
 
 /*
  * Check if we should use the background registers for the two
@@ -919,7 +921,16 @@ restart:
 return TRANSLATE_FAIL;
 }
 
-hwaddr ppn = pte >> PTE_PPN_SHIFT;
+if (riscv_cpu_sxl(env) == MXL_RV32) {
+ppn = pte >> PTE_PPN_SHIFT;
+} else if (cpu->cfg.ext_svpbmt || cpu->cfg.ext_svnapot) {
+ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT;
+} else {
+ppn = pte >> PTE_PPN_SHIFT;
+if ((pte & ~(target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT) {
+return TRANSLATE_FAIL;
+}
+}
 
 if (!(pte & PTE_V)) {
 /* Invalid PTE */
-- 
2.34.1




[PULL 38/40] target/riscv: add support for svinval extension

2022-02-11 Thread Alistair Francis
From: Weiwei Li 

- sinval.vma, hinval.vvma and hinval.gvma do the same as sfence.vma, 
hfence.vvma and hfence.gvma except extension check
- do nothing other than extension check for sfence.w.inval and sfence.inval.ir

Signed-off-by: Weiwei Li 
Signed-off-by: Junqiang Wang 
Reviewed-by: Anup Patel 
Reviewed-by: Alistair Francis 
Message-Id: <20220204022658.18097-5-liwei...@iscas.ac.cn>
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h  |  1 +
 target/riscv/insn32.decode  |  7 ++
 target/riscv/cpu.c  |  1 +
 target/riscv/translate.c|  1 +
 target/riscv/insn_trans/trans_svinval.c.inc | 75 +
 5 files changed, 85 insertions(+)
 create mode 100644 target/riscv/insn_trans/trans_svinval.c.inc

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index cefccb4016..8183fb86d5 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -359,6 +359,7 @@ struct RISCVCPUConfig {
 bool ext_counters;
 bool ext_ifencei;
 bool ext_icsr;
+bool ext_svinval;
 bool ext_svnapot;
 bool ext_svpbmt;
 bool ext_zfh;
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 5bbedc254c..1d3ff1efe1 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -809,3 +809,10 @@ fcvt_l_h   1100010  00010 . ... . 1010011 @r2_rm
 fcvt_lu_h  1100010  00011 . ... . 1010011 @r2_rm
 fcvt_h_l   1101010  00010 . ... . 1010011 @r2_rm
 fcvt_h_lu  1101010  00011 . ... . 1010011 @r2_rm
+
+# *** Svinval Standard Extension ***
+sinval_vma0001011 . . 000 0 1110011 @sfence_vma
+sfence_w_inval0001100 0 0 000 0 1110011
+sfence_inval_ir   0001100 1 0 000 0 1110011
+hinval_vvma   0010011 . . 000 0 1110011 @hfence_vvma
+hinval_gvma   0110011 . . 000 0 1110011 @hfence_gvma
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index fda99c2a81..e5676b40d1 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -774,6 +774,7 @@ static Property riscv_cpu_properties[] = {
 DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128),
 DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
 
+DEFINE_PROP_BOOL("svinval", RISCVCPU, cfg.ext_svinval, false),
 DEFINE_PROP_BOOL("svnapot", RISCVCPU, cfg.ext_svnapot, false),
 
 DEFINE_PROP_BOOL("zba", RISCVCPU, cfg.ext_zba, true),
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index eaf5a72c81..84dbfa6340 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -862,6 +862,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, 
target_ulong pc)
 #include "insn_trans/trans_rvb.c.inc"
 #include "insn_trans/trans_rvzfh.c.inc"
 #include "insn_trans/trans_privileged.c.inc"
+#include "insn_trans/trans_svinval.c.inc"
 #include "insn_trans/trans_xventanacondops.c.inc"
 
 /* Include the auto-generated decoder for 16 bit insn */
diff --git a/target/riscv/insn_trans/trans_svinval.c.inc 
b/target/riscv/insn_trans/trans_svinval.c.inc
new file mode 100644
index 00..2682bd969f
--- /dev/null
+++ b/target/riscv/insn_trans/trans_svinval.c.inc
@@ -0,0 +1,75 @@
+/*
+ * RISC-V translation routines for the Svinval Standard Instruction Set.
+ *
+ * Copyright (c) 2020-2022 PLCT lab
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see .
+ */
+
+#define REQUIRE_SVINVAL(ctx) do {  \
+if (!ctx->cfg_ptr->ext_svinval) {  \
+return false;  \
+}  \
+} while (0)
+
+static bool trans_sinval_vma(DisasContext *ctx, arg_sinval_vma *a)
+{
+REQUIRE_SVINVAL(ctx);
+/* Do the same as sfence.vma currently */
+REQUIRE_EXT(ctx, RVS);
+#ifndef CONFIG_USER_ONLY
+gen_helper_tlb_flush(cpu_env);
+return true;
+#endif
+return false;
+}
+
+static bool trans_sfence_w_inval(DisasContext *ctx, arg_sfence_w_inval *a)
+{
+REQUIRE_SVINVAL(ctx);
+REQUIRE_EXT(ctx, RVS);
+/* Do nothing currently */
+return true;
+}
+
+static bool trans_sfence_inval_ir(DisasContext *ctx, arg_sfence_inval_ir *a)
+{
+REQUIRE_SVINVAL(ctx);
+REQUIRE_EXT(ctx, RVS);
+/* Do nothing currently */
+return true;
+}
+
+static bool trans_hinval_vvma(DisasContext *ctx, arg_hinval_vvma *a)
+{
+REQUIRE_SVINVAL(ctx);
+/* Do the same as hfence.vvma currently */
+REQUIRE_EXT(ctx, RVH);

[PULL 29/40] hw/intc: Add RISC-V AIA APLIC device emulation

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The RISC-V AIA (Advanced Interrupt Architecture) defines a new
interrupt controller for wired interrupts called APLIC (Advanced
Platform Level Interrupt Controller). The APLIC is capabable of
forwarding wired interupts to RISC-V HARTs directly or as MSIs
(Message Signaled Interupts).

This patch adds device emulation for RISC-V AIA APLIC.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-19-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 include/hw/intc/riscv_aplic.h |  79 +++
 hw/intc/riscv_aplic.c | 978 ++
 hw/intc/Kconfig   |   3 +
 hw/intc/meson.build   |   1 +
 4 files changed, 1061 insertions(+)
 create mode 100644 include/hw/intc/riscv_aplic.h
 create mode 100644 hw/intc/riscv_aplic.c

diff --git a/include/hw/intc/riscv_aplic.h b/include/hw/intc/riscv_aplic.h
new file mode 100644
index 00..de8532fbc3
--- /dev/null
+++ b/include/hw/intc/riscv_aplic.h
@@ -0,0 +1,79 @@
+/*
+ * RISC-V APLIC (Advanced Platform Level Interrupt Controller) interface
+ *
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see .
+ */
+
+#ifndef HW_RISCV_APLIC_H
+#define HW_RISCV_APLIC_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_RISCV_APLIC "riscv.aplic"
+
+typedef struct RISCVAPLICState RISCVAPLICState;
+DECLARE_INSTANCE_CHECKER(RISCVAPLICState, RISCV_APLIC, TYPE_RISCV_APLIC)
+
+#define APLIC_MIN_SIZE0x4000
+#define APLIC_SIZE_ALIGN(__x) (((__x) + (APLIC_MIN_SIZE - 1)) & \
+   ~(APLIC_MIN_SIZE - 1))
+#define APLIC_SIZE(__num_harts)   (APLIC_MIN_SIZE + \
+   APLIC_SIZE_ALIGN(32 * (__num_harts)))
+
+struct RISCVAPLICState {
+/*< private >*/
+SysBusDevice parent_obj;
+qemu_irq *external_irqs;
+
+/*< public >*/
+MemoryRegion mmio;
+uint32_t bitfield_words;
+uint32_t domaincfg;
+uint32_t mmsicfgaddr;
+uint32_t mmsicfgaddrH;
+uint32_t smsicfgaddr;
+uint32_t smsicfgaddrH;
+uint32_t genmsi;
+uint32_t *sourcecfg;
+uint32_t *state;
+uint32_t *target;
+uint32_t *idelivery;
+uint32_t *iforce;
+uint32_t *ithreshold;
+
+/* topology */
+#define QEMU_APLIC_MAX_CHILDREN16
+struct RISCVAPLICState *parent;
+struct RISCVAPLICState *children[QEMU_APLIC_MAX_CHILDREN];
+uint16_t num_children;
+
+/* config */
+uint32_t aperture_size;
+uint32_t hartid_base;
+uint32_t num_harts;
+uint32_t iprio_mask;
+uint32_t num_irqs;
+bool msimode;
+bool mmode;
+};
+
+void riscv_aplic_add_child(DeviceState *parent, DeviceState *child);
+
+DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size,
+uint32_t hartid_base, uint32_t num_harts, uint32_t num_sources,
+uint32_t iprio_bits, bool msimode, bool mmode, DeviceState *parent);
+
+#endif
diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
new file mode 100644
index 00..e7809fb6b2
--- /dev/null
+++ b/hw/intc/riscv_aplic.c
@@ -0,0 +1,978 @@
+/*
+ * RISC-V APLIC (Advanced Platform Level Interrupt Controller)
+ *
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see .
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "qemu/bswap.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"
+#include "hw/pci/msi.h"
+#include "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "hw/intc/riscv_aplic.h"
+#include "hw/irq.h"
+#include "target/riscv/cpu.h"
+#include "sysemu/sysemu.h"
+#include "migration/vmstate.h"
+
+#define APLIC_MAX_IDC  (1UL << 14)
+#define 

[PULL 30/40] hw/riscv: virt: Add optional AIA APLIC support to virt machine

2022-02-11 Thread Alistair Francis
From: Anup Patel 

We extend virt machine to emulate AIA APLIC devices only when
"aia=aplic" parameter is passed along with machine name in QEMU
command-line. When "aia=none" or not specified then we fallback
to original PLIC device emulation.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Message-id: 20220204174700.534953-20-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 include/hw/riscv/virt.h |  26 +++-
 hw/riscv/virt.c | 291 
 hw/riscv/Kconfig|   1 +
 3 files changed, 259 insertions(+), 59 deletions(-)

diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 6e9f61ccd9..47706b456d 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -32,18 +32,24 @@ typedef struct RISCVVirtState RISCVVirtState;
 DECLARE_INSTANCE_CHECKER(RISCVVirtState, RISCV_VIRT_MACHINE,
  TYPE_RISCV_VIRT_MACHINE)
 
+typedef enum RISCVVirtAIAType {
+VIRT_AIA_TYPE_NONE = 0,
+VIRT_AIA_TYPE_APLIC,
+} RISCVVirtAIAType;
+
 struct RISCVVirtState {
 /*< private >*/
 MachineState parent;
 
 /*< public >*/
 RISCVHartArrayState soc[VIRT_SOCKETS_MAX];
-DeviceState *plic[VIRT_SOCKETS_MAX];
+DeviceState *irqchip[VIRT_SOCKETS_MAX];
 PFlashCFI01 *flash[2];
 FWCfgState *fw_cfg;
 
 int fdt_size;
 bool have_aclint;
+RISCVVirtAIAType aia_type;
 };
 
 enum {
@@ -54,6 +60,8 @@ enum {
 VIRT_CLINT,
 VIRT_ACLINT_SSWI,
 VIRT_PLIC,
+VIRT_APLIC_M,
+VIRT_APLIC_S,
 VIRT_UART0,
 VIRT_VIRTIO,
 VIRT_FW_CFG,
@@ -73,8 +81,9 @@ enum {
 VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
 };
 
-#define VIRT_PLIC_NUM_SOURCES 127
-#define VIRT_PLIC_NUM_PRIORITIES 7
+#define VIRT_IRQCHIP_NUM_SOURCES 127
+#define VIRT_IRQCHIP_NUM_PRIO_BITS 3
+
 #define VIRT_PLIC_PRIORITY_BASE 0x04
 #define VIRT_PLIC_PENDING_BASE 0x1000
 #define VIRT_PLIC_ENABLE_BASE 0x2000
@@ -86,9 +95,14 @@ enum {
 
 #define FDT_PCI_ADDR_CELLS3
 #define FDT_PCI_INT_CELLS 1
-#define FDT_PLIC_ADDR_CELLS   0
 #define FDT_PLIC_INT_CELLS1
-#define FDT_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + 1 + \
-   FDT_PLIC_ADDR_CELLS + FDT_PLIC_INT_CELLS)
+#define FDT_APLIC_INT_CELLS   2
+#define FDT_MAX_INT_CELLS 2
+#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+ 1 + FDT_MAX_INT_CELLS)
+#define FDT_PLIC_INT_MAP_WIDTH  (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+ 1 + FDT_PLIC_INT_CELLS)
+#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+ 1 + FDT_APLIC_INT_CELLS)
 
 #endif
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index e3068d6126..6b06f79b46 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -33,6 +33,7 @@
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
 #include "hw/intc/riscv_aclint.h"
+#include "hw/intc/riscv_aplic.h"
 #include "hw/intc/sifive_plic.h"
 #include "hw/misc/sifive_test.h"
 #include "chardev/char.h"
@@ -52,6 +53,8 @@ static const MemMapEntry virt_memmap[] = {
 [VIRT_ACLINT_SSWI] = {  0x2F0,0x4000 },
 [VIRT_PCIE_PIO] ={  0x300,   0x1 },
 [VIRT_PLIC] ={  0xc00, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
+[VIRT_APLIC_M] = {  0xc00, APLIC_SIZE(VIRT_CPUS_MAX) },
+[VIRT_APLIC_S] = {  0xd00, APLIC_SIZE(VIRT_CPUS_MAX) },
 [VIRT_UART0] =   { 0x1000, 0x100 },
 [VIRT_VIRTIO] =  { 0x10001000,0x1000 },
 [VIRT_FW_CFG] =  { 0x1010,  0x18 },
@@ -133,12 +136,13 @@ static void virt_flash_map(RISCVVirtState *s,
 sysmem);
 }
 
-static void create_pcie_irq_map(void *fdt, char *nodename,
-uint32_t plic_phandle)
+static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
+uint32_t irqchip_phandle)
 {
 int pin, dev;
-uint32_t
-full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * FDT_INT_MAP_WIDTH] = {};
+uint32_t irq_map_stride = 0;
+uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+  FDT_MAX_INT_MAP_WIDTH] = {};
 uint32_t *irq_map = full_irq_map;
 
 /* This code creates a standard swizzle of interrupts such that
@@ -156,23 +160,31 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
 int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
 int i = 0;
 
+/* Fill PCI address cells */
 irq_map[i] = cpu_to_be32(devfn << 8);
-
 i += FDT_PCI_ADDR_CELLS;
-irq_map[i] = cpu_to_be32(pin + 1);
 
+/* Fill PCI Interrupt cells */
+irq_map[i] = cpu_to_be32(pin + 1);
 i += FDT_PCI_INT_CELLS;
-irq_map[i++] = cpu_to_be32(plic_phandle);
 
-i 

[PULL 34/40] hw/riscv: virt: Increase maximum number of allowed CPUs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

To facilitate software development of RISC-V systems with large number
of HARTs, we increase the maximum number of allowed CPUs to 512 (2^9).

We also add a detailed source level comments about limit defines which
impact the physical address space utilization.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-24-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 include/hw/riscv/virt.h |  2 +-
 hw/riscv/virt.c | 10 ++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index d248d0dfa0..78b058ec86 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -24,7 +24,7 @@
 #include "hw/block/flash.h"
 #include "qom/object.h"
 
-#define VIRT_CPUS_MAX_BITS 3
+#define VIRT_CPUS_MAX_BITS 9
 #define VIRT_CPUS_MAX  (1 << VIRT_CPUS_MAX_BITS)
 #define VIRT_SOCKETS_MAX_BITS  2
 #define VIRT_SOCKETS_MAX   (1 << VIRT_SOCKETS_MAX_BITS)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index c02710f711..7d5f1e58c9 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -45,6 +45,16 @@
 #include "hw/pci-host/gpex.h"
 #include "hw/display/ramfb.h"
 
+/*
+ * The virt machine physical address space used by some of the devices
+ * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets,
+ * number of CPUs, and number of IMSIC guest files.
+ *
+ * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS,
+ * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization
+ * of virt machine physical address space.
+ */
+
 #define VIRT_IMSIC_GROUP_MAX_SIZE  (1U << IMSIC_MMIO_GROUP_MIN_SHIFT)
 #if VIRT_IMSIC_GROUP_MAX_SIZE < \
 IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS)
-- 
2.34.1




[PULL 28/40] target/riscv: Allow users to force enable AIA CSRs in HART

2022-02-11 Thread Alistair Francis
From: Anup Patel 

We add "x-aia" command-line option for RISC-V HART using which
allows users to force enable CPU AIA CSRs without changing the
interrupt controller available in RISC-V machine.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-18-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h | 1 +
 target/riscv/cpu.c | 5 +
 2 files changed, 6 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index c70de10c85..7ecb1387dd 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -376,6 +376,7 @@ struct RISCVCPUConfig {
 bool mmu;
 bool pmp;
 bool epmp;
+bool aia;
 uint64_t resetvec;
 };
 
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5fb0a61036..9dce57a380 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -537,6 +537,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
+if (cpu->cfg.aia) {
+riscv_set_feature(env, RISCV_FEATURE_AIA);
+}
+
 set_resetvec(env, cpu->cfg.resetvec);
 
 /* Validate that MISA_MXL is set properly. */
@@ -782,6 +786,7 @@ static Property riscv_cpu_properties[] = {
 DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
 /* ePMP 0.9.3 */
 DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
+DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),
 
 DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
 DEFINE_PROP_END_OF_LIST(),
-- 
2.34.1




[PULL 33/40] docs/system: riscv: Document AIA options for virt machine

2022-02-11 Thread Alistair Francis
From: Anup Patel 

We have two new machine options "aia" and "aia-guests" available
for the RISC-V virt machine so let's document these options.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-23-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 docs/system/riscv/virt.rst | 16 
 1 file changed, 16 insertions(+)

diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst
index fa016584bf..373645513a 100644
--- a/docs/system/riscv/virt.rst
+++ b/docs/system/riscv/virt.rst
@@ -63,6 +63,22 @@ The following machine-specific options are supported:
   When this option is "on", ACLINT devices will be emulated instead of
   SiFive CLINT. When not specified, this option is assumed to be "off".
 
+- aia=[none|aplic|aplic-imsic]
+
+  This option allows selecting interrupt controller defined by the AIA
+  (advanced interrupt architecture) specification. The "aia=aplic" selects
+  APLIC (advanced platform level interrupt controller) to handle wired
+  interrupts whereas the "aia=aplic-imsic" selects APLIC and IMSIC (incoming
+  message signaled interrupt controller) to handle both wired interrupts and
+  MSIs. When not specified, this option is assumed to be "none" which selects
+  SiFive PLIC to handle wired interrupts.
+
+- aia-guests=nnn
+
+  The number of per-HART VS-level AIA IMSIC pages to be emulated for a guest
+  having AIA IMSIC (i.e. "aia=aplic-imsic" selected). When not specified,
+  the default number of per-HART VS-level AIA IMSIC pages is 0.
+
 Running Linux kernel
 
 
-- 
2.34.1




[PULL 31/40] hw/intc: Add RISC-V AIA IMSIC device emulation

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The RISC-V AIA (Advanced Interrupt Architecture) defines a new
interrupt controller for MSIs (message signal interrupts) called
IMSIC (Incoming Message Signal Interrupt Controller). The IMSIC
is per-HART device and also suppport virtualizaiton of MSIs using
dedicated VS-level guest interrupt files.

This patch adds device emulation for RISC-V AIA IMSIC which
supports M-level, S-level, and VS-level MSIs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-21-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 include/hw/intc/riscv_imsic.h |  68 ++
 hw/intc/riscv_imsic.c | 448 ++
 hw/intc/Kconfig   |   3 +
 hw/intc/meson.build   |   1 +
 4 files changed, 520 insertions(+)
 create mode 100644 include/hw/intc/riscv_imsic.h
 create mode 100644 hw/intc/riscv_imsic.c

diff --git a/include/hw/intc/riscv_imsic.h b/include/hw/intc/riscv_imsic.h
new file mode 100644
index 00..58c2aaa8dc
--- /dev/null
+++ b/include/hw/intc/riscv_imsic.h
@@ -0,0 +1,68 @@
+/*
+ * RISC-V IMSIC (Incoming Message Signal Interrupt Controller) interface
+ *
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see .
+ */
+
+#ifndef HW_RISCV_IMSIC_H
+#define HW_RISCV_IMSIC_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_RISCV_IMSIC "riscv.imsic"
+
+typedef struct RISCVIMSICState RISCVIMSICState;
+DECLARE_INSTANCE_CHECKER(RISCVIMSICState, RISCV_IMSIC, TYPE_RISCV_IMSIC)
+
+#define IMSIC_MMIO_PAGE_SHIFT  12
+#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT)
+#define IMSIC_MMIO_SIZE(__num_pages)   ((__num_pages) * IMSIC_MMIO_PAGE_SZ)
+
+#define IMSIC_MMIO_HART_GUEST_MAX_BTIS 6
+#define IMSIC_MMIO_GROUP_MIN_SHIFT 24
+
+#define IMSIC_HART_NUM_GUESTS(__guest_bits)   \
+(1U << (__guest_bits))
+#define IMSIC_HART_SIZE(__guest_bits) \
+(IMSIC_HART_NUM_GUESTS(__guest_bits) * IMSIC_MMIO_PAGE_SZ)
+#define IMSIC_GROUP_NUM_HARTS(__hart_bits)\
+(1U << (__hart_bits))
+#define IMSIC_GROUP_SIZE(__hart_bits, __guest_bits)   \
+(IMSIC_GROUP_NUM_HARTS(__hart_bits) * IMSIC_HART_SIZE(__guest_bits))
+
+struct RISCVIMSICState {
+/*< private >*/
+SysBusDevice parent_obj;
+qemu_irq *external_irqs;
+
+/*< public >*/
+MemoryRegion mmio;
+uint32_t num_eistate;
+uint32_t *eidelivery;
+uint32_t *eithreshold;
+uint32_t *eistate;
+
+/* config */
+bool mmode;
+uint32_t hartid;
+uint32_t num_pages;
+uint32_t num_irqs;
+};
+
+DeviceState *riscv_imsic_create(hwaddr addr, uint32_t hartid, bool mmode,
+uint32_t num_pages, uint32_t num_ids);
+
+#endif
diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
new file mode 100644
index 00..8615e4cc1d
--- /dev/null
+++ b/hw/intc/riscv_imsic.c
@@ -0,0 +1,448 @@
+/*
+ * RISC-V IMSIC (Incoming Message Signaled Interrupt Controller)
+ *
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see .
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "qemu/bswap.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"
+#include "hw/pci/msi.h"
+#include "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "hw/intc/riscv_imsic.h"
+#include "hw/irq.h"
+#include "target/riscv/cpu.h"
+#include "target/riscv/cpu_bits.h"
+#include "sysemu/sysemu.h"
+#include "migration/vmstate.h"
+
+#define IMSIC_MMIO_PAGE_LE 0x00
+#define IMSIC_MMIO_PAGE_BE 0x04
+
+#define IMSIC_MIN_ID   ((IMSIC_EIPx_BITS * 2) - 1)
+#define IMSIC_MAX_ID

[PULL 23/40] target/riscv: Implement AIA interrupt filtering CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA specificaiton adds interrupt filtering support for M-mode
and HS-mode. Using AIA interrupt filtering M-mode and H-mode can
take local interrupt 13 or above and selectively inject same local
interrupt to lower privilege modes.

At the moment, we don't have any local interrupts above 12 so we
add dummy implementation (i.e. read zero and ignore write) of AIA
interrupt filtering CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-13-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/csr.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 46448a2b7e..89700038fb 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -158,6 +158,15 @@ static RISCVException any32(CPURISCVState *env, int csrno)
 
 }
 
+static int aia_any(CPURISCVState *env, int csrno)
+{
+if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+return any(env, csrno);
+}
+
 static int aia_any32(CPURISCVState *env, int csrno)
 {
 if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
@@ -568,6 +577,12 @@ static RISCVException read_zero(CPURISCVState *env, int 
csrno,
 return RISCV_EXCP_NONE;
 }
 
+static RISCVException write_ignore(CPURISCVState *env, int csrno,
+   target_ulong val)
+{
+return RISCV_EXCP_NONE;
+}
+
 static RISCVException read_mhartid(CPURISCVState *env, int csrno,
target_ulong *val)
 {
@@ -2598,9 +2613,15 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
 [CSR_MTVAL]= { "mtval",any,  read_mtval,write_mtval},
 [CSR_MIP]  = { "mip",  any,  NULL,NULL, rmw_mip},
 
+/* Virtual Interrupts for Supervisor Level (AIA) */
+[CSR_MVIEN]  = { "mvien", aia_any, read_zero, write_ignore },
+[CSR_MVIP]   = { "mvip",  aia_any, read_zero, write_ignore },
+
 /* Machine-Level High-Half CSRs (AIA) */
 [CSR_MIDELEGH] = { "midelegh", aia_any32, NULL, NULL, rmw_midelegh },
 [CSR_MIEH] = { "mieh", aia_any32, NULL, NULL, rmw_mieh },
+[CSR_MVIENH]   = { "mvienh",   aia_any32, read_zero,  write_ignore },
+[CSR_MVIPH]= { "mviph",aia_any32, read_zero,  write_ignore },
 [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph },
 
 /* Supervisor Trap Setup */
@@ -2654,12 +2675,14 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
 [CSR_MTINST]  = { "mtinst",  hmode,   read_mtinst,  
write_mtinst  },
 
 /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
+[CSR_HVIEN]   = { "hvien",   aia_hmode, read_zero, write_ignore },
 [CSR_HVICTL]  = { "hvictl",  aia_hmode, read_hvictl, write_hvictl 
},
 [CSR_HVIPRIO1]= { "hviprio1",aia_hmode, read_hviprio1,   
write_hviprio1 },
 [CSR_HVIPRIO2]= { "hviprio2",aia_hmode, read_hviprio2,   
write_hviprio2 },
 
 /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
 [CSR_HIDELEGH]= { "hidelegh",aia_hmode32, NULL, NULL, rmw_hidelegh 
},
+[CSR_HVIENH]  = { "hvienh",  aia_hmode32, read_zero, write_ignore 
},
 [CSR_HVIPH]   = { "hviph",   aia_hmode32, NULL, NULL, rmw_hviph },
 [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, 
write_hviprio1h },
 [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, 
write_hviprio2h },
-- 
2.34.1




[PULL 27/40] hw/riscv: virt: Use AIA INTC compatible string when available

2022-02-11 Thread Alistair Francis
From: Anup Patel 

We should use the AIA INTC compatible string in the CPU INTC
DT nodes when the CPUs support AIA feature. This will allow
Linux INTC driver to use AIA local interrupt CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-17-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 hw/riscv/virt.c | 13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 2643c8bc37..e3068d6126 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -212,8 +212,17 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int 
socket,
 qemu_fdt_add_subnode(mc->fdt, intc_name);
 qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
 intc_phandles[cpu]);
-qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
-"riscv,cpu-intc");
+if (riscv_feature(>soc[socket].harts[cpu].env,
+  RISCV_FEATURE_AIA)) {
+static const char * const compat[2] = {
+"riscv,cpu-intc-aia", "riscv,cpu-intc"
+};
+qemu_fdt_setprop_string_array(mc->fdt, intc_name, "compatible",
+  (char **), ARRAY_SIZE(compat));
+} else {
+qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
+"riscv,cpu-intc");
+}
 qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
 qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
 
-- 
2.34.1




[PULL 20/40] target/riscv: Implement AIA local interrupt priorities

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA spec defines programmable 8-bit priority for each local interrupt
at M-level, S-level and VS-level so we extend local interrupt processing
to consider AIA interrupt priorities. The AIA CSRs which help software
configure local interrupt priorities will be added by subsequent patches.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Message-id: 20220204174700.534953-10-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h|  12 ++
 target/riscv/cpu.c|  19 +++
 target/riscv/cpu_helper.c | 281 +++---
 target/riscv/machine.c|   3 +
 4 files changed, 294 insertions(+), 21 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6b6df57c42..89e9cc558d 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -192,6 +192,10 @@ struct CPURISCVState {
 target_ulong mcause;
 target_ulong mtval;  /* since: priv-1.10.0 */
 
+/* Machine and Supervisor interrupt priorities */
+uint8_t miprio[64];
+uint8_t siprio[64];
+
 /* Hypervisor CSRs */
 target_ulong hstatus;
 target_ulong hedeleg;
@@ -204,6 +208,9 @@ struct CPURISCVState {
 target_ulong hgeip;
 uint64_t htimedelta;
 
+/* Hypervisor controlled virtual interrupt priorities */
+uint8_t hviprio[64];
+
 /* Upper 64-bits of 128-bit CSRs */
 uint64_t mscratchh;
 uint64_t sscratchh;
@@ -415,6 +422,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, 
CPUState *cs,
int cpuid, void *opaque);
 int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
+uint8_t riscv_cpu_default_priority(int irq);
+int riscv_cpu_mirq_pending(CPURISCVState *env);
+int riscv_cpu_sirq_pending(CPURISCVState *env);
+int riscv_cpu_vsirq_pending(CPURISCVState *env);
 bool riscv_cpu_fp_enabled(CPURISCVState *env);
 target_ulong riscv_cpu_get_geilen(CPURISCVState *env);
 void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ff766acc21..5fb0a61036 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -400,6 +400,10 @@ void restore_state_to_opc(CPURISCVState *env, 
TranslationBlock *tb,
 
 static void riscv_cpu_reset(DeviceState *dev)
 {
+#ifndef CONFIG_USER_ONLY
+uint8_t iprio;
+int i, irq, rdzero;
+#endif
 CPUState *cs = CPU(dev);
 RISCVCPU *cpu = RISCV_CPU(cs);
 RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
@@ -432,6 +436,21 @@ static void riscv_cpu_reset(DeviceState *dev)
 env->miclaim = MIP_SGEIP;
 env->pc = env->resetvec;
 env->two_stage_lookup = false;
+
+/* Initialized default priorities of local interrupts. */
+for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
+iprio = riscv_cpu_default_priority(i);
+env->miprio[i] = (i == IRQ_M_EXT) ? 0 : iprio;
+env->siprio[i] = (i == IRQ_S_EXT) ? 0 : iprio;
+env->hviprio[i] = 0;
+}
+i = 0;
+while (!riscv_cpu_hviprio_index2irq(i, , )) {
+if (!rdzero) {
+env->hviprio[irq] = env->miprio[irq];
+}
+i++;
+}
 /* mmte is supposed to have pm.current hardwired to 1 */
 env->mmte |= (PM_EXT_INITIAL | MMTE_M_PM_CURRENT);
 #endif
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 37c58a891b..1a9534d6d7 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -152,36 +152,275 @@ void riscv_cpu_update_mask(CPURISCVState *env)
 }
 
 #ifndef CONFIG_USER_ONLY
-static int riscv_cpu_local_irq_pending(CPURISCVState *env)
+
+/*
+ * The HS-mode is allowed to configure priority only for the
+ * following VS-mode local interrupts:
+ *
+ * 0  (Reserved interrupt, reads as zero)
+ * 1  Supervisor software interrupt
+ * 4  (Reserved interrupt, reads as zero)
+ * 5  Supervisor timer interrupt
+ * 8  (Reserved interrupt, reads as zero)
+ * 13 (Reserved interrupt)
+ * 14 "
+ * 15 "
+ * 16 "
+ * 18 Debug/trace interrupt
+ * 20 (Reserved interrupt)
+ * 22 "
+ * 24 "
+ * 26 "
+ * 28 "
+ * 30 (Reserved for standard reporting of bus or system errors)
+ */
+
+static const int hviprio_index2irq[] = {
+0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
+static const int hviprio_index2rdzero[] = {
+1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
+{
+if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
+return -EINVAL;
+}
+
+if (out_irq) {
+*out_irq = hviprio_index2irq[index];
+}
+
+if (out_rdzero) {
+*out_rdzero = hviprio_index2rdzero[index];
+}
+
+return 0;
+}
+
+/*
+ * Default priorities of local interrupts are defined in the
+ * RISC-V Advanced Interrupt Architecture specification.
+ *

[PULL 26/40] target/riscv: Implement AIA IMSIC interface CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA specification defines IMSIC interface CSRs for easy access
to the per-HART IMSIC registers without using indirect xiselect and
xireg CSRs. This patch implements the AIA IMSIC interface CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-16-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/csr.c | 203 +
 1 file changed, 203 insertions(+)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index a186b31fcf..fe2c8dd40e 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -942,6 +942,16 @@ static int aia_xlate_vs_csrno(CPURISCVState *env, int 
csrno)
 return CSR_VSISELECT;
 case CSR_SIREG:
 return CSR_VSIREG;
+case CSR_SSETEIPNUM:
+return CSR_VSSETEIPNUM;
+case CSR_SCLREIPNUM:
+return CSR_VSCLREIPNUM;
+case CSR_SSETEIENUM:
+return CSR_VSSETEIENUM;
+case CSR_SCLREIENUM:
+return CSR_VSCLREIENUM;
+case CSR_STOPEI:
+return CSR_VSTOPEI;
 default:
 return csrno;
 };
@@ -1094,6 +1104,178 @@ done:
 return RISCV_EXCP_NONE;
 }
 
+static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val,
+target_ulong new_val, target_ulong wr_mask)
+{
+int ret = -EINVAL;
+bool set, pend, virt;
+target_ulong priv, isel, vgein, xlen, nval, wmask;
+
+/* Translate CSR number for VS-mode */
+csrno = aia_xlate_vs_csrno(env, csrno);
+
+/* Decode register details from CSR number */
+virt = set = pend = false;
+switch (csrno) {
+case CSR_MSETEIPNUM:
+priv = PRV_M;
+set = true;
+pend = true;
+break;
+case CSR_MCLREIPNUM:
+priv = PRV_M;
+pend = true;
+break;
+case CSR_MSETEIENUM:
+priv = PRV_M;
+set = true;
+break;
+case CSR_MCLREIENUM:
+priv = PRV_M;
+break;
+case CSR_SSETEIPNUM:
+priv = PRV_S;
+set = true;
+pend = true;
+break;
+case CSR_SCLREIPNUM:
+priv = PRV_S;
+pend = true;
+break;
+case CSR_SSETEIENUM:
+priv = PRV_S;
+set = true;
+break;
+case CSR_SCLREIENUM:
+priv = PRV_S;
+break;
+case CSR_VSSETEIPNUM:
+priv = PRV_S;
+virt = true;
+set = true;
+pend = true;
+break;
+case CSR_VSCLREIPNUM:
+priv = PRV_S;
+virt = true;
+pend = true;
+break;
+case CSR_VSSETEIENUM:
+priv = PRV_S;
+virt = true;
+set = true;
+break;
+case CSR_VSCLREIENUM:
+priv = PRV_S;
+virt = true;
+break;
+default:
+ goto done;
+};
+
+/* IMSIC CSRs only available when machine implements IMSIC. */
+if (!env->aia_ireg_rmw_fn[priv]) {
+goto done;
+}
+
+/* Find the selected guest interrupt file */
+vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0;
+
+/* Selected guest interrupt file should be valid */
+if (virt && (!vgein || env->geilen < vgein)) {
+goto done;
+}
+
+/* Set/Clear CSRs always read zero */
+if (val) {
+*val = 0;
+}
+
+if (wr_mask) {
+/* Get interrupt number */
+new_val &= wr_mask;
+
+/* Find target interrupt pending/enable register */
+xlen = riscv_cpu_mxl_bits(env);
+isel = (new_val / xlen);
+isel *= (xlen / IMSIC_EIPx_BITS);
+isel += (pend) ? ISELECT_IMSIC_EIP0 : ISELECT_IMSIC_EIE0;
+
+/* Find the interrupt bit to be set/clear */
+wmask = ((target_ulong)1) << (new_val % xlen);
+nval = (set) ? wmask : 0;
+
+/* Call machine specific IMSIC register emulation */
+ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv],
+ AIA_MAKE_IREG(isel, priv, virt,
+   vgein, xlen),
+ NULL, nval, wmask);
+} else {
+ret = 0;
+}
+
+done:
+if (ret) {
+return (riscv_cpu_virt_enabled(env) && virt) ?
+   RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
+}
+return RISCV_EXCP_NONE;
+}
+
+static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val,
+  target_ulong new_val, target_ulong wr_mask)
+{
+bool virt;
+int ret = -EINVAL;
+target_ulong priv, vgein;
+
+/* Translate CSR number for VS-mode */
+csrno = aia_xlate_vs_csrno(env, csrno);
+
+/* Decode register details from CSR number */
+virt = false;
+switch (csrno) {
+case CSR_MTOPEI:
+priv = PRV_M;
+break;
+case CSR_STOPEI:
+priv = PRV_S;
+break;
+case CSR_VSTOPEI:
+priv = PRV_S;
+virt = true;
+break;
+default:
+   

[PULL 21/40] target/riscv: Implement AIA CSRs for 64 local interrupts on RV32

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA specification adds new CSRs for RV32 so that RISC-V hart can
support 64 local interrupts on both RV32 and RV64.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-11-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h|  14 +-
 target/riscv/cpu_helper.c |  10 +-
 target/riscv/csr.c| 560 +++---
 target/riscv/machine.c|  10 +-
 4 files changed, 474 insertions(+), 120 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 89e9cc558d..2dc2485bb4 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -172,12 +172,12 @@ struct CPURISCVState {
  */
 uint64_t mstatus;
 
-target_ulong mip;
+uint64_t mip;
 
-uint32_t miclaim;
+uint64_t miclaim;
 
-target_ulong mie;
-target_ulong mideleg;
+uint64_t mie;
+uint64_t mideleg;
 
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
@@ -199,7 +199,7 @@ struct CPURISCVState {
 /* Hypervisor CSRs */
 target_ulong hstatus;
 target_ulong hedeleg;
-target_ulong hideleg;
+uint64_t hideleg;
 target_ulong hcounteren;
 target_ulong htval;
 target_ulong htinst;
@@ -456,8 +456,8 @@ void riscv_cpu_list(void);
 #ifndef CONFIG_USER_ONLY
 bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
 void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
-int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
-uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
+int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
+uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
 #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
 void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
  uint32_t arg);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 1a9534d6d7..430060dcd8 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -585,7 +585,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
 return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
 }
 
-int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
+int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
 {
 CPURISCVState *env = >env;
 if (env->miclaim & interrupts) {
@@ -596,11 +596,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t 
interrupts)
 }
 }
 
-uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
+uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
 {
 CPURISCVState *env = >env;
 CPUState *cs = CPU(cpu);
-uint32_t gein, vsgein = 0, old = env->mip;
+uint64_t gein, vsgein = 0, old = env->mip;
 bool locked = false;
 
 if (riscv_cpu_virt_enabled(env)) {
@@ -1306,7 +1306,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
  */
 bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
 target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
-target_ulong deleg = async ? env->mideleg : env->medeleg;
+uint64_t deleg = async ? env->mideleg : env->medeleg;
 target_ulong tval = 0;
 target_ulong htval = 0;
 target_ulong mtval2 = 0;
@@ -1373,7 +1373,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
 /* handle the trap in S-mode */
 if (riscv_has_ext(env, RVH)) {
-target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
+uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
 
 if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1)) {
 /* Trap to VS mode */
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index b23195b479..d8283160b1 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -158,6 +158,15 @@ static RISCVException any32(CPURISCVState *env, int csrno)
 
 }
 
+static int aia_any32(CPURISCVState *env, int csrno)
+{
+if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+return any32(env, csrno);
+}
+
 static RISCVException smode(CPURISCVState *env, int csrno)
 {
 if (riscv_has_ext(env, RVS)) {
@@ -167,6 +176,24 @@ static RISCVException smode(CPURISCVState *env, int csrno)
 return RISCV_EXCP_ILLEGAL_INST;
 }
 
+static int smode32(CPURISCVState *env, int csrno)
+{
+if (riscv_cpu_mxl(env) != MXL_RV32) {
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+return smode(env, csrno);
+}
+
+static int aia_smode32(CPURISCVState *env, int csrno)
+{
+if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+return smode32(env, csrno);
+}
+
 static RISCVException hmode(CPURISCVState *env, int csrno)
 {
 if (riscv_has_ext(env, RVS) &&
@@ 

[PULL 25/40] target/riscv: Implement AIA xiselect and xireg CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA specification defines [m|s|vs]iselect and [m|s|vs]ireg CSRs
which allow indirect access to interrupt priority arrays and per-HART
IMSIC registers. This patch implements AIA xiselect and xireg CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-15-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h |   7 ++
 target/riscv/csr.c | 177 +
 target/riscv/machine.c |   3 +
 3 files changed, 187 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index f0e69f2871..c70de10c85 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -196,6 +196,10 @@ struct CPURISCVState {
 uint8_t miprio[64];
 uint8_t siprio[64];
 
+/* AIA CSRs */
+target_ulong miselect;
+target_ulong siselect;
+
 /* Hypervisor CSRs */
 target_ulong hstatus;
 target_ulong hedeleg;
@@ -229,6 +233,9 @@ struct CPURISCVState {
 target_ulong vstval;
 target_ulong vsatp;
 
+/* AIA VS-mode CSRs */
+target_ulong vsiselect;
+
 target_ulong mtval2;
 target_ulong mtinst;
 
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 39402a6a49..a186b31fcf 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -931,6 +931,169 @@ static int read_mtopi(CPURISCVState *env, int csrno, 
target_ulong *val)
 return RISCV_EXCP_NONE;
 }
 
+static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
+{
+if (!riscv_cpu_virt_enabled(env)) {
+return csrno;
+}
+
+switch (csrno) {
+case CSR_SISELECT:
+return CSR_VSISELECT;
+case CSR_SIREG:
+return CSR_VSIREG;
+default:
+return csrno;
+};
+}
+
+static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
+target_ulong new_val, target_ulong wr_mask)
+{
+target_ulong *iselect;
+
+/* Translate CSR number for VS-mode */
+csrno = aia_xlate_vs_csrno(env, csrno);
+
+/* Find the iselect CSR based on CSR number */
+switch (csrno) {
+case CSR_MISELECT:
+iselect = >miselect;
+break;
+case CSR_SISELECT:
+iselect = >siselect;
+break;
+case CSR_VSISELECT:
+iselect = >vsiselect;
+break;
+default:
+ return RISCV_EXCP_ILLEGAL_INST;
+};
+
+if (val) {
+*val = *iselect;
+}
+
+wr_mask &= ISELECT_MASK;
+if (wr_mask) {
+*iselect = (*iselect & ~wr_mask) | (new_val & wr_mask);
+}
+
+return RISCV_EXCP_NONE;
+}
+
+static int rmw_iprio(target_ulong xlen,
+ target_ulong iselect, uint8_t *iprio,
+ target_ulong *val, target_ulong new_val,
+ target_ulong wr_mask, int ext_irq_no)
+{
+int i, firq, nirqs;
+target_ulong old_val;
+
+if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
+return -EINVAL;
+}
+if (xlen != 32 && iselect & 0x1) {
+return -EINVAL;
+}
+
+nirqs = 4 * (xlen / 32);
+firq = ((iselect - ISELECT_IPRIO0) / (xlen / 32)) * (nirqs);
+
+old_val = 0;
+for (i = 0; i < nirqs; i++) {
+old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
+}
+
+if (val) {
+*val = old_val;
+}
+
+if (wr_mask) {
+new_val = (old_val & ~wr_mask) | (new_val & wr_mask);
+for (i = 0; i < nirqs; i++) {
+/*
+ * M-level and S-level external IRQ priority always read-only
+ * zero. This means default priority order is always preferred
+ * for M-level and S-level external IRQs.
+ */
+if ((firq + i) == ext_irq_no) {
+continue;
+}
+iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
+}
+}
+
+return 0;
+}
+
+static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
+ target_ulong new_val, target_ulong wr_mask)
+{
+bool virt;
+uint8_t *iprio;
+int ret = -EINVAL;
+target_ulong priv, isel, vgein;
+
+/* Translate CSR number for VS-mode */
+csrno = aia_xlate_vs_csrno(env, csrno);
+
+/* Decode register details from CSR number */
+virt = false;
+switch (csrno) {
+case CSR_MIREG:
+iprio = env->miprio;
+isel = env->miselect;
+priv = PRV_M;
+break;
+case CSR_SIREG:
+iprio = env->siprio;
+isel = env->siselect;
+priv = PRV_S;
+break;
+case CSR_VSIREG:
+iprio = env->hviprio;
+isel = env->vsiselect;
+priv = PRV_S;
+virt = true;
+break;
+default:
+ goto done;
+};
+
+/* Find the selected guest interrupt file */
+vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0;
+
+if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
+/* Local interrupt priority registers not available for VS-mode 

[PULL 18/40] target/riscv: Add defines for AIA CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The RISC-V AIA specification extends RISC-V local interrupts and
introduces new CSRs. This patch adds defines for the new AIA CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-8-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu_bits.h | 119 
 1 file changed, 119 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index a541705760..068c4d8034 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -168,6 +168,31 @@
 #define CSR_MTVAL   0x343
 #define CSR_MIP 0x344
 
+/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_MISELECT0x350
+#define CSR_MIREG   0x351
+
+/* Machine-Level Interrupts (AIA) */
+#define CSR_MTOPI   0xfb0
+
+/* Machine-Level IMSIC Interface (AIA) */
+#define CSR_MSETEIPNUM  0x358
+#define CSR_MCLREIPNUM  0x359
+#define CSR_MSETEIENUM  0x35a
+#define CSR_MCLREIENUM  0x35b
+#define CSR_MTOPEI  0x35c
+
+/* Virtual Interrupts for Supervisor Level (AIA) */
+#define CSR_MVIEN   0x308
+#define CSR_MVIP0x309
+
+/* Machine-Level High-Half CSRs (AIA) */
+#define CSR_MIDELEGH0x313
+#define CSR_MIEH0x314
+#define CSR_MVIENH  0x318
+#define CSR_MVIPH   0x319
+#define CSR_MIPH0x354
+
 /* Supervisor Trap Setup */
 #define CSR_SSTATUS 0x100
 #define CSR_SEDELEG 0x102
@@ -187,6 +212,24 @@
 #define CSR_SPTBR   0x180
 #define CSR_SATP0x180
 
+/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_SISELECT0x150
+#define CSR_SIREG   0x151
+
+/* Supervisor-Level Interrupts (AIA) */
+#define CSR_STOPI   0xdb0
+
+/* Supervisor-Level IMSIC Interface (AIA) */
+#define CSR_SSETEIPNUM  0x158
+#define CSR_SCLREIPNUM  0x159
+#define CSR_SSETEIENUM  0x15a
+#define CSR_SCLREIENUM  0x15b
+#define CSR_STOPEI  0x15c
+
+/* Supervisor-Level High-Half CSRs (AIA) */
+#define CSR_SIEH0x114
+#define CSR_SIPH0x154
+
 /* Hpervisor CSRs */
 #define CSR_HSTATUS 0x600
 #define CSR_HEDELEG 0x602
@@ -217,6 +260,35 @@
 #define CSR_MTINST  0x34a
 #define CSR_MTVAL2  0x34b
 
+/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
+#define CSR_HVIEN   0x608
+#define CSR_HVICTL  0x609
+#define CSR_HVIPRIO10x646
+#define CSR_HVIPRIO20x647
+
+/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
+#define CSR_VSISELECT   0x250
+#define CSR_VSIREG  0x251
+
+/* VS-Level Interrupts (H-extension with AIA) */
+#define CSR_VSTOPI  0xeb0
+
+/* VS-Level IMSIC Interface (H-extension with AIA) */
+#define CSR_VSSETEIPNUM 0x258
+#define CSR_VSCLREIPNUM 0x259
+#define CSR_VSSETEIENUM 0x25a
+#define CSR_VSCLREIENUM 0x25b
+#define CSR_VSTOPEI 0x25c
+
+/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
+#define CSR_HIDELEGH0x613
+#define CSR_HVIENH  0x618
+#define CSR_HVIPH   0x655
+#define CSR_HVIPRIO1H   0x656
+#define CSR_HVIPRIO2H   0x657
+#define CSR_VSIEH   0x214
+#define CSR_VSIPH   0x254
+
 /* Enhanced Physical Memory Protection (ePMP) */
 #define CSR_MSECCFG 0x747
 #define CSR_MSECCFGH0x757
@@ -635,4 +707,51 @@ typedef enum RISCVException {
 #define UMTE_U_PM_INSN  U_PM_INSN
 #define UMTE_MASK (UMTE_U_PM_ENABLE | MMTE_U_PM_CURRENT | UMTE_U_PM_INSN)
 
+/* MISELECT, SISELECT, and VSISELECT bits (AIA) */
+#define ISELECT_IPRIO0 0x30
+#define ISELECT_IPRIO150x3f
+#define ISELECT_IMSIC_EIDELIVERY   0x70
+#define ISELECT_IMSIC_EITHRESHOLD  0x72
+#define ISELECT_IMSIC_EIP0 0x80
+#define ISELECT_IMSIC_EIP630xbf
+#define ISELECT_IMSIC_EIE0 0xc0
+#define ISELECT_IMSIC_EIE630xff
+#define ISELECT_IMSIC_FIRSTISELECT_IMSIC_EIDELIVERY
+#define ISELECT_IMSIC_LAST ISELECT_IMSIC_EIE63
+#define ISELECT_MASK   0x1ff
+
+/* Dummy [M|S|VS]ISELECT value for emulating [M|S|VS]TOPEI CSRs */
+#define ISELECT_IMSIC_TOPEI(ISELECT_MASK + 1)
+
+/* IMSIC bits (AIA) */
+#define IMSIC_TOPEI_IID_SHIFT  16
+#define IMSIC_TOPEI_IID_MASK   0x7ff
+#define IMSIC_TOPEI_IPRIO_MASK 0x7ff
+#define IMSIC_EIPx_BITS32
+#define IMSIC_EIEx_BITS32
+
+/* MTOPI and STOPI bits (AIA) */
+#define TOPI_IID_SHIFT 16
+#define TOPI_IID_MASK  0xfff
+#define TOPI_IPRIO_MASK0xff
+
+/* Interrupt priority bits (AIA) */
+#define IPRIO_IRQ_BITS

[PULL 24/40] target/riscv: Implement AIA mtopi, stopi, and vstopi CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA specification introduces new [m|s|vs]topi CSRs for
reporting pending local IRQ number and associated IRQ priority.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-14-a...@brainfault.org
[ Changed by AF:
 - Fixup indentation
]
Signed-off-by: Alistair Francis 
---
 target/riscv/csr.c | 156 +
 1 file changed, 156 insertions(+)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 89700038fb..39402a6a49 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -194,6 +194,15 @@ static int smode32(CPURISCVState *env, int csrno)
 return smode(env, csrno);
 }
 
+static int aia_smode(CPURISCVState *env, int csrno)
+{
+if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+return smode(env, csrno);
+}
+
 static int aia_smode32(CPURISCVState *env, int csrno)
 {
 if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
@@ -517,6 +526,8 @@ static RISCVException read_timeh(CPURISCVState *env, int 
csrno,
 #define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
 #define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
 
+#define VSTOPI_NUM_SRCS 5
+
 static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
VS_MODE_INTERRUPTS;
 static const uint64_t vs_delegable_ints = VS_MODE_INTERRUPTS;
@@ -898,6 +909,28 @@ static RISCVException rmw_mieh(CPURISCVState *env, int 
csrno,
 return ret;
 }
 
+static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
+{
+int irq;
+uint8_t iprio;
+
+irq = riscv_cpu_mirq_pending(env);
+if (irq <= 0 || irq > 63) {
+*val = 0;
+} else {
+iprio = env->miprio[irq];
+if (!iprio) {
+if (riscv_cpu_default_priority(irq) > IPRIO_DEFAULT_M) {
+iprio = IPRIO_MMAXIPRIO;
+}
+}
+*val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
+*val |= iprio;
+}
+
+return RISCV_EXCP_NONE;
+}
+
 static RISCVException read_mtvec(CPURISCVState *env, int csrno,
  target_ulong *val)
 {
@@ -1478,6 +1511,120 @@ static RISCVException write_satp(CPURISCVState *env, 
int csrno,
 return RISCV_EXCP_NONE;
 }
 
+static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
+{
+int irq, ret;
+target_ulong topei;
+uint64_t vseip, vsgein;
+uint32_t iid, iprio, hviid, hviprio, gein;
+uint32_t s, scount = 0, siid[VSTOPI_NUM_SRCS], siprio[VSTOPI_NUM_SRCS];
+
+gein = get_field(env->hstatus, HSTATUS_VGEIN);
+hviid = get_field(env->hvictl, HVICTL_IID);
+hviprio = get_field(env->hvictl, HVICTL_IPRIO);
+
+if (gein) {
+vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
+vseip = env->mie & (env->mip | vsgein) & MIP_VSEIP;
+if (gein <= env->geilen && vseip) {
+siid[scount] = IRQ_S_EXT;
+siprio[scount] = IPRIO_MMAXIPRIO + 1;
+if (env->aia_ireg_rmw_fn[PRV_S]) {
+/*
+ * Call machine specific IMSIC register emulation for
+ * reading TOPEI.
+ */
+ret = env->aia_ireg_rmw_fn[PRV_S](
+env->aia_ireg_rmw_fn_arg[PRV_S],
+AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, PRV_S, true, gein,
+  riscv_cpu_mxl_bits(env)),
+, 0, 0);
+if (!ret && topei) {
+siprio[scount] = topei & IMSIC_TOPEI_IPRIO_MASK;
+}
+}
+scount++;
+}
+} else {
+if (hviid == IRQ_S_EXT && hviprio) {
+siid[scount] = IRQ_S_EXT;
+siprio[scount] = hviprio;
+scount++;
+}
+}
+
+if (env->hvictl & HVICTL_VTI) {
+if (hviid != IRQ_S_EXT) {
+siid[scount] = hviid;
+siprio[scount] = hviprio;
+scount++;
+}
+} else {
+irq = riscv_cpu_vsirq_pending(env);
+if (irq != IRQ_S_EXT && 0 < irq && irq <= 63) {
+siid[scount] = irq;
+siprio[scount] = env->hviprio[irq];
+scount++;
+}
+}
+
+iid = 0;
+iprio = UINT_MAX;
+for (s = 0; s < scount; s++) {
+if (siprio[s] < iprio) {
+iid = siid[s];
+iprio = siprio[s];
+}
+}
+
+if (iid) {
+if (env->hvictl & HVICTL_IPRIOM) {
+if (iprio > IPRIO_MMAXIPRIO) {
+iprio = IPRIO_MMAXIPRIO;
+}
+if (!iprio) {
+if (riscv_cpu_default_priority(iid) > IPRIO_DEFAULT_S) {
+iprio = IPRIO_MMAXIPRIO;
+}
+}
+} else {
+iprio = 1;
+}
+} else {
+iprio = 0;
+}
+
+*val = (iid & TOPI_IID_MASK) << 

[PULL 19/40] target/riscv: Allow AIA device emulation to set ireg rmw callback

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA device emulation (such as AIA IMSIC) should be able to set
(or provide) AIA ireg read-modify-write callback for each privilege
level of a RISC-V HART.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-9-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h| 23 +++
 target/riscv/cpu_helper.c | 14 ++
 2 files changed, 37 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 8838c61ae4..6b6df57c42 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -256,6 +256,22 @@ struct CPURISCVState {
 uint64_t (*rdtime_fn)(uint32_t);
 uint32_t rdtime_fn_arg;
 
+/* machine specific AIA ireg read-modify-write callback */
+#define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen) \
+__xlen) & 0xff) << 24) | \
+ (((__vgein) & 0x3f) << 20) | \
+ (((__virt) & 0x1) << 18) | \
+ (((__priv) & 0x3) << 16) | \
+ (__isel & 0x))
+#define AIA_IREG_ISEL(__ireg)  ((__ireg) & 0x)
+#define AIA_IREG_PRIV(__ireg)  (((__ireg) >> 16) & 0x3)
+#define AIA_IREG_VIRT(__ireg)  (((__ireg) >> 18) & 0x1)
+#define AIA_IREG_VGEIN(__ireg) (((__ireg) >> 20) & 0x3f)
+#define AIA_IREG_XLEN(__ireg)  (((__ireg) >> 24) & 0xff)
+int (*aia_ireg_rmw_fn[4])(void *arg, target_ulong reg,
+target_ulong *val, target_ulong new_val, target_ulong write_mask);
+void *aia_ireg_rmw_fn_arg[4];
+
 /* True if in debugger mode.  */
 bool debugger;
 
@@ -433,6 +449,13 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t 
mask, uint32_t value);
 #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
 void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
  uint32_t arg);
+void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
+   int (*rmw_fn)(void *arg,
+ target_ulong reg,
+ target_ulong *val,
+ target_ulong new_val,
+ target_ulong write_mask),
+   void *rmw_fn_arg);
 #endif
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
 
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index e45ca08ea9..37c58a891b 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -396,6 +396,20 @@ void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t 
(*fn)(uint32_t),
 env->rdtime_fn_arg = arg;
 }
 
+void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
+   int (*rmw_fn)(void *arg,
+ target_ulong reg,
+ target_ulong *val,
+ target_ulong new_val,
+ target_ulong write_mask),
+   void *rmw_fn_arg)
+{
+if (priv <= PRV_M) {
+env->aia_ireg_rmw_fn[priv] = rmw_fn;
+env->aia_ireg_rmw_fn_arg[priv] = rmw_fn_arg;
+}
+}
+
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
 {
 if (newpriv > PRV_M) {
-- 
2.34.1




[PULL 16/40] target/riscv: Allow setting CPU feature from machine/device emulation

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The machine or device emulation should be able to force set certain
CPU features because:
1) We can have certain CPU features which are in-general optional
   but implemented by RISC-V CPUs on the machine.
2) We can have devices which require a certain CPU feature. For example,
   AIA IMSIC devices expect AIA CSRs implemented by RISC-V CPUs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Bin Meng 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-6-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h |  5 +
 target/riscv/cpu.c | 11 +++
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index f030cb58b2..283a3cda4b 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -379,6 +379,11 @@ static inline bool riscv_feature(CPURISCVState *env, int 
feature)
 return env->features & (1ULL << feature);
 }
 
+static inline void riscv_set_feature(CPURISCVState *env, int feature)
+{
+env->features |= (1ULL << feature);
+}
+
 #include "cpu_user.h"
 
 extern const char * const riscv_int_regnames[];
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index f1c268415a..ff766acc21 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -135,11 +135,6 @@ static void set_vext_version(CPURISCVState *env, int 
vext_ver)
 env->vext_ver = vext_ver;
 }
 
-static void set_feature(CPURISCVState *env, int feature)
-{
-env->features |= (1ULL << feature);
-}
-
 static void set_resetvec(CPURISCVState *env, target_ulong resetvec)
 {
 #ifndef CONFIG_USER_ONLY
@@ -508,18 +503,18 @@ static void riscv_cpu_realize(DeviceState *dev, Error 
**errp)
 }
 
 if (cpu->cfg.mmu) {
-set_feature(env, RISCV_FEATURE_MMU);
+riscv_set_feature(env, RISCV_FEATURE_MMU);
 }
 
 if (cpu->cfg.pmp) {
-set_feature(env, RISCV_FEATURE_PMP);
+riscv_set_feature(env, RISCV_FEATURE_PMP);
 
 /*
  * Enhanced PMP should only be available
  * on harts with PMP support
  */
 if (cpu->cfg.epmp) {
-set_feature(env, RISCV_FEATURE_EPMP);
+riscv_set_feature(env, RISCV_FEATURE_EPMP);
 }
 }
 
-- 
2.34.1




[PULL 15/40] target/riscv: Improve delivery of guest external interrupts

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The guest external interrupts from an interrupt controller are
delivered only when the Guest/VM is running (i.e. V=1). This means
any guest external interrupt which is triggered while the Guest/VM
is not running (i.e. V=0) will be missed on QEMU resulting in Guest
with sluggish response to serial console input and other I/O events.

To solve this, we check and inject interrupt after setting V=1.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-5-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu_helper.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 698389ba1b..e45ca08ea9 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -326,6 +326,19 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool 
enable)
 }
 
 env->virt = set_field(env->virt, VIRT_ONOFF, enable);
+
+if (enable) {
+/*
+ * The guest external interrupts from an interrupt controller are
+ * delivered only when the Guest/VM is running (i.e. V=1). This means
+ * any guest external interrupt which is triggered while the Guest/VM
+ * is not running (i.e. V=0) will be missed on QEMU resulting in guest
+ * with sluggish response to serial console input and other I/O events.
+ *
+ * To solve this, we check and inject interrupt after setting V=1.
+ */
+riscv_cpu_update_mip(env_archcpu(env), 0, 0);
+}
 }
 
 bool riscv_cpu_two_stage_lookup(int mmu_idx)
-- 
2.34.1




[PULL 22/40] target/riscv: Implement AIA hvictl and hviprioX CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The AIA hvictl and hviprioX CSRs allow hypervisor to control
interrupts visible at VS-level. This patch implements AIA hvictl
and hviprioX CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-12-a...@brainfault.org
[ Changes by AF:
 - Fix possible unintilised variable error in rmw_sie()
]
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h |   2 +
 target/riscv/csr.c | 128 -
 target/riscv/machine.c |   2 +
 3 files changed, 131 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 2dc2485bb4..f0e69f2871 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -209,6 +209,7 @@ struct CPURISCVState {
 uint64_t htimedelta;
 
 /* Hypervisor controlled virtual interrupt priorities */
+target_ulong hvictl;
 uint8_t hviprio[64];
 
 /* Upper 64-bits of 128-bit CSRs */
@@ -512,6 +513,7 @@ static inline RISCVMXL riscv_cpu_mxl(CPURISCVState *env)
 return env->misa_mxl;
 }
 #endif
+#define riscv_cpu_mxl_bits(env) (1UL << (4 + riscv_cpu_mxl(env)))
 
 #if defined(TARGET_RISCV32)
 #define cpu_recompute_xl(env)  ((void)(env), MXL_RV32)
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index d8283160b1..46448a2b7e 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -234,6 +234,15 @@ static RISCVException pointer_masking(CPURISCVState *env, 
int csrno)
 return RISCV_EXCP_ILLEGAL_INST;
 }
 
+static int aia_hmode(CPURISCVState *env, int csrno)
+{
+if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return hmode(env, csrno);
+}
+
 static int aia_hmode32(CPURISCVState *env, int csrno)
 {
 if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
@@ -1142,6 +1151,9 @@ static RISCVException rmw_sie64(CPURISCVState *env, int 
csrno,
 uint64_t mask = env->mideleg & S_MODE_INTERRUPTS;
 
 if (riscv_cpu_virt_enabled(env)) {
+if (env->hvictl & HVICTL_VTI) {
+return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+}
 ret = rmw_vsie64(env, CSR_VSIE, ret_val, new_val, wr_mask);
 } else {
 ret = rmw_mie64(env, csrno, ret_val, new_val, wr_mask & mask);
@@ -1162,7 +1174,7 @@ static RISCVException rmw_sie(CPURISCVState *env, int 
csrno,
 RISCVException ret;
 
 ret = rmw_sie64(env, csrno, , new_val, wr_mask);
-if (ret_val) {
+if (ret == RISCV_EXCP_NONE && ret_val) {
 *ret_val = rval;
 }
 
@@ -1355,6 +1367,9 @@ static RISCVException rmw_sip64(CPURISCVState *env, int 
csrno,
 uint64_t mask = env->mideleg & sip_writable_mask;
 
 if (riscv_cpu_virt_enabled(env)) {
+if (env->hvictl & HVICTL_VTI) {
+return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+}
 ret = rmw_vsip64(env, CSR_VSIP, ret_val, new_val, wr_mask);
 } else {
 ret = rmw_mip64(env, csrno, ret_val, new_val, wr_mask & mask);
@@ -1741,6 +1756,110 @@ static RISCVException write_htimedeltah(CPURISCVState 
*env, int csrno,
 return RISCV_EXCP_NONE;
 }
 
+static int read_hvictl(CPURISCVState *env, int csrno, target_ulong *val)
+{
+*val = env->hvictl;
+return RISCV_EXCP_NONE;
+}
+
+static int write_hvictl(CPURISCVState *env, int csrno, target_ulong val)
+{
+env->hvictl = val & HVICTL_VALID_MASK;
+return RISCV_EXCP_NONE;
+}
+
+static int read_hvipriox(CPURISCVState *env, int first_index,
+ uint8_t *iprio, target_ulong *val)
+{
+int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32);
+
+/* First index has to be a multiple of number of irqs per register */
+if (first_index % num_irqs) {
+return (riscv_cpu_virt_enabled(env)) ?
+   RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
+}
+
+/* Fill-up return value */
+*val = 0;
+for (i = 0; i < num_irqs; i++) {
+if (riscv_cpu_hviprio_index2irq(first_index + i, , )) {
+continue;
+}
+if (rdzero) {
+continue;
+}
+*val |= ((target_ulong)iprio[irq]) << (i * 8);
+}
+
+return RISCV_EXCP_NONE;
+}
+
+static int write_hvipriox(CPURISCVState *env, int first_index,
+  uint8_t *iprio, target_ulong val)
+{
+int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32);
+
+/* First index has to be a multiple of number of irqs per register */
+if (first_index % num_irqs) {
+return (riscv_cpu_virt_enabled(env)) ?
+   RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
+}
+
+/* Fill-up priority arrary */
+for (i = 0; i < num_irqs; i++) {
+if (riscv_cpu_hviprio_index2irq(first_index + i, , )) {
+continue;
+}
+if (rdzero) {
+iprio[irq] = 0;
+} else {
+iprio[irq] = (val >> (i * 8)) & 0xff;
+}
+}
+
+return RISCV_EXCP_NONE;
+}

[PULL 13/40] target/riscv: Implement SGEIP bit in hip and hie CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

A hypervisor can optionally take guest external interrupts using
SGEIP bit of hip and hie CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-3-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu_bits.h |  3 +++
 target/riscv/cpu.c  |  3 ++-
 target/riscv/csr.c  | 18 +++---
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 7c87433645..e1256a9982 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -540,6 +540,8 @@ typedef enum RISCVException {
 #define IRQ_S_EXT  9
 #define IRQ_VS_EXT 10
 #define IRQ_M_EXT  11
+#define IRQ_S_GEXT 12
+#define IRQ_LOCAL_MAX  16
 
 /* mip masks */
 #define MIP_USIP   (1 << IRQ_U_SOFT)
@@ -554,6 +556,7 @@ typedef enum RISCVException {
 #define MIP_SEIP   (1 << IRQ_S_EXT)
 #define MIP_VSEIP  (1 << IRQ_VS_EXT)
 #define MIP_MEIP   (1 << IRQ_M_EXT)
+#define MIP_SGEIP  (1 << IRQ_S_GEXT)
 
 /* sip masks */
 #define SIP_SSIP   MIP_SSIP
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 1238aabe3f..e1224d26dc 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -434,6 +434,7 @@ static void riscv_cpu_reset(DeviceState *dev)
 }
 }
 env->mcause = 0;
+env->miclaim = MIP_SGEIP;
 env->pc = env->resetvec;
 env->two_stage_lookup = false;
 /* mmte is supposed to have pm.current hardwired to 1 */
@@ -695,7 +696,7 @@ static void riscv_cpu_init(Object *obj)
 cpu_set_cpustate_pointers(cpu);
 
 #ifndef CONFIG_USER_ONLY
-qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, 12);
+qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, IRQ_LOCAL_MAX);
 #endif /* CONFIG_USER_ONLY */
 }
 
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 41a533a310..c635ffb089 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -461,12 +461,13 @@ static RISCVException read_timeh(CPURISCVState *env, int 
csrno,
 #define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
 #define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
 #define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
+#define HS_MODE_INTERRUPTS (MIP_SGEIP | VS_MODE_INTERRUPTS)
 
 static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
VS_MODE_INTERRUPTS;
 static const target_ulong vs_delegable_ints = VS_MODE_INTERRUPTS;
 static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
- VS_MODE_INTERRUPTS;
+ HS_MODE_INTERRUPTS;
 #define DELEGABLE_EXCPS ((1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | \
  (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | \
  (1ULL << (RISCV_EXCP_ILLEGAL_INST)) | \
@@ -748,7 +749,7 @@ static RISCVException write_mideleg(CPURISCVState *env, int 
csrno,
 {
 env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
 if (riscv_has_ext(env, RVH)) {
-env->mideleg |= VS_MODE_INTERRUPTS;
+env->mideleg |= HS_MODE_INTERRUPTS;
 }
 return RISCV_EXCP_NONE;
 }
@@ -764,6 +765,9 @@ static RISCVException write_mie(CPURISCVState *env, int 
csrno,
 target_ulong val)
 {
 env->mie = (env->mie & ~all_ints) | (val & all_ints);
+if (!riscv_has_ext(env, RVH)) {
+env->mie &= ~MIP_SGEIP;
+}
 return RISCV_EXCP_NONE;
 }
 
@@ -1110,7 +1114,7 @@ static RISCVException rmw_sip(CPURISCVState *env, int 
csrno,
 }
 
 if (ret_value) {
-*ret_value &= env->mideleg;
+*ret_value &= env->mideleg & S_MODE_INTERRUPTS;
 }
 return ret;
 }
@@ -1228,7 +1232,7 @@ static RISCVException rmw_hvip(CPURISCVState *env, int 
csrno,
   write_mask & hvip_writable_mask);
 
 if (ret_value) {
-*ret_value &= hvip_writable_mask;
+*ret_value &= VS_MODE_INTERRUPTS;
 }
 return ret;
 }
@@ -1241,7 +1245,7 @@ static RISCVException rmw_hip(CPURISCVState *env, int 
csrno,
   write_mask & hip_writable_mask);
 
 if (ret_value) {
-*ret_value &= hip_writable_mask;
+*ret_value &= HS_MODE_INTERRUPTS;
 }
 return ret;
 }
@@ -1249,14 +1253,14 @@ static RISCVException rmw_hip(CPURISCVState *env, int 
csrno,
 static RISCVException read_hie(CPURISCVState *env, int csrno,
target_ulong *val)
 {
-*val = env->mie & VS_MODE_INTERRUPTS;
+*val = env->mie & HS_MODE_INTERRUPTS;
 return RISCV_EXCP_NONE;
 }
 
 static RISCVException write_hie(CPURISCVState *env, int csrno,
 

[PULL 17/40] target/riscv: Add AIA cpu feature

2022-02-11 Thread Alistair Francis
From: Anup Patel 

We define a CPU feature for AIA CSR support in RISC-V CPUs which
can be set by machine/device emulation. The RISC-V CSR emulation
will also check this feature for emulating AIA CSRs.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Bin Meng 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-7-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 283a3cda4b..8838c61ae4 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -78,7 +78,8 @@ enum {
 RISCV_FEATURE_MMU,
 RISCV_FEATURE_PMP,
 RISCV_FEATURE_EPMP,
-RISCV_FEATURE_MISA
+RISCV_FEATURE_MISA,
+RISCV_FEATURE_AIA
 };
 
 #define PRIV_VERSION_1_10_0 0x00011000
-- 
2.34.1




[PULL 12/40] target/riscv: Fix trap cause for RV32 HS-mode CSR access from RV64 HS-mode

2022-02-11 Thread Alistair Francis
From: Anup Patel 

We should be returning illegal instruction trap when RV64 HS-mode tries
to access RV32 HS-mode CSR.

Fixes: d6f20dacea51 ("target/riscv: Fix 32-bit HS mode access permissions")
Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Bin Meng 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-2-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/csr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index e5f9d4ef93..41a533a310 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -186,7 +186,7 @@ static RISCVException hmode(CPURISCVState *env, int csrno)
 static RISCVException hmode32(CPURISCVState *env, int csrno)
 {
 if (riscv_cpu_mxl(env) != MXL_RV32) {
-if (riscv_cpu_virt_enabled(env)) {
+if (!riscv_cpu_virt_enabled(env)) {
 return RISCV_EXCP_ILLEGAL_INST;
 } else {
 return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
-- 
2.34.1




[PULL 14/40] target/riscv: Implement hgeie and hgeip CSRs

2022-02-11 Thread Alistair Francis
From: Anup Patel 

The hgeie and hgeip CSRs are required for emulating an external
interrupt controller capable of injecting virtual external interrupt
to Guest/VM running at VS-level.

Signed-off-by: Anup Patel 
Signed-off-by: Anup Patel 
Reviewed-by: Alistair Francis 
Reviewed-by: Frank Chang 
Message-id: 20220204174700.534953-4-a...@brainfault.org
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h|  5 +++
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu.c| 67 +++
 target/riscv/cpu_helper.c | 37 +++--
 target/riscv/csr.c| 43 +
 target/riscv/machine.c|  6 ++--
 6 files changed, 121 insertions(+), 38 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index aacc997d56..f030cb58b2 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -161,6 +161,7 @@ struct CPURISCVState {
 target_ulong priv;
 /* This contains QEMU specific information about the virt state. */
 target_ulong virt;
+target_ulong geilen;
 target_ulong resetvec;
 
 target_ulong mhartid;
@@ -198,6 +199,8 @@ struct CPURISCVState {
 target_ulong htval;
 target_ulong htinst;
 target_ulong hgatp;
+target_ulong hgeie;
+target_ulong hgeip;
 uint64_t htimedelta;
 
 /* Upper 64-bits of 128-bit CSRs */
@@ -391,6 +394,8 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, 
CPUState *cs,
 int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 bool riscv_cpu_fp_enabled(CPURISCVState *env);
+target_ulong riscv_cpu_get_geilen(CPURISCVState *env);
+void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen);
 bool riscv_cpu_vector_enabled(CPURISCVState *env);
 bool riscv_cpu_virt_enabled(CPURISCVState *env);
 void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index e1256a9982..a541705760 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -542,6 +542,7 @@ typedef enum RISCVException {
 #define IRQ_M_EXT  11
 #define IRQ_S_GEXT 12
 #define IRQ_LOCAL_MAX  16
+#define IRQ_LOCAL_GUEST_MAX(TARGET_LONG_BITS - 1)
 
 /* mip masks */
 #define MIP_USIP   (1 << IRQ_U_SOFT)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e1224d26dc..f1c268415a 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -663,27 +663,53 @@ static void riscv_cpu_realize(DeviceState *dev, Error 
**errp)
 static void riscv_cpu_set_irq(void *opaque, int irq, int level)
 {
 RISCVCPU *cpu = RISCV_CPU(opaque);
+CPURISCVState *env = >env;
 
-switch (irq) {
-case IRQ_U_SOFT:
-case IRQ_S_SOFT:
-case IRQ_VS_SOFT:
-case IRQ_M_SOFT:
-case IRQ_U_TIMER:
-case IRQ_S_TIMER:
-case IRQ_VS_TIMER:
-case IRQ_M_TIMER:
-case IRQ_U_EXT:
-case IRQ_S_EXT:
-case IRQ_VS_EXT:
-case IRQ_M_EXT:
-if (kvm_enabled()) {
-kvm_riscv_set_irq(cpu, irq, level);
-} else {
-riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level));
+if (irq < IRQ_LOCAL_MAX) {
+switch (irq) {
+case IRQ_U_SOFT:
+case IRQ_S_SOFT:
+case IRQ_VS_SOFT:
+case IRQ_M_SOFT:
+case IRQ_U_TIMER:
+case IRQ_S_TIMER:
+case IRQ_VS_TIMER:
+case IRQ_M_TIMER:
+case IRQ_U_EXT:
+case IRQ_S_EXT:
+case IRQ_VS_EXT:
+case IRQ_M_EXT:
+ if (kvm_enabled()) {
+kvm_riscv_set_irq(cpu, irq, level);
+ } else {
+riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level));
+ }
+ break;
+default:
+g_assert_not_reached();
 }
-break;
-default:
+} else if (irq < (IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX)) {
+/* Require H-extension for handling guest local interrupts */
+if (!riscv_has_ext(env, RVH)) {
+g_assert_not_reached();
+}
+
+/* Compute bit position in HGEIP CSR */
+irq = irq - IRQ_LOCAL_MAX + 1;
+if (env->geilen < irq) {
+g_assert_not_reached();
+}
+
+/* Update HGEIP CSR */
+env->hgeip &= ~((target_ulong)1 << irq);
+if (level) {
+env->hgeip |= (target_ulong)1 << irq;
+}
+
+/* Update mip.SGEIP bit */
+riscv_cpu_update_mip(cpu, MIP_SGEIP,
+ BOOL_TO_MASK(!!(env->hgeie & env->hgeip)));
+} else {
 g_assert_not_reached();
 }
 }
@@ -696,7 +722,8 @@ static void riscv_cpu_init(Object *obj)
 cpu_set_cpustate_pointers(cpu);
 
 #ifndef CONFIG_USER_ONLY
-qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, IRQ_LOCAL_MAX);
+qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq,
+   

[PULL 11/40] target/riscv: Fix vill field write in vtype

2022-02-11 Thread Alistair Francis
From: LIU Zhiwei 

The guest should be able to set the vill bit as part of vsetvl.

Currently we may set env->vill to 1 in the vsetvl helper, but there
is nowhere that we set it to 0, so once it transitions to 1 it's stuck
there until the system is reset.

Signed-off-by: LIU Zhiwei 
Reviewed-by: Richard Henderson 
Reviewed-by: Alistair Francis 
Message-Id: <20220201064601.41143-1-zhiwei_...@c-sky.com>
Signed-off-by: Alistair Francis 
---
 target/riscv/vector_helper.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index 020d2e841f..3bd4aac9c9 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -71,6 +71,7 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong 
s1,
 env->vl = vl;
 env->vtype = s2;
 env->vstart = 0;
+env->vill = 0;
 return vl;
 }
 
-- 
2.34.1




[PULL 05/40] target/riscv: riscv_tr_init_disas_context: copy pointer-to-cfg into cfg_ptr

2022-02-11 Thread Alistair Francis
From: Philipp Tomsich 

As the number of extensions is growing, copying them individiually
into the DisasContext will scale less and less... instead we populate
a pointer to the RISCVCPUConfig structure in the DisasContext.

This adds an extra indirection when checking for the availability of
an extension (compared to copying the fields into DisasContext).
While not a performance problem today, we can always (shallow) copy
the entire structure into the DisasContext (instead of putting a
pointer to it) if this is ever deemed necessary.

Signed-off-by: Philipp Tomsich 
Reviewed-by: Alistair Francis 
Suggested-by: Richard Henderson 
Reviewed-by: Richard Henderson 
Message-Id: <20220202005249.3566542-3-philipp.toms...@vrull.eu>
Signed-off-by: Alistair Francis 
---
 target/riscv/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index f0bbe80875..49e40735ce 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -76,6 +76,7 @@ typedef struct DisasContext {
 int frm;
 RISCVMXL ol;
 bool virt_enabled;
+const RISCVCPUConfig *cfg_ptr;
 bool ext_ifencei;
 bool ext_zfh;
 bool ext_zfhmin;
@@ -908,6 +909,7 @@ static void riscv_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
 #endif
 ctx->misa_ext = env->misa_ext;
 ctx->frm = -1;  /* unknown rounding mode */
+ctx->cfg_ptr = &(cpu->cfg);
 ctx->ext_ifencei = cpu->cfg.ext_ifencei;
 ctx->ext_zfh = cpu->cfg.ext_zfh;
 ctx->ext_zfhmin = cpu->cfg.ext_zfhmin;
-- 
2.34.1




[PULL 10/40] target/riscv: add a MAINTAINERS entry for XVentanaCondOps

2022-02-11 Thread Alistair Francis
From: Philipp Tomsich 

The XVentanaCondOps extension is supported by VRULL on behalf of the
Ventana Micro.  Add myself as a point-of-contact.

Signed-off-by: Philipp Tomsich 
Reviewed-by: Richard Henderson 
Reviewed-by: Alistair Francis 
Message-Id: <20220202005249.3566542-8-philipp.toms...@vrull.eu>
Signed-off-by: Alistair Francis 
---
 MAINTAINERS | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9814580975..c3f6e70a15 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -286,6 +286,13 @@ F: include/hw/riscv/
 F: linux-user/host/riscv32/
 F: linux-user/host/riscv64/
 
+RISC-V XVentanaCondOps extension
+M: Philipp Tomsich 
+L: qemu-ri...@nongnu.org
+S: Supported
+F: target/riscv/XVentanaCondOps.decode
+F: target/riscv/insn_trans/trans_xventanacondops.c.inc
+
 RENESAS RX CPUs
 R: Yoshinori Sato 
 S: Orphan
-- 
2.34.1




[PULL 09/40] target/riscv: Add XVentanaCondOps custom extension

2022-02-11 Thread Alistair Francis
From: Philipp Tomsich 

This adds the decoder and translation for the XVentanaCondOps custom
extension (vendor-defined by Ventana Micro Systems), which is
documented at 
https://github.com/ventanamicro/ventana-custom-extensions/releases/download/v1.0.0/ventana-custom-extensions-v1.0.0.pdf

This commit then also adds a guard-function (has_XVentanaCondOps_p)
and the decoder function to the table of decoders, enabling the
support for the XVentanaCondOps extension.

Signed-off-by: Philipp Tomsich 
Reviewed-by: Richard Henderson 
Reviewed-by: Alistair Francis 
Message-Id: <20220202005249.3566542-7-philipp.toms...@vrull.eu>
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h|  3 ++
 target/riscv/XVentanaCondOps.decode   | 25 
 target/riscv/cpu.c|  3 ++
 target/riscv/translate.c  | 12 ++
 .../insn_trans/trans_xventanacondops.c.inc| 39 +++
 target/riscv/meson.build  |  1 +
 6 files changed, 83 insertions(+)
 create mode 100644 target/riscv/XVentanaCondOps.decode
 create mode 100644 target/riscv/insn_trans/trans_xventanacondops.c.inc

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 1175915c0d..aacc997d56 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -329,6 +329,9 @@ struct RISCVCPUConfig {
 bool ext_zve32f;
 bool ext_zve64f;
 
+/* Vendor-specific custom extensions */
+bool ext_XVentanaCondOps;
+
 char *priv_spec;
 char *user_spec;
 char *bext_spec;
diff --git a/target/riscv/XVentanaCondOps.decode 
b/target/riscv/XVentanaCondOps.decode
new file mode 100644
index 00..5aef7c3d72
--- /dev/null
+++ b/target/riscv/XVentanaCondOps.decode
@@ -0,0 +1,25 @@
+#
+# RISC-V translation routines for the XVentanaCondOps extension
+#
+# Copyright (c) 2022 Dr. Philipp Tomsich, philipp.toms...@vrull.eu
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Reference: VTx-family custom instructions
+#Custom ISA extensions for Ventana Micro Systems RISC-V cores
+#
(https://github.com/ventanamicro/ventana-custom-extensions/releases/download/v1.0.0/ventana-custom-extensions-v1.0.0.pdf)
+
+# Fields
+%rs2  20:5
+%rs1  15:5
+%rd7:5
+
+# Argument sets
+rd rs1 rs2  !extern
+
+# Formats
+@r ...  . . ... . ... %rs2 %rs1 
%rd
+
+# *** RV64 Custom-3 Extension ***
+vt_maskc   000  . . 110 . 011 @r
+vt_maskcn  000  . . 111 . 011 @r
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5ada71e5bf..1238aabe3f 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -733,6 +733,9 @@ static Property riscv_cpu_properties[] = {
 DEFINE_PROP_BOOL("zbc", RISCVCPU, cfg.ext_zbc, true),
 DEFINE_PROP_BOOL("zbs", RISCVCPU, cfg.ext_zbs, true),
 
+/* Vendor-specific custom extensions */
+DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, 
false),
+
 /* These are experimental so mark with 'x-' */
 DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
 /* ePMP 0.9.3 */
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 30b1b68341..eaf5a72c81 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -116,6 +116,14 @@ static bool always_true_p(DisasContext *ctx  
__attribute__((__unused__)))
 return true;
 }
 
+#define MATERIALISE_EXT_PREDICATE(ext)  \
+static bool has_ ## ext ## _p(DisasContext *ctx)\
+{ \
+return ctx->cfg_ptr->ext_ ## ext ; \
+}
+
+MATERIALISE_EXT_PREDICATE(XVentanaCondOps);
+
 #ifdef TARGET_RISCV32
 #define get_xl(ctx)MXL_RV32
 #elif defined(CONFIG_USER_ONLY)
@@ -854,9 +862,12 @@ static uint32_t opcode_at(DisasContextBase *dcbase, 
target_ulong pc)
 #include "insn_trans/trans_rvb.c.inc"
 #include "insn_trans/trans_rvzfh.c.inc"
 #include "insn_trans/trans_privileged.c.inc"
+#include "insn_trans/trans_xventanacondops.c.inc"
 
 /* Include the auto-generated decoder for 16 bit insn */
 #include "decode-insn16.c.inc"
+/* Include decoders for factored-out extensions */
+#include "decode-XVentanaCondOps.c.inc"
 
 static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
 {
@@ -869,6 +880,7 @@ static void decode_opc(CPURISCVState *env, DisasContext 
*ctx, uint16_t opcode)
 bool (*decode_func)(DisasContext *, uint32_t);
 } decoders[] = {
 { always_true_p,  decode_insn32 },
+{ has_XVentanaCondOps_p,  decode_XVentanaCodeOps },
 };
 
 /* Check for compressed insn */
diff --git a/target/riscv/insn_trans/trans_xventanacondops.c.inc 
b/target/riscv/insn_trans/trans_xventanacondops.c.inc
new file mode 100644
index 00..16849e6d4e
--- /dev/null
+++ b/target/riscv/insn_trans/trans_xventanacondops.c.inc
@@ -0,0 +1,39 @@
+/*
+ * RISC-V translation routines for the XVentanaCondOps extension.
+ *
+ * Copyright (c) 2021-2022 VRULL GmbH.
+ *
+ * This program is free 

[PULL 08/40] target/riscv: iterate over a table of decoders

2022-02-11 Thread Alistair Francis
From: Philipp Tomsich 

To split up the decoder into multiple functions (both to support
vendor-specific opcodes in separate files and to simplify maintenance
of orthogonal extensions), this changes decode_op to iterate over a
table of decoders predicated on guard functions.

This commit only adds the new structure and the table, allowing for
the easy addition of additional decoders in the future.

Signed-off-by: Philipp Tomsich 
Reviewed-by: Richard Henderson 
Reviewed-by: Alistair Francis 
Message-Id: <20220202005249.3566542-6-philipp.toms...@vrull.eu>
Signed-off-by: Alistair Francis 
---
 target/riscv/translate.c | 32 +++-
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index f19d5cd0c0..30b1b68341 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -111,6 +111,11 @@ static inline bool has_ext(DisasContext *ctx, uint32_t ext)
 return ctx->misa_ext & ext;
 }
 
+static bool always_true_p(DisasContext *ctx  __attribute__((__unused__)))
+{
+return true;
+}
+
 #ifdef TARGET_RISCV32
 #define get_xl(ctx)MXL_RV32
 #elif defined(CONFIG_USER_ONLY)
@@ -855,15 +860,26 @@ static uint32_t opcode_at(DisasContextBase *dcbase, 
target_ulong pc)
 
 static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
 {
-/* check for compressed insn */
+/*
+ * A table with predicate (i.e., guard) functions and decoder functions
+ * that are tested in-order until a decoder matches onto the opcode.
+ */
+static const struct {
+bool (*guard_func)(DisasContext *);
+bool (*decode_func)(DisasContext *, uint32_t);
+} decoders[] = {
+{ always_true_p,  decode_insn32 },
+};
+
+/* Check for compressed insn */
 if (extract16(opcode, 0, 2) != 3) {
 if (!has_ext(ctx, RVC)) {
 gen_exception_illegal(ctx);
 } else {
 ctx->opcode = opcode;
 ctx->pc_succ_insn = ctx->base.pc_next + 2;
-if (!decode_insn16(ctx, opcode)) {
-gen_exception_illegal(ctx);
+if (decode_insn16(ctx, opcode)) {
+return;
 }
 }
 } else {
@@ -873,10 +889,16 @@ static void decode_opc(CPURISCVState *env, DisasContext 
*ctx, uint16_t opcode)
  ctx->base.pc_next + 2));
 ctx->opcode = opcode32;
 ctx->pc_succ_insn = ctx->base.pc_next + 4;
-if (!decode_insn32(ctx, opcode32)) {
-gen_exception_illegal(ctx);
+
+for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i) {
+if (decoders[i].guard_func(ctx) &&
+decoders[i].decode_func(ctx, opcode32)) {
+return;
+}
 }
 }
+
+gen_exception_illegal(ctx);
 }
 
 static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
-- 
2.34.1




[PULL 04/40] target/riscv: refactor (anonymous struct) RISCVCPU.cfg into 'struct RISCVCPUConfig'

2022-02-11 Thread Alistair Francis
From: Philipp Tomsich 

Signed-off-by: Philipp Tomsich 
Reviewed-by: Alistair Francis 
Suggested-by: Richard Henderson 
Reviewed-by: Richard Henderson 
Message-Id: <20220202005249.3566542-2-philipp.toms...@vrull.eu>
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.h | 78 --
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 55635d68d5..1175915c0d 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -303,6 +303,46 @@ struct RISCVCPUClass {
 DeviceReset parent_reset;
 };
 
+struct RISCVCPUConfig {
+bool ext_i;
+bool ext_e;
+bool ext_g;
+bool ext_m;
+bool ext_a;
+bool ext_f;
+bool ext_d;
+bool ext_c;
+bool ext_s;
+bool ext_u;
+bool ext_h;
+bool ext_j;
+bool ext_v;
+bool ext_zba;
+bool ext_zbb;
+bool ext_zbc;
+bool ext_zbs;
+bool ext_counters;
+bool ext_ifencei;
+bool ext_icsr;
+bool ext_zfh;
+bool ext_zfhmin;
+bool ext_zve32f;
+bool ext_zve64f;
+
+char *priv_spec;
+char *user_spec;
+char *bext_spec;
+char *vext_spec;
+uint16_t vlen;
+uint16_t elen;
+bool mmu;
+bool pmp;
+bool epmp;
+uint64_t resetvec;
+};
+
+typedef struct RISCVCPUConfig RISCVCPUConfig;
+
 /**
  * RISCVCPU:
  * @env: #CPURISCVState
@@ -320,43 +360,7 @@ struct RISCVCPU {
 char *dyn_vreg_xml;
 
 /* Configuration Settings */
-struct {
-bool ext_i;
-bool ext_e;
-bool ext_g;
-bool ext_m;
-bool ext_a;
-bool ext_f;
-bool ext_d;
-bool ext_c;
-bool ext_s;
-bool ext_u;
-bool ext_h;
-bool ext_j;
-bool ext_v;
-bool ext_zba;
-bool ext_zbb;
-bool ext_zbc;
-bool ext_zbs;
-bool ext_counters;
-bool ext_ifencei;
-bool ext_icsr;
-bool ext_zfh;
-bool ext_zfhmin;
-bool ext_zve32f;
-bool ext_zve64f;
-
-char *priv_spec;
-char *user_spec;
-char *bext_spec;
-char *vext_spec;
-uint16_t vlen;
-uint16_t elen;
-bool mmu;
-bool pmp;
-bool epmp;
-uint64_t resetvec;
-} cfg;
+RISCVCPUConfig cfg;
 };
 
 static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext)
-- 
2.34.1




[PULL 03/40] target/riscv: correct "code should not be reached" for x-rv128

2022-02-11 Thread Alistair Francis
From: Frédéric Pétrot 

The addition of uxl support in gdbstub adds a few checks on the maximum
register length, but omitted MXL_RV128, an experimental feature.
This patch makes rv128 react as rv64, as previously.

Signed-off-by: Frédéric Pétrot 
Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: LIU Zhiwei 
Reviewed-by: Alistair Francis 
Message-id: 20220124202456.420258-1-frederic.pet...@univ-grenoble-alpes.fr
Signed-off-by: Alistair Francis 
---
 target/riscv/cpu.c | 3 +--
 target/riscv/gdbstub.c | 3 +++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 1cb0436187..5ada71e5bf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -528,9 +528,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error 
**errp)
 switch (env->misa_mxl_max) {
 #ifdef TARGET_RISCV64
 case MXL_RV64:
-cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
-break;
 case MXL_RV128:
+cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
 break;
 #endif
 case MXL_RV32:
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index f531a74c2f..9ed049c29e 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -64,6 +64,7 @@ int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray 
*mem_buf, int n)
 case MXL_RV32:
 return gdb_get_reg32(mem_buf, tmp);
 case MXL_RV64:
+case MXL_RV128:
 return gdb_get_reg64(mem_buf, tmp);
 default:
 g_assert_not_reached();
@@ -84,6 +85,7 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t 
*mem_buf, int n)
 length = 4;
 break;
 case MXL_RV64:
+case MXL_RV128:
 if (env->xl < MXL_RV64) {
 tmp = (int32_t)ldq_p(mem_buf);
 } else {
@@ -420,6 +422,7 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
  1, "riscv-32bit-virtual.xml", 0);
 break;
 case MXL_RV64:
+case MXL_RV128:
 gdb_register_coprocessor(cs, riscv_gdb_get_virtual,
  riscv_gdb_set_virtual,
  1, "riscv-64bit-virtual.xml", 0);
-- 
2.34.1




[PULL 06/40] target/riscv: access configuration through cfg_ptr in DisasContext

2022-02-11 Thread Alistair Francis
From: Philipp Tomsich 

The implementation in trans_{rvi,rvv,rvzfh}.c.inc accesses the shallow
copies (in DisasContext) of some of the elements available in the
RISCVCPUConfig structure.  This commit redirects accesses to use the
cfg_ptr copied into DisasContext and removes the shallow copies.

Signed-off-by: Philipp Tomsich 
Reviewed-by: Alistair Francis 
Suggested-by: Richard Henderson 
Reviewed-by: Richard Henderson 
Message-Id: <20220202005249.3566542-4-philipp.toms...@vrull.eu>
[ Changes by AF:
 - Fixup checkpatch failures
]
Signed-off-by: Alistair Francis 
---
 target/riscv/translate.c  |  14 ---
 target/riscv/insn_trans/trans_rvi.c.inc   |   2 +-
 target/riscv/insn_trans/trans_rvv.c.inc   | 146 ++
 target/riscv/insn_trans/trans_rvzfh.c.inc |   4 +-
 4 files changed, 97 insertions(+), 69 deletions(-)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 49e40735ce..f19d5cd0c0 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -77,11 +77,6 @@ typedef struct DisasContext {
 RISCVMXL ol;
 bool virt_enabled;
 const RISCVCPUConfig *cfg_ptr;
-bool ext_ifencei;
-bool ext_zfh;
-bool ext_zfhmin;
-bool ext_zve32f;
-bool ext_zve64f;
 bool hlsx;
 /* vector extension */
 bool vill;
@@ -99,8 +94,6 @@ typedef struct DisasContext {
  */
 int8_t lmul;
 uint8_t sew;
-uint16_t vlen;
-uint16_t elen;
 target_ulong vstart;
 bool vl_eq_vlmax;
 uint8_t ntemp;
@@ -910,13 +903,6 @@ static void riscv_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
 ctx->misa_ext = env->misa_ext;
 ctx->frm = -1;  /* unknown rounding mode */
 ctx->cfg_ptr = &(cpu->cfg);
-ctx->ext_ifencei = cpu->cfg.ext_ifencei;
-ctx->ext_zfh = cpu->cfg.ext_zfh;
-ctx->ext_zfhmin = cpu->cfg.ext_zfhmin;
-ctx->ext_zve32f = cpu->cfg.ext_zve32f;
-ctx->ext_zve64f = cpu->cfg.ext_zve64f;
-ctx->vlen = cpu->cfg.vlen;
-ctx->elen = cpu->cfg.elen;
 ctx->mstatus_hs_fs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_FS);
 ctx->mstatus_hs_vs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_VS);
 ctx->hlsx = FIELD_EX32(tb_flags, TB_FLAGS, HLSX);
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc 
b/target/riscv/insn_trans/trans_rvi.c.inc
index 3cd1b3f877..f1342f30f8 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -806,7 +806,7 @@ static bool trans_fence(DisasContext *ctx, arg_fence *a)
 
 static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
 {
-if (!ctx->ext_ifencei) {
+if (!ctx->cfg_ptr->ext_ifencei) {
 return false;
 }
 
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc 
b/target/riscv/insn_trans/trans_rvv.c.inc
index f85a9e83b4..275fded6e4 100644
--- a/target/riscv/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -74,7 +74,7 @@ static bool require_zve32f(DisasContext *s)
 }
 
 /* Zve32f doesn't support FP64. (Section 18.2) */
-return s->ext_zve32f ? s->sew <= MO_32 : true;
+return s->cfg_ptr->ext_zve32f ? s->sew <= MO_32 : true;
 }
 
 static bool require_scale_zve32f(DisasContext *s)
@@ -85,7 +85,7 @@ static bool require_scale_zve32f(DisasContext *s)
 }
 
 /* Zve32f doesn't support FP64. (Section 18.2) */
-return s->ext_zve64f ? s->sew <= MO_16 : true;
+return s->cfg_ptr->ext_zve64f ? s->sew <= MO_16 : true;
 }
 
 static bool require_zve64f(DisasContext *s)
@@ -96,7 +96,7 @@ static bool require_zve64f(DisasContext *s)
 }
 
 /* Zve64f doesn't support FP64. (Section 18.2) */
-return s->ext_zve64f ? s->sew <= MO_32 : true;
+return s->cfg_ptr->ext_zve64f ? s->sew <= MO_32 : true;
 }
 
 static bool require_scale_zve64f(DisasContext *s)
@@ -107,7 +107,7 @@ static bool require_scale_zve64f(DisasContext *s)
 }
 
 /* Zve64f doesn't support FP64. (Section 18.2) */
-return s->ext_zve64f ? s->sew <= MO_16 : true;
+return s->cfg_ptr->ext_zve64f ? s->sew <= MO_16 : true;
 }
 
 /* Destination vector register group cannot overlap source mask register. */
@@ -174,7 +174,8 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, 
TCGv s2)
 TCGv s1, dst;
 
 if (!require_rvv(s) ||
-!(has_ext(s, RVV) || s->ext_zve32f || s->ext_zve64f)) {
+!(has_ext(s, RVV) || s->cfg_ptr->ext_zve32f ||
+  s->cfg_ptr->ext_zve64f)) {
 return false;
 }
 
@@ -210,7 +211,8 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, 
TCGv s2)
 TCGv dst;
 
 if (!require_rvv(s) ||
-!(has_ext(s, RVV) || s->ext_zve32f || s->ext_zve64f)) {
+!(has_ext(s, RVV) || s->cfg_ptr->ext_zve32f ||
+  s->cfg_ptr->ext_zve64f)) {
 return false;
 }
 
@@ -248,7 +250,7 @@ static bool trans_vsetivli(DisasContext *s, arg_vsetivli *a)
 /* vector register offset from env */
 static uint32_t vreg_ofs(DisasContext *s, int reg)
 {
-return offsetof(CPURISCVState, vreg) + reg * 

[PULL 01/40] include: hw: remove ibex_plic.h

2022-02-11 Thread Alistair Francis
From: Wilfred Mallawa 

This patch removes the left-over/unused `ibex_plic.h` file. Previously
used by opentitan, which now follows the RISC-V standard and uses the
SiFivePlicState.

Fixes: 434e7e021 ("hw/intc: Remove the Ibex PLIC")
Signed-off-by: Wilfred Mallawa 
Reviewed-by: Alistair Francis 
Reviewed-by: Philippe Mathieu-Daudé 
Message-id: 20220121055005.3159846-1-alistair.fran...@opensource.wdc.com
Signed-off-by: Alistair Francis 
---
 include/hw/intc/ibex_plic.h | 67 -
 1 file changed, 67 deletions(-)
 delete mode 100644 include/hw/intc/ibex_plic.h

diff --git a/include/hw/intc/ibex_plic.h b/include/hw/intc/ibex_plic.h
deleted file mode 100644
index d596436e06..00
--- a/include/hw/intc/ibex_plic.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * QEMU RISC-V lowRISC Ibex PLIC
- *
- * Copyright (c) 2020 Western Digital
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see .
- */
-
-#ifndef HW_IBEX_PLIC_H
-#define HW_IBEX_PLIC_H
-
-#include "hw/sysbus.h"
-#include "qom/object.h"
-
-#define TYPE_IBEX_PLIC "ibex-plic"
-OBJECT_DECLARE_SIMPLE_TYPE(IbexPlicState, IBEX_PLIC)
-
-struct IbexPlicState {
-/*< private >*/
-SysBusDevice parent_obj;
-
-/*< public >*/
-MemoryRegion mmio;
-
-uint32_t *pending;
-uint32_t *hidden_pending;
-uint32_t *claimed;
-uint32_t *source;
-uint32_t *priority;
-uint32_t *enable;
-uint32_t threshold;
-uint32_t claim;
-
-/* config */
-uint32_t num_cpus;
-uint32_t num_sources;
-
-uint32_t pending_base;
-uint32_t pending_num;
-
-uint32_t source_base;
-uint32_t source_num;
-
-uint32_t priority_base;
-uint32_t priority_num;
-
-uint32_t enable_base;
-uint32_t enable_num;
-
-uint32_t threshold_base;
-
-uint32_t claim_base;
-
-qemu_irq *external_irqs;
-};
-
-#endif /* HW_IBEX_PLIC_H */
-- 
2.34.1




[PULL 07/40] target/riscv: access cfg structure through DisasContext

2022-02-11 Thread Alistair Francis
From: Philipp Tomsich 

The Zb[abcs] support code still uses the RISCV_CPU macros to access
the configuration information (i.e., check whether an extension is
available/enabled).  Now that we provide this information directly
from DisasContext, we can access this directly via the cfg_ptr field.

Signed-off-by: Philipp Tomsich 
Reviewed-by: Alistair Francis 
Suggested-by: Richard Henderson 
Reviewed-by: Richard Henderson 
Message-Id: <20220202005249.3566542-5-philipp.toms...@vrull.eu>
Signed-off-by: Alistair Francis 
---
 target/riscv/insn_trans/trans_rvb.c.inc | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/target/riscv/insn_trans/trans_rvb.c.inc 
b/target/riscv/insn_trans/trans_rvb.c.inc
index 810431a1d6..f9bd3b7ec4 100644
--- a/target/riscv/insn_trans/trans_rvb.c.inc
+++ b/target/riscv/insn_trans/trans_rvb.c.inc
@@ -19,25 +19,25 @@
  */
 
 #define REQUIRE_ZBA(ctx) do {\
-if (!RISCV_CPU(ctx->cs)->cfg.ext_zba) {  \
+if (ctx->cfg_ptr->ext_zba) { \
 return false;\
 }\
 } while (0)
 
 #define REQUIRE_ZBB(ctx) do {\
-if (!RISCV_CPU(ctx->cs)->cfg.ext_zbb) {  \
+if (ctx->cfg_ptr->ext_zbb) { \
 return false;\
 }\
 } while (0)
 
 #define REQUIRE_ZBC(ctx) do {\
-if (!RISCV_CPU(ctx->cs)->cfg.ext_zbc) {  \
+if (ctx->cfg_ptr->ext_zbc) { \
 return false;\
 }\
 } while (0)
 
 #define REQUIRE_ZBS(ctx) do {\
-if (!RISCV_CPU(ctx->cs)->cfg.ext_zbs) {  \
+if (ctx->cfg_ptr->ext_zbs) { \
 return false;\
 }\
 } while (0)
-- 
2.34.1




[PULL 02/40] Allow setting up to 8 bytes with the generic loader

2022-02-11 Thread Alistair Francis
From: Petr Tesarik 

The documentation for the generic loader says that "the maximum size of
the data is 8 bytes". However, attempts to set data-len=8 trigger the
following assertion failure:

../hw/core/generic-loader.c:59: generic_loader_reset: Assertion `s->data_len < 
sizeof(s->data)' failed.

The type of s->data is uint64_t (i.e. 8 bytes long), so I believe this
assert should use <= instead of <.

Fixes: e481a1f63c93 ("generic-loader: Add a generic loader")
Signed-off-by: Petr Tesarik 
Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Alistair Francis 
Message-id: 20220120092715.7805-1-ptesa...@suse.com
Signed-off-by: Alistair Francis 
---
 hw/core/generic-loader.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c
index 9a24ffb880..504ed7ca72 100644
--- a/hw/core/generic-loader.c
+++ b/hw/core/generic-loader.c
@@ -56,7 +56,7 @@ static void generic_loader_reset(void *opaque)
 }
 
 if (s->data_len) {
-assert(s->data_len < sizeof(s->data));
+assert(s->data_len <= sizeof(s->data));
 dma_memory_write(s->cpu->as, s->addr, >data, s->data_len,
  MEMTXATTRS_UNSPECIFIED);
 }
-- 
2.34.1




[PULL 00/40] riscv-to-apply queue

2022-02-11 Thread Alistair Francis
From: Alistair Francis 

The following changes since commit 0a301624c2f4ced3331ffd5bce85b4274fe132af:

  Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20220208' 
into staging (2022-02-08 11:40:08 +)

are available in the Git repository at:

  g...@github.com:alistair23/qemu.git tags/pull-riscv-to-apply-20220212

for you to fetch changes up to 31d69b66ed89fa0f66d4e5a15e9664c92c3ed8f8:

  docs/system: riscv: Update description of CPU (2022-02-11 18:31:29 +1000)


Fourth RISC-V PR for QEMU 7.0

 * Remove old Ibex PLIC header file
 * Allow writing 8 bytes with generic loader
 * Fixes for RV128
 * Refactor RISC-V CPU configs
 * Initial support for XVentanaCondOps custom extension
 * Fix for vill field in vtype
 * Fix trap cause for RV32 HS-mode CSR access from RV64 HS-mode
 * RISC-V AIA support for virt machine
 * Support for svnapot, svinval and svpbmt extensions


Anup Patel (23):
  target/riscv: Fix trap cause for RV32 HS-mode CSR access from RV64 HS-mode
  target/riscv: Implement SGEIP bit in hip and hie CSRs
  target/riscv: Implement hgeie and hgeip CSRs
  target/riscv: Improve delivery of guest external interrupts
  target/riscv: Allow setting CPU feature from machine/device emulation
  target/riscv: Add AIA cpu feature
  target/riscv: Add defines for AIA CSRs
  target/riscv: Allow AIA device emulation to set ireg rmw callback
  target/riscv: Implement AIA local interrupt priorities
  target/riscv: Implement AIA CSRs for 64 local interrupts on RV32
  target/riscv: Implement AIA hvictl and hviprioX CSRs
  target/riscv: Implement AIA interrupt filtering CSRs
  target/riscv: Implement AIA mtopi, stopi, and vstopi CSRs
  target/riscv: Implement AIA xiselect and xireg CSRs
  target/riscv: Implement AIA IMSIC interface CSRs
  hw/riscv: virt: Use AIA INTC compatible string when available
  target/riscv: Allow users to force enable AIA CSRs in HART
  hw/intc: Add RISC-V AIA APLIC device emulation
  hw/riscv: virt: Add optional AIA APLIC support to virt machine
  hw/intc: Add RISC-V AIA IMSIC device emulation
  hw/riscv: virt: Add optional AIA IMSIC support to virt machine
  docs/system: riscv: Document AIA options for virt machine
  hw/riscv: virt: Increase maximum number of allowed CPUs

Frédéric Pétrot (1):
  target/riscv: correct "code should not be reached" for x-rv128

Guo Ren (1):
  target/riscv: Ignore reserved bits in PTE for RV64

LIU Zhiwei (1):
  target/riscv: Fix vill field write in vtype

Petr Tesarik (1):
  Allow setting up to 8 bytes with the generic loader

Philipp Tomsich (7):
  target/riscv: refactor (anonymous struct) RISCVCPU.cfg into 'struct 
RISCVCPUConfig'
  target/riscv: riscv_tr_init_disas_context: copy pointer-to-cfg into 
cfg_ptr
  target/riscv: access configuration through cfg_ptr in DisasContext
  target/riscv: access cfg structure through DisasContext
  target/riscv: iterate over a table of decoders
  target/riscv: Add XVentanaCondOps custom extension
  target/riscv: add a MAINTAINERS entry for XVentanaCondOps

Weiwei Li (4):
  target/riscv: add PTE_A/PTE_D/PTE_U bits check for inner PTE
  target/riscv: add support for svnapot extension
  target/riscv: add support for svinval extension
  target/riscv: add support for svpbmt extension

Wilfred Mallawa (1):
  include: hw: remove ibex_plic.h

Yu Li (1):
  docs/system: riscv: Update description of CPU

 docs/system/riscv/virt.rst |   22 +-
 include/hw/intc/ibex_plic.h|   67 -
 include/hw/intc/riscv_aplic.h  |   79 ++
 include/hw/intc/riscv_imsic.h  |   68 ++
 include/hw/riscv/virt.h|   41 +-
 target/riscv/cpu.h |  169 ++-
 target/riscv/cpu_bits.h|  129 ++
 target/riscv/XVentanaCondOps.decode|   25 +
 target/riscv/insn32.decode |7 +
 hw/core/generic-loader.c   |2 +-
 hw/intc/riscv_aplic.c  |  978 +++
 hw/intc/riscv_imsic.c  |  448 +++
 hw/riscv/virt.c|  712 +--
 target/riscv/cpu.c |  113 +-
 target/riscv/cpu_helper.c  |  377 +-
 target/riscv/csr.c | 1282 ++--
 target/riscv/gdbstub.c |3 +
 target/riscv/machine.c |   24 +-
 target/riscv/translate.c   |   61 +-
 target/riscv/vector_helper.c   |1 +
 target/riscv/insn_trans/trans_rvb.c.inc|8 +-
 

Re: [PATCH v4 04/12] mm/shmem: Support memfile_notifier

2022-02-11 Thread Andy Lutomirski

On 1/18/22 05:21, Chao Peng wrote:

It maintains a memfile_notifier list in shmem_inode_info structure and
implements memfile_pfn_ops callbacks defined by memfile_notifier. It
then exposes them to memfile_notifier via
shmem_get_memfile_notifier_info.

We use SGP_NOALLOC in shmem_get_lock_pfn since the pages should be
allocated by userspace for private memory. If there is no pages
allocated at the offset then error should be returned so KVM knows that
the memory is not private memory.

Signed-off-by: Kirill A. Shutemov 
Signed-off-by: Chao Peng 



  static int memfile_get_notifier_info(struct inode *inode,
 struct memfile_notifier_list **list,
 struct memfile_pfn_ops **ops)
  {
-   return -EOPNOTSUPP;
+   int ret = -EOPNOTSUPP;
+#ifdef CONFIG_SHMEM
+   ret = shmem_get_memfile_notifier_info(inode, list, ops);
+#endif
+   return ret;
  }



+int shmem_get_memfile_notifier_info(struct inode *inode,
+   struct memfile_notifier_list **list,
+   struct memfile_pfn_ops **ops)
+{
+   struct shmem_inode_info *info;
+
+   if (!shmem_mapping(inode->i_mapping))
+   return -EINVAL;
+
+   info = SHMEM_I(inode);
+   *list = >memfile_notifiers;
+   if (ops)
+   *ops = _pfn_ops;
+
+   return 0;


I can't wrap my head around exactly who is supposed to call these 
functions and when, but there appears to be a missing check that the 
inode is actually a shmem inode.


What is this code trying to do?  It's very abstract.



Re: [PATCH v4 01/12] mm/shmem: Introduce F_SEAL_INACCESSIBLE

2022-02-11 Thread Andy Lutomirski

On 1/18/22 05:21, Chao Peng wrote:

From: "Kirill A. Shutemov" 

Introduce a new seal F_SEAL_INACCESSIBLE indicating the content of
the file is inaccessible from userspace through ordinary MMU access
(e.g., read/write/mmap). However, the file content can be accessed
via a different mechanism (e.g. KVM MMU) indirectly.

It provides semantics required for KVM guest private memory support
that a file descriptor with this seal set is going to be used as the
source of guest memory in confidential computing environments such
as Intel TDX/AMD SEV but may not be accessible from host userspace.

At this time only shmem implements this seal.



I don't dislike this *that* much, but I do dislike this. 
F_SEAL_INACCESSIBLE essentially transmutes a memfd into a different type 
of object.  While this can apparently be done successfully and without 
races (as in this code), it's at least awkward.  I think that either 
creating a special inaccessible memfd should be a single operation that 
create the correct type of object or there should be a clear 
justification for why it's a two-step process.


(Imagine if the way to create an eventfd would be to call 
timerfd_create() and then do a special fcntl to turn it into an eventfd 
but only if it's not currently armed.  This would be weird.)




[RFC PATCH 25/25] virtio-snd: Replaced AUD_log with tracepoints

2022-02-11 Thread Shreyansh Chouhan
Replaced the use of AUD_log via macros in virtio sound with
tracepoints.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/trace-events | 14 +++
 hw/audio/virtio-snd.c | 55 +--
 2 files changed, 36 insertions(+), 33 deletions(-)

diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index e0e71cd9b1..a747648e4d 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -11,3 +11,17 @@ hda_audio_running(const char *stream, int nr, bool running) 
"st %s, nr %d, run %
 hda_audio_format(const char *stream, int chan, const char *fmt, int freq) "st 
%s, %d x %s @ %d Hz"
 hda_audio_adjust(const char *stream, int pos) "st %s, pos %d"
 hda_audio_overrun(const char *stream) "st %s"
+
+#virtio-snd.c
+virtio_snd_pcm_stream_flush(int stream) "flushing st %d"
+virtio_snd_handle_jack_info(int jack) "VIRTIO_SND_JACK_INFO called for jack %d"
+virtio_snd_handle_jack_remap(void) "VIRTIO_SND_PCM_JACK_REMAP called"
+virtio_snd_handle_pcm_info(int stream) "VIRTIO_SND_PCM_INFO called for stream 
%d"
+virtio_snd_handle_pcm_set_params(int stream) "VIRTIO_SND_PCM_SET_PARAMS called 
for stream %d"
+virtio_snd_handle_pcm_start(int stream) "VIRTIO_SND_PCM_START called for 
stream %d"
+virtio_snd_handle_pcm_stop(int stream) "VIRTIO_SND_PCM_STOP called for stream 
%id"
+virtio_snd_handle_pcm_release(int stream) "VIRTIO_SND_PCM_RELEASE called for 
stream %id"
+virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called"
+virtio_snd_output_cb(int to_play, int written) "to play: %d, written: %d"
+virtio_snd_handle_xfer(void) "tx/rx queue callback called"
+virtio_snd_handle_event(void) "event queue callback called"
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 81a478d039..38a3b5e555 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -39,10 +39,6 @@
 #define VIRTIO_SOUND_HDA_FN_NID_OUT 0
 #define VIRTIO_SOUND_HDA_FN_NID_IN 1
 
-#define virtio_snd_log(...) AUD_log("virtio sound info", __VA_ARGS__)
-#define virtio_snd_warn(...) AUD_log("virtio sound warn", __VA_ARGS__)
-#define virtio_snd_err(...) AUD_log("virtio sound err", __VA_ARGS__)
-
 static void virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
 {
 VirtIOSound *s = VIRTIO_SOUND(vdev);
@@ -125,7 +121,7 @@ static uint32_t virtio_snd_handle_jack_info(VirtIOSound *s,
 
 if (iov_size(elem->in_sg, elem->in_num) <
 sizeof(virtio_snd_hdr) + req.count * req.size) {
-virtio_snd_err("jack info: buffer too small got: %lu needed: %lu\n",
+error_report("jack info: buffer too small got: %lu needed: %lu\n",
iov_size(elem->in_sg, elem->in_num),
sizeof(virtio_snd_hdr) + req.count * req.size);
 resp.code = VIRTIO_SND_S_BAD_MSG;
@@ -134,9 +130,10 @@ static uint32_t virtio_snd_handle_jack_info(VirtIOSound *s,
 
 virtio_snd_jack_info *jack_info = g_new0(virtio_snd_jack_info, req.count);
 for (int i = req.start_id; i < req.count + req.start_id; i++) {
+trace_virtio_snd_handle_jack_info(i);
 virtio_snd_jack *jack = virtio_snd_get_jack(s, i);
 if (!jack) {
-virtio_snd_err("Invalid jack id: %d\n", i);
+error_report("Invalid jack id: %d\n", i);
 resp.code = VIRTIO_SND_S_BAD_MSG;
 goto done;
 }
@@ -180,6 +177,7 @@ static uint32_t virtio_snd_handle_jack_remap(VirtIOSound *s,
 virtio_snd_hdr resp;
 resp.code = VIRTIO_SND_S_OK;
 
+trace_virtio_snd_handle_jack_remap();
 /* TODO: implement remap */
 
 size_t sz;
@@ -202,7 +200,6 @@ static virtio_snd_pcm_stream 
*virtio_snd_pcm_get_stream(VirtIOSound *s,
 uint32_t stream)
 {
 if (stream >= s->snd_conf.streams) {
-virtio_snd_err("Invalid stream request %d\n", stream);
 return NULL;
 }
 return s->streams[stream];
@@ -218,7 +215,6 @@ static virtio_snd_pcm_params 
*virtio_snd_pcm_get_params(VirtIOSound *s,
 uint32_t stream)
 {
 if (stream >= s->snd_conf.streams) {
-virtio_snd_err("Invalid stream request %d\n", stream);
 return NULL;
 }
 return s->pcm_params[stream];
@@ -243,7 +239,7 @@ static uint32_t virtio_snd_handle_pcm_info(VirtIOSound *s,
 virtio_snd_hdr resp;
 if (iov_size(elem->in_sg, elem->in_num) <
 sizeof(virtio_snd_hdr) + req.size * req.count) {
-virtio_snd_err("pcm info: buffer too small, got: %lu, needed: %lu\n",
+error_report("pcm info: buffer too small, got: %lu, needed: %lu\n",
 iov_size(elem->in_sg, elem->in_num),
 sizeof(virtio_snd_pcm_info));
 resp.code = VIRTIO_SND_S_BAD_MSG;
@@ -253,10 +249,11 @@ static uint32_t virtio_snd_handle_pcm_info(VirtIOSound *s,
 virtio_snd_pcm_stream *stream;
 virtio_snd_pcm_info *pcm_info = g_new0(virtio_snd_pcm_info, req.count);
 for (int i = req.start_id; i < req.start_id + 

[RFC PATCH 24/25] virtio-snd: Add event vq and a handler stub

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 80a34e1207..81a478d039 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -1080,6 +1080,18 @@ static void virtio_snd_handle_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 }
 }
 
+/*
+ * The event virtqueue handler.
+ * Not implemented yet.
+ *
+ * @vdev: VirtIOSound card
+ * @vq: event vq
+ */
+static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq)
+{
+virtio_snd_log("event queue callback called\n");
+}
+
 /*
  * Initializes the VirtIOSound card device. Validates the configuration
  * passed by the command line. Initializes the virtqueues. Allocates resources
@@ -1124,6 +1136,7 @@ static void virtio_snd_device_realize(DeviceState *dev, 
Error **errp)
 default_params.rate = VIRTIO_SND_PCM_RATE_44100;
 
 s->ctrl_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
+s->event_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_event);
 s->tx_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_xfer);
 s->rx_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_xfer);
 
@@ -1192,6 +1205,7 @@ static void virtio_snd_device_unrealize(DeviceState *dev)
 s->jacks = NULL;
 
 virtio_delete_queue(s->ctrl_vq);
+virtio_delete_queue(s->event_vq);
 virtio_delete_queue(s->tx_vq);
 virtio_delete_queue(s->rx_vq);
 }
-- 
2.31.1




[RFC PATCH 21/25] virtio-snd: Replaced goto with if else

2022-02-11 Thread Shreyansh Chouhan
Removed goto from the ctrl vq handler and added an if else
branch for error handling.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 21 -
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 7b80a92737..cb83db0e89 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -947,7 +947,7 @@ static uint32_t virtio_snd_handle_pcm_release(VirtIOSound 
*s,
 static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
 {
 VirtIOSound *s = VIRTIO_SOUND(vdev);
-virtio_snd_hdr ctrl;
+virtio_snd_hdr ctrl, resp;
 
 VirtQueueElement *elem = NULL;
 size_t sz;
@@ -959,7 +959,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 if (!elem) {
 break;
 }
-if (iov_size(elem->in_sg, elem->in_num) < sizeof(ctrl) ||
+if (iov_size(elem->in_sg, elem->in_num) < sizeof(resp) ||
 iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) {
 virtio_snd_err("virtio-snd ctrl missing headers\n");
 virtqueue_detach_element(vq, elem, 0);
@@ -975,41 +975,36 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 if (sz != sizeof(ctrl)) {
 /* error */
 virtio_snd_err("virtio snd ctrl could not read header\n");
+resp.code = VIRTIO_SND_S_BAD_MSG;
 } else if (ctrl.code == VIRTIO_SND_R_JACK_INFO) {
 sz = virtio_snd_handle_jack_info(s, elem);
-goto done;
 } else if (ctrl.code == VIRTIO_SND_R_JACK_REMAP) {
 sz = virtio_snd_handle_jack_remap(s, elem);
-goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_INFO) {
 sz = virtio_snd_handle_pcm_info(s, elem);
-goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_SET_PARAMS) {
 sz = virtio_snd_handle_pcm_set_params(s, elem);
-goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_PREPARE) {
 sz = virtio_snd_handle_pcm_prepare(s, elem);
-goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_START) {
 sz = virtio_snd_handle_pcm_start_stop(s, elem, true);
-goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_STOP) {
 sz = virtio_snd_handle_pcm_start_stop(s, elem, false);
 } else if (ctrl.code == VIRTIO_SND_R_PCM_RELEASE) {
 sz = virtio_snd_handle_pcm_release(s, elem);
 } else if (ctrl.code == VIRTIO_SND_R_CHMAP_INFO) {
 virtio_snd_log("VIRTIO_SND_R_CHMAP_INFO");
-goto done;
 } else {
 /* error */
 virtio_snd_err("virtio snd header not recognized: %d\n", 
ctrl.code);
+resp.code = VIRTIO_SND_S_BAD_MSG;
 }
 
-virtio_snd_hdr resp;
-resp.code = VIRTIO_SND_S_OK;
-sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
+if (resp.code == VIRTIO_SND_S_BAD_MSG) {
+sz = iov_from_buf(elem->in_sg, elem->in_num, 0, ,
+  sizeof(resp));
+}
 
-done:
 virtqueue_push(vq, elem, sz);
 virtio_notify(vdev, vq);
 g_free(iov2);
-- 
2.31.1




[RFC PATCH 17/25] virtio-snd: Add default configs to realize fn

2022-02-11 Thread Shreyansh Chouhan
Added default configurations for streams and jacks in the
realize function.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 40 
 1 file changed, 40 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index b7c4dc691d..5ed8e524a6 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -698,11 +698,51 @@ static void virtio_snd_device_realize(DeviceState *dev, 
Error **errp)
 /* set up QEMUSoundCard and audiodev */
 AUD_register_card ("virtio_snd_card", >card);
 
+// set default params for all streams
+virtio_snd_pcm_set_params default_params;
+default_params.features = 0;
+default_params.buffer_bytes = 8192;
+default_params.period_bytes = 4096;
+default_params.channel = 2;
+default_params.format = VIRTIO_SND_PCM_FMT_S16;
+default_params.rate = VIRTIO_SND_PCM_RATE_44100;
+
 s->ctrl_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
 
 s->streams = g_new0(virtio_snd_pcm_stream *, s->snd_conf.streams);
 s->pcm_params = g_new0(virtio_snd_pcm_params *, s->snd_conf.streams);
 s->jacks = g_new0(virtio_snd_jack *, s->snd_conf.jacks);
+
+uint32_t status;
+for (int i = 0; i < s->snd_conf.streams; i++) {
+default_params.hdr.stream_id = i;
+status = virtio_snd_pcm_set_params_impl(s, _params);
+if (status != VIRTIO_SND_S_OK) {
+error_setg(errp, "Can't initalize stream params.\n");
+return;
+}
+status = virtio_snd_pcm_prepare_impl(s, i);
+if (status != VIRTIO_SND_S_OK) {
+error_setg(errp, "Can't prepare streams.\n");
+return;
+}
+}
+
+for (int i = 0; i < s->snd_conf.jacks; i++) {
+// TODO: For now the hda_fn_nid connects the starting streams to these
+// jacks. This isn't working for now since the directions will be wrong
+// for a few jacks. Similarly the capabilities are just placeholders.
+s->jacks[i] = (virtio_snd_jack *)g_malloc0(sizeof(virtio_snd_jack));
+s->jacks[i]->features = 0;
+s->jacks[i]->hda_fn_nid = i;
+s->jacks[i]->hda_reg_defconf = ((AC_JACK_PORT_COMPLEX << 
AC_DEFCFG_PORT_CONN_SHIFT) |
+   (AC_JACK_LINE_OUT << 
AC_DEFCFG_DEVICE_SHIFT)|
+   (AC_JACK_CONN_1_8 << 
AC_DEFCFG_CONN_TYPE_SHIFT) |
+   (AC_JACK_COLOR_GREEN  << 
AC_DEFCFG_COLOR_SHIFT) |
+   0x10);
+s->jacks[i]->hda_reg_caps = AC_PINCAP_OUT;
+s->jacks[i]->connected = false;
+}
 }
 
 static void virtio_snd_device_unrealize(DeviceState *dev)
-- 
2.31.1




[RFC PATCH 19/25] virtio-snd: Add start/stop handler

2022-02-11 Thread Shreyansh Chouhan
Added handlers for VIRTIO_SND_PCM_START and VIRTIO_SND_PCM_STOP.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 35 +--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index b74c9e4a1f..1b3e1f75f4 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -828,6 +828,36 @@ static uint32_t virtio_snd_handle_pcm_prepare(VirtIOSound 
*s,
 return sz;
 }
 
+/*
+ * Handles VIRTIO_SND_R_PCM_START.
+ * The function writes the response to the virtqueue element.
+ * Returns the used size in bytes.
+ *
+ * @s: VirtIOSound card
+ * @elem: The request element from control queue
+ */
+static uint32_t virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
+ VirtQueueElement *elem,
+ bool start)
+{
+virtio_snd_pcm_hdr req;
+size_t sz;
+
+sz = iov_to_buf(elem->out_sg, elem->out_num, 0, , sizeof(req));
+assert(sz == sizeof(virtio_snd_pcm_hdr));
+
+virtio_snd_hdr resp;
+resp.code = VIRTIO_SND_S_OK;
+
+virtio_snd_pcm_stream *st = virtio_snd_pcm_get_stream(s, req.stream_id);
+if (st->direction == VIRTIO_SND_D_OUTPUT)
+AUD_set_active_out(st->voice.out, start);
+
+sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
+assert(sz == sizeof(virtio_snd_hdr));
+return sz;
+}
+
 /* The control queue handler. Pops an element from the control virtqueue,
  * checks the header and performs the requested action. Finally marks the
  * element as used.
@@ -882,9 +912,10 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 sz = virtio_snd_handle_pcm_prepare(s, elem);
 goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_START) {
-virtio_snd_log("VIRTIO_SND_R_PCM_START");
+sz = virtio_snd_handle_pcm_start_stop(s, elem, true);
+goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_STOP) {
-virtio_snd_log("VIRTIO_SND_R_PCM_STOP");
+sz = virtio_snd_handle_pcm_start_stop(s, elem, false);
 } else if (ctrl.code == VIRTIO_SND_R_PCM_RELEASE) {
 virtio_snd_log("VIRTIO_SND_R_PCM_RELEASE");
 } else if (ctrl.code == VIRTIO_SND_R_CHMAP_INFO) {
-- 
2.31.1




[RFC PATCH 14/25] virtio-snd: Add VIRTIO_SND_R_PCM_INFO handler

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 88 ++-
 1 file changed, 87 insertions(+), 1 deletion(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index aec3e86db2..a53a6be168 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -188,6 +188,91 @@ static uint32_t virtio_snd_handle_jack_remap(VirtIOSound 
*s,
 return sz;
 }
 
+/*
+ * Get a specific stream from the virtio sound card device.
+ *
+ * @s: VirtIOSound card device
+ * @stream: Stream id
+ *
+ * Returns NULL if function fails.
+ * TODO: Make failure more explicit. Output can be NULL if the stream number
+ *   is valid but the stream hasn't been allocated yet.
+ */
+static virtio_snd_pcm_stream *virtio_snd_pcm_get_stream(VirtIOSound *s,
+uint32_t stream)
+{
+if (stream >= s->snd_conf.streams) {
+virtio_snd_err("Invalid stream request %d\n", stream);
+return NULL;
+}
+return s->streams[stream];
+}
+
+/*
+ * Handle the VIRTIO_SND_R_PCM_INFO request.
+ * The function writes the info structs to the request element.
+ * Returns the used size in bytes.
+ *
+ * @s: VirtIOSound card device
+ * @elem: The request element from control queue
+ */
+static uint32_t virtio_snd_handle_pcm_info(VirtIOSound *s,
+   VirtQueueElement *elem)
+{
+virtio_snd_query_info req;
+uint32_t sz;
+sz = iov_to_buf(elem->out_sg, elem->out_num, 0, , sizeof(req));
+assert(sz == sizeof(virtio_snd_query_info));
+
+virtio_snd_hdr resp;
+if (iov_size(elem->in_sg, elem->in_num) <
+sizeof(virtio_snd_hdr) + req.size * req.count) {
+virtio_snd_err("pcm info: buffer too small, got: %lu, needed: %lu\n",
+iov_size(elem->in_sg, elem->in_num),
+sizeof(virtio_snd_pcm_info));
+resp.code = VIRTIO_SND_S_BAD_MSG;
+goto done;
+}
+
+virtio_snd_pcm_stream *stream;
+virtio_snd_pcm_info *pcm_info = g_new0(virtio_snd_pcm_info, req.count);
+for (int i = req.start_id; i < req.start_id + req.count; i++) {
+stream = virtio_snd_pcm_get_stream(s, i);
+
+if (!stream) {
+virtio_snd_err("Invalid stream id: %d\n", i);
+resp.code = VIRTIO_SND_S_BAD_MSG;
+goto done;
+}
+
+pcm_info[i - req.start_id].hdr.hda_fn_nid = stream->hda_fn_nid;
+pcm_info[i - req.start_id].features = stream->features;
+pcm_info[i - req.start_id].formats = stream->formats;
+pcm_info[i - req.start_id].rates = stream->rates;
+pcm_info[i - req.start_id].direction = stream->direction;
+pcm_info[i - req.start_id].channels_min = stream->channels_min;
+pcm_info[i - req.start_id].channels_max = stream->channels_max;
+
+memset(_info[i].padding, 0, sizeof(pcm_info[i].padding));
+}
+
+resp.code = VIRTIO_SND_S_OK;
+done:
+sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
+assert(sz == sizeof(virtio_snd_hdr));
+
+if (resp.code == VIRTIO_SND_S_BAD_MSG) {
+g_free(pcm_info);
+return sz;
+}
+
+sz = iov_from_buf(elem->in_sg, elem->in_num, sizeof(virtio_snd_hdr),
+  pcm_info, sizeof(virtio_snd_pcm_info) * req.count);
+assert(sz == req.size * req.count);
+g_free(pcm_info);
+return sizeof(virtio_snd_hdr) + sz;
+}
+
 /* The control queue handler. Pops an element from the control virtqueue,
  * checks the header and performs the requested action. Finally marks the
  * element as used.
@@ -233,7 +318,8 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 sz = virtio_snd_handle_jack_remap(s, elem);
 goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_INFO) {
-virtio_snd_log("VIRTIO_SND_R_PCM_INFO");
+sz = virtio_snd_handle_pcm_info(s, elem);
+goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_SET_PARAMS) {
 virtio_snd_log("VIRTIO_SND_R_PCM_SET_PARAMS");
 } else if (ctrl.code == VIRTIO_SND_R_PCM_PREPARE) {
-- 
2.31.1




[RFC PATCH 12/25] virtio-snd: Add VIRTIO_SND_R_JACK_INFO handler

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 81 +--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index a87922f91b..c2af26f3cb 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -92,6 +92,80 @@ static uint64_t virtio_snd_get_features(VirtIODevice *vdev, 
uint64_t features,
 {
 return vdev->host_features;
 }
+/*
+ * Get a specific jack from the VirtIOSound card.
+ *
+ * @s: VirtIOSound card device.
+ * @id: Jack id
+ */
+static virtio_snd_jack *virtio_snd_get_jack(VirtIOSound *s, uint32_t id)
+{
+if (id >= s->snd_conf.jacks) {
+return NULL;
+}
+return s->jacks[id];
+}
+
+/*
+ * Handles VIRTIO_SND_R_JACK_INFO.
+ * The function writes the info structs and response to the virtqueue element.
+ * Returns the used size in bytes.
+ *
+ * @s: VirtIOSound card
+ * @elem: The request element from control queue
+ */
+static uint32_t virtio_snd_handle_jack_info(VirtIOSound *s,
+VirtQueueElement *elem)
+{
+virtio_snd_query_info req;
+size_t sz = iov_to_buf(elem->out_sg, elem->out_num, 0, , sizeof(req));
+assert(sz == sizeof(virtio_snd_query_info));
+
+virtio_snd_hdr resp;
+
+if (iov_size(elem->in_sg, elem->in_num) <
+sizeof(virtio_snd_hdr) + req.count * req.size) {
+virtio_snd_err("jack info: buffer too small got: %lu needed: %lu\n",
+   iov_size(elem->in_sg, elem->in_num),
+   sizeof(virtio_snd_hdr) + req.count * req.size);
+resp.code = VIRTIO_SND_S_BAD_MSG;
+goto done;
+}
+
+virtio_snd_jack_info *jack_info = g_new0(virtio_snd_jack_info, req.count);
+for (int i = req.start_id; i < req.count + req.start_id; i++) {
+virtio_snd_jack *jack = virtio_snd_get_jack(s, i);
+if (!jack) {
+virtio_snd_err("Invalid jack id: %d\n", i);
+resp.code = VIRTIO_SND_S_BAD_MSG;
+goto done;
+}
+
+jack_info[i - req.start_id].hdr.hda_fn_nid = jack->hda_fn_nid;
+jack_info[i - req.start_id].features = jack->features;
+jack_info[i - req.start_id].hda_reg_defconf = jack->hda_reg_defconf;
+jack_info[i - req.start_id].hda_reg_caps = jack->hda_reg_caps;
+jack_info[i - req.start_id].connected = jack->connected;
+memset(jack_info[i - req.start_id].padding, 0,
+   sizeof(jack_info[i - req.start_id].padding));
+}
+
+resp.code = VIRTIO_SND_S_OK;
+done:
+sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
+assert(sz == sizeof(virtio_snd_hdr));
+
+if (resp.code == VIRTIO_SND_S_BAD_MSG) {
+g_free(jack_info);
+return sz;
+}
+
+sz = iov_from_buf(elem->in_sg, elem->in_num, sizeof(virtio_snd_hdr),
+  jack_info, sizeof(virtio_snd_jack_info) * req.count);
+assert(sz == req.count * req.size);
+g_free(jack_info);
+return sizeof(virtio_snd_hdr) + sz;
+}
 
 /* The control queue handler. Pops an element from the control virtqueue,
  * checks the header and performs the requested action. Finally marks the
@@ -102,6 +176,7 @@ static uint64_t virtio_snd_get_features(VirtIODevice *vdev, 
uint64_t features,
  */
 static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
 {
+VirtIOSound *s = VIRTIO_SOUND(vdev);
 virtio_snd_hdr ctrl;
 
 VirtQueueElement *elem = NULL;
@@ -131,7 +206,8 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 /* error */
 virtio_snd_err("virtio snd ctrl could not read header\n");
 } else if (ctrl.code == VIRTIO_SND_R_JACK_INFO) {
-virtio_snd_log("VIRTIO_SND_R_JACK_INFO");
+sz = virtio_snd_handle_jack_info(s, elem);
+goto done;
 } else if (ctrl.code == VIRTIO_SND_R_JACK_REMAP) {
 virtio_snd_log("VIRTIO_SND_R_JACK_REMAP");
 } else if (ctrl.code == VIRTIO_SND_R_PCM_INFO) {
@@ -156,8 +232,9 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 virtio_snd_hdr resp;
 resp.code = VIRTIO_SND_S_OK;
 sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
-virtqueue_push(vq, elem, sz);
 
+done:
+virtqueue_push(vq, elem, sz);
 virtio_notify(vdev, vq);
 g_free(iov2);
 g_free(elem);
-- 
2.31.1




[RFC PATCH 18/25] virtio-snd: Add callback for SWVoiceOut

2022-02-11 Thread Shreyansh Chouhan
Added the callback for writing audio using AUD_write. The callback uses
two helper functions for reading the buffers from the streams and
handling the buffers that were written. initialized the
SWVoiceOut using this callback.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 254 +-
 1 file changed, 248 insertions(+), 6 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 5ed8e524a6..b74c9e4a1f 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -476,6 +476,248 @@ static int 
virtio_snd_pcm_get_nelems(virtio_snd_pcm_stream *st)
+ !!(st->buffer_bytes % st->period_bytes);
 }
 
+static uint32_t virtio_snd_pcm_get_buf_pos(virtio_snd_pcm_stream *st,
+   uint32_t dir)
+{
+return (dir == VIRTIO_SND_D_OUTPUT) ? st->w_pos : st->r_pos;
+}
+
+static uint32_t virtio_snd_pcm_get_curr_elem(virtio_snd_pcm_stream *st,
+uint32_t dir)
+{
+uint32_t pos;
+int nelems;
+
+nelems = virtio_snd_pcm_get_nelems(st);
+pos = virtio_snd_pcm_get_buf_pos(st, dir);
+
+return (pos / st->period_bytes) % nelems;
+}
+
+static uint32_t virtio_snd_pcm_get_curr_elem_cap(virtio_snd_pcm_stream *st,
+ uint32_t dir)
+{
+uint32_t cap_bytes;
+int i;
+
+i = virtio_snd_pcm_get_curr_elem(st, dir);
+
+if (dir == VIRTIO_SND_D_OUTPUT)
+cap_bytes = iov_size(st->elems[i]->out_sg, st->elems[i]->out_num)
+- sizeof(virtio_snd_pcm_xfer);
+else
+cap_bytes = iov_size(st->elems[i]->in_sg, st->elems[i]->in_num)
+- sizeof(virtio_snd_pcm_status);
+
+return cap_bytes;
+}
+
+static uint32_t virtio_snd_pcm_get_curr_elem_used(virtio_snd_pcm_stream *st,
+  uint32_t dir)
+{
+uint32_t pos;
+
+pos = virtio_snd_pcm_get_buf_pos(st, dir);
+
+return pos % st->period_bytes;
+}
+
+static uint32_t virtio_snd_pcm_get_curr_elem_free(virtio_snd_pcm_stream *st,
+  uint32_t dir)
+{
+uint32_t free_bytes, used;
+
+used = virtio_snd_pcm_get_curr_elem_used(st, dir);
+free_bytes = virtio_snd_pcm_get_curr_elem_cap(st, dir) - used;
+
+return free_bytes;
+}
+
+/*
+ * Get the size in bytes of the buffer that still has to be written.
+ *
+ * @st: virtio sound pcm stream
+ */
+static uint32_t virtio_snd_pcm_get_pending_bytes(virtio_snd_pcm_stream *st)
+{
+return (st->direction == VIRTIO_SND_D_OUTPUT) ?
+st->r_pos - st->w_pos :
+st->w_pos - st->r_pos;
+}
+
+static uint32_t virtio_snd_pcm_get_buf_to_proc(virtio_snd_pcm_stream *st,
+   size_t size)
+{
+uint32_t to_proc, elem_free;
+
+elem_free = virtio_snd_pcm_get_curr_elem_free(st, st->direction);
+to_proc = MIN(elem_free, size);
+
+return to_proc;
+}
+
+static void virtio_snd_pcm_update_buf_pos(virtio_snd_pcm_stream *st, uint32_t 
dir,
+  uint32_t size)
+{
+if (dir == VIRTIO_SND_D_OUTPUT)
+st->w_pos += size;
+else
+st->r_pos += size;
+}
+
+/*
+ * Get data from a stream of the virtio sound device. Only reads upto the
+ * end of the current virtqueue element. Returns the number of bytes read.
+ *
+ * @buffer: Write to this buffer
+ * @size: The number of bytes to read
+ * @st: VirtIOSound card stream
+ * @offset: Start reading from this offseta in the stream (in bytes)
+ */
+static size_t virtio_snd_pcm_buf_read(void *buf, size_t to_read,
+  virtio_snd_pcm_stream *st)
+{
+size_t sz;
+int i, used;
+
+used = virtio_snd_pcm_get_curr_elem_used(st, st->direction);
+i = virtio_snd_pcm_get_curr_elem(st, st->direction);
+
+sz = iov_to_buf(st->elems[i]->out_sg, st->elems[i]->out_num,
+sizeof(virtio_snd_pcm_xfer) + used, buf, to_read);
+
+assert(sz == to_read);
+return sz;
+}
+
+/*
+ * Marks an element as used, pushes it to queue and notifies the device.
+ * Also frees the element
+ */
+static void virtio_snd_pcm_handle_elem_used(virtio_snd_pcm_stream *st)
+{
+int elem_size, i;
+size_t sz, offset;
+
+virtio_snd_pcm_status status;
+status.status = VIRTIO_SND_S_OK;
+status.latency_bytes = 0;
+
+i = virtio_snd_pcm_get_curr_elem(st, st->direction);
+elem_size = iov_size(st->elems[i]->out_sg, st->elems[i]->out_num)
++ iov_size(st->elems[i]->in_sg, st->elems[i]->in_num);
+offset = iov_size(st->elems[i]->in_sg, st->elems[i]->in_num)
+ - sizeof(virtio_snd_pcm_status);
+
+sz = iov_from_buf(st->elems[i]->in_sg, st->elems[i]->in_num, offset,
+  , sizeof(status));
+assert(sz == sizeof(virtio_snd_pcm_status));
+
+virtqueue_push(st->s->tx_vq, st->elems[i], elem_size);
+

[RFC PATCH 23/25] virtio-snd: Add xfer handler

2022-02-11 Thread Shreyansh Chouhan
The handler demultiplexes the buffers recieved in the
tx/rx virtqueue. It uses a helper function for adding these
buffers, (along with the entire virtqueue element,) to
their respective streams.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 71 ++-
 1 file changed, 70 insertions(+), 1 deletion(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 7dd89c444b..80a34e1207 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -1012,6 +1012,74 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 }
 }
 
+/*
+ * Adds a virtqueue element to a VirtIOSound card stream. Makes the buffer
+ * available to the stream for consumption.
+ *
+ * @s: VirtIOSound card
+ * @stream: stream id
+ * @elem: The tx virtqueue element that contains the I/O message
+ */
+static void virtio_snd_pcm_add_buf(VirtIOSound *s, uint32_t stream,
+   VirtQueueElement *elem)
+{
+virtio_snd_log("add_buf called\n");
+
+virtio_snd_pcm_stream *st = virtio_snd_pcm_get_stream(s, stream);
+uint32_t buf_size, dir;
+int i;
+
+// get the direction opposite to the stream. We need read position if we 
are
+// writing because we want to add data to the buffer and not consume it.
+dir = VIRTIO_SND_D_INPUT ^ VIRTIO_SND_D_OUTPUT ^ st->direction;
+i = virtio_snd_pcm_get_curr_elem(st, dir);
+
+if (st->elems[i]) {
+return;
+}
+
+buf_size = iov_size(elem->out_sg, elem->out_num)
+   - sizeof(virtio_snd_pcm_xfer);
+
+st->elems[i] = elem;
+virtio_snd_pcm_update_buf_pos(st, dir, buf_size);
+}
+
+/*
+ * The tx virtqueue handler. Makes the buffers available to their respective
+ * streams for consumption.
+ *
+ * @vdev: VirtIOSound card
+ * @vq: tx virtqueue
+ */
+static void virtio_snd_handle_xfer(VirtIODevice *vdev, VirtQueue *vq)
+{
+virtio_snd_log("tx/rx queue callback called\n");
+VirtIOSound *s = VIRTIO_SOUND(vdev);
+VirtQueueElement *elem;
+size_t sz;
+virtio_snd_pcm_xfer hdr;
+
+for (;;) {
+elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+if (!elem) {
+break;
+}
+if (iov_size(elem->in_sg, elem->in_num) < 
sizeof(virtio_snd_pcm_status) ||
+iov_size(elem->out_sg, elem->out_num) < 
sizeof(virtio_snd_pcm_xfer)) {
+virtqueue_detach_element(vq, elem, 0);
+g_free(elem);
+break;
+}
+
+/* get the message hdr object */
+sz = iov_to_buf(elem->out_sg, elem->out_num, 0, , sizeof(hdr));
+assert(sz == sizeof(hdr));
+
+virtio_snd_pcm_add_buf(s, hdr.stream_id, elem);
+}
+}
+
 /*
  * Initializes the VirtIOSound card device. Validates the configuration
  * passed by the command line. Initializes the virtqueues. Allocates resources
@@ -1056,6 +1124,8 @@ static void virtio_snd_device_realize(DeviceState *dev, 
Error **errp)
 default_params.rate = VIRTIO_SND_PCM_RATE_44100;
 
 s->ctrl_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
+s->tx_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_xfer);
+s->rx_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_xfer);
 
 s->streams = g_new0(virtio_snd_pcm_stream *, s->snd_conf.streams);
 s->pcm_params = g_new0(virtio_snd_pcm_params *, s->snd_conf.streams);
@@ -1123,7 +1193,6 @@ static void virtio_snd_device_unrealize(DeviceState *dev)
 
 virtio_delete_queue(s->ctrl_vq);
 virtio_delete_queue(s->tx_vq);
-virtio_delete_queue(s->event_vq);
 virtio_delete_queue(s->rx_vq);
 }
 
-- 
2.31.1




[RFC PATCH 11/25] virtio-snd: Add control virtqueue handler

2022-02-11 Thread Shreyansh Chouhan
The handler prints the requests that came in the ctrl virtqueue.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 73 +++
 1 file changed, 73 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 40829fa329..a87922f91b 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -93,6 +93,77 @@ static uint64_t virtio_snd_get_features(VirtIODevice *vdev, 
uint64_t features,
 return vdev->host_features;
 }
 
+/* The control queue handler. Pops an element from the control virtqueue,
+ * checks the header and performs the requested action. Finally marks the
+ * element as used.
+ *
+ * @vdev: VirtIOSound card device
+ * @vq: Control virtqueue
+ */
+static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+virtio_snd_hdr ctrl;
+
+VirtQueueElement *elem = NULL;
+size_t sz;
+struct iovec *iov, *iov2;
+unsigned int iov_cnt;
+
+for (;;) {
+elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+if (!elem) {
+break;
+}
+if (iov_size(elem->in_sg, elem->in_num) < sizeof(ctrl) ||
+iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) {
+virtio_snd_err("virtio-snd ctrl missing headers\n");
+virtqueue_detach_element(vq, elem, 0);
+g_free(elem);
+break;
+}
+
+iov_cnt = elem->out_num;
+iov2 = iov = g_memdup(elem->out_sg,
+  sizeof(struct iovec) * elem->out_num);
+sz = iov_to_buf(iov, iov_cnt, 0, , sizeof(ctrl));
+iov_discard_front(, _cnt, sizeof(ctrl));
+if (sz != sizeof(ctrl)) {
+/* error */
+virtio_snd_err("virtio snd ctrl could not read header\n");
+} else if (ctrl.code == VIRTIO_SND_R_JACK_INFO) {
+virtio_snd_log("VIRTIO_SND_R_JACK_INFO");
+} else if (ctrl.code == VIRTIO_SND_R_JACK_REMAP) {
+virtio_snd_log("VIRTIO_SND_R_JACK_REMAP");
+} else if (ctrl.code == VIRTIO_SND_R_PCM_INFO) {
+virtio_snd_log("VIRTIO_SND_R_PCM_INFO");
+} else if (ctrl.code == VIRTIO_SND_R_PCM_SET_PARAMS) {
+virtio_snd_log("VIRTIO_SND_R_PCM_SET_PARAMS");
+} else if (ctrl.code == VIRTIO_SND_R_PCM_PREPARE) {
+virtio_snd_log("VIRTIO_SND_R_PCM_PREPARE");
+} else if (ctrl.code == VIRTIO_SND_R_PCM_START) {
+virtio_snd_log("VIRTIO_SND_R_PCM_START");
+} else if (ctrl.code == VIRTIO_SND_R_PCM_STOP) {
+virtio_snd_log("VIRTIO_SND_R_PCM_STOP");
+} else if (ctrl.code == VIRTIO_SND_R_PCM_RELEASE) {
+virtio_snd_log("VIRTIO_SND_R_PCM_RELEASE");
+} else if (ctrl.code == VIRTIO_SND_R_CHMAP_INFO) {
+virtio_snd_log("VIRTIO_SND_R_CHMAP_INFO");
+} else {
+/* error */
+virtio_snd_err("virtio snd header not recognized: %d\n", 
ctrl.code);
+}
+
+virtio_snd_hdr resp;
+resp.code = VIRTIO_SND_S_OK;
+sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
+virtqueue_push(vq, elem, sz);
+
+virtio_notify(vdev, vq);
+g_free(iov2);
+g_free(elem);
+}
+}
+
 /*
  * Initializes the VirtIOSound card device. Validates the configuration
  * passed by the command line. Initializes the virtqueues. Allocates resources
@@ -127,6 +198,8 @@ static void virtio_snd_device_realize(DeviceState *dev, 
Error **errp)
 /* set up QEMUSoundCard and audiodev */
 AUD_register_card ("virtio_snd_card", >card);
 
+s->ctrl_vq = virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
+
 s->streams = g_new0(virtio_snd_pcm_stream *, s->snd_conf.streams);
 s->pcm_params = g_new0(virtio_snd_pcm_params *, s->snd_conf.streams);
 s->jacks = g_new0(virtio_snd_jack *, s->snd_conf.jacks);
-- 
2.31.1




[RFC PATCH 13/25] virtio-snd: Add stub for VIRTIO_SND_R_JACK_REMAP handler

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 24 +++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index c2af26f3cb..aec3e86db2 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -167,6 +167,27 @@ done:
 return sizeof(virtio_snd_hdr) + sz;
 }
 
+/*
+ * Handles VIRTIO_SND_R_JACK_REMAP.
+ * Not implemented yet.
+ *
+ * @s: VirtIOSound card
+ * @elem: The request element from control queue
+ */
+static uint32_t virtio_snd_handle_jack_remap(VirtIOSound *s,
+ VirtQueueElement *elem)
+{
+virtio_snd_hdr resp;
+resp.code = VIRTIO_SND_S_OK;
+
+/* TODO: implement remap */
+
+size_t sz;
+sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
+assert(sz == sizeof(virtio_snd_hdr));
+return sz;
+}
+
 /* The control queue handler. Pops an element from the control virtqueue,
  * checks the header and performs the requested action. Finally marks the
  * element as used.
@@ -209,7 +230,8 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 sz = virtio_snd_handle_jack_info(s, elem);
 goto done;
 } else if (ctrl.code == VIRTIO_SND_R_JACK_REMAP) {
-virtio_snd_log("VIRTIO_SND_R_JACK_REMAP");
+sz = virtio_snd_handle_jack_remap(s, elem);
+goto done;
 } else if (ctrl.code == VIRTIO_SND_R_PCM_INFO) {
 virtio_snd_log("VIRTIO_SND_R_PCM_INFO");
 } else if (ctrl.code == VIRTIO_SND_R_PCM_SET_PARAMS) {
-- 
2.31.1




[RFC PATCH 22/25] virtio-snd: Add code to device unrealize function

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 30 ++
 1 file changed, 30 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index cb83db0e89..7dd89c444b 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -1093,8 +1093,38 @@ static void virtio_snd_device_realize(DeviceState *dev, 
Error **errp)
 }
 }
 
+/*
+ * Frees the resources allocated to the device and then frees the device
+ * itself.
+ *
+ * @dev: VirtIOSound card device
+ */
 static void virtio_snd_device_unrealize(DeviceState *dev)
 {
+VirtIOSound *s = VIRTIO_SOUND(dev);
+
+for (int i = 0; i < s->snd_conf.streams; i++) {
+virtio_snd_pcm_stream *st = virtio_snd_pcm_get_stream(s, i);
+virtio_snd_pcm_release_impl(st, i);
+g_free(s->pcm_params[i]);
+s->pcm_params[i] = NULL;
+}
+g_free(s->streams);
+s->streams = NULL;
+g_free(s->pcm_params);
+s->pcm_params = NULL;
+
+for (int i = 0; i < s->snd_conf.jacks; i++) {
+g_free(s->jacks[i]);
+s->jacks[i] = NULL;
+}
+g_free(s->jacks);
+s->jacks = NULL;
+
+virtio_delete_queue(s->ctrl_vq);
+virtio_delete_queue(s->tx_vq);
+virtio_delete_queue(s->event_vq);
+virtio_delete_queue(s->rx_vq);
 }
 
 static void virtio_snd_reset(VirtIODevice *vdev)
-- 
2.31.1




[RFC PATCH 09/25] virtio-snd: Add code for the realize function

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 35 +++
 1 file changed, 35 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index afa38adee7..b51f6c7523 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -89,8 +89,43 @@ static uint64_t virtio_snd_get_features(VirtIODevice *vdev, 
uint64_t features,
 return vdev->host_features;
 }
 
+/*
+ * Initializes the VirtIOSound card device. Validates the configuration
+ * passed by the command line. Initializes the virtqueues. Allocates resources
+ * for and initializes streams, jacks and chmaps.
+ *
+ * @dev: VirtIOSound card device
+ * @errp: Set if there is an error
+ */
 static void virtio_snd_device_realize(DeviceState *dev, Error **errp)
 {
+VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+VirtIOSound *s = VIRTIO_SOUND(dev);
+
+virtio_init(vdev, "virtio-snd", VIRTIO_ID_SOUND, 
sizeof(virtio_snd_config));
+
+/* set number of jacks and streams */
+if (s->snd_conf.jacks > 8) {
+error_setg(errp, "Invalid number of jacks: %d", s->snd_conf.jacks);
+return;
+}
+if (s->snd_conf.streams < 1 || s->snd_conf.streams > 10) {
+error_setg(errp, "Invalid number of streams: %d", s->snd_conf.streams);
+return;
+}
+
+if (s->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) {
+error_setg(errp, "Invalid number of channel maps: %d",
+   s->snd_conf.chmaps);
+return;
+}
+
+/* set up QEMUSoundCard and audiodev */
+AUD_register_card ("virtio_snd_card", >card);
+
+s->streams = g_new0(virtio_snd_pcm_stream *, s->snd_conf.streams);
+s->pcm_params = g_new0(virtio_snd_pcm_params *, s->snd_conf.streams);
+s->jacks = g_new0(virtio_snd_jack *, s->snd_conf.jacks);
 }
 
 static void virtio_snd_device_unrealize(DeviceState *dev)
-- 
2.31.1




[RFC PATCH 10/25] virtio-snd: Add macros for logging

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index b51f6c7523..40829fa329 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -39,6 +39,10 @@
 #define VIRTIO_SOUND_HDA_FN_NID_OUT 0
 #define VIRTIO_SOUND_HDA_FN_NID_IN 1
 
+#define virtio_snd_log(...) AUD_log("virtio sound info", __VA_ARGS__)
+#define virtio_snd_warn(...) AUD_log("virtio sound warn", __VA_ARGS__)
+#define virtio_snd_err(...) AUD_log("virtio sound err", __VA_ARGS__)
+
 static void virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
 {
 VirtIOSound *s = VIRTIO_SOUND(vdev);
@@ -167,4 +171,8 @@ static void virtio_register_types(void)
 type_register_static(_snd_dev_info);
 }
 
+#undef virtio_snd_log
+#undef virtio_snd_warn
+#undef virtio_snd_err
+
 type_init(virtio_register_types)
-- 
2.31.1




[RFC PATCH 20/25] virtio-snd: Add VIRTIO_SND_R_PCM_RELEASE handler

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 82 ++-
 1 file changed, 81 insertions(+), 1 deletion(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 1b3e1f75f4..7b80a92737 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -858,6 +858,85 @@ static uint32_t 
virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
 return sz;
 }
 
+/*
+ * Releases the resources allocated to a stream. Sepearated from the handler
+ * so that the code could be reused in the unrealize function.
+ *
+ * TODO: Doesn't handle the stream buffers that are yet to be played.
+ *
+ * @s: VirtIOSound card
+ * @stream: stream id
+ */
+static uint32_t virtio_snd_pcm_release_impl(virtio_snd_pcm_stream *st, 
uint32_t stream)
+{
+// if there are still pending io messages do nothing
+if (virtio_snd_pcm_get_pending_bytes(st)) {
+// flush the stream
+virtio_snd_log("Started flushing stream");
+
+// set flushing to true, the callback will automatically close the
+// stream once the flushing is done
+st->flushing = true;
+
+if (st->direction == VIRTIO_SND_D_OUTPUT)
+AUD_set_active_out(st->voice.out, true);
+else
+AUD_set_active_in(st->voice.in, true);
+return VIRTIO_SND_S_OK;
+}
+
+if (st->direction == VIRTIO_SND_D_OUTPUT)
+AUD_close_out(>s->card, st->voice.out);
+else
+AUD_close_in(>s->card, st->voice.in);
+
+if (st->elems) {
+int nelems = virtio_snd_pcm_get_nelems(st);
+for (int i = 0; i < nelems; i++) {
+g_free(st->elems[i]);
+st->elems[i] = NULL;
+}
+g_free(st->elems);
+st->elems = NULL;
+}
+
+g_free(st->s->streams[stream]);
+st->s->streams[stream] = NULL;
+return VIRTIO_SND_S_OK;
+}
+
+/*
+ * Handles VIRTIO_SND_R_PCM_RELEASE.
+ * The function writes the response to the virtqueue element.
+ * Returns the used size in bytes.
+ * TODO: Doesn't handle the stream buffers that are yet to be played.
+ *
+ * @s: VirtIOSound card
+ * @elem: The request element from control queue
+ */
+static uint32_t virtio_snd_handle_pcm_release(VirtIOSound *s,
+  VirtQueueElement *elem)
+{
+virtio_snd_pcm_hdr req;
+virtio_snd_hdr resp;
+size_t sz;
+sz = iov_to_buf(elem->out_sg, elem->out_num, 0, , sizeof(req));
+assert(sz == sizeof(virtio_snd_pcm_hdr));
+
+virtio_snd_log("Release called\n");
+
+virtio_snd_pcm_stream *st = virtio_snd_pcm_get_stream(s, req.stream_id);
+if (!st) {
+virtio_snd_err("already released %d\n", req.stream_id);
+return VIRTIO_SND_S_BAD_MSG;
+}
+
+resp.code = virtio_snd_pcm_release_impl(st, req.stream_id);
+sz = iov_from_buf(elem->in_sg, elem->in_num, 0, , sizeof(resp));
+assert(sz == sizeof(virtio_snd_hdr));
+return sz;
+}
+
 /* The control queue handler. Pops an element from the control virtqueue,
  * checks the header and performs the requested action. Finally marks the
  * element as used.
@@ -917,9 +996,10 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 } else if (ctrl.code == VIRTIO_SND_R_PCM_STOP) {
 sz = virtio_snd_handle_pcm_start_stop(s, elem, false);
 } else if (ctrl.code == VIRTIO_SND_R_PCM_RELEASE) {
-virtio_snd_log("VIRTIO_SND_R_PCM_RELEASE");
+sz = virtio_snd_handle_pcm_release(s, elem);
 } else if (ctrl.code == VIRTIO_SND_R_CHMAP_INFO) {
 virtio_snd_log("VIRTIO_SND_R_CHMAP_INFO");
+goto done;
 } else {
 /* error */
 virtio_snd_err("virtio snd header not recognized: %d\n", 
ctrl.code);
-- 
2.31.1




[RFC PATCH 16/25] virtio-snd: Add VIRTIO_SND_R_PCM_PREPARE handler

2022-02-11 Thread Shreyansh Chouhan
The handler doesn't intialize the SWVoiceOut streams for now.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 203 +-
 1 file changed, 202 insertions(+), 1 deletion(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index acb126f392..b7c4dc691d 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -386,6 +386,206 @@ static uint32_t 
virtio_snd_handle_pcm_set_params(VirtIOSound *s,
 return sz;
 }
 
+/*
+ * Get a QEMU Audiosystem compatible format value from a VIRTIO_SND_PCM_FMT_*
+ */
+static AudioFormat virtio_snd_get_qemu_format(uint32_t format)
+{
+switch (format) {
+case VIRTIO_SND_PCM_FMT_U8:
+return AUDIO_FORMAT_U8;
+case VIRTIO_SND_PCM_FMT_S8:
+return AUDIO_FORMAT_S8;
+case VIRTIO_SND_PCM_FMT_U16:
+return AUDIO_FORMAT_U16;
+case VIRTIO_SND_PCM_FMT_S16:
+return AUDIO_FORMAT_S16;
+case VIRTIO_SND_PCM_FMT_U32:
+return AUDIO_FORMAT_U32;
+case VIRTIO_SND_PCM_FMT_S32:
+return AUDIO_FORMAT_S32;
+case VIRTIO_SND_PCM_FMT_FLOAT:
+return AUDIO_FORMAT_F32;
+default:
+return -1;
+}
+}
+
+/*
+ * Get a QEMU Audiosystem compatible frequency value from a
+ * VIRTIO_SND_PCM_RATE_*
+ */
+static uint32_t virtio_snd_get_qemu_freq(uint32_t rate)
+{
+switch (rate) {
+case VIRTIO_SND_PCM_RATE_5512:
+return 5512;
+case VIRTIO_SND_PCM_RATE_8000:
+return 8000;
+case VIRTIO_SND_PCM_RATE_11025:
+return 11025;
+case VIRTIO_SND_PCM_RATE_16000:
+return 16000;
+case VIRTIO_SND_PCM_RATE_22050:
+return 22050;
+case VIRTIO_SND_PCM_RATE_32000:
+return 32000;
+case VIRTIO_SND_PCM_RATE_44100:
+return 44100;
+case VIRTIO_SND_PCM_RATE_48000:
+return 48000;
+case VIRTIO_SND_PCM_RATE_64000:
+return 64000;
+case VIRTIO_SND_PCM_RATE_88200:
+return 88200;
+case VIRTIO_SND_PCM_RATE_96000:
+return 96000;
+case VIRTIO_SND_PCM_RATE_176399:
+return 176399;
+case VIRTIO_SND_PCM_RATE_192000:
+return 192000;
+case VIRTIO_SND_PCM_RATE_384000:
+return 384000;
+default:
+return -1;
+}
+}
+
+/*
+ * Get QEMU Audiosystem compatible audsettings from virtio based pcm stream
+ * params.
+ */
+static void virtio_snd_get_qemu_audsettings(audsettings *as,
+virtio_snd_pcm_params *params)
+{
+as->nchannels = params->channel;
+as->fmt = virtio_snd_get_qemu_format(params->format);
+as->freq = virtio_snd_get_qemu_freq(params->rate);
+as->endianness = AUDIO_HOST_ENDIANNESS;
+}
+
+/*
+ * Get the maximum number of virtqueue elements that can be inserted
+ * into a virtio sound pcm stream
+ *
+ * @st: virtio sound pcm stream
+ */
+static int virtio_snd_pcm_get_nelems(virtio_snd_pcm_stream *st)
+{
+return st->buffer_bytes / st->period_bytes
+   + !!(st->buffer_bytes % st->period_bytes);
+}
+
+/*
+ * Prepares a VirtIOSound card stream.
+ * Returns a virtio sound status (VIRTIO_SND_S_*).
+ *
+ * @s: VirtIOSound card
+ * @stream: stream id
+ */
+static uint32_t virtio_snd_pcm_prepare_impl(VirtIOSound *s, uint32_t stream)
+{
+if (!s->streams || !s->pcm_params || !s->pcm_params[stream]) {
+virtio_snd_err("Cannot prepare stream %d without params.\n", stream);
+return VIRTIO_SND_S_BAD_MSG;
+}
+
+uint32_t supported_formats = 1 << VIRTIO_SND_PCM_FMT_S8 |
+ 1 << VIRTIO_SND_PCM_FMT_U8 |
+ 1 << VIRTIO_SND_PCM_FMT_S16 |
+ 1 << VIRTIO_SND_PCM_FMT_U16 |
+ 1 << VIRTIO_SND_PCM_FMT_S32 |
+ 1 << VIRTIO_SND_PCM_FMT_U32 |
+ 1 << VIRTIO_SND_PCM_FMT_FLOAT;
+
+uint32_t supported_rates = 1 << VIRTIO_SND_PCM_RATE_5512 |
+   1 << VIRTIO_SND_PCM_RATE_8000 |
+   1 << VIRTIO_SND_PCM_RATE_11025 |
+   1 << VIRTIO_SND_PCM_RATE_16000 |
+   1 << VIRTIO_SND_PCM_RATE_22050 |
+   1 << VIRTIO_SND_PCM_RATE_32000 |
+   1 << VIRTIO_SND_PCM_RATE_44100 |
+   1 << VIRTIO_SND_PCM_RATE_48000 |
+   1 << VIRTIO_SND_PCM_RATE_64000 |
+   1 << VIRTIO_SND_PCM_RATE_88200 |
+   1 << VIRTIO_SND_PCM_RATE_96000 |
+   1 << VIRTIO_SND_PCM_RATE_176399 |
+   1 << VIRTIO_SND_PCM_RATE_192000 |
+   1 << VIRTIO_SND_PCM_RATE_384000;
+
+virtio_snd_pcm_params *params = virtio_snd_pcm_get_params(s, stream);
+virtio_snd_pcm_stream *st = g_new0(virtio_snd_pcm_stream, 1);
+st->hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID_OUT;

[RFC PATCH 06/25] virtio-snd: Add PCI wrapper code for VirtIOSound

2022-02-11 Thread Shreyansh Chouhan
Added the virito-snd.c file which contains a wrapper
for combining the device with the VirtIOPCIProxy.

Signed-off-by: Shreyansh Chouhan 
---
 hw/virtio/meson.build  |  1 +
 hw/virtio/virtio-snd-pci.c | 72 ++
 2 files changed, 73 insertions(+)
 create mode 100644 hw/virtio/virtio-snd-pci.c

diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 521f7d64a8..86d6594c20 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -49,6 +49,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: 
files('virtio-serial-pc
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: 
files('virtio-pmem-pci.c'))
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: 
files('virtio-iommu-pci.c'))
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: 
files('virtio-mem-pci.c'))
+virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SND', if_true: 
files('virtio-snd-pci.c'))
 
 virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss)
 
diff --git a/hw/virtio/virtio-snd-pci.c b/hw/virtio/virtio-snd-pci.c
new file mode 100644
index 00..8d8e4ffa51
--- /dev/null
+++ b/hw/virtio/virtio-snd-pci.c
@@ -0,0 +1,72 @@
+/*
+ * Virtio sound PCI Bindings
+ */
+
+#include "qemu/osdep.h"
+#include "hw/virtio/virtio-snd.h"
+#include "hw/virtio/virtio-pci.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "qom/object.h"
+
+typedef struct VirtIOSoundPCI VirtIOSoundPCI;
+
+/*
+ * virtio-snd-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_SOUND_PCI "virtio-sound-pci-base"
+DECLARE_INSTANCE_CHECKER(VirtIOSoundPCI, VIRTIO_SOUND_PCI,
+ TYPE_VIRTIO_SOUND_PCI)
+
+struct VirtIOSoundPCI {
+VirtIOPCIProxy parent_obj;
+VirtIOSound vdev;
+};
+
+static Property virtio_sound_properties[] = {
+DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+VirtIOSoundPCI *dev = VIRTIO_SOUND_PCI(vpci_dev);
+DeviceState *vdev = DEVICE(>vdev);
+
+qdev_realize(vdev, BUS(_dev->bus), errp);
+}
+
+static void virtio_snd_pci_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
+
+k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
+device_class_set_props(dc, virtio_sound_properties);
+vpciklass->realize = virtio_snd_pci_realize;
+}
+
+static void virtio_snd_pci_instance_init(Object *obj)
+{
+VirtIOSoundPCI *dev = VIRTIO_SOUND_PCI(obj);
+virtio_instance_init_common(obj, >vdev, sizeof(dev->vdev),
+TYPE_VIRTIO_SOUND);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_snd_pci_info = {
+.base_name  = TYPE_VIRTIO_SOUND_PCI,
+.generic_name   = "virtio-snd-pci",
+.instance_size = sizeof(VirtIOSoundPCI),
+.instance_init = virtio_snd_pci_instance_init,
+.class_init= virtio_snd_pci_class_init,
+};
+
+static void virtio_snd_pci_register(void)
+{
+virtio_pci_types_register(_snd_pci_info);
+}
+
+type_init(virtio_snd_pci_register);
-- 
2.31.1




[RFC PATCH 08/25] virtio-snd: Add code for get config function

2022-02-11 Thread Shreyansh Chouhan
Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index ae438aa7ec..afa38adee7 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -41,6 +41,15 @@
 
 static void virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
 {
+VirtIOSound *s = VIRTIO_SOUND(vdev);
+virtio_snd_config sndcfg;
+
+memset(, 0, sizeof(virtio_snd_config));
+stl_le_p(&(sndcfg.jacks), s->snd_conf.jacks);
+stl_le_p(&(sndcfg.streams), s->snd_conf.streams);
+stl_le_p(&(sndcfg.chmaps), s->snd_conf.chmaps);
+
+memcpy(config, , sizeof(virtio_snd_config));
 }
 
 static void virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
-- 
2.31.1




[RFC PATCH 05/25] virtio-snd: Add device implementation structures

2022-02-11 Thread Shreyansh Chouhan
Added jacks, pcm streams and the VirtIOSound structure for actual
device implementation.

Signed-off-by: Shreyansh Chouhan 
---
 include/hw/virtio/virtio-snd.h | 66 ++
 1 file changed, 66 insertions(+)

diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h
index 3c16609a25..4d800a9626 100644
--- a/include/hw/virtio/virtio-snd.h
+++ b/include/hw/virtio/virtio-snd.h
@@ -13,6 +13,9 @@
 
 #define VIRTIO_ID_SOUND 25
 
+#define TYPE_VIRTIO_SOUND "virtio-sound-device"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOSound, VIRTIO_SOUND)
+
 /* CONFIGURATION SPACE */
 
 typedef struct virtio_snd_config {
@@ -314,4 +317,67 @@ typedef struct virtio_snd_chmap_info {
 uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
 } virtio_snd_chmap_info;
 
+/* VIRTIO SOUND DEVICE */
+
+/* Jacks */
+typedef struct virtio_snd_jack {
+uint32_t features; /* 1 << VIRTIO_SND_JACK_F_XXX */
+uint32_t hda_fn_nid;
+uint32_t hda_reg_defconf;
+uint32_t hda_reg_caps;
+uint8_t connected;
+} virtio_snd_jack;
+
+/* Streams */
+typedef struct virtio_snd_pcm_stream {
+uint32_t hda_fn_nid;
+uint32_t buffer_bytes;
+uint32_t period_bytes;
+uint32_t features; /* 1 << VIRTIO_SND_PCM_F_XXX */
+uint32_t flags; /* 1 << VIRTIO_SND_PCM_FL_XXX */
+uint32_t direction;
+uint8_t channels_min;
+uint8_t channels_max;
+uint64_t formats; /* 1 << VIRTIO_SND_PCM_FMT_XXX */
+uint64_t rates; /* 1 << VIRTIO_SND_PCM_RATE_XXX */
+uint32_t r_pos, w_pos;
+bool flushing;
+uint8_t chmap[VIRTIO_SND_CHMAP_MAX_SIZE];
+VirtQueueElement **elems;
+VirtIOSound *s;
+union {
+SWVoiceIn *in;
+SWVoiceOut *out;
+} voice;
+} virtio_snd_pcm_stream;
+
+/* Stream params */
+typedef struct virtio_snd_pcm_params {
+uint32_t features;
+uint32_t buffer_bytes;  /* size of hardware buffer in bytes */
+uint32_t period_bytes;  /* size of hardware period in bytes */
+uint8_t channel;
+uint8_t format;
+uint8_t rate;
+} virtio_snd_pcm_params;
+
+/* Sound device */
+struct VirtIOSound {
+/* Parent VirtIODevice object */
+VirtIODevice parent_obj;
+virtio_snd_config snd_conf;
+
+VirtQueue *ctrl_vq;
+VirtQueue *event_vq;
+VirtQueue *tx_vq;
+VirtQueue *rx_vq;
+
+QEMUSoundCard card;
+size_t config_size;
+
+virtio_snd_pcm_params **pcm_params;
+virtio_snd_pcm_stream **streams;
+virtio_snd_jack **jacks;
+};
+
 #endif
-- 
2.31.1




[RFC PATCH 15/25] virtio-snd: Add VIRITO_SND_R_PCM_SET_PARAMS handle

2022-02-11 Thread Shreyansh Chouhan
Added handler for the VIRTIO_SND_R_PCM_SET_PARAMS control request.
The handler was split up into two functions in so that the code
could be reused in the realize function.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/virtio-snd.c | 116 +-
 1 file changed, 115 insertions(+), 1 deletion(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index a53a6be168..acb126f392 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -208,6 +208,22 @@ static virtio_snd_pcm_stream 
*virtio_snd_pcm_get_stream(VirtIOSound *s,
 return s->streams[stream];
 }
 
+/*
+ * Get params for a sepific stream.
+ *
+ * @s: VirtIOSound card device
+ * @stream: Stream id
+ */
+static virtio_snd_pcm_params *virtio_snd_pcm_get_params(VirtIOSound *s,
+uint32_t stream)
+{
+if (stream >= s->snd_conf.streams) {
+virtio_snd_err("Invalid stream request %d\n", stream);
+return NULL;
+}
+return s->pcm_params[stream];
+}
+
 /*
  * Handle the VIRTIO_SND_R_PCM_INFO request.
  * The function writes the info structs to the request element.
@@ -273,6 +289,103 @@ done:
 return sizeof(virtio_snd_hdr) + sz;
 }
 
+/*
+ * Set the given stream params.
+ * Called by both virtio_snd_handle_pcm_set_params and during device
+ * initialization.
+ * Returns a virtio sound status VIRTIO_SND_S_*
+ *
+ * @s: VirtIOSound card device
+ * @params: The PCM params as defined in the virtio specification
+ */
+static uint32_t virtio_snd_pcm_set_params_impl(VirtIOSound *s,
+   virtio_snd_pcm_set_params 
*params)
+{
+uint32_t st = params->hdr.stream_id;
+if (st > s->snd_conf.streams || !(s->pcm_params)) {
+virtio_error(VIRTIO_DEVICE(s), "Streams not initalized\n");
+return VIRTIO_SND_S_BAD_MSG;
+}
+
+if (!s->pcm_params[st]) {
+s->pcm_params[st] = g_new0(virtio_snd_pcm_params, 1);
+}
+virtio_snd_pcm_params *st_params = virtio_snd_pcm_get_params(s, st);
+
+st_params->features = params->features;
+st_params->buffer_bytes = params->buffer_bytes;
+st_params->period_bytes = params->period_bytes;
+
+if (params->channel < 1 || params->channel > AUDIO_MAX_CHANNELS) {
+virtio_snd_err("Number of channels not supported\n");
+return VIRTIO_SND_S_NOT_SUPP;
+}
+st_params->channel = params->channel;
+
+uint32_t supported_formats = 1 << VIRTIO_SND_PCM_FMT_S8 |
+ 1 << VIRTIO_SND_PCM_FMT_U8 |
+ 1 << VIRTIO_SND_PCM_FMT_S16 |
+ 1 << VIRTIO_SND_PCM_FMT_U16 |
+ 1 << VIRTIO_SND_PCM_FMT_S32 |
+ 1 << VIRTIO_SND_PCM_FMT_U32 |
+ 1 << VIRTIO_SND_PCM_FMT_FLOAT;
+
+uint32_t supported_rates = 1 << VIRTIO_SND_PCM_RATE_5512 |
+   1 << VIRTIO_SND_PCM_RATE_8000 |
+   1 << VIRTIO_SND_PCM_RATE_11025 |
+   1 << VIRTIO_SND_PCM_RATE_16000 |
+   1 << VIRTIO_SND_PCM_RATE_22050 |
+   1 << VIRTIO_SND_PCM_RATE_32000 |
+   1 << VIRTIO_SND_PCM_RATE_44100 |
+   1 << VIRTIO_SND_PCM_RATE_48000 |
+   1 << VIRTIO_SND_PCM_RATE_64000 |
+   1 << VIRTIO_SND_PCM_RATE_88200 |
+   1 << VIRTIO_SND_PCM_RATE_96000 |
+   1 << VIRTIO_SND_PCM_RATE_176399 |
+   1 << VIRTIO_SND_PCM_RATE_192000 |
+   1 << VIRTIO_SND_PCM_RATE_384000;
+
+if (!(supported_formats & (1 << params->format))) {
+virtio_snd_err("Stream format not supported\n");
+return VIRTIO_SND_S_NOT_SUPP;
+}
+st_params->format = params->format;
+
+if (!(supported_rates & (1 << params->rate))) {
+virtio_snd_err("Stream rate not supported\n");
+return VIRTIO_SND_S_NOT_SUPP;
+}
+st_params->rate = params->rate;
+
+st_params->period_bytes = params->period_bytes;
+st_params->buffer_bytes = params->buffer_bytes;
+return VIRTIO_SND_S_OK;
+}
+
+/*
+ * Handles the VIRTIO_SND_R_PCM_SET_PARAMS request.
+ * The function writes the response to the virtqueue element.
+ * Returns the used size in bytes.
+ *
+ * @s: VirtIOSound card device
+ * @elem: The request element from control queue
+ */
+static uint32_t virtio_snd_handle_pcm_set_params(VirtIOSound *s,
+ VirtQueueElement *elem)
+{
+virtio_snd_pcm_set_params req;
+uint32_t sz;
+sz = iov_to_buf(elem->out_sg, elem->out_num, 0, , sizeof(req));
+assert(sz == sizeof(virtio_snd_pcm_set_params));
+
+virtio_snd_hdr resp;
+resp.code = virtio_snd_pcm_set_params_impl(s, );
+
+sz 

[RFC PATCH 03/25] virtio-snd: Add PCM control structures

2022-02-11 Thread Shreyansh Chouhan
Added structures for handle PCM control requests
to the heaer file.

Signed-off-by: Shreyansh Chouhan 
---
 include/hw/virtio/virtio-snd.h | 123 +
 1 file changed, 123 insertions(+)

diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h
index f58b06a949..a7828c4ab8 100644
--- a/include/hw/virtio/virtio-snd.h
+++ b/include/hw/virtio/virtio-snd.h
@@ -134,4 +134,127 @@ typedef struct virtio_snd_jack_remap {
 uint32_t sequence;
 } virtio_snd_jack_remap;
 
+/* PCM CONTROL MESSAGES */
+
+typedef struct virtio_snd_pcm_hdr {
+/* .code = VIRTIO_SND_R_PCM_* */
+virtio_snd_hdr hdr;
+/* 0 to (virtio_snd_config.streams - 1) */
+uint32_t stream_id;
+} virtio_snd_pcm_hdr;
+
+
+/* Supported PCM stream features */
+enum {
+VIRTIO_SND_PCM_F_SHMEM_HOST = 0,
+VIRTIO_SND_PCM_F_SHMEM_GUEST,
+VIRTIO_SND_PCM_F_MSG_POLLING,
+VIRTIO_SND_PCM_F_EVT_SHMEM_PERIODS,
+VIRTIO_SNDPCM_F_EVT_XRUNS
+};
+
+/* Supported sample formats */
+enum {
+/* analog formats (width / physical width) */
+VIRTIO_SND_PCM_FMT_IMA_ADPCM = 0,   /*  4 /  4 bits */
+VIRTIO_SND_PCM_FMT_MU_LAW,  /*  8 /  8 bits */
+VIRTIO_SND_PCM_FMT_A_LAW,   /*  8 /  8 bits */
+VIRTIO_SND_PCM_FMT_S8,  /*  8 /  8 bits */
+VIRTIO_SND_PCM_FMT_U8,  /*  8 /  8 bits */
+VIRTIO_SND_PCM_FMT_S16, /* 16 / 16 bits */
+VIRTIO_SND_PCM_FMT_U16, /* 16 / 16 bits */
+VIRTIO_SND_PCM_FMT_S18_3,   /* 18 / 24 bits */
+VIRTIO_SND_PCM_FMT_U18_3,   /* 18 / 24 bits */
+VIRTIO_SND_PCM_FMT_S20_3,   /* 20 / 24 bits */
+VIRTIO_SND_PCM_FMT_U20_3,   /* 20 / 24 bits */
+VIRTIO_SND_PCM_FMT_S24_3,   /* 24 / 24 bits */
+VIRTIO_SND_PCM_FMT_U24_3,   /* 24 / 24 bits */
+VIRTIO_SND_PCM_FMT_S20, /* 20 / 32 bits */
+VIRTIO_SND_PCM_FMT_U20, /* 20 / 32 bits */
+VIRTIO_SND_PCM_FMT_S24, /* 24 / 32 bits */
+VIRTIO_SND_PCM_FMT_U24, /* 24 / 32 bits */
+VIRTIO_SND_PCM_FMT_S32, /* 32 / 32 bits */
+VIRTIO_SND_PCM_FMT_U32, /* 32 / 32 bits */
+VIRTIO_SND_PCM_FMT_FLOAT,   /* 32 / 32 bits */
+VIRTIO_SND_PCM_FMT_FLOAT64, /* 64 / 64 bits */
+/* digital formats (width / physical width) */
+VIRTIO_SND_PCM_FMT_DSD_U8,  /*  8 /  8 bits */
+VIRTIO_SND_PCM_FMT_DSD_U16, /* 16 / 16 bits */
+VIRTIO_SND_PCM_FMT_DSD_U32, /* 32 / 32 bits */
+VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME  /* 32 / 32 bits */
+};
+
+/* Supported PCM frame rates */
+enum {
+VIRTIO_SND_PCM_RATE_5512 = 0,
+VIRTIO_SND_PCM_RATE_8000,
+VIRTIO_SND_PCM_RATE_11025,
+VIRTIO_SND_PCM_RATE_16000,
+VIRTIO_SND_PCM_RATE_22050,
+VIRTIO_SND_PCM_RATE_32000,
+VIRTIO_SND_PCM_RATE_44100,
+VIRTIO_SND_PCM_RATE_48000,
+VIRTIO_SND_PCM_RATE_64000,
+VIRTIO_SND_PCM_RATE_88200,
+VIRTIO_SND_PCM_RATE_96000,
+VIRTIO_SND_PCM_RATE_176399,
+VIRTIO_SND_PCM_RATE_192000,
+VIRTIO_SND_PCM_RATE_384000
+};
+
+/* PCM stream info structure */
+typedef struct virtio_snd_pcm_info {
+/* common header */
+virtio_snd_info hdr;
+/* supported features bitmap (1 << VIRTIO_SND_PCM_F_*) */
+uint32_t features;
+/* supported sample formats bitmap (1 << VIRTIO_SND_PCM_FMT_*) */
+uint64_t formats;
+/* supported sample rates bitmap (1 << VIRTIO_SND_PCM_RATE_*) */
+uint64_t rates;
+/* direction of the stream (VIRTIO_SND_D_*) */
+uint8_t direction;
+/* min # of supported channels */
+uint8_t channels_min;
+/* max # of supported channels */
+uint8_t channels_max;
+
+uint8_t padding[5];
+} virtio_snd_pcm_info;
+
+/* set PCM stream params */
+typedef struct virtio_snd_pcm_set_params {
+virtio_snd_pcm_hdr hdr;
+/* size of hardware buffer in bytes */
+uint32_t buffer_bytes;
+/* size of hardware period in bytes */
+uint32_t period_bytes;
+/* selected feature bitmap */
+uint32_t features;
+/* number of channels */
+uint8_t channel;
+/* VIRTIO_SND_PCM_FMT_* */
+uint8_t format;
+/* VIRTIO_SND_PCM_RATE_* */
+uint8_t rate;
+
+uint8_t padding;
+} virtio_snd_pcm_set_params;
+
+/* PCM I/O MESSAGES */
+
+/* I/O request header */
+typedef struct virtio_snd_pcm_xfer {
+/* 0 to (virtio_snd_config.stream - 1 */
+uint32_t stream_id;
+} virtio_snd_pcm_xfer;
+
+/* I/O request status */
+typedef struct virtio_snd_pcm_status {
+/* VIRTIO_SND_S_* */
+uint32_t status;
+/* current device latency */
+uint32_t latency_bytes;
+} virtio_snd_pcm_status;
+
 #endif
-- 
2.31.1




[RFC PATCH 01/25] virtio-snd: Add virtio sound header file

2022-02-11 Thread Shreyansh Chouhan
Added device configuration and common definitions to the header
file.

Signed-off-by: Shreyansh Chouhan 
---
 include/hw/virtio/virtio-snd.h | 97 ++
 1 file changed, 97 insertions(+)
 create mode 100644 include/hw/virtio/virtio-snd.h

diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h
new file mode 100644
index 00..bbbf174c51
--- /dev/null
+++ b/include/hw/virtio/virtio-snd.h
@@ -0,0 +1,97 @@
+/*
+ * Virtio Sound Device
+ */
+
+#ifndef QEMU_VIRTIO_SOUND_H
+#define QEMU_VIRTIO_SOUND_H
+
+#include "qemu/units.h"
+#include "hw/virtio/virtio.h"
+#include "qemu/queue.h"
+#include "audio/audio.h"
+#include "audio/audio_int.h"
+
+#define VIRTIO_ID_SOUND 25
+
+/* CONFIGURATION SPACE */
+
+typedef struct virtio_snd_config {
+/* # of jacks available */
+uint32_t jacks;
+/* # of streams avalable */
+uint32_t streams;
+/* # chmaps available */
+uint32_t chmaps;
+} virtio_snd_config;
+
+/* COMMON DEFINITIONS */
+
+/* supported sample data directions. */
+enum {
+VIRTIO_SND_D_OUTPUT = 0,
+VIRTIO_SND_D_INPUT
+};
+
+enum {
+/* jack control request types */
+VIRTIO_SND_R_JACK_INFO = 1,
+VIRTIO_SND_R_JACK_REMAP,
+
+/* PCM control request types */
+VIRTIO_SND_R_PCM_INFO = 0x0100,
+VIRTIO_SND_R_PCM_SET_PARAMS,
+VIRTIO_SND_R_PCM_PREPARE,
+VIRTIO_SND_R_PCM_RELEASE,
+VIRTIO_SND_R_PCM_START,
+VIRTIO_SND_R_PCM_STOP,
+
+/* channel map control request type */
+VIRTIO_SND_R_CHMAP_INFO = 0x200,
+
+/* jack event types */
+VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
+VIRTIO_SND_EVT_JACK_DISCONNECTED,
+
+/* PCM event types */
+VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
+VIRTIO_SND_EVT_PCM_XRUN,
+
+/* common status codes */
+VIRTIO_SND_S_OK = 0x8000,
+VIRTIO_SND_S_BAD_MSG,
+VIRTIO_SND_S_NOT_SUPP,
+VIRTIO_SND_S_IO_ERR
+};
+
+/* common header for request/response*/
+typedef struct virtio_snd_hdr {
+uint32_t code;
+} virtio_snd_hdr;
+
+/* event notification */
+typedef struct virtio_snd_event {
+/* VIRTIO_SND_EVT_* */
+virtio_snd_hdr hdr;
+/* Optional event data */
+uint32_t data;
+} virtio_snd_event;
+
+/* common control request to query an item information */
+typedef struct virtio_snd_query_info {
+/* VIRTIO_SND_R_*_INFO */
+struct virtio_snd_hdr hdr;
+/* item start identifier */
+uint32_t start_id;
+/* # of items to query */
+uint32_t count;
+/* size of a single item information in bytes */
+uint32_t size;
+} virtio_snd_query_info;
+
+/* common item information header */
+typedef struct virtio_snd_info {
+/* functional group node id (HDA Spec 7.1.2) */
+uint32_t hda_fn_nid;
+} virtio_snd_info;
+
+#endif
-- 
2.31.1




[RFC PATCH 07/25] virtio-snd: Add properties for class init

2022-02-11 Thread Shreyansh Chouhan
Added properties and function stubs for virtio sound device class
init.

Signed-off-by: Shreyansh Chouhan 
---
 hw/audio/Kconfig  |   5 ++
 hw/audio/meson.build  |   1 +
 hw/audio/virtio-snd.c | 126 ++
 3 files changed, 132 insertions(+)
 create mode 100644 hw/audio/virtio-snd.c

diff --git a/hw/audio/Kconfig b/hw/audio/Kconfig
index e9c6fed826..d12df06699 100644
--- a/hw/audio/Kconfig
+++ b/hw/audio/Kconfig
@@ -50,3 +50,8 @@ config CS4231
 
 config MARVELL_88W8618
 bool
+
+config VIRTIO_SND
+bool
+default y
+depends on VIRTIO
diff --git a/hw/audio/meson.build b/hw/audio/meson.build
index e48a9fc73d..455e6a1501 100644
--- a/hw/audio/meson.build
+++ b/hw/audio/meson.build
@@ -12,3 +12,4 @@ softmmu_ss.add(when: 'CONFIG_PL041', if_true: 
files('pl041.c', 'lm4549.c'))
 softmmu_ss.add(when: 'CONFIG_SB16', if_true: files('sb16.c'))
 softmmu_ss.add(when: 'CONFIG_VT82C686', if_true: files('via-ac97.c'))
 softmmu_ss.add(when: 'CONFIG_WM8750', if_true: files('wm8750.c'))
+softmmu_ss.add(when: 'CONFIG_VIRTIO_SND', if_true: files('virtio-snd.c'))
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
new file mode 100644
index 00..ae438aa7ec
--- /dev/null
+++ b/hw/audio/virtio-snd.c
@@ -0,0 +1,126 @@
+/*
+ * Virtio Sound device
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/atomic.h"
+#include "qemu/iov.h"
+#include "qemu/main-loop.h"
+#include "qemu/module.h"
+#include "hw/virtio/virtio.h"
+#include "audio/audio.h"
+#include "qemu/error-report.h"
+#include "qemu/timer.h"
+#include "qemu/option.h"
+#include "qemu/option_int.h"
+#include "qemu/config-file.h"
+#include "qapi/qmp/qdict.h"
+#include "hw/virtio/virtio-snd.h"
+#include "hw/virtio/virtio-bus.h"
+#include "qapi/error.h"
+#include "qapi/qapi-events-audio.h"
+#include "hw/qdev-properties.h"
+#include "qapi/qapi-types-migration.h"
+#include "qapi/qapi-events-migration.h"
+#include "migration/misc.h"
+#include "standard-headers/linux/ethtool.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+#include "monitor/qdev.h"
+#include "hw/pci/pci.h"
+#include "intel-hda-defs.h"
+
+#define VIRTIO_SOUND_VM_VERSION 1
+
+#define VIRTIO_SOUND_JACK_DEFAULT 0
+#define VIRTIO_SOUND_STREAM_DEFAULT 1
+#define VIRTIO_SOUND_CHMAP_DEFAULT 0
+
+#define VIRTIO_SOUND_HDA_FN_NID_OUT 0
+#define VIRTIO_SOUND_HDA_FN_NID_IN 1
+
+static void virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+}
+
+static void virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+}
+
+static const VMStateDescription vmstate_virtio_snd_device = {
+.name = "virtio-snd-device",
+.version_id = VIRTIO_SOUND_VM_VERSION,
+.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
+};
+
+static const VMStateDescription vmstate_virtio_snd = {
+.name = "virtio-sound",
+.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
+.version_id = VIRTIO_SOUND_VM_VERSION,
+.fields = (VMStateField[]) {
+VMSTATE_VIRTIO_DEVICE,
+VMSTATE_END_OF_LIST()
+},
+};
+
+static Property virtio_snd_properties[] = {
+DEFINE_AUDIO_PROPERTIES(VirtIOSound, card),
+DEFINE_PROP_UINT32("jacks", VirtIOSound, snd_conf.jacks,
+   VIRTIO_SOUND_JACK_DEFAULT),
+DEFINE_PROP_UINT32("streams", VirtIOSound, snd_conf.streams,
+   VIRTIO_SOUND_STREAM_DEFAULT),
+DEFINE_PROP_UINT32("chmaps", VirtIOSound, snd_conf.chmaps,
+   VIRTIO_SOUND_CHMAP_DEFAULT),
+DEFINE_PROP_END_OF_LIST(),
+};
+
+static uint64_t virtio_snd_get_features(VirtIODevice *vdev, uint64_t features,
+Error **errp)
+{
+return vdev->host_features;
+}
+
+static void virtio_snd_device_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void virtio_snd_device_unrealize(DeviceState *dev)
+{
+}
+
+static void virtio_snd_reset(VirtIODevice *vdev)
+{
+}
+
+static void virtio_snd_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+device_class_set_props(dc, virtio_snd_properties);
+dc->vmsd = _virtio_snd;
+set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
+vdc->realize = virtio_snd_device_realize;
+vdc->unrealize = virtio_snd_device_unrealize;
+vdc->get_config = virtio_snd_get_config;
+vdc->set_config = virtio_snd_set_config;
+vdc->get_features = virtio_snd_get_features;
+vdc->reset = virtio_snd_reset;
+vdc->legacy_features = 0;
+vdc->vmsd = _virtio_snd_device;
+}
+
+
+static const TypeInfo virtio_snd_dev_info = {
+.name = TYPE_VIRTIO_SOUND,
+.parent = TYPE_VIRTIO_DEVICE,
+.instance_size = sizeof(VirtIOSound),
+.class_init = virtio_snd_class_init,
+};
+
+static void virtio_register_types(void)
+{
+type_register_static(_snd_dev_info);
+}
+
+type_init(virtio_register_types)
-- 
2.31.1




[RFC PATCH 04/25] virtio-snd: Add chmap control structures

2022-02-11 Thread Shreyansh Chouhan
Added structures for handling channel map control
requests to the header file.

Signed-off-by: Shreyansh Chouhan 
---
 include/hw/virtio/virtio-snd.h | 57 ++
 1 file changed, 57 insertions(+)

diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h
index a7828c4ab8..3c16609a25 100644
--- a/include/hw/virtio/virtio-snd.h
+++ b/include/hw/virtio/virtio-snd.h
@@ -257,4 +257,61 @@ typedef struct virtio_snd_pcm_status {
 uint32_t latency_bytes;
 } virtio_snd_pcm_status;
 
+/* CHANNEL MAP CONTROL MESSAGES */
+
+/* standard channel position definition */
+enum {
+VIRTIO_SND_CHMAP_NONE = 0,  /* undefined */
+VIRTIO_SND_CHMAP_NA,/* silent */
+VIRTIO_SND_CHMAP_MONO,  /* mono stream */
+VIRTIO_SND_CHMAP_FL,/* front left */
+VIRTIO_SND_CHMAP_FR,/* front right */
+VIRTIO_SND_CHMAP_RL,/* rear left */
+VIRTIO_SND_CHMAP_RR,/* rear right */
+VIRTIO_SND_CHMAP_FC,/* front center */
+VIRTIO_SND_CHMAP_LFE,   /* low frequency (LFE) */
+VIRTIO_SND_CHMAP_SL,/* side left */
+VIRTIO_SND_CHMAP_SR,/* side right */
+VIRTIO_SND_CHMAP_RC,/* rear center */
+VIRTIO_SND_CHMAP_FLC,   /* front left center */
+VIRTIO_SND_CHMAP_FRC,   /* front right center */
+VIRTIO_SND_CHMAP_RLC,   /* rear left center */
+VIRTIO_SND_CHMAP_RRC,   /* rear right center */
+VIRTIO_SND_CHMAP_FLW,   /* front left wide */
+VIRTIO_SND_CHMAP_FRW,   /* front right wide */
+VIRTIO_SND_CHMAP_FLH,   /* front left high */
+VIRTIO_SND_CHMAP_FCH,   /* front center high */
+VIRTIO_SND_CHMAP_FRH,   /* front right high */
+VIRTIO_SND_CHMAP_TC,/* top center */
+VIRTIO_SND_CHMAP_TFL,   /* top front left */
+VIRTIO_SND_CHMAP_TFR,   /* top front right */
+VIRTIO_SND_CHMAP_TFC,   /* top front center */
+VIRTIO_SND_CHMAP_TRL,   /* top rear left */
+VIRTIO_SND_CHMAP_TRR,   /* top rear right */
+VIRTIO_SND_CHMAP_TRC,   /* top rear center */
+VIRTIO_SND_CHMAP_TFLC,  /* top front left center */
+VIRTIO_SND_CHMAP_TFRC,  /* top front right center */
+VIRTIO_SND_CHMAP_TSL,   /* top side left */
+VIRTIO_SND_CHMAP_TSR,   /* top side right */
+VIRTIO_SND_CHMAP_LLFE,  /* left LFE */
+VIRTIO_SND_CHMAP_RLFE,  /* right LFE */
+VIRTIO_SND_CHMAP_BC,/* bottom center */
+VIRTIO_SND_CHMAP_BLC,   /* bottom left center */
+VIRTIO_SND_CHMAP_BRC/* bottom right center */
+};
+
+/* maximum possible number of channels */
+#define VIRTIO_SND_CHMAP_MAX_SIZE   18
+
+typedef struct virtio_snd_chmap_info {
+/* common header */
+virtio_snd_info hdr;
+/* direction */
+uint8_t direction;
+/* # of valid channel position values */
+uint8_t channels;
+/* channel position values (VIRTIO_SND_CHMAP_*) */
+uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
+} virtio_snd_chmap_info;
+
 #endif
-- 
2.31.1




[RFC PATCH 02/25] virtio-snd: Add jack control structures

2022-02-11 Thread Shreyansh Chouhan
Added structures for handling jack control requests
to the header file.

Signed-off-by: Shreyansh Chouhan 
---
 include/hw/virtio/virtio-snd.h | 40 ++
 1 file changed, 40 insertions(+)

diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h
index bbbf174c51..f58b06a949 100644
--- a/include/hw/virtio/virtio-snd.h
+++ b/include/hw/virtio/virtio-snd.h
@@ -94,4 +94,44 @@ typedef struct virtio_snd_info {
 uint32_t hda_fn_nid;
 } virtio_snd_info;
 
+/* JACK CONTROL MESSAGES */
+
+typedef struct virtio_snd_jack_hdr {
+/* VIRTIO_SND_R_JACK_* */
+virtio_snd_hdr hdr;
+/* 0 to (virtio_snd_config.jacks - 1) */
+uint32_t jack_id;
+} virtio_snd_jack_hdr;
+
+/* Supported jack features */
+enum {
+VIRTIO_SND_F_JACK_REMAP = 0
+};
+
+/* jack information structure */
+typedef struct virtio_snd_jack_info {
+/* common header */
+virtio_snd_info hdr;
+/* 1 << VIRTIO_SND_JACK_F_* */
+uint32_t features;
+/* pin default configuration from HDA spec */
+uint32_t hda_reg_defconf;
+/* pin capabilities from HDA spec */
+uint32_t hda_reg_caps;
+/* connection status (0: disconnected, 1: connected) */
+uint8_t connected;
+
+uint8_t padding[7];
+} virtio_snd_jack_info;
+
+/* jack remapping control request */
+typedef struct virtio_snd_jack_remap {
+/* .code = VIRTIO_SND_R_JACK_REMAP */
+virtio_snd_jack_hdr hdr;
+/* selected association number */
+uint32_t association;
+/* selected sequence number */
+uint32_t sequence;
+} virtio_snd_jack_remap;
+
 #endif
-- 
2.31.1




[RFC PATCH v2 00/25] Virtio Sound card Implementation

2022-02-11 Thread Shreyansh Chouhan
The second RFC for implementing the VirtIO Sound card as described in
the virtio specs. Sorry for the absence of activity on this.

The output from the sound card works.

What remains to be done:
- Features defined in PCM features. (Eg message polling)
- Channel maps
- Jack remaps
- Input

I will work on the input after I have implemented the output
along with all the features since at that point it should just be a
matter of reversing a few things in the code that writes the audio.

I can work on this patchset mostly on weekends now but I will try to be
more regular with this.

Reviews are welcome :)

Shreyansh Chouhan (25):
  virtio-snd: Add virtio sound header file
  virtio-snd: Add jack control structures
  virtio-snd: Add PCM control structures
  virtio-snd: Add chmap control structures
  virtio-snd: Add device implementation structures
  virtio-snd: Add PCI wrapper code for VirtIOSound
  virtio-snd: Add properties for class init
  virtio-snd: Add code for get config function
  virtio-snd: Add code for the realize function
  virtio-snd: Add macros for logging
  virtio-snd: Add control virtqueue handler
  virtio-snd: Add VIRTIO_SND_R_JACK_INFO handler
  virtio-snd: Add stub for VIRTIO_SND_R_JACK_REMAP handler
  virtio-snd: Add VIRTIO_SND_R_PCM_INFO handler
  virtio-snd: Add VIRITO_SND_R_PCM_SET_PARAMS handle
  virtio-snd: Add VIRTIO_SND_R_PCM_PREPARE handler
  virtio-snd: Add default configs to realize fn
  virtio-snd: Add callback for SWVoiceOut
  virtio-snd: Add start/stop handler
  virtio-snd: Add VIRTIO_SND_R_PCM_RELEASE handler
  virtio-snd: Replaced goto with if else
  virtio-snd: Add code to device unrealize function
  virtio-snd: Add xfer handler
  virtio-snd: Add event vq and a handler stub
  virtio-snd: Replaced AUD_log with tracepoints

 hw/audio/Kconfig   |5 +
 hw/audio/meson.build   |1 +
 hw/audio/trace-events  |   14 +
 hw/audio/virtio-snd.c  | 1241 
 hw/virtio/meson.build  |1 +
 hw/virtio/virtio-snd-pci.c |   72 ++
 include/hw/virtio/virtio-snd.h |  383 ++
 7 files changed, 1717 insertions(+)
 create mode 100644 hw/audio/virtio-snd.c
 create mode 100644 hw/virtio/virtio-snd-pci.c
 create mode 100644 include/hw/virtio/virtio-snd.h

-- 
2.31.1




Re: [PATCH v1 09/11] tests/tcg: build sha1-vector with O3 and compare

2022-02-11 Thread Richard Henderson

On 2/12/22 03:03, Alex Bennée wrote:

The aim of this is to test code generation for vectorised operations.
Unfortunately gcc struggles to do much with the messy sha1 code (try
-fopt-info-vec-missed to see why). However it's better than nothing.

We assume the non-vectorised output is gold and baring compiler bugs
the outputs should match.

Signed-off-by: Alex Bennée
Message-Id:<20220202191242.652607-3-alex.ben...@linaro.org>
---
  tests/tcg/aarch64/Makefile.target | 10 ++
  tests/tcg/arm/Makefile.target |  9 +
  2 files changed, 19 insertions(+)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v1 05/11] tests/docker: introduce debian-riscv64-test-cross

2022-02-11 Thread Richard Henderson

On 2/12/22 03:03, Alex Bennée wrote:

Cross building QEMU for riscv64 still involves messing about with sid
and ports. However for building tests we can have a slimmer compiler
only container which should be more stable.

Signed-off-by: Alex Bennée
---
  .gitlab-ci.d/container-cross.yml |  7 +++
  tests/docker/Makefile.include|  2 ++
  .../dockerfiles/debian-riscv64-test-cross.docker | 12 
  tests/tcg/configure.sh   |  2 +-
  4 files changed, 22 insertions(+), 1 deletion(-)
  create mode 100644 tests/docker/dockerfiles/debian-riscv64-test-cross.docker


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v1 04/11] tests/docker: update debian-arm64-cross with lci-tool

2022-02-11 Thread Richard Henderson

On 2/12/22 03:03, Alex Bennée wrote:

Using lci-tool update debian-arm64-cross to a Debian 11 based system.
As a result we can drop debian-arm64-test-cross just for building
tests.

Signed-off-by: Alex Bennée
---
  .gitlab-ci.d/container-cross.yml  |  10 +-
  tests/docker/Makefile.include |   3 -
  .../dockerfiles/debian-arm64-cross.docker | 186 +++---
  .../debian-arm64-test-cross.docker|  13 --
  tests/lcitool/refresh |  11 ++
  tests/tcg/configure.sh|   2 +-
  6 files changed, 173 insertions(+), 52 deletions(-)
  delete mode 100644 tests/docker/dockerfiles/debian-arm64-test-cross.docker


Reviewed-by: Richard Henderson 

r~



Re: [RFC PATCH 0/3] tests/tcg/ppc64le: fix the build of TCG tests with Clang

2022-02-11 Thread Matheus K. Ferst

On 09/02/2022 09:31, Cédric Le Goater wrote:

Hello Matheus,

[ Adding Miroslav ]

On 2/8/22 21:31, matheus.fe...@eldorado.org.br wrote:

From: Matheus Ferst 

Based-on: 
https://lists.gnu.org/archive/html/qemu-devel/2022-01/msg06506.html


As the configuration scripts used -mbig and -mlittle, building PPC tests
with Clang was silently skipped. With the patch to fix these options[1],
"make check-tcg" fails because of build and runtime errors. This patch
series tries to fix some of these problems.

The first patch fixes "tests/tcg/ppc64le/mtfsf.c" by removing the
GCC-only builtins used to emit mtfsf and mffs. We can emit these insns
with inline asm instead.

The second patch addresses differences in the output of float_madds.c.
The __builtin_fmaf used in this test emits fmadds with GCC and xsmaddasp
with LLVM. The first insn had rounding errors fixed in
d04ca895dc7f ("target/ppc: Add helpers for fmadds et al"), we apply
a similar fix to xsmaddasp.

Then we have the build errors of tests/tcg/ppc64le/bcdsub.c. According
to GCC docs[2], the '-mpower8-vector' flag provides some bcdsub
builtins, so it'd be reasonable to assume that the rest of the toolchain
knows about the insn if the compiler accepts this flag. Clang supports
this flag since version 3.6[3], but the insn and builtins were only
added in LLVM 14[4]. I couldn't find a good solution. Should we write a
test to check for this insn at configuration time? Should we detect the
compiler at build time and emit the insns with ".long" and fixed
registers?

Even building with Clang 14, the test will fail in runtime because
LLVM doesn't like "__int128" in inline asm. No error or warning is
emitted, but the generated code only loads one doubleword of the VSR.
The third patch of this series avoids this issue by using a vector
type for VSR values.

Finally, it seems that the insns tested by
tests/tcg/ppc64le/byte_reverse.c are not yet supported by LLVM. Since
the configuration script uses '-mpower10' to check for POWER10 support
and Clang doesn't support this flag, "make check-tcg" doesn't fail. We
should probably change this check in the future, but since LLVM support
of POWER10 seems incomplete, I guess we can leave it for now.


gitlab didn't spot any issues with the 4 patches applied.



AFAICT, CI wouldn't run into this kind of problem because we don't have 
PPC runners, and the cross-compiler containers use GCC.



Should we merge all patches :

   Use long endian options for ppc64
   tests/tcg/ppc64le: Use vector types instead of __int128
   target/ppc: change xs[n]madd[am]sp to use float64r32_muladd
   tests/tcg/ppc64le: use inline asm instead of __builtin_mtfsf

and see how we can address the LLVM support for P10 later ?



The problems with bcdsub.c are not resolved for Clang < 14, but I guess 
it's ok to merge anyway.


Thanks,
Matheus K. Ferst
Instituto de Pesquisas ELDORADO 
Analista de Software
Aviso Legal - Disclaimer 


Adding a handshake to qemu-guest-agent

2022-02-11 Thread John Snow
[Moving our discussion upstream, because it stopped being brief and simple.]

What about something like this:

Add a new "request-negotiation" command to qemu-guest-agent 7.0.0.

[Modern client to unknown server]
1. A modern client connects to a server of unknown version, and
without waiting, issues the "request-negotiation" command.
2. An old server will reply with CommandNotFound. We are done negotiating.
3. A modern server will reply with the greeting in the traditional
format, but as a reply object (to preserve "execute" semantics.)
4. The modern client will now issue qmp-capabilities as normal.
5. The server replies with success or failure as normal.
6. Connection is fully established.

[Old client to unknown server]
1. An old client connects to an unknown version server.
2. A command is issued some time later.
  2a. The server is old, the command worked as anticipated.
  2b. The server is new, the command fails with CommandNotFound and
urges the use of 'request-negotiation'.

Compatibility matrix summary:
Old client on old server: Works just fine, as always.
Old client on new server: Will fail; the new server requires the
negotiation step to be performed. This is a tractable problem.
POSSIBLY we need to send some kind of "warning event" for two versions
before making it genuinely mandatory. Also tractable.
New client on old server: Works, albeit with a single failed execute
command now in the log file.
New client on new server: Works, though handshaking is now permanently
a little chattier than with any other QMP server.

***The QMP spec will need to be updated*** to state: the asynchronous
greeting is mandatory on all QMP implementations, EXCEPT for the
qemu-guest-agent, which for historical reasons, uses an alternate
handshaking process, ...

Compatibility concerns:
- We must never remove the 'request-negotiation' command from QGA,
forever-and-ever, unless we also make a new error class for
"NegotiationRequired" that's distinct from "CommandNotFound", but
that's more divergence. Supporting the negotiation request command
forever-and-ever is probably fine.
- QGA is now officially on a different flavor of QMP protocol. You
still need to know in advance if you are connecting to QGA or anything
else. That's still a little sad, but maybe that's just simply an
impossible goal.

Bonus:
- If an execution ID is used when sending "request-negotiation", we
know that the server is at least version 4.0.0 if it responds to us
using that ID. A modern client can then easily distinguish between
pre-4.0, post-4.0 and post-7.0 servers. It's a useful probe.

--js




Re: [PATCH] scripts/qapi: minor delinting

2022-02-11 Thread John Snow
On Fri, Feb 11, 2022 at 12:11 PM John Snow  wrote:
>
> On Fri, Feb 11, 2022 at 6:58 AM Markus Armbruster  wrote:
> >
> > John Snow  writes:
> >
> > > On Thu, Feb 10, 2022 at 10:56 AM Markus Armbruster  
> > > wrote:
> > >>
> > >> John Snow  writes:
> > >>
> > >> > Just cleaning up some cobwebs.
> > >> >
> > >> > Signed-off-by: John Snow 
> > >> > ---
> > >> >  scripts/qapi/commands.py | 2 +-
> > >> >  scripts/qapi/events.py   | 6 +++---
> > >> >  scripts/qapi/types.py| 6 +-
> > >> >  scripts/qapi/visit.py| 6 +-
> > >> >  4 files changed, 14 insertions(+), 6 deletions(-)
> > >> >
> > >> > diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
> > >> > index 869d799ed2..38ca38a7b9 100644
> > >> > --- a/scripts/qapi/commands.py
> > >> > +++ b/scripts/qapi/commands.py
> > >> > @@ -25,8 +25,8 @@
> > >> >  QAPIGenC,
> > >> >  QAPISchemaModularCVisitor,
> > >> >  build_params,
> > >> > -ifcontext,
> > >> >  gen_special_features,
> > >> > +ifcontext,
> > >> >  )
> > >> >  from .schema import (
> > >> >  QAPISchema,
> > >> > diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
> > >> > index 27b44c49f5..8edf43d8da 100644
> > >> > --- a/scripts/qapi/events.py
> > >> > +++ b/scripts/qapi/events.py
> > >> > @@ -109,15 +109,15 @@ def gen_event_send(name: str,
> > >> >  if not boxed:
> > >> >  ret += gen_param_var(arg_type)
> > >> >
> > >> > -for f in features:
> > >> > -if f.is_special():
> > >> > +for feat in features:
> > >> > +if feat.is_special():
> > >> >  ret += mcgen('''
> > >> >
> > >> >  if (compat_policy.%(feat)s_output == COMPAT_POLICY_OUTPUT_HIDE) {
> > >> >  return;
> > >> >  }
> > >> >  ''',
> > >> > - feat=f.name)
> > >> > + feat=feat.name)
> > >> >
> > >> >  ret += mcgen('''
> > >> >
> > >>
> > >> Meh.  Expressive variable names are good when there's something useful
> > >> to express.  But what's the added value in such a simple, obvious loop?
> > >>
> > >> Besides:
> > >>
> > >> $ git-grep 'for . in' scripts/qapi | wc -l
> > >> 42
> > >> $ git-grep -E 'for [A-Za-z0-9]{2,} in' scripts/qapi | wc -l
> > >> 31
> > >>
> > >> > diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
> > >> > index 3013329c24..477d027001 100644
> > >> > --- a/scripts/qapi/types.py
> > >> > +++ b/scripts/qapi/types.py
> > >> > @@ -16,7 +16,11 @@
> > >> >  from typing import List, Optional
> > >> >
> > >> >  from .common import c_enum_const, c_name, mcgen
> > >> > -from .gen import QAPISchemaModularCVisitor, gen_special_features, 
> > >> > ifcontext
> > >> > +from .gen import (
> > >> > +QAPISchemaModularCVisitor,
> > >> > +gen_special_features,
> > >> > +ifcontext,
> > >> > +)
> > >> >  from .schema import (
> > >> >  QAPISchema,
> > >> >  QAPISchemaEnumMember,
> > >> > diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
> > >> > index e13bbe4292..380fa197f5 100644
> > >> > --- a/scripts/qapi/visit.py
> > >> > +++ b/scripts/qapi/visit.py
> > >> > @@ -21,7 +21,11 @@
> > >> >  indent,
> > >> >  mcgen,
> > >> >  )
> > >> > -from .gen import QAPISchemaModularCVisitor, gen_special_features, 
> > >> > ifcontext
> > >> > +from .gen import (
> > >> > +QAPISchemaModularCVisitor,
> > >> > +gen_special_features,
> > >> > +ifcontext,
> > >> > +)
> > >> >  from .schema import (
> > >> >  QAPISchema,
> > >> >  QAPISchemaEnumMember,
> > >>
> > >> Everything else, gladly
> > >> Reviewed-by: Markus Armbruster 
> > >
> > > The problem with whitelisting single-letter variable names is that
> > > it's done on a per-name basis, like allowing "x, y, z" or "i, j, k". I
> > > could whitelist "f", "m", etc but there's no way to whitelist "for f
> > > in features" or "for m im members" ... So admittedly, I just stuck
> > > with the default, even though it's a little annoying. It's what I use
> > > for python/, and I had previously used it for ./scripts/qapi/, so I
> > > was just carrying on.
> >
> > There are only 26 single-letter variable names.  Whitelist them all?
> >
> > > In general: I like the idea of forbidding single-letter variable names
> > > because I prefer things to be more verbose than terse as a habit. In
> > > practice: yeah, it's hard to strictly defend any one change as
> > > obviously superior. I preferred "for feature in features", which you
> > > did not like because the plural wasn't distinct enough (fair!), so I
> > > started using "for feat in features" as a compromise.
> >
> > @feat is a perfectly adequate name.  So is @f as long as the loop is
> > small.  What annoys me here is the churn.
> >
> > Sadly, pylint's invalid-name mixes up two things: PEP-8 conventions like
> > "use CamelCase for class names", and its own style rules like "names
> > should be least three characters long".  The former is easy to decide,
> > and welcome help.  The latter is actually a proxy for 

[PATCH v2] scripts/qapi: minor delinting

2022-02-11 Thread John Snow
Get isort and pylint tools passing again.

Signed-off-by: John Snow 
---
 scripts/qapi/commands.py |  2 +-
 scripts/qapi/pylintrc| 15 +--
 scripts/qapi/types.py|  6 +-
 scripts/qapi/visit.py|  6 +-
 4 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 869d799ed22..38ca38a7b9d 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -25,8 +25,8 @@
 QAPIGenC,
 QAPISchemaModularCVisitor,
 build_params,
-ifcontext,
 gen_special_features,
+ifcontext,
 )
 from .schema import (
 QAPISchema,
diff --git a/scripts/qapi/pylintrc b/scripts/qapi/pylintrc
index b259531a726..1fed2e69620 100644
--- a/scripts/qapi/pylintrc
+++ b/scripts/qapi/pylintrc
@@ -34,16 +34,11 @@ disable=fixme,
 
 [BASIC]
 
-# Good variable names which should always be accepted, separated by a comma.
-good-names=i,
-   j,
-   k,
-   ex,
-   Run,
-   _,
-   fp,  # fp = open(...)
-   fd,  # fd = os.open(...)
-   ch,
+# Good variable names regexes, separated by a comma. If names match any regex,
+# they will always be accepted
+
+# Allow just about anything, as per Markus's preference.
+good-names-rgxs=^[_a-z][_a-z0-9]?$
 
 [VARIABLES]
 
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 3013329c248..477d0270013 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -16,7 +16,11 @@
 from typing import List, Optional
 
 from .common import c_enum_const, c_name, mcgen
-from .gen import QAPISchemaModularCVisitor, gen_special_features, ifcontext
+from .gen import (
+QAPISchemaModularCVisitor,
+gen_special_features,
+ifcontext,
+)
 from .schema import (
 QAPISchema,
 QAPISchemaEnumMember,
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index e13bbe42925..380fa197f58 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -21,7 +21,11 @@
 indent,
 mcgen,
 )
-from .gen import QAPISchemaModularCVisitor, gen_special_features, ifcontext
+from .gen import (
+QAPISchemaModularCVisitor,
+gen_special_features,
+ifcontext,
+)
 from .schema import (
 QAPISchema,
 QAPISchemaEnumMember,
-- 
2.34.1




[PATCH v11 4/4] target/ppc: trigger PERFM EBBs from power8-pmu.c

2022-02-11 Thread Daniel Henrique Barboza
This patch adds the EBB exception support that are triggered by
Performance Monitor alerts. This happens when a Performance Monitor
alert occurs and MMCR0_EBE, BESCR_PME and BESCR_GE are set.

fire_PMC_interrupt() will execute a new ebb_perfm_excp() helper that
will check for MMCR0_EBE, BESCR_PME and BESCR_GE bits. If all bits are
set, do_ebb() will attempt to trigger a PERFM EBB event.

If the EBB facility is enabled in both FSCR and HFSCR we consider that
the EBB is valid and set BESCR_PMEO. After that, if we're running in
problem state, fire a POWERPC_EXCP_PERM_EBB immediately. Otherwise we'll
queue a PPC_INTERRUPT_EBB.

Signed-off-by: Daniel Henrique Barboza 
---
 target/ppc/excp_helper.c | 48 
 target/ppc/helper.h  |  1 +
 target/ppc/power8-pmu.c  |  3 +--
 3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index ad40a0f8e6..0c031e67b1 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1948,6 +1948,54 @@ void helper_rfebb(CPUPPCState *env, target_ulong s)
 env->spr[SPR_BESCR] &= ~BESCR_GE;
 }
 }
+
+/*
+ * Triggers or queues an 'ebb_excp' EBB exception. All checks
+ * but FSCR, HFSCR and msr_pr must be done beforehand.
+ *
+ * PowerISA v3.1 isn't clear about whether an EBB should be
+ * postponed or cancelled if the EBB facility is unavailable.
+ * Our assumption here is that the EBB is cancelled if both
+ * FSCR and HFSCR EBB facilities aren't available.
+ */
+static void do_ebb(CPUPPCState *env, int ebb_excp)
+{
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = CPU(cpu);
+
+/*
+ * FSCR_EBB and FSCR_IC_EBB are the same bits used with
+ * HFSCR.
+ */
+helper_fscr_facility_check(env, FSCR_EBB, 0, FSCR_IC_EBB);
+helper_hfscr_facility_check(env, FSCR_EBB, "EBB", FSCR_IC_EBB);
+
+if (ebb_excp == POWERPC_EXCP_PERFM_EBB) {
+env->spr[SPR_BESCR] |= BESCR_PMEO;
+} else if (ebb_excp == POWERPC_EXCP_EXTERNAL_EBB) {
+env->spr[SPR_BESCR] |= BESCR_EEO;
+}
+
+if (msr_pr == 1) {
+powerpc_excp(cpu, ebb_excp);
+} else {
+env->pending_interrupts |= 1 << PPC_INTERRUPT_EBB;
+cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+}
+}
+
+void helper_ebb_perfm_excp(CPUPPCState *env)
+{
+bool perfm_ebb_enabled = env->spr[SPR_POWER_MMCR0] & MMCR0_EBE &&
+ env->spr[SPR_BESCR] & BESCR_PME &&
+ env->spr[SPR_BESCR] & BESCR_GE;
+
+if (!perfm_ebb_enabled) {
+return;
+}
+
+do_ebb(env, POWERPC_EXCP_PERFM_EBB);
+}
 #endif
 
 /*/
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index f2e5060910..adc31235a8 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -19,6 +19,7 @@ DEF_HELPER_1(rfid, void, env)
 DEF_HELPER_1(rfscv, void, env)
 DEF_HELPER_1(hrfid, void, env)
 DEF_HELPER_2(rfebb, void, env, tl)
+DEF_HELPER_1(ebb_perfm_excp, void, env)
 DEF_HELPER_2(store_lpcr, void, env, tl)
 DEF_HELPER_2(store_pcr, void, env, tl)
 DEF_HELPER_2(store_mmcr0, void, env, tl)
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index d245663158..38e1ecb782 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -307,8 +307,7 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
 env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO;
 }
 
-/* PMC interrupt not implemented yet */
-return;
+helper_ebb_perfm_excp(env);
 }
 
 /* This helper assumes that the PMC is running. */
-- 
2.34.1




[PATCH v11 3/4] target/ppc: add PPC_INTERRUPT_EBB and EBB exceptions

2022-02-11 Thread Daniel Henrique Barboza
PPC_INTERRUPT_EBB is a new interrupt that will be used to deliver EBB
exceptions that had to be postponed because the thread wasn't in problem
state at the time the event-based branch was supposed to occur.

ISA 3.1 also defines two EBB exceptions: Performance Monitor EBB
exception and External EBB exception. They are being added as
POWERPC_EXCP_PERFM_EBB and POWERPC_EXCP_EXTERNAL_EBB.

PPC_INTERRUPT_EBB will check BESCR bits to see the EBB type that
occurred and trigger the appropriate exception. Both exceptions are
doing the same thing in this first implementation: clear BESCR_GE and
enter the branch with env->nip retrieved from SPR_EBBHR.

The checks being done by the interrupt code are msr_pr and BESCR_GE
states. All other checks (EBB facility check, BESCR_PME bit, specific
bits related to the event type) must be done beforehand.

Signed-off-by: Daniel Henrique Barboza 
---
 target/ppc/cpu.h |  5 -
 target/ppc/cpu_init.c|  4 
 target/ppc/excp_helper.c | 33 +
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index dcd83b503c..3962c8f6f4 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -129,8 +129,10 @@ enum {
 /* ISA 3.00 additions */
 POWERPC_EXCP_HVIRT= 101,
 POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception 
*/
+POWERPC_EXCP_PERFM_EBB = 103,/* Performance Monitor EBB Exception*/
+POWERPC_EXCP_EXTERNAL_EBB = 104, /* External EBB Exception   */
 /* EOL   */
-POWERPC_EXCP_NB   = 103,
+POWERPC_EXCP_NB   = 105,
 /* QEMU exceptions: special cases we want to stop translation*/
 POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only  */
 };
@@ -2453,6 +2455,7 @@ enum {
 PPC_INTERRUPT_HMI,/* Hypervisor Maintenance interrupt*/
 PPC_INTERRUPT_HDOORBELL,  /* Hypervisor Doorbell interrupt*/
 PPC_INTERRUPT_HVIRT,  /* Hypervisor virtualization interrupt  */
+PPC_INTERRUPT_EBB,/* Event-based Branch exception */
 };
 
 /* Processor Compatibility mask (PCR) */
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index bf60529d37..136d8ca8b5 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -2336,6 +2336,10 @@ static void init_excp_POWER8(CPUPPCState *env)
 env->excp_vectors[POWERPC_EXCP_FU]   = 0x0F60;
 env->excp_vectors[POWERPC_EXCP_HV_FU]= 0x0F80;
 env->excp_vectors[POWERPC_EXCP_SDOOR_HV] = 0x0E80;
+
+/* Userland exceptions without vector value in PowerISA v3.1 */
+env->excp_vectors[POWERPC_EXCP_PERFM_EBB] = 0x0;
+env->excp_vectors[POWERPC_EXCP_EXTERNAL_EBB] = 0x0;
 #endif
 }
 
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 8a49a4ab90..ad40a0f8e6 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -990,6 +990,21 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
 new_msr |= (target_ulong)MSR_HVB;
 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
 break;
+case POWERPC_EXCP_PERFM_EBB:/* Performance Monitor EBB Exception  
*/
+case POWERPC_EXCP_EXTERNAL_EBB: /* External EBB Exception 
*/
+env->spr[SPR_BESCR] &= ~BESCR_GE;
+
+/*
+ * Save NIP for rfebb insn in SPR_EBBRR. Next nip is
+ * stored in the EBB Handler SPR_EBBHR.
+ */
+env->spr[SPR_EBBRR] = env->nip;
+powerpc_set_excp_state(cpu, env->spr[SPR_EBBHR], env->msr);
+
+/*
+ * This exception is handled in userspace. No need to proceed.
+ */
+return;
 case POWERPC_EXCP_THERM: /* Thermal interrupt*/
 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt   */
 case POWERPC_EXCP_VPUA:  /* Vector assist exception  */
@@ -1681,6 +1696,24 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 powerpc_excp(cpu, POWERPC_EXCP_THERM);
 return;
 }
+/* EBB exception */
+if (env->pending_interrupts & (1 << PPC_INTERRUPT_EBB)) {
+/*
+ * EBB exception must be taken in problem state and
+ * with BESCR_GE set.
+ */
+if (msr_pr == 1 && env->spr[SPR_BESCR] & BESCR_GE) {
+env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EBB);
+
+if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+}
+
+return;
+}
+}
 }
 
 if (env->resume_as_sreset) {
-- 
2.34.1




[PATCH v11 2/4] target/ppc: finalize pre-EBB PMU logic

2022-02-11 Thread Daniel Henrique Barboza
There are still PMU exclusive bits to handle in fire_PMC_interrupt()
before implementing the EBB support. Let's finalize it now to avoid
dealing with PMU and EBB logic at the same time in the next patches.

fire_PMC_interrupt() will fire an Performance Monitor alert depending on
MMCR0_PMAE. If we are required to freeze the timers (MMCR0_FCECE) we'll
also need to update summaries and delete the existing overflow timers.
In all cases we're going to update the cycle counters.

Signed-off-by: Daniel Henrique Barboza 
---
 target/ppc/power8-pmu.c | 36 ++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 236e8e66e9..d245663158 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -222,6 +222,20 @@ static void pmu_update_overflow_timers(CPUPPCState *env)
 }
 }
 
+static void pmu_delete_timers(CPUPPCState *env)
+{
+QEMUTimer *pmc_overflow_timer;
+int sprn;
+
+for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
+pmc_overflow_timer = get_cyc_overflow_timer(env, sprn);
+
+if (pmc_overflow_timer) {
+timer_del(pmc_overflow_timer);
+}
+}
+}
+
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
 {
 bool hflags_pmcc0 = (value & MMCR0_PMCC0) != 0;
@@ -271,8 +285,26 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
 {
 CPUPPCState *env = >env;
 
-if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_EBE)) {
-return;
+pmu_update_cycles(env);
+
+if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) {
+env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
+env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
+
+/* Changing MMCR0_FC requires a new HFLAGS_INSN_CNT calc */
+pmu_update_summaries(env);
+
+/*
+ * Delete all pending timers if we need to freeze
+ * the PMC. We'll restart them when the PMC starts
+ * running again.
+ */
+pmu_delete_timers(env);
+}
+
+if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE) {
+env->spr[SPR_POWER_MMCR0] &= ~MMCR0_PMAE;
+env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO;
 }
 
 /* PMC interrupt not implemented yet */
-- 
2.34.1




[PATCH v11 1/4] target/ppc: fix indent of function parameters

2022-02-11 Thread Daniel Henrique Barboza
Fix indentation of powerpc_set_excp_state() and ppc_excp_apply_ail()
parameters.

Reviewed-by: David Gibson 
Signed-off-by: Daniel Henrique Barboza 
---
 target/ppc/excp_helper.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index c107953dec..8a49a4ab90 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -265,9 +265,9 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState 
*env, int excp,
  * ++
  */
 static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
-  target_ulong msr,
-  target_ulong *new_msr,
-  target_ulong *vector)
+   target_ulong msr,
+   target_ulong *new_msr,
+   target_ulong *vector)
 {
 #if defined(TARGET_PPC64)
 CPUPPCState *env = >env;
@@ -362,7 +362,7 @@ static void ppc_excp_apply_ail(PowerPCCPU *cpu, int 
excp_model, int excp,
 }
 
 static void powerpc_set_excp_state(PowerPCCPU *cpu,
-  target_ulong vector, target_ulong 
msr)
+   target_ulong vector, target_ulong msr)
 {
 CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
-- 
2.34.1




[PATCH v11 0/4] PMU-EBB support for PPC64 TCG

2022-02-11 Thread Daniel Henrique Barboza
Hi,

This new version makes a few modifications to make the EBB support more
generic.

A new patch (3) was added to implement PPC_INTERRUPT_EBB and its two
internal exceptions described by ISA v3.1: POWERPC_EXCP_PERFM_EBB and
POWERPC_EXCP_EXTERNAL_EBB. When receiving an EBB interrupt we check
BESCR bits to fire the appropriate exception. They are doing the same
thing ATM (clear GE and enter the branch with env->nip = SPR_EBBHR).
PPC_INTERRUPT_EBB will be used for the future XIVE IC EBB lane as well.

Patch 4 (previous 3) contains the helpers used by the PMU to fire the
PERFM_EBB exception, but now we're checking msr_pr and either throwing
the exception immediately or queueing it up for later via
PPC_INTERRUPT_EBB.  This change covers all the race conditions that the
kernel EBB selftests seems to trigger, and without using ppc_set_irq()
to handle BQL.

Changes from v10:
- patch 1:
  * added David's r-b
- patch 3 (new):
  * add PPC_INTERRUPT_EBB, POWERPC_EXCP_PERFM_EBB and
POWERPC_EXCP_EXTERNAL_EBB
- patch 4:
  * all EBB bits are now being checked in the helper
  * a new static do_ebb() helper was created to handle the common
EBB logic
  * we're now checking msr_pr and either throwing the exception immediately
or queueing it for later using PPC_INTERRUPT_EBB
  * ppc_set_irq() call was removed
- v10 link: https://lists.gnu.org/archive/html/qemu-devel/2022-02/msg01856.html


Daniel Henrique Barboza (4):
  target/ppc: fix indent of function parameters
  target/ppc: finalize pre-EBB PMU logic
  target/ppc: add PPC_INTERRUPT_EBB and EBB exceptions
  target/ppc: trigger PERFM EBBs from power8-pmu.c

 target/ppc/cpu.h |  5 ++-
 target/ppc/cpu_init.c|  4 ++
 target/ppc/excp_helper.c | 89 ++--
 target/ppc/helper.h  |  1 +
 target/ppc/power8-pmu.c  | 39 --
 5 files changed, 129 insertions(+), 9 deletions(-)

-- 
2.34.1




Re: [PATCH v1 02/11] tests/docker: add NOUSER for alpine image

2022-02-11 Thread Daniel P . Berrangé
On Fri, Feb 11, 2022 at 05:51:25PM +, Alex Bennée wrote:
> 
> Daniel P. Berrangé  writes:
> 
> > On Fri, Feb 11, 2022 at 04:03:00PM +, Alex Bennée wrote:
> >> The alpine image doesn't have a standard useradd binary so disable
> >> this convenience feature for it.
> >
> > Hmm, can you elaborate on the problem here ?
> >
> > IIUC, the NOUSER env was just about controlling what docker
> > flags we added. I didn't know it had a dependancy on stuff
> > inside the image ?
> 
> The docker.py script expands the dockerfiles with a:
> 
>   "RUN id %s 2>/dev/null || useradd -u %d -U %s"
> 
> when they are built so when they are invoked for building TCG tests they
> won't mess up permissions of the final files. It is a useful convenience
> for the other images as well so you can access compilers and tools with
> something like:
> 
>   docker run --rm -it -u (id -u) -v $HOME:$HOME -w (pwd) 
> qemu/debian-arm64-cross /bin/bash
> 
> however it's not required for the normal cross-compile tests as they are
> all done inside the docker image. The alpine image being slim doesn't
> have this nicety although there is an adduser binary. However given we
> don't use alpine for TCG tests I demurred from adding more complexity to
> docker.py to handle it.

Ah, I understand now, so

Reviewed-by: Daniel P. Berrangé 



> 
> >
> >> 
> >> Signed-off-by: Alex Bennée 
> >> ---
> >>  tests/docker/Makefile.include | 3 +++
> >>  1 file changed, 3 insertions(+)
> >> 
> >> diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
> >> index 0ec59b2193..286f0ac5b5 100644
> >> --- a/tests/docker/Makefile.include
> >> +++ b/tests/docker/Makefile.include
> >> @@ -158,6 +158,9 @@ docker-image-debian-native: DOCKER_REGISTRY=
> >>  docker-image-debian10: NOUSER=1
> >>  docker-image-debian11: NOUSER=1
> >>  
> >> +# alpine has no adduser
> >> +docker-image-alpine: NOUSER=1
> >> +
> >>  #
> >>  # The build rule for hexagon-cross is special in so far for most of
> >>  # the time we don't want to build it. While dockers caching does avoid
> >> -- 
> >> 2.30.2
> >> 
> >
> > Regards,
> > Daniel
> 
> 
> -- 
> Alex Bennée
> 

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 :|




[PULL 0/3] Block layer patches

2022-02-11 Thread Kevin Wolf
The following changes since commit 0a301624c2f4ced3331ffd5bce85b4274fe132af:

  Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20220208' 
into staging (2022-02-08 11:40:08 +)

are available in the Git repository at:

  https://gitlab.com/kmwolf/qemu.git tags/for-upstream

for you to fetch changes up to fdb8541b2e4f6ff60f435fbb5a5e1df20c275a86:

  hw/block/fdc-isa: Respect QOM properties when building AML (2022-02-11 
17:37:26 +0100)


Block layer patches

- Fix crash in blockdev-reopen with iothreads
- fdc-isa: Respect QOM properties when building AML


Bernhard Beschow (1):
  hw/block/fdc-isa: Respect QOM properties when building AML

Kevin Wolf (2):
  block: Lock AioContext for drain_end in blockdev-reopen
  iotests: Test blockdev-reopen with iothreads and throttling

 blockdev.c | 11 ++-
 hw/block/fdc-isa.c | 11 +++
 tests/qemu-iotests/245 | 36 +---
 tests/qemu-iotests/245.out |  4 ++--
 4 files changed, 52 insertions(+), 10 deletions(-)




[PULL 3/3] hw/block/fdc-isa: Respect QOM properties when building AML

2022-02-11 Thread Kevin Wolf
From: Bernhard Beschow 

Other ISA devices such as serial-isa use the properties in their
build_aml functions. fdc-isa not using them is probably an oversight.

Signed-off-by: Bernhard Beschow 
Message-Id: <20220209191558.30393-1-shen...@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Kevin Wolf 
---
 hw/block/fdc-isa.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c
index 3bf64e0665..ab663dce93 100644
--- a/hw/block/fdc-isa.c
+++ b/hw/block/fdc-isa.c
@@ -216,6 +216,7 @@ int cmos_get_fd_drive_type(FloppyDriveType fd0)
 
 static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope)
 {
+FDCtrlISABus *isa = ISA_FDC(isadev);
 Aml *dev;
 Aml *crs;
 int i;
@@ -227,11 +228,13 @@ static void fdc_isa_build_aml(ISADevice *isadev, Aml 
*scope)
 };
 
 crs = aml_resource_template();
-aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04));
-aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01));
-aml_append(crs, aml_irq_no_flags(6));
 aml_append(crs,
-aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2));
+aml_io(AML_DECODE16, isa->iobase + 2, isa->iobase + 2, 0x00, 0x04));
+aml_append(crs,
+aml_io(AML_DECODE16, isa->iobase + 7, isa->iobase + 7, 0x00, 0x01));
+aml_append(crs, aml_irq_no_flags(isa->irq));
+aml_append(crs,
+aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, isa->dma));
 
 dev = aml_device("FDC0");
 aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
-- 
2.34.1




[PULL 1/3] block: Lock AioContext for drain_end in blockdev-reopen

2022-02-11 Thread Kevin Wolf
bdrv_subtree_drained_end() requires the caller to hold the AioContext
lock for the drained node. Not doing this for nodes outside of the main
AioContext leads to crashes when AIO_WAIT_WHILE() needs to wait and
tries to temporarily release the lock.

Fixes: 3908b7a8994fa5ef7a89aa58cd5a02fc58141592
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2046659
Reported-by: Qing Wang 
Signed-off-by: Kevin Wolf 
Message-Id: <20220203140534.36522-2-kw...@redhat.com>
Reviewed-by: Hanna Reitz 
Signed-off-by: Kevin Wolf 
---
 blockdev.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/blockdev.c b/blockdev.c
index 8197165bb5..42e098b458 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3530,6 +3530,7 @@ void qmp_blockdev_reopen(BlockdevOptionsList 
*reopen_list, Error **errp)
 {
 BlockReopenQueue *queue = NULL;
 GSList *drained = NULL;
+GSList *p;
 
 /* Add each one of the BDS that we want to reopen to the queue */
 for (; reopen_list != NULL; reopen_list = reopen_list->next) {
@@ -3579,7 +3580,15 @@ void qmp_blockdev_reopen(BlockdevOptionsList 
*reopen_list, Error **errp)
 
 fail:
 bdrv_reopen_queue_free(queue);
-g_slist_free_full(drained, (GDestroyNotify) bdrv_subtree_drained_end);
+for (p = drained; p; p = p->next) {
+BlockDriverState *bs = p->data;
+AioContext *ctx = bdrv_get_aio_context(bs);
+
+aio_context_acquire(ctx);
+bdrv_subtree_drained_end(bs);
+aio_context_release(ctx);
+}
+g_slist_free(drained);
 }
 
 void qmp_blockdev_del(const char *node_name, Error **errp)
-- 
2.34.1




[PULL 2/3] iotests: Test blockdev-reopen with iothreads and throttling

2022-02-11 Thread Kevin Wolf
The 'throttle' block driver implements .bdrv_co_drain_end, so
blockdev-reopen will have to wait for it to complete in the polling
loop at the end of qmp_blockdev_reopen(). This makes AIO_WAIT_WHILE()
release the AioContext lock, which causes a crash if the lock hasn't
correctly been taken.

Signed-off-by: Kevin Wolf 
Message-Id: <20220203140534.36522-3-kw...@redhat.com>
Reviewed-by: Hanna Reitz 
Signed-off-by: Kevin Wolf 
---
 tests/qemu-iotests/245 | 36 +---
 tests/qemu-iotests/245.out |  4 ++--
 2 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
index 24ac43f70e..8cbed7821b 100755
--- a/tests/qemu-iotests/245
+++ b/tests/qemu-iotests/245
@@ -1138,12 +1138,13 @@ class TestBlockdevReopen(iotests.QMPTestCase):
 self.assertEqual(self.get_node('hd1'), None)
 self.assert_qmp(self.get_node('hd2'), 'ro', True)
 
-def run_test_iothreads(self, iothread_a, iothread_b, errmsg = None):
-opts = hd_opts(0)
+def run_test_iothreads(self, iothread_a, iothread_b, errmsg = None,
+   opts_a = None, opts_b = None):
+opts = opts_a or hd_opts(0)
 result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
 self.assert_qmp(result, 'return', {})
 
-opts2 = hd_opts(2)
+opts2 = opts_b or hd_opts(2)
 result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2)
 self.assert_qmp(result, 'return', {})
 
@@ -1194,6 +1195,35 @@ class TestBlockdevReopen(iotests.QMPTestCase):
 def test_iothreads_switch_overlay(self):
 self.run_test_iothreads('', 'iothread0')
 
+def test_iothreads_with_throttling(self):
+# Create a throttle-group object
+opts = { 'qom-type': 'throttle-group', 'id': 'group0',
+ 'limits': { 'iops-total': 1000 } }
+result = self.vm.qmp('object-add', conv_keys = False, **opts)
+self.assert_qmp(result, 'return', {})
+
+# Options with a throttle filter between format and protocol
+opts = [
+{
+'driver': iotests.imgfmt,
+'node-name': f'hd{idx}',
+'file' : {
+'node-name': f'hd{idx}-throttle',
+'driver': 'throttle',
+'throttle-group': 'group0',
+'file': {
+'driver': 'file',
+'node-name': f'hd{idx}-file',
+'filename': hd_path[idx],
+},
+},
+}
+for idx in (0, 2)
+]
+
+self.run_test_iothreads('iothread0', 'iothread0', None,
+opts[0], opts[1])
+
 if __name__ == '__main__':
 iotests.activate_logging()
 iotests.main(supported_fmts=["qcow2"],
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
index 4eced19294..a4e04a3266 100644
--- a/tests/qemu-iotests/245.out
+++ b/tests/qemu-iotests/245.out
@@ -17,8 +17,8 @@ read 1/1 bytes at offset 262152
 read 1/1 bytes at offset 262160
 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
-...
+
 --
-Ran 25 tests
+Ran 26 tests
 
 OK
-- 
2.34.1




Re: [PATCH v1 02/11] tests/docker: add NOUSER for alpine image

2022-02-11 Thread Alex Bennée


Daniel P. Berrangé  writes:

> On Fri, Feb 11, 2022 at 04:03:00PM +, Alex Bennée wrote:
>> The alpine image doesn't have a standard useradd binary so disable
>> this convenience feature for it.
>
> Hmm, can you elaborate on the problem here ?
>
> IIUC, the NOUSER env was just about controlling what docker
> flags we added. I didn't know it had a dependancy on stuff
> inside the image ?

The docker.py script expands the dockerfiles with a:

  "RUN id %s 2>/dev/null || useradd -u %d -U %s"

when they are built so when they are invoked for building TCG tests they
won't mess up permissions of the final files. It is a useful convenience
for the other images as well so you can access compilers and tools with
something like:

  docker run --rm -it -u (id -u) -v $HOME:$HOME -w (pwd) 
qemu/debian-arm64-cross /bin/bash

however it's not required for the normal cross-compile tests as they are
all done inside the docker image. The alpine image being slim doesn't
have this nicety although there is an adduser binary. However given we
don't use alpine for TCG tests I demurred from adding more complexity to
docker.py to handle it.

>
>> 
>> Signed-off-by: Alex Bennée 
>> ---
>>  tests/docker/Makefile.include | 3 +++
>>  1 file changed, 3 insertions(+)
>> 
>> diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
>> index 0ec59b2193..286f0ac5b5 100644
>> --- a/tests/docker/Makefile.include
>> +++ b/tests/docker/Makefile.include
>> @@ -158,6 +158,9 @@ docker-image-debian-native: DOCKER_REGISTRY=
>>  docker-image-debian10: NOUSER=1
>>  docker-image-debian11: NOUSER=1
>>  
>> +# alpine has no adduser
>> +docker-image-alpine: NOUSER=1
>> +
>>  #
>>  # The build rule for hexagon-cross is special in so far for most of
>>  # the time we don't want to build it. While dockers caching does avoid
>> -- 
>> 2.30.2
>> 
>
> Regards,
> Daniel


-- 
Alex Bennée



Re: [PATCH v2 1/8] tests/qemu-iotests/testrunner: Allow parallel test invocations

2022-02-11 Thread Kevin Wolf
Am 11.02.2022 um 17:14 hat Hanna Reitz geschrieben:
> On 11.02.22 17:00, Kevin Wolf wrote:
> > Am 11.02.2022 um 14:53 hat Thomas Huth geschrieben:
> > > On 11/02/2022 10.29, Kevin Wolf wrote:
> > > > Am 09.02.2022 um 11:15 hat Thomas Huth geschrieben:
> > > > > If multiple tests run in parallel, they must use unique file
> > > > > names for the test output.
> > > > > 
> > > > > Suggested-by: Hanna Reitz 
> > > > > Signed-off-by: Thomas Huth 
> > > > > ---
> > > > >tests/qemu-iotests/testrunner.py | 2 +-
> > > > >1 file changed, 1 insertion(+), 1 deletion(-)
> > > > > 
> > > > > diff --git a/tests/qemu-iotests/testrunner.py 
> > > > > b/tests/qemu-iotests/testrunner.py
> > > > > index 0eace147b8..9d20f51bb1 100644
> > > > > --- a/tests/qemu-iotests/testrunner.py
> > > > > +++ b/tests/qemu-iotests/testrunner.py
> > > > > @@ -259,7 +259,7 @@ def do_run_test(self, test: str, mp: bool) -> 
> > > > > TestResult:
> > > > >"""
> > > > >f_test = Path(test)
> > > > > -f_bad = Path(f_test.name + '.out.bad')
> > > > > +f_bad = Path(f'{os.getpid()}-{f_test.name}.out.bad')
> > > > >f_notrun = Path(f_test.name + '.notrun')
> > > > >f_casenotrun = Path(f_test.name + '.casenotrun')
> > > > >f_reference = Path(self.find_reference(test))
> > > > Hmm... It does make sense, but nobody ever cleans those files up.
> > > > Currently, the next run of the test will just overwrite the existing
> > > > file or delete it when the test succeeds. So after running the test
> > > > suite, you have .out.bad files for every failed test, but not for those
> > > > that succeeded.
> > > > 
> > > > After this change, won't the test directory accumulate tons of .out.bad
> > > > files over time?
> > > True ... but we certainly want to keep the file for failed tests for 
> > > further
> > > analysis instead of immediately deleting them ... maybe it would be enough
> > > to encode the image format (qcow2, qed, vmdk, ...) into the output name,
> > > instead of using the PID, so that "make check SPEED=thorough" works as
> > > expected here?
> > It depends on what the supported use case for test suites running in
> > parallel is. If it's just for testing multiple formats at the same time,
> > then this would work, yes.
> > 
> > I could think of more test runs that you might want to do in parallel,
> > like different protocols, different image format options, maybe even
> > different host file system. I'm not sure if all (or any) of these are
> > relevant, though.
> > 
> > Supporting only things that "make check" uses might be a good
> > compromise.
> 
> Personally and originally, I wrote that diff to allow me to actually run the
> very same test many times in parallel.  If an error occurs only very rarely,
> then I like running like 24 loops of the same test with exactly the same
> configuration (just different TEST_DIRs, of course) in parallel.
> 
> The fact that the .out.bad files tend to accumulate is why I haven’t sent it
> upstream so far.  Personally, I like Vladimir’s idea to put them into
> TEST_DIR, but probably just because this works so well for my usual case
> where TEST_DIR is on tmpfs and I thus don’t have to clean it up.

I think it could actually work fine because if you don't override
TEST_DIR, it's the same every time, and then you get the old behaviour,
just with the .out.bad files moved into scratch/.

Kevin




Re: [PATCH] scripts/qapi: minor delinting

2022-02-11 Thread John Snow
On Fri, Feb 11, 2022 at 6:58 AM Markus Armbruster  wrote:
>
> John Snow  writes:
>
> > On Thu, Feb 10, 2022 at 10:56 AM Markus Armbruster  
> > wrote:
> >>
> >> John Snow  writes:
> >>
> >> > Just cleaning up some cobwebs.
> >> >
> >> > Signed-off-by: John Snow 
> >> > ---
> >> >  scripts/qapi/commands.py | 2 +-
> >> >  scripts/qapi/events.py   | 6 +++---
> >> >  scripts/qapi/types.py| 6 +-
> >> >  scripts/qapi/visit.py| 6 +-
> >> >  4 files changed, 14 insertions(+), 6 deletions(-)
> >> >
> >> > diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
> >> > index 869d799ed2..38ca38a7b9 100644
> >> > --- a/scripts/qapi/commands.py
> >> > +++ b/scripts/qapi/commands.py
> >> > @@ -25,8 +25,8 @@
> >> >  QAPIGenC,
> >> >  QAPISchemaModularCVisitor,
> >> >  build_params,
> >> > -ifcontext,
> >> >  gen_special_features,
> >> > +ifcontext,
> >> >  )
> >> >  from .schema import (
> >> >  QAPISchema,
> >> > diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
> >> > index 27b44c49f5..8edf43d8da 100644
> >> > --- a/scripts/qapi/events.py
> >> > +++ b/scripts/qapi/events.py
> >> > @@ -109,15 +109,15 @@ def gen_event_send(name: str,
> >> >  if not boxed:
> >> >  ret += gen_param_var(arg_type)
> >> >
> >> > -for f in features:
> >> > -if f.is_special():
> >> > +for feat in features:
> >> > +if feat.is_special():
> >> >  ret += mcgen('''
> >> >
> >> >  if (compat_policy.%(feat)s_output == COMPAT_POLICY_OUTPUT_HIDE) {
> >> >  return;
> >> >  }
> >> >  ''',
> >> > - feat=f.name)
> >> > + feat=feat.name)
> >> >
> >> >  ret += mcgen('''
> >> >
> >>
> >> Meh.  Expressive variable names are good when there's something useful
> >> to express.  But what's the added value in such a simple, obvious loop?
> >>
> >> Besides:
> >>
> >> $ git-grep 'for . in' scripts/qapi | wc -l
> >> 42
> >> $ git-grep -E 'for [A-Za-z0-9]{2,} in' scripts/qapi | wc -l
> >> 31
> >>
> >> > diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
> >> > index 3013329c24..477d027001 100644
> >> > --- a/scripts/qapi/types.py
> >> > +++ b/scripts/qapi/types.py
> >> > @@ -16,7 +16,11 @@
> >> >  from typing import List, Optional
> >> >
> >> >  from .common import c_enum_const, c_name, mcgen
> >> > -from .gen import QAPISchemaModularCVisitor, gen_special_features, 
> >> > ifcontext
> >> > +from .gen import (
> >> > +QAPISchemaModularCVisitor,
> >> > +gen_special_features,
> >> > +ifcontext,
> >> > +)
> >> >  from .schema import (
> >> >  QAPISchema,
> >> >  QAPISchemaEnumMember,
> >> > diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
> >> > index e13bbe4292..380fa197f5 100644
> >> > --- a/scripts/qapi/visit.py
> >> > +++ b/scripts/qapi/visit.py
> >> > @@ -21,7 +21,11 @@
> >> >  indent,
> >> >  mcgen,
> >> >  )
> >> > -from .gen import QAPISchemaModularCVisitor, gen_special_features, 
> >> > ifcontext
> >> > +from .gen import (
> >> > +QAPISchemaModularCVisitor,
> >> > +gen_special_features,
> >> > +ifcontext,
> >> > +)
> >> >  from .schema import (
> >> >  QAPISchema,
> >> >  QAPISchemaEnumMember,
> >>
> >> Everything else, gladly
> >> Reviewed-by: Markus Armbruster 
> >
> > The problem with whitelisting single-letter variable names is that
> > it's done on a per-name basis, like allowing "x, y, z" or "i, j, k". I
> > could whitelist "f", "m", etc but there's no way to whitelist "for f
> > in features" or "for m im members" ... So admittedly, I just stuck
> > with the default, even though it's a little annoying. It's what I use
> > for python/, and I had previously used it for ./scripts/qapi/, so I
> > was just carrying on.
>
> There are only 26 single-letter variable names.  Whitelist them all?
>
> > In general: I like the idea of forbidding single-letter variable names
> > because I prefer things to be more verbose than terse as a habit. In
> > practice: yeah, it's hard to strictly defend any one change as
> > obviously superior. I preferred "for feature in features", which you
> > did not like because the plural wasn't distinct enough (fair!), so I
> > started using "for feat in features" as a compromise.
>
> @feat is a perfectly adequate name.  So is @f as long as the loop is
> small.  What annoys me here is the churn.
>
> Sadly, pylint's invalid-name mixes up two things: PEP-8 conventions like
> "use CamelCase for class names", and its own style rules like "names
> should be least three characters long".  The former is easy to decide,
> and welcome help.  The latter is actually a proxy for "use sensible
> names to make the code easier to read", because pylint isn't smart
> enough to judge "easy to read".  Fine, leave it to reviewers then!
>
> > If on third thought you don't like any of this, we can change course,
> > but then maybe we should also undo the other changes we already
> > checked in. 

[PATCH] hw/virtio: vdpa: Fix leak of host-notifier memory-region

2022-02-11 Thread Laurent Vivier
If call virtio_queue_set_host_notifier_mr fails, should free
host-notifier memory-region.

This problem can trigger a coredump with some vDPA drivers (mlx5,
but not with the vdpasim), if we unplug the virtio-net card from
the guest after a stop/start.

The same fix has been done for vhost-user:
  1f89d3b91e3e ("hw/virtio: Fix leak of host-notifier memory-region")

Fixes: d0416d487bd5 ("vhost-vdpa: map virtqueue notification area if possible")
Cc: jasow...@redhat.com
Resolves: https://bugzilla.redhat.com/2027208
Signed-off-by: Laurent Vivier 
---
 hw/virtio/vhost-vdpa.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index 04ea43704f5d..11f696468dc1 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -431,6 +431,7 @@ static int vhost_vdpa_host_notifier_init(struct vhost_dev 
*dev, int queue_index)
 g_free(name);
 
 if (virtio_queue_set_host_notifier_mr(vdev, queue_index, >mr, true)) {
+object_unparent(OBJECT(>mr));
 munmap(addr, page_size);
 goto err;
 }
-- 
2.34.1




Re: [PATCH v5 20/43] hw/cxl/device: Add a memory device (8.2.8.5)

2022-02-11 Thread Ben Widawsky
On 22-02-11 16:45:19, Jonathan Cameron wrote:
> On Fri, 11 Feb 2022 07:50:00 -0800
> Ben Widawsky  wrote:
> 
> > On 22-02-02 14:10:14, Jonathan Cameron wrote:
> > > From: Ben Widawsky 
> > > 
> > > A CXL memory device (AKA Type 3) is a CXL component that contains some
> > > combination of volatile and persistent memory. It also implements the
> > > previously defined mailbox interface as well as the memory device
> > > firmware interface.
> > > 
> > > Although the memory device is configured like a normal PCIe device, the
> > > memory traffic is on an entirely separate bus conceptually (using the
> > > same physical wires as PCIe, but different protocol).
> > > 
> > > Once the CXL topology is fully configure and address decoders committed,
> > > the guest physical address for the memory device is part of a larger
> > > window which is owned by the platform.  The creation of these windows
> > > is later in this series.
> > > 
> > > The following example will create a 256M device in a 512M window:
> > > -object 
> > > "memory-backend-file,id=cxl-mem1,share,mem-path=cxl-type3,size=512M"
> > > -device "cxl-type3,bus=rp0,memdev=cxl-mem1,id=cxl-pmem0"
> > > 
> > > Note: Dropped PCDIMM info interfaces for now.  They can be added if
> > > appropriate at a later date.
> > > 
> > > Signed-off-by: Ben Widawsky 
> > > Signed-off-by: Jonathan Cameron 
> > > ---
> > >  hw/cxl/cxl-mailbox-utils.c |  47 ++
> > >  hw/mem/Kconfig |   5 ++
> > >  hw/mem/cxl_type3.c | 170 +
> > >  hw/mem/meson.build |   1 +
> > >  include/hw/cxl/cxl.h   |   1 +
> > >  include/hw/cxl/cxl_pci.h   |  22 +
> > >  include/hw/pci/pci_ids.h   |   1 +
> > >  7 files changed, 247 insertions(+)
> > >  create mode 100644 hw/mem/cxl_type3.c
> > > 
> > > diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
> > > index 16bb998735..808faec114 100644
> > > --- a/hw/cxl/cxl-mailbox-utils.c
> > > +++ b/hw/cxl/cxl-mailbox-utils.c
> > > @@ -50,6 +50,8 @@ enum {
> > >  LOGS= 0x04,
> > >  #define GET_SUPPORTED 0x0
> > >  #define GET_LOG   0x1
> > > +IDENTIFY= 0x40,
> > > +#define MEMORY_DEVICE 0x0
> > >  };
> > >  
> > >  /* 8.2.8.4.5.1 Command Return Codes */
> > > @@ -216,6 +218,48 @@ static ret_code cmd_logs_get_log(struct cxl_cmd *cmd,
> > >  return CXL_MBOX_SUCCESS;
> > >  }
> > >  
> > > +/* 8.2.9.5.1.1 */
> > > +static ret_code cmd_identify_memory_device(struct cxl_cmd *cmd,
> > > +   CXLDeviceState *cxl_dstate,
> > > +   uint16_t *len)
> > > +{
> > > +struct {
> > > +char fw_revision[0x10];
> > > +uint64_t total_capacity;
> > > +uint64_t volatile_capacity;
> > > +uint64_t persistent_capacity;
> > > +uint64_t partition_align;
> > > +uint16_t info_event_log_size;
> > > +uint16_t warning_event_log_size;
> > > +uint16_t failure_event_log_size;
> > > +uint16_t fatal_event_log_size;
> > > +uint32_t lsa_size;
> > > +uint8_t poison_list_max_mer[3];
> > > +uint16_t inject_poison_limit;
> > > +uint8_t poison_caps;
> > > +uint8_t qos_telemetry_caps;
> > > +} __attribute__((packed)) *id;
> > > +_Static_assert(sizeof(*id) == 0x43, "Bad identify size");
> > > +
> > > +uint64_t size = cxl_dstate->pmem_size;
> > > +
> > > +if (!QEMU_IS_ALIGNED(size, 256 << 20)) {
> > > +return CXL_MBOX_INTERNAL_ERROR;
> > > +}
> > > +
> > > +id = (void *)cmd->payload;
> > > +memset(id, 0, sizeof(*id));
> > > +
> > > +/* PMEM only */
> > > +snprintf(id->fw_revision, 0x10, "BWFW VERSION %02d", 0);
> > > +
> > > +id->total_capacity = size / (256 << 20);
> > > +id->persistent_capacity = size / (256 << 20);
> > > +
> > > +*len = sizeof(*id);
> > > +return CXL_MBOX_SUCCESS;
> > > +}
> > > +
> > >  #define IMMEDIATE_CONFIG_CHANGE (1 << 1)
> > >  #define IMMEDIATE_POLICY_CHANGE (1 << 3)
> > >  #define IMMEDIATE_LOG_CHANGE (1 << 4)
> > > @@ -233,8 +277,11 @@ static struct cxl_cmd cxl_cmd_set[256][256] = {
> > >  [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, 
> > > IMMEDIATE_POLICY_CHANGE },
> > >  [LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", 
> > > cmd_logs_get_supported, 0, 0 },
> > >  [LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 },
> > > +[IDENTIFY][MEMORY_DEVICE] = { "IDENTIFY_MEMORY_DEVICE",
> > > +cmd_identify_memory_device, 0, 0 },
> > >  };
> > >  
> > > +
> > >  void cxl_process_mailbox(CXLDeviceState *cxl_dstate)
> > >  {
> > >  uint16_t ret = CXL_MBOX_SUCCESS;
> > > diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig
> > > index 03dbb3c7df..73c5ae8ad9 100644
> > > --- a/hw/mem/Kconfig
> > > +++ b/hw/mem/Kconfig
> > > @@ -11,3 +11,8 @@ config NVDIMM
> > >  
> > >  config SPARSE_MEM
> > >  bool
> > > +
> > > +config CXL_MEM_DEVICE
> > 

Re: [PATCH 1/6] tests/qemu-iotests: Improve the check for GNU sed

2022-02-11 Thread Thomas Huth

On 11/02/2022 17.14, Eric Blake wrote:

On Tue, Feb 08, 2022 at 03:52:19PM +0100, Thomas Huth wrote:

The current code with $SED has been introduced almost three years
ago already...


   Can’t we just do `alias sed=gsed`?


Maybe ... but let's ask Philippe and Kevin first, who Signed-off
commit bde36af1ab4f476 that introduced the current way with $SED:
What's your opinion about this?


This commit was to have check-block working on the OpenBSD VM image.


Sure. The question was whether using an alias as suggested by Hanna would be
nicer instead of using $SED ?


Scripting with aliases becomes a nightmare to debug, since it is
relatively uncommon.  In particular, in bash, you have to explicitly
opt in to using aliases (contrary to POSIX sh where aliases are
available to scripts at startup).


shopt -s expand_aliases
... as I just learnt the hard way ;-)


Using $SED everywhere may require
more hunting, but it is more obvious when reading a test that "oh
yeah, I might be using extensions that the default 'sed' can't
support" than a script that blindly uses 'sed' and depends on it
aliasing to a more-capable sed at a distance.

The other question is how many GNU sed features are we actually
depending on?  Which tests break if we have BSD sed or busybox sed?
Can we rewrite those sed scripts to avoid GNU extensions?  But
auditing for s/sed/$SED/ seems easier than auditing for which
non-portable sed extensions we depend on.


The most obvious part are the filter functions in common.filter - we're 
using "-r" here that is not part of the POSIX sed as far as I can see.


Not sure whether anybody really wants to rewrite all sed statements for full 
portability, but maybe we could also introduce a wrapper for GNU sed like this:


if ! command -v gsed >/dev/null 2>&1; then
if sed --version | grep -v 'not GNU sed' | grep 'GNUx sed' \
   > /dev/null 2>&1;
then
gsed()
{
sed $*
}
else
gsed()
{
_notrun "GNU sed not available"
}
fi
fi

... then we could simply use "gsed" everywhere we depend on the GNU 
behavior, and the tests don't look as ugly as with the $SED ?


 Thomas




Re: [PATCH v6 17/43] hw/cxl/device: Add a memory device (8.2.8.5)

2022-02-11 Thread Jonathan Cameron via
On Fri, 11 Feb 2022 12:07:21 +
Jonathan Cameron  wrote:

> From: Ben Widawsky 
> 
> A CXL memory device (AKA Type 3) is a CXL component that contains some
> combination of volatile and persistent memory. It also implements the
> previously defined mailbox interface as well as the memory device
> firmware interface.
> 
> Although the memory device is configured like a normal PCIe device, the
> memory traffic is on an entirely separate bus conceptually (using the
> same physical wires as PCIe, but different protocol).
> 
> Once the CXL topology is fully configure and address decoders committed,
> the guest physical address for the memory device is part of a larger
> window which is owned by the platform.  The creation of these windows
> is later in this series.
> 
> The following example will create a 256M device in a 512M window:
> -object "memory-backend-file,id=cxl-mem1,share,mem-path=cxl-type3,size=512M"
> -device "cxl-type3,bus=rp0,memdev=cxl-mem1,id=cxl-pmem0"
> 
> Note: Dropped PCDIMM info interfaces for now.  They can be added if
> appropriate at a later date.
> 
> Signed-off-by: Ben Widawsky 
> Signed-off-by: Jonathan Cameron 

...

> +
> +static void cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
> +{
> +MemoryRegion *mr;
> +
> +if (!ct3d->hostmem) {
> +error_setg(errp, "memdev property must be set");
> +return;
> +}
> +
> +mr = host_memory_backend_get_memory(ct3d->hostmem);
> +if (!mr) {
> +error_setg(errp, "memdev property must be set");
> +return;
> +}
> +memory_region_set_nonvolatile(mr, true);
> +memory_region_set_enabled(mr, true);
> +host_memory_backend_set_mapped(ct3d->hostmem, true);
> +ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size;
> +}
> +
> +
> +static void ct3_realize(PCIDevice *pci_dev, Error **errp)
> +{
> +CXLType3Dev *ct3d = CT3(pci_dev);
> +CXLComponentState *cxl_cstate = >cxl_cstate;
> +ComponentRegisters *regs = _cstate->crb;
> +MemoryRegion *mr = >component_registers;
> +uint8_t *pci_conf = pci_dev->config;
> +
> +if (!ct3d->hostmem) {

Ben pointed out in reply to v5 that this is backwards.
I'll fix in v7.  Clearly some of the cxl_setup_memory()
logic may also not be needed seeing as it wasn't running.


> +cxl_setup_memory(ct3d, errp);
> +}
> +
> +pci_config_set_prog_interface(pci_conf, 0x10);
> +pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_CXL);
> +



Re: [PATCH] hw/block/fdc-isa: Respect QOM properties when building AML

2022-02-11 Thread Kevin Wolf
Am 09.02.2022 um 20:15 hat Bernhard Beschow geschrieben:
> Other ISA devices such as serial-isa use the properties in their
> build_aml functions. fdc-isa not using them is probably an oversight.
> 
> Signed-off-by: Bernhard Beschow 

Thanks, applied to the block branch.

Kevin




[PATCH v4 11/13] audio/dbus: Fix building with modules on macOS

2022-02-11 Thread Philippe Mathieu-Daudé via
When configuring QEMU with --enable-modules we get on macOS:

  --- stderr ---
  Dependency ui-dbus cannot be satisfied

ui-dbus depends on pixman and opengl, so add these dependencies
to audio-dbus.

Fixes: 739362d420 ("audio: add "dbus" audio backend")
Reviewed-by: Li Zhang 
Signed-off-by: Philippe Mathieu-Daudé 
---
 audio/meson.build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/audio/meson.build b/audio/meson.build
index 0ac3791d0b..d9b295514f 100644
--- a/audio/meson.build
+++ b/audio/meson.build
@@ -28,7 +28,7 @@ endforeach
 
 if dbus_display
 module_ss = ss.source_set()
-module_ss.add(when: gio, if_true: files('dbusaudio.c'))
+module_ss.add(when: [gio, pixman, opengl, 'CONFIG_GIO'], if_true: 
files('dbusaudio.c'))
 audio_modules += {'dbus': module_ss}
 endif
 
-- 
2.34.1




[PATCH v4 13/13] gitlab-ci: Support macOS 12 via cirrus-run

2022-02-11 Thread Philippe Mathieu-Daudé via
Add support for macOS 12 build on Cirrus-CI, similarly to commit
0e103a65ba1 ("gitlab: support for ... macOS 11 via cirrus-run"),
but with the following differences:
 - Enable modules (configure --enable-modules)
 - Do not run softfloat3 tests (make check-softfloat)

Generate the vars file by calling 'make lcitool-refresh'.

Signed-off-by: Philippe Mathieu-Daudé 
---
 .gitlab-ci.d/cirrus.yml   | 16 
 .gitlab-ci.d/cirrus/macos-12.vars | 16 
 tests/lcitool/refresh |  1 +
 3 files changed, 33 insertions(+)
 create mode 100644 .gitlab-ci.d/cirrus/macos-12.vars

diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml
index b96b22e269..b4e501d423 100644
--- a/.gitlab-ci.d/cirrus.yml
+++ b/.gitlab-ci.d/cirrus.yml
@@ -87,6 +87,22 @@ x64-macos-11-base-build:
 PKG_CONFIG_PATH: 
/usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig
 TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat 
check-qtest-x86_64
 
+x64-macos-12-base-build:
+  extends: .cirrus_build_job
+  variables:
+NAME: macos-12
+CIRRUS_VM_INSTANCE_TYPE: osx_instance
+CIRRUS_VM_IMAGE_SELECTOR: image
+CIRRUS_VM_IMAGE_NAME: monterey-base
+CIRRUS_VM_CPUS: 12
+CIRRUS_VM_RAM: 24G
+UPDATE_COMMAND: brew update
+INSTALL_COMMAND: brew install
+PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin
+PKG_CONFIG_PATH: 
/usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig
+CONFIGURE_ARGS: --enable-modules
+TEST_TARGETS: check-unit check-block check-qapi-schema check-qtest-x86_64
+
 
 # The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
 .cirrus_kvm_job:
diff --git a/.gitlab-ci.d/cirrus/macos-12.vars 
b/.gitlab-ci.d/cirrus/macos-12.vars
new file mode 100644
index 00..a793258c64
--- /dev/null
+++ b/.gitlab-ci.d/cirrus/macos-12.vars
@@ -0,0 +1,16 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+#  $ lcitool variables macos-12 qemu
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+CCACHE='/usr/local/bin/ccache'
+CPAN_PKGS='Test::Harness'
+CROSS_PKGS=''
+MAKE='/usr/local/bin/gmake'
+NINJA='/usr/local/bin/ninja'
+PACKAGING_COMMAND='brew'
+PIP3='/usr/local/bin/pip3'
+PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils dtc 
gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi 
libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make 
meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 
sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 
zlib zstd'
+PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme virtualenv'
+PYTHON='/usr/local/bin/python3'
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index 4ab90a310a..a714e2851d 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -89,6 +89,7 @@ try:
generate_cirrus("freebsd-12")
generate_cirrus("freebsd-13")
generate_cirrus("macos-11")
+   generate_cirrus("macos-12")
 
sys.exit(0)
 except Exception as ex:
-- 
2.34.1




Re: [PATCH v5 20/43] hw/cxl/device: Add a memory device (8.2.8.5)

2022-02-11 Thread Jonathan Cameron via
On Fri, 11 Feb 2022 07:50:00 -0800
Ben Widawsky  wrote:

> On 22-02-02 14:10:14, Jonathan Cameron wrote:
> > From: Ben Widawsky 
> > 
> > A CXL memory device (AKA Type 3) is a CXL component that contains some
> > combination of volatile and persistent memory. It also implements the
> > previously defined mailbox interface as well as the memory device
> > firmware interface.
> > 
> > Although the memory device is configured like a normal PCIe device, the
> > memory traffic is on an entirely separate bus conceptually (using the
> > same physical wires as PCIe, but different protocol).
> > 
> > Once the CXL topology is fully configure and address decoders committed,
> > the guest physical address for the memory device is part of a larger
> > window which is owned by the platform.  The creation of these windows
> > is later in this series.
> > 
> > The following example will create a 256M device in a 512M window:
> > -object "memory-backend-file,id=cxl-mem1,share,mem-path=cxl-type3,size=512M"
> > -device "cxl-type3,bus=rp0,memdev=cxl-mem1,id=cxl-pmem0"
> > 
> > Note: Dropped PCDIMM info interfaces for now.  They can be added if
> > appropriate at a later date.
> > 
> > Signed-off-by: Ben Widawsky 
> > Signed-off-by: Jonathan Cameron 
> > ---
> >  hw/cxl/cxl-mailbox-utils.c |  47 ++
> >  hw/mem/Kconfig |   5 ++
> >  hw/mem/cxl_type3.c | 170 +
> >  hw/mem/meson.build |   1 +
> >  include/hw/cxl/cxl.h   |   1 +
> >  include/hw/cxl/cxl_pci.h   |  22 +
> >  include/hw/pci/pci_ids.h   |   1 +
> >  7 files changed, 247 insertions(+)
> >  create mode 100644 hw/mem/cxl_type3.c
> > 
> > diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
> > index 16bb998735..808faec114 100644
> > --- a/hw/cxl/cxl-mailbox-utils.c
> > +++ b/hw/cxl/cxl-mailbox-utils.c
> > @@ -50,6 +50,8 @@ enum {
> >  LOGS= 0x04,
> >  #define GET_SUPPORTED 0x0
> >  #define GET_LOG   0x1
> > +IDENTIFY= 0x40,
> > +#define MEMORY_DEVICE 0x0
> >  };
> >  
> >  /* 8.2.8.4.5.1 Command Return Codes */
> > @@ -216,6 +218,48 @@ static ret_code cmd_logs_get_log(struct cxl_cmd *cmd,
> >  return CXL_MBOX_SUCCESS;
> >  }
> >  
> > +/* 8.2.9.5.1.1 */
> > +static ret_code cmd_identify_memory_device(struct cxl_cmd *cmd,
> > +   CXLDeviceState *cxl_dstate,
> > +   uint16_t *len)
> > +{
> > +struct {
> > +char fw_revision[0x10];
> > +uint64_t total_capacity;
> > +uint64_t volatile_capacity;
> > +uint64_t persistent_capacity;
> > +uint64_t partition_align;
> > +uint16_t info_event_log_size;
> > +uint16_t warning_event_log_size;
> > +uint16_t failure_event_log_size;
> > +uint16_t fatal_event_log_size;
> > +uint32_t lsa_size;
> > +uint8_t poison_list_max_mer[3];
> > +uint16_t inject_poison_limit;
> > +uint8_t poison_caps;
> > +uint8_t qos_telemetry_caps;
> > +} __attribute__((packed)) *id;
> > +_Static_assert(sizeof(*id) == 0x43, "Bad identify size");
> > +
> > +uint64_t size = cxl_dstate->pmem_size;
> > +
> > +if (!QEMU_IS_ALIGNED(size, 256 << 20)) {
> > +return CXL_MBOX_INTERNAL_ERROR;
> > +}
> > +
> > +id = (void *)cmd->payload;
> > +memset(id, 0, sizeof(*id));
> > +
> > +/* PMEM only */
> > +snprintf(id->fw_revision, 0x10, "BWFW VERSION %02d", 0);
> > +
> > +id->total_capacity = size / (256 << 20);
> > +id->persistent_capacity = size / (256 << 20);
> > +
> > +*len = sizeof(*id);
> > +return CXL_MBOX_SUCCESS;
> > +}
> > +
> >  #define IMMEDIATE_CONFIG_CHANGE (1 << 1)
> >  #define IMMEDIATE_POLICY_CHANGE (1 << 3)
> >  #define IMMEDIATE_LOG_CHANGE (1 << 4)
> > @@ -233,8 +277,11 @@ static struct cxl_cmd cxl_cmd_set[256][256] = {
> >  [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, 
> > IMMEDIATE_POLICY_CHANGE },
> >  [LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", 
> > cmd_logs_get_supported, 0, 0 },
> >  [LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 },
> > +[IDENTIFY][MEMORY_DEVICE] = { "IDENTIFY_MEMORY_DEVICE",
> > +cmd_identify_memory_device, 0, 0 },
> >  };
> >  
> > +
> >  void cxl_process_mailbox(CXLDeviceState *cxl_dstate)
> >  {
> >  uint16_t ret = CXL_MBOX_SUCCESS;
> > diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig
> > index 03dbb3c7df..73c5ae8ad9 100644
> > --- a/hw/mem/Kconfig
> > +++ b/hw/mem/Kconfig
> > @@ -11,3 +11,8 @@ config NVDIMM
> >  
> >  config SPARSE_MEM
> >  bool
> > +
> > +config CXL_MEM_DEVICE
> > +bool
> > +default y if CXL
> > +select MEM_DEVICE
> > diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
> > new file mode 100644
> > index 00..c4021d2434
> > --- /dev/null
> > +++ b/hw/mem/cxl_type3.c
> > @@ -0,0 +1,170 @@
> > +#include "qemu/osdep.h"
> > +#include "qemu/units.h"

[PATCH v4 09/13] block/file-posix: Remove a deprecation warning on macOS 12

2022-02-11 Thread Philippe Mathieu-Daudé via
When building on macOS 12 we get:

  block/file-posix.c:3335:18: warning: 'IOMasterPort' is deprecated: first 
deprecated in macOS 12.0 [-Wdeprecated-declarations]
  kernResult = IOMasterPort( MACH_PORT_NULL,  );
   ^~~~
   IOMainPort

Replace by IOMainPort, redefining it to IOMasterPort if not available.

Suggested-by: Akihiko Odaki 
Signed-off-by: Philippe Mathieu-Daudé 
---
 block/file-posix.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/block/file-posix.c b/block/file-posix.c
index 1f1756e192..13393ad296 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -3319,17 +3319,23 @@ BlockDriver bdrv_file = {
 #if defined(__APPLE__) && defined(__MACH__)
 static kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath,
 CFIndex maxPathSize, int flags);
+
+#if !defined(MAC_OS_VERSION_12_0) \
+|| (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_12_0)
+#define IOMainPort IOMasterPort
+#endif
+
 static char *FindEjectableOpticalMedia(io_iterator_t *mediaIterator)
 {
 kern_return_t kernResult = KERN_FAILURE;
-mach_port_t masterPort;
+mach_port_t mainPort;
 CFMutableDictionaryRef  classesToMatch;
 const char *matching_array[] = {kIODVDMediaClass, kIOCDMediaClass};
 char *mediaType = NULL;
 
-kernResult = IOMasterPort( MACH_PORT_NULL,  );
+kernResult = IOMainPort(MACH_PORT_NULL, );
 if ( KERN_SUCCESS != kernResult ) {
-printf( "IOMasterPort returned %d\n", kernResult );
+printf("IOMainPort returned %d\n", kernResult);
 }
 
 int index;
@@ -3342,7 +3348,7 @@ static char *FindEjectableOpticalMedia(io_iterator_t 
*mediaIterator)
 }
 CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey),
  kCFBooleanTrue);
-kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch,
+kernResult = IOServiceGetMatchingServices(mainPort, classesToMatch,
   mediaIterator);
 if (kernResult != KERN_SUCCESS) {
 error_report("Note: IOServiceGetMatchingServices returned %d",
-- 
2.34.1




[PATCH v4 10/13] audio/coreaudio: Remove a deprecation warning on macOS 12

2022-02-11 Thread Philippe Mathieu-Daudé via
When building on macOS 12 we get:

  audio/coreaudio.c:50:5: error: 'kAudioObjectPropertyElementMaster' is 
deprecated: first deprecated in macOS 12.0 [-Werror,-Wdeprecated-declarations]
  kAudioObjectPropertyElementMaster
  ^
  kAudioObjectPropertyElementMain
  
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreAudio.framework/Headers/AudioHardwareBase.h:208:5:
 note: 'kAudioObjectPropertyElementMaster' has been explicitly marked 
deprecated here
  kAudioObjectPropertyElementMaster 
API_DEPRECATED_WITH_REPLACEMENT("kAudioObjectPropertyElementMain", macos(10.0, 
12.0), ios(2.0, 15.0), watchos(1.0, 8.0), tvos(9.0, 15.0)) = 
kAudioObjectPropertyElementMain
  ^

Replace by kAudioObjectPropertyElementMain, redefining it to
kAudioObjectPropertyElementMaster if not available.

Suggested-by: Akihiko Odaki 
Suggested-by: Christian Schoenebeck 
Suggested-by: Roman Bolshakov 
Signed-off-by: Philippe Mathieu-Daudé 
---
 audio/coreaudio.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index d8a21d3e50..5b3aeaced0 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -44,10 +44,15 @@ typedef struct coreaudioVoiceOut {
 bool enabled;
 } coreaudioVoiceOut;
 
+#if !defined(MAC_OS_VERSION_12_0) \
+|| (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_12_0)
+#define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
+#endif
+
 static const AudioObjectPropertyAddress voice_addr = {
 kAudioHardwarePropertyDefaultOutputDevice,
 kAudioObjectPropertyScopeGlobal,
-kAudioObjectPropertyElementMaster
+kAudioObjectPropertyElementMain
 };
 
 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
@@ -69,7 +74,7 @@ static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
 AudioObjectPropertyAddress addr = {
 kAudioDevicePropertyBufferFrameSizeRange,
 kAudioDevicePropertyScopeOutput,
-kAudioObjectPropertyElementMaster
+kAudioObjectPropertyElementMain
 };
 
 return AudioObjectGetPropertyData(id,
@@ -86,7 +91,7 @@ static OSStatus coreaudio_get_framesize(AudioDeviceID id, 
UInt32 *framesize)
 AudioObjectPropertyAddress addr = {
 kAudioDevicePropertyBufferFrameSize,
 kAudioDevicePropertyScopeOutput,
-kAudioObjectPropertyElementMaster
+kAudioObjectPropertyElementMain
 };
 
 return AudioObjectGetPropertyData(id,
@@ -103,7 +108,7 @@ static OSStatus coreaudio_set_framesize(AudioDeviceID id, 
UInt32 *framesize)
 AudioObjectPropertyAddress addr = {
 kAudioDevicePropertyBufferFrameSize,
 kAudioDevicePropertyScopeOutput,
-kAudioObjectPropertyElementMaster
+kAudioObjectPropertyElementMain
 };
 
 return AudioObjectSetPropertyData(id,
@@ -121,7 +126,7 @@ static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
 AudioObjectPropertyAddress addr = {
 kAudioDevicePropertyStreamFormat,
 kAudioDevicePropertyScopeOutput,
-kAudioObjectPropertyElementMaster
+kAudioObjectPropertyElementMain
 };
 
 return AudioObjectSetPropertyData(id,
@@ -138,7 +143,7 @@ static OSStatus coreaudio_get_isrunning(AudioDeviceID id, 
UInt32 *result)
 AudioObjectPropertyAddress addr = {
 kAudioDevicePropertyDeviceIsRunning,
 kAudioDevicePropertyScopeOutput,
-kAudioObjectPropertyElementMaster
+kAudioObjectPropertyElementMain
 };
 
 return AudioObjectGetPropertyData(id,
-- 
2.34.1




  1   2   3   >