Re: [PATCH 4/4] hw/net: Fix the transmission return size

2024-06-03 Thread Fea Wang
I just encountered this issue when running Linux, and the trouble will be
fixed after the patches. So I think they work.

Sincerely,
Fea

On Mon, Jun 3, 2024 at 6:31 PM Edgar E. Iglesias 
wrote:

> On Mon, Jun 3, 2024 at 7:48 AM Fea.Wang  wrote:
>
>> Fix the transmission return size because not all bytes could be
>> transmitted successfully. So, return a successful length instead of a
>> constant value.
>>
>>
> How did you test this patch, on Linux or something else? I have some
> memory that we had some trouble with similar patches before.
>
> Anyway, the change looks good to me:
> Reviewed-by: Edgar E. Iglesias 
>
>
>
>> Signed-off-by: Fea.Wang 
>> ---
>>  hw/net/xilinx_axienet.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
>> index 7d1fd37b4a..05d41bd548 100644
>> --- a/hw/net/xilinx_axienet.c
>> +++ b/hw/net/xilinx_axienet.c
>> @@ -847,7 +847,7 @@ static ssize_t eth_rx(NetClientState *nc, const
>> uint8_t *buf, size_t size)
>>  axienet_eth_rx_notify(s);
>>
>>  enet_update_irq(s);
>> -return size;
>> +return s->rxpos;
>>  }
>>
>>  static size_t
>> --
>> 2.34.1
>>
>>


Re: [PATCH 2/4] hw/dma: Break the loop when loading descriptions fails

2024-06-03 Thread Fea Wang
Hi Edgar,
thank you for the advice, I will squash them in the next version of the
patch series.

Sincerely,
Fea

On Mon, Jun 3, 2024 at 6:21 PM Edgar E. Iglesias 
wrote:

> On Mon, Jun 3, 2024 at 7:48 AM Fea.Wang  wrote:
>
>> When calling the loading a description function, it should be noticed
>> that the function may return a failure value. Breaking the loop is one
>> of the possible ways to handle it.
>>
>> Signed-off-by: Fea.Wang 
>>
>
>
> Looks good, a nitpick comment, I would either squash this with patch #1
> or move the change to return of error code in stream_desc_load() to this
> patch.
>
>
>
>
>> ---
>>  hw/dma/xilinx_axidma.c | 8 ++--
>>  1 file changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
>> index 4b475e5484..b8ab5a423d 100644
>> --- a/hw/dma/xilinx_axidma.c
>> +++ b/hw/dma/xilinx_axidma.c
>> @@ -291,7 +291,9 @@ static void stream_process_mem2s(struct Stream *s,
>> StreamSink *tx_data_dev,
>>  }
>>
>>  while (1) {
>> -stream_desc_load(s, s->regs[R_CURDESC]);
>> +if (MEMTX_OK != stream_desc_load(s, s->regs[R_CURDESC])) {
>> +break;
>> +}
>>
>>  if (s->desc.status & SDESC_STATUS_COMPLETE) {
>>  s->regs[R_DMASR] |= DMASR_HALTED;
>> @@ -348,7 +350,9 @@ static size_t stream_process_s2mem(struct Stream *s,
>> unsigned char *buf,
>>  }
>>
>>  while (len) {
>> -stream_desc_load(s, s->regs[R_CURDESC]);
>> +if (MEMTX_OK != stream_desc_load(s, s->regs[R_CURDESC])) {
>> +break;
>> +}
>>
>>  if (s->desc.status & SDESC_STATUS_COMPLETE) {
>>  s->regs[R_DMASR] |= DMASR_HALTED;
>> --
>> 2.34.1
>>
>>


[PULL 29/45] i386/sev: Add the SNP launch start context

2024-06-03 Thread Paolo Bonzini
From: Brijesh Singh 

The SNP_LAUNCH_START is called first to create a cryptographic launch
context within the firmware.

Signed-off-by: Brijesh Singh 
Signed-off-by: Michael Roth 
Co-developed-by: Pankaj Gupta 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-16-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c| 39 +++
 target/i386/trace-events |  1 +
 2 files changed, 40 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 43d1c48bd9e..e89b87d2f55 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -39,6 +39,7 @@
 #include "confidential-guest.h"
 #include "hw/i386/pc.h"
 #include "exec/address-spaces.h"
+#include "qemu/queue.h"
 
 OBJECT_DECLARE_TYPE(SevCommonState, SevCommonStateClass, SEV_COMMON)
 OBJECT_DECLARE_TYPE(SevGuestState, SevCommonStateClass, SEV_GUEST)
@@ -115,6 +116,16 @@ struct SevSnpGuestState {
 #define DEFAULT_SEV_DEVICE  "/dev/sev"
 #define DEFAULT_SEV_SNP_POLICY  0x3
 
+typedef struct SevLaunchUpdateData {
+QTAILQ_ENTRY(SevLaunchUpdateData) next;
+hwaddr gpa;
+void *hva;
+uint64_t len;
+int type;
+} SevLaunchUpdateData;
+
+static QTAILQ_HEAD(, SevLaunchUpdateData) launch_update;
+
 #define SEV_INFO_BLOCK_GUID "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
 typedef struct __attribute__((__packed__)) SevInfoBlock {
 /* SEV-ES Reset Vector Address */
@@ -674,6 +685,31 @@ sev_read_file_base64(const char *filename, guchar **data, 
gsize *len)
 return 0;
 }
 
+static int
+sev_snp_launch_start(SevCommonState *sev_common)
+{
+int fw_error, rc;
+SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(sev_common);
+struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
+
+trace_kvm_sev_snp_launch_start(start->policy,
+   sev_snp_guest->guest_visible_workarounds);
+
+rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START,
+   start, &fw_error);
+if (rc < 0) {
+error_report("%s: SNP_LAUNCH_START ret=%d fw_error=%d '%s'",
+__func__, rc, fw_error, fw_error_to_str(fw_error));
+return 1;
+}
+
+QTAILQ_INIT(&launch_update);
+
+sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
+
+return 0;
+}
+
 static int
 sev_launch_start(SevCommonState *sev_common)
 {
@@ -1003,6 +1039,7 @@ static int sev_common_kvm_init(ConfidentialGuestSupport 
*cgs, Error **errp)
 }
 
 ret = klass->launch_start(sev_common);
+
 if (ret) {
 error_setg(errp, "%s: failed to create encryption context", __func__);
 return -1;
@@ -1794,9 +1831,11 @@ sev_snp_guest_class_init(ObjectClass *oc, void *data)
 SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
 X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
 
+klass->launch_start = sev_snp_launch_start;
 klass->kvm_init = sev_snp_kvm_init;
 x86_klass->kvm_type = sev_snp_kvm_type;
 
+
 object_class_property_add(oc, "policy", "uint64",
   sev_snp_guest_get_policy,
   sev_snp_guest_set_policy, NULL, NULL);
diff --git a/target/i386/trace-events b/target/i386/trace-events
index 2cd8726eebb..cb26d8a9257 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -11,3 +11,4 @@ kvm_sev_launch_measurement(const char *value) "data %s"
 kvm_sev_launch_finish(void) ""
 kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) 
"hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
 kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s 
data %s"
+kvm_sev_snp_launch_start(uint64_t policy, char *gosvw) "policy 0x%" PRIx64 " 
gosvw %s"
-- 
2.45.1




[PULL 42/45] i386/sev: Allow measured direct kernel boot on SNP

2024-06-03 Thread Paolo Bonzini
From: Dov Murik 

In SNP, the hashes page designated with a specific metadata entry
published in AmdSev OVMF.

Therefore, if the user enabled kernel hashes (for measured direct boot),
QEMU should prepare the content of hashes table, and during the
processing of the metadata entry it copy the content into the designated
page and encrypt it.

Note that in SNP (unlike SEV and SEV-ES) the measurements is done in
whole 4KB pages.  Therefore QEMU zeros the whole page that includes the
hashes table, and fills in the kernel hashes area in that page, and then
encrypts the whole page.  The rest of the page is reserved for SEV
launch secrets which are not usable anyway on SNP.

If the user disabled kernel hashes, QEMU pre-validates the kernel hashes
page as a zero page.

Signed-off-by: Dov Murik 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-24-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 include/hw/i386/pc.h |   2 +
 target/i386/sev.c| 113 ---
 2 files changed, 86 insertions(+), 29 deletions(-)

diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index c653b8eeb24..ca7904ac2c4 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -172,6 +172,8 @@ typedef enum {
 SEV_DESC_TYPE_SNP_SECRETS,
 /* The section contains address that can be used as a CPUID page */
 SEV_DESC_TYPE_CPUID,
+/* The section contains the region for kernel hashes for measured direct 
boot */
+SEV_DESC_TYPE_SNP_KERNEL_HASHES = 0x10,
 
 } ovmf_sev_metadata_desc_type;
 
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 3fce4c08ebb..004c667ac14 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -115,6 +115,10 @@ struct SevCommonStateClass {
 X86ConfidentialGuestClass parent_class;
 
 /* public */
+bool (*build_kernel_loader_hashes)(SevCommonState *sev_common,
+   SevHashTableDescriptor *area,
+   SevKernelLoaderContext *ctx,
+   Error **errp);
 int (*launch_start)(SevCommonState *sev_common);
 void (*launch_finish)(SevCommonState *sev_common);
 int (*launch_update_data)(SevCommonState *sev_common, hwaddr gpa, uint8_t 
*ptr, uint64_t len);
@@ -154,6 +158,9 @@ struct SevSnpGuestState {
 
 struct kvm_sev_snp_launch_start kvm_start_conf;
 struct kvm_sev_snp_launch_finish kvm_finish_conf;
+
+uint32_t kernel_hashes_offset;
+PaddedSevHashTable *kernel_hashes_data;
 };
 
 #define DEFAULT_GUEST_POLICY0x1 /* disable debug */
@@ -1189,6 +1196,23 @@ snp_launch_update_cpuid(uint32_t cpuid_addr, void *hva, 
uint32_t cpuid_len)
   KVM_SEV_SNP_PAGE_TYPE_CPUID);
 }
 
+static int
+snp_launch_update_kernel_hashes(SevSnpGuestState *sev_snp, uint32_t addr,
+void *hva, uint32_t len)
+{
+int type = KVM_SEV_SNP_PAGE_TYPE_ZERO;
+if (sev_snp->parent_obj.kernel_hashes) {
+assert(sev_snp->kernel_hashes_data);
+assert((sev_snp->kernel_hashes_offset +
+sizeof(*sev_snp->kernel_hashes_data)) <= len);
+memset(hva, 0, len);
+memcpy(hva + sev_snp->kernel_hashes_offset, 
sev_snp->kernel_hashes_data,
+   sizeof(*sev_snp->kernel_hashes_data));
+type = KVM_SEV_SNP_PAGE_TYPE_NORMAL;
+}
+return snp_launch_update_data(addr, hva, len, type);
+}
+
 static int
 snp_metadata_desc_to_page_type(int desc_type)
 {
@@ -1225,6 +1249,9 @@ snp_populate_metadata_pages(SevSnpGuestState *sev_snp,
 
 if (type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
 ret = snp_launch_update_cpuid(desc->base, hva, desc->len);
+} else if (desc->type == SEV_DESC_TYPE_SNP_KERNEL_HASHES) {
+ret = snp_launch_update_kernel_hashes(sev_snp, desc->base, hva,
+  desc->len);
 } else {
 ret = snp_launch_update_data(desc->base, hva, desc->len, type);
 }
@@ -1823,40 +1850,31 @@ static bool 
build_kernel_loader_hashes(PaddedSevHashTable *padded_ht,
 return true;
 }
 
-/*
- * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
- * which is included in SEV's initial memory measurement.
- */
-bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
+static bool sev_snp_build_kernel_loader_hashes(SevCommonState *sev_common,
+   SevHashTableDescriptor *area,
+   SevKernelLoaderContext *ctx,
+   Error **errp)
+{
+/*
+ * SNP: Populate the hashes table in an area that later in
+ * snp_launch_update_kernel_hashes() will be copied to the guest memory
+ * and encrypted.
+ */
+SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(sev_common);
+sev_snp_guest->kernel_hashes_offset = area->base & ~TARGET_P

[PULL 37/45] i386/sev: Invoke launch_updata_data() for SNP class

2024-06-03 Thread Paolo Bonzini
From: Pankaj Gupta 

Invoke as sev_snp_launch_update_data() for SNP object.

Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-27-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 8834cf9441a..eaf5fc6c6b5 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1091,6 +1091,15 @@ snp_launch_update_data(uint64_t gpa, void *hva,
 return 0;
 }
 
+static int
+sev_snp_launch_update_data(SevCommonState *sev_common, hwaddr gpa,
+   uint8_t *ptr, uint64_t len)
+{
+   int ret = snp_launch_update_data(gpa, ptr, len,
+ KVM_SEV_SNP_PAGE_TYPE_NORMAL);
+   return ret;
+}
+
 static int
 sev_snp_cpuid_info_fill(SnpCpuidInfo *snp_cpuid_info,
 const KvmCpuidInfo *kvm_cpuid_info)
@@ -2216,6 +2225,7 @@ sev_snp_guest_class_init(ObjectClass *oc, void *data)
 
 klass->launch_start = sev_snp_launch_start;
 klass->launch_finish = sev_snp_launch_finish;
+klass->launch_update_data = sev_snp_launch_update_data;
 klass->kvm_init = sev_snp_kvm_init;
 x86_klass->kvm_type = sev_snp_kvm_type;
 
-- 
2.45.1




[PULL 05/45] host/i386: assume presence of SSE2

2024-06-03 Thread Paolo Bonzini
QEMU now requires an x86-64-v2 host, which has SSE2.
Use it freely in buffer_is_zero.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 host/include/i386/host/cpuinfo.h | 1 -
 util/bufferiszero.c  | 4 ++--
 util/cpuinfo-i386.c  | 1 -
 3 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/host/include/i386/host/cpuinfo.h b/host/include/i386/host/cpuinfo.h
index 81771733eaa..72f6fad61e5 100644
--- a/host/include/i386/host/cpuinfo.h
+++ b/host/include/i386/host/cpuinfo.h
@@ -14,7 +14,6 @@
 #define CPUINFO_POPCNT  (1u << 4)
 #define CPUINFO_BMI1(1u << 5)
 #define CPUINFO_BMI2(1u << 6)
-#define CPUINFO_SSE2(1u << 7)
 #define CPUINFO_AVX1(1u << 9)
 #define CPUINFO_AVX2(1u << 10)
 #define CPUINFO_AVX512F (1u << 11)
diff --git a/util/bufferiszero.c b/util/bufferiszero.c
index 74864f7b782..11c080e02cf 100644
--- a/util/bufferiszero.c
+++ b/util/bufferiszero.c
@@ -188,14 +188,14 @@ static biz_accel_fn const accel_table[] = {
 
 static unsigned best_accel(void)
 {
+#ifdef CONFIG_AVX2_OPT
 unsigned info = cpuinfo_init();
 
-#ifdef CONFIG_AVX2_OPT
 if (info & CPUINFO_AVX2) {
 return 2;
 }
 #endif
-return info & CPUINFO_SSE2 ? 1 : 0;
+return 1;
 }
 
 #elif defined(__aarch64__) && defined(__ARM_NEON)
diff --git a/util/cpuinfo-i386.c b/util/cpuinfo-i386.c
index 90f92a42dc8..ca74ef04f54 100644
--- a/util/cpuinfo-i386.c
+++ b/util/cpuinfo-i386.c
@@ -34,7 +34,6 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
 if (max >= 1) {
 __cpuid(1, a, b, c, d);
 
-info |= (d & bit_SSE2 ? CPUINFO_SSE2 : 0);
 info |= (c & bit_MOVBE ? CPUINFO_MOVBE : 0);
 info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
 info |= (c & bit_PCLMUL ? CPUINFO_PCLMUL : 0);
-- 
2.45.1




Re: [PATCH v2 4/4] vga/cirrus: deprecate, don't build by default

2024-06-03 Thread Mark Cave-Ayland

On 03/06/2024 12:40, Daniel P. Berrangé wrote:


On Thu, May 30, 2024 at 01:22:11PM +0100, Mark Cave-Ayland wrote:

On 30/05/2024 12:40, BALATON Zoltan wrote:


On Thu, 30 May 2024, Gerd Hoffmann wrote:

stdvga is the much better option.

Signed-off-by: Gerd Hoffmann 
---
hw/display/cirrus_vga.c | 1 +
hw/display/cirrus_vga_isa.c | 1 +
hw/display/Kconfig  | 1 -
3 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 150883a97166..81421be1f89d 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -3007,6 +3007,7 @@ static void cirrus_vga_class_init(ObjectClass
*klass, void *data)
     dc->vmsd = &vmstate_pci_cirrus_vga;
     device_class_set_props(dc, pci_vga_cirrus_properties);
     dc->hotpluggable = false;
+    klass->deprecation_note = "use stdvga instead";
}

static const TypeInfo cirrus_vga_info = {
diff --git a/hw/display/cirrus_vga_isa.c b/hw/display/cirrus_vga_isa.c
index 84be51670ed8..3abbf490 100644
--- a/hw/display/cirrus_vga_isa.c
+++ b/hw/display/cirrus_vga_isa.c
@@ -85,6 +85,7 @@ static void isa_cirrus_vga_class_init(ObjectClass
*klass, void *data)
     dc->realize = isa_cirrus_vga_realizefn;
     device_class_set_props(dc, isa_cirrus_vga_properties);
     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+    klass->deprecation_note = "use stdvga instead";


Excepr some old OSes work better with this than stdvga so could this be
left and not removed? Does it cause a lot of work to keep this device? I
thought it's stable already and were not many changes for it lately. If
something works why drop it?


Seconded: whilst stdvga is preferred, there are a lot of older OSs that work
well in QEMU using the Cirrus emulation. I appreciate that the code could do
with a bit of work, but is there a more specific reason that it should be
deprecated?


I think there's different answers here for upstream vs downstream.

Upstream QEMU's scope is to emulate pretty much arbitrary hardware that
may have existed at any point in time. Emulating Cirrus is very much
in scope upstream, and even if there are other better VGA devices, that
doesn't make emulation of Cirrus redundant.

Downstream is a different matter - if a downstream vendor wants to be
opinionated and limit the scope of devices they ship to customers, it
is totally valid to cull Cirrus.


The concern for me is that if someone such as RedHat decided not to ship Cirrus then 
we'd end up in a place where command lines for some legacy OSs would work on an 
upstream build, but if someone was using RHEL then they would fail due to the device 
not being present. I can see this causing confusion for users since they would report 
that a command line doesn't work whilst others would shrug and report back that it 
works for them.


I do wonder if a solution for this would be to add a blocklist file in /etc that 
prevents the listed QOM types from being instantiated. The file could contain also 
contain a machine regex to match and a reason that can be reported to the user e.g.


# QEMU QOM type blocklist
#
# QOM type regex, machine regex list, reason
"cirrus*","pc*,machine*","contains insecure blitter routines"
"fdc","pc*","may not be completely secure"

This feels like a better solution because:

- It's easy to add a message that reports "The requested QOM type  cannot be 
instantiated because " for specific machine types. The machine regex also 
fixes the problem where usb-ohci should be allowed for PPC machines, but not 
generally for PC machines.


- Downstream can ship with a secure policy for production environments but also a 
less restrictive policy for more casual users


- If someone really needs a device that is not enabled by default, a privileged user 
can simply edit the blocklist file and allow it


- It should work both with or without modules


ATB,

Mark.




[PULL 20/45] i386/sev: Move sev_launch_finish to separate class method

2024-06-03 Thread Paolo Bonzini
From: Pankaj Gupta 

When sev-snp-guest objects are introduced there will be a number of
differences in how the launch finish is handled compared to the existing
sev-guest object. Move sev_launch_finish() to a class method to make it
easier to implement SNP-specific launch update functionality later.

Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-7-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index b2aa0d6f99b..28a018ed833 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -71,6 +71,7 @@ struct SevCommonStateClass {
 
 /* public */
 int (*launch_start)(SevCommonState *sev_common);
+void (*launch_finish)(SevCommonState *sev_common);
 };
 
 /**
@@ -801,12 +802,12 @@ static Notifier sev_machine_done_notify = {
 };
 
 static void
-sev_launch_finish(SevGuestState *sev_guest)
+sev_launch_finish(SevCommonState *sev_common)
 {
 int ret, error;
 
 trace_kvm_sev_launch_finish();
-ret = sev_ioctl(SEV_COMMON(sev_guest)->sev_fd, KVM_SEV_LAUNCH_FINISH, 0,
+ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_FINISH, 0,
 &error);
 if (ret) {
 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
@@ -814,7 +815,7 @@ sev_launch_finish(SevGuestState *sev_guest)
 exit(1);
 }
 
-sev_set_guest_state(SEV_COMMON(sev_guest), SEV_STATE_RUNNING);
+sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
 
 /* add migration blocker */
 error_setg(&sev_mig_blocker,
@@ -826,10 +827,11 @@ static void
 sev_vm_state_change(void *opaque, bool running, RunState state)
 {
 SevCommonState *sev_common = opaque;
+SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(opaque);
 
 if (running) {
 if (!sev_check_state(sev_common, SEV_STATE_RUNNING)) {
-sev_launch_finish(SEV_GUEST(sev_common));
+klass->launch_finish(sev_common);
 }
 }
 }
@@ -1457,6 +1459,7 @@ sev_guest_class_init(ObjectClass *oc, void *data)
 SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
 
 klass->launch_start = sev_launch_start;
+klass->launch_finish = sev_launch_finish;
 
 object_class_property_add_str(oc, "dh-cert-file",
   sev_guest_get_dh_cert_file,
-- 
2.45.1




[PULL 30/45] i386/sev: Add handling to encrypt/finalize guest launch data

2024-06-03 Thread Paolo Bonzini
From: Brijesh Singh 

Process any queued up launch data and encrypt/measure it into the SNP
guest instance prior to initial guest launch.

This also updates the KVM_SEV_SNP_LAUNCH_UPDATE call to handle partial
update responses.

Signed-off-by: Brijesh Singh 
Co-developed-by: Michael Roth 
Signed-off-by: Michael Roth 
Co-developed-by: Pankaj Gupta 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-17-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c| 112 ++-
 target/i386/trace-events |   2 +
 2 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index e89b87d2f55..ef2e592ca76 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -756,6 +756,76 @@ out:
 return ret;
 }
 
+static const char *
+snp_page_type_to_str(int type)
+{
+switch (type) {
+case KVM_SEV_SNP_PAGE_TYPE_NORMAL: return "Normal";
+case KVM_SEV_SNP_PAGE_TYPE_ZERO: return "Zero";
+case KVM_SEV_SNP_PAGE_TYPE_UNMEASURED: return "Unmeasured";
+case KVM_SEV_SNP_PAGE_TYPE_SECRETS: return "Secrets";
+case KVM_SEV_SNP_PAGE_TYPE_CPUID: return "Cpuid";
+default: return "unknown";
+}
+}
+
+static int
+sev_snp_launch_update(SevSnpGuestState *sev_snp_guest,
+  SevLaunchUpdateData *data)
+{
+int ret, fw_error;
+struct kvm_sev_snp_launch_update update = {0};
+
+if (!data->hva || !data->len) {
+error_report("SNP_LAUNCH_UPDATE called with invalid address"
+ "/ length: %p / %lx",
+ data->hva, data->len);
+return 1;
+}
+
+update.uaddr = (__u64)(unsigned long)data->hva;
+update.gfn_start = data->gpa >> TARGET_PAGE_BITS;
+update.len = data->len;
+update.type = data->type;
+
+/*
+ * KVM_SEV_SNP_LAUNCH_UPDATE requires that GPA ranges have the private
+ * memory attribute set in advance.
+ */
+ret = kvm_set_memory_attributes_private(data->gpa, data->len);
+if (ret) {
+error_report("SEV-SNP: failed to configure initial"
+ "private guest memory");
+goto out;
+}
+
+while (update.len || ret == -EAGAIN) {
+trace_kvm_sev_snp_launch_update(update.uaddr, update.gfn_start <<
+TARGET_PAGE_BITS, update.len,
+snp_page_type_to_str(update.type));
+
+ret = sev_ioctl(SEV_COMMON(sev_snp_guest)->sev_fd,
+KVM_SEV_SNP_LAUNCH_UPDATE,
+&update, &fw_error);
+if (ret && ret != -EAGAIN) {
+error_report("SNP_LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
+ ret, fw_error, fw_error_to_str(fw_error));
+break;
+}
+}
+
+out:
+if (!ret && update.gfn_start << TARGET_PAGE_BITS != data->gpa + data->len) 
{
+error_report("SEV-SNP: expected update of GPA range %lx-%lx,"
+ "got GPA range %lx-%llx",
+ data->gpa, data->gpa + data->len, data->gpa,
+ update.gfn_start << TARGET_PAGE_BITS);
+ret = -EIO;
+}
+
+return ret;
+}
+
 static int
 sev_launch_update_data(SevGuestState *sev_guest, uint8_t *addr, uint64_t len)
 {
@@ -901,6 +971,46 @@ sev_launch_finish(SevCommonState *sev_common)
 migrate_add_blocker(&sev_mig_blocker, &error_fatal);
 }
 
+static void
+sev_snp_launch_finish(SevCommonState *sev_common)
+{
+int ret, error;
+Error *local_err = NULL;
+SevLaunchUpdateData *data;
+SevSnpGuestState *sev_snp = SEV_SNP_GUEST(sev_common);
+struct kvm_sev_snp_launch_finish *finish = &sev_snp->kvm_finish_conf;
+
+QTAILQ_FOREACH(data, &launch_update, next) {
+ret = sev_snp_launch_update(sev_snp, data);
+if (ret) {
+exit(1);
+}
+}
+
+trace_kvm_sev_snp_launch_finish(sev_snp->id_block, sev_snp->id_auth,
+sev_snp->host_data);
+ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_FINISH,
+finish, &error);
+if (ret) {
+error_report("SNP_LAUNCH_FINISH ret=%d fw_error=%d '%s'",
+ ret, error, fw_error_to_str(error));
+exit(1);
+}
+
+sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
+
+/* add migration blocker */
+error_setg(&sev_mig_blocker,
+   "SEV-SNP: Migration is not implemented");
+ret = migrate_add_blocker(&sev_mig_blocker, &local_err);
+if (local_err) {
+error_report_err(local_err);
+error_free(sev_mig_blocker);
+exit(1);
+}
+}
+
+
 static void
 sev_vm_state_change(void *opaque, bool running, RunState state)
 {
@@ -1832,10 +1942,10 @@ sev_snp_guest_class_init(ObjectClass *oc, void *data)
 X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
 
 klass->launch_start = sev_snp_launch_start;
+klass->launch_finish = sev_snp_launch_fi

[PULL 31/45] i386/sev: Set CPU state to protected once SNP guest payload is finalized

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

Once KVM_SNP_LAUNCH_FINISH is called the vCPU state is copied into the
vCPU's VMSA page and measured/encrypted. Any attempt to read/write CPU
state afterward will only be acting on the initial data and so are
effectively no-ops.

Set the vCPU state to protected at this point so that QEMU don't
continue trying to re-sync vCPU data during guest runtime.

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-18-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index ef2e592ca76..e84e4395a53 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -997,6 +997,7 @@ sev_snp_launch_finish(SevCommonState *sev_common)
 exit(1);
 }
 
+kvm_mark_guest_state_protected();
 sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
 
 /* add migration blocker */
-- 
2.45.1




[PULL 10/45] target/i386/tcg: Fix RDPID feature check

2024-06-03 Thread Paolo Bonzini
From: Zhao Liu 

DisasContext.cpuid_ext_features indicates CPUID.01H.ECX.

Use DisasContext.cpuid_7_0_ecx_features field to check RDPID feature bit
(CPUID_7_0_ECX_RDPID).

Fixes: 6750485bf42a ("target/i386: implement RDPID in TCG")
Inspired-by: Xinyu Li 
Signed-off-by: Zhao Liu 
Message-ID: <20240603080723.1256662-1-zhao1@intel.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 6dedfe94c04..0486ab69112 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3199,7 +3199,7 @@ static void disas_insn_old(DisasContext *s, CPUState 
*cpu, int b)
 goto illegal_op;
 }
 if (s->prefix & PREFIX_REPZ) {
-if (!(s->cpuid_ext_features & CPUID_7_0_ECX_RDPID)) {
+if (!(s->cpuid_7_0_ecx_features & CPUID_7_0_ECX_RDPID)) {
 goto illegal_op;
 }
 gen_helper_rdpid(s->T0, tcg_env);
-- 
2.45.1




[PULL 45/45] hw/i386: Add support for loading BIOS using guest_memfd

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

When guest_memfd is enabled, the BIOS is generally part of the initial
encrypted guest image and will be accessed as private guest memory. Add
the necessary changes to set up the associated RAM region with a
guest_memfd backend to allow for this.

Current support centers around using -bios to load the BIOS data.
Support for loading the BIOS via pflash requires additional enablement
since those interfaces rely on the use of ROM memory regions which make
use of the KVM_MEM_READONLY memslot flag, which is not supported for
guest_memfd-backed memslots.

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-29-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 hw/i386/x86-common.c | 17 -
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index f41cb0a6a8b..c0c66a0eb52 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -1001,8 +1001,13 @@ void x86_bios_rom_init(X86MachineState *x86ms, const 
char *default_firmware,
 (bios_size % 65536) != 0) {
 goto bios_error;
 }
-memory_region_init_ram(&x86ms->bios, NULL, "pc.bios", bios_size,
-   &error_fatal);
+if (machine_require_guest_memfd(MACHINE(x86ms))) {
+memory_region_init_ram_guest_memfd(&x86ms->bios, NULL, "pc.bios",
+   bios_size, &error_fatal);
+} else {
+memory_region_init_ram(&x86ms->bios, NULL, "pc.bios",
+   bios_size, &error_fatal);
+}
 if (sev_enabled()) {
 /*
  * The concept of a "reset" simply doesn't exist for
@@ -1023,9 +1028,11 @@ void x86_bios_rom_init(X86MachineState *x86ms, const 
char *default_firmware,
 }
 g_free(filename);
 
-/* map the last 128KB of the BIOS in ISA space */
-x86_isa_bios_init(&x86ms->isa_bios, rom_memory, &x86ms->bios,
-  !isapc_ram_fw);
+if (!machine_require_guest_memfd(MACHINE(x86ms))) {
+/* map the last 128KB of the BIOS in ISA space */
+x86_isa_bios_init(&x86ms->isa_bios, rom_memory, &x86ms->bios,
+  !isapc_ram_fw);
+}
 
 /* map all the bios at the top of memory */
 memory_region_add_subregion(rom_memory,
-- 
2.45.1




[PULL 43/45] memory: Introduce memory_region_init_ram_guest_memfd()

2024-06-03 Thread Paolo Bonzini
From: Xiaoyao Li 

Introduce memory_region_init_ram_guest_memfd() to allocate private
guset memfd on the MemoryRegion initialization. It's for the use case of
TDVF, which must be private on TDX case.

Signed-off-by: Xiaoyao Li 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-4-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 include/exec/memory.h |  6 ++
 system/memory.c   | 24 
 2 files changed, 30 insertions(+)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 9cdd64e9c69..1be58f694c9 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1638,6 +1638,12 @@ bool memory_region_init_ram(MemoryRegion *mr,
 uint64_t size,
 Error **errp);
 
+bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
+Object *owner,
+const char *name,
+uint64_t size,
+Error **errp);
+
 /**
  * memory_region_init_rom: Initialize a ROM memory region.
  *
diff --git a/system/memory.c b/system/memory.c
index 9540caa8a1f..74cd73ebc78 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -3649,6 +3649,30 @@ bool memory_region_init_ram(MemoryRegion *mr,
 return true;
 }
 
+bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
+Object *owner,
+const char *name,
+uint64_t size,
+Error **errp)
+{
+DeviceState *owner_dev;
+
+if (!memory_region_init_ram_flags_nomigrate(mr, owner, name, size,
+RAM_GUEST_MEMFD, errp)) {
+return false;
+}
+/* This will assert if owner is neither NULL nor a DeviceState.
+ * We only want the owner here for the purposes of defining a
+ * unique name for migration. TODO: Ideally we should implement
+ * a naming scheme for Objects which are not DeviceStates, in
+ * which case we can relax this restriction.
+ */
+owner_dev = DEVICE(owner);
+vmstate_register_ram(mr, owner_dev);
+
+return true;
+}
+
 bool memory_region_init_rom(MemoryRegion *mr,
 Object *owner,
 const char *name,
-- 
2.45.1




[PULL 41/45] i386/sev: Reorder struct declarations

2024-06-03 Thread Paolo Bonzini
From: Dov Murik 

Move the declaration of PaddedSevHashTable before SevSnpGuest so
we can add a new such field to the latter.

No functional change intended.

Signed-off-by: Dov Murik 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-23-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 84 +++
 1 file changed, 42 insertions(+), 42 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 73f94067155..3fce4c08ebb 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -46,6 +46,48 @@ OBJECT_DECLARE_TYPE(SevCommonState, SevCommonStateClass, 
SEV_COMMON)
 OBJECT_DECLARE_TYPE(SevGuestState, SevCommonStateClass, SEV_GUEST)
 OBJECT_DECLARE_TYPE(SevSnpGuestState, SevCommonStateClass, SEV_SNP_GUEST)
 
+/* hard code sha256 digest size */
+#define HASH_SIZE 32
+
+typedef struct QEMU_PACKED SevHashTableEntry {
+QemuUUID guid;
+uint16_t len;
+uint8_t hash[HASH_SIZE];
+} SevHashTableEntry;
+
+typedef struct QEMU_PACKED SevHashTable {
+QemuUUID guid;
+uint16_t len;
+SevHashTableEntry cmdline;
+SevHashTableEntry initrd;
+SevHashTableEntry kernel;
+} SevHashTable;
+
+/*
+ * Data encrypted by sev_encrypt_flash() must be padded to a multiple of
+ * 16 bytes.
+ */
+typedef struct QEMU_PACKED PaddedSevHashTable {
+SevHashTable ht;
+uint8_t padding[ROUND_UP(sizeof(SevHashTable), 16) - sizeof(SevHashTable)];
+} PaddedSevHashTable;
+
+QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
+
+#define SEV_INFO_BLOCK_GUID "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
+typedef struct __attribute__((__packed__)) SevInfoBlock {
+/* SEV-ES Reset Vector Address */
+uint32_t reset_addr;
+} SevInfoBlock;
+
+#define SEV_HASH_TABLE_RV_GUID  "7255371f-3a3b-4b04-927b-1da6efa8d454"
+typedef struct QEMU_PACKED SevHashTableDescriptor {
+/* SEV hash table area guest address */
+uint32_t base;
+/* SEV hash table area size (in bytes) */
+uint32_t size;
+} SevHashTableDescriptor;
+
 struct SevCommonState {
 X86ConfidentialGuest parent_obj;
 
@@ -128,48 +170,6 @@ typedef struct SevLaunchUpdateData {
 
 static QTAILQ_HEAD(, SevLaunchUpdateData) launch_update;
 
-#define SEV_INFO_BLOCK_GUID "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
-typedef struct __attribute__((__packed__)) SevInfoBlock {
-/* SEV-ES Reset Vector Address */
-uint32_t reset_addr;
-} SevInfoBlock;
-
-#define SEV_HASH_TABLE_RV_GUID  "7255371f-3a3b-4b04-927b-1da6efa8d454"
-typedef struct QEMU_PACKED SevHashTableDescriptor {
-/* SEV hash table area guest address */
-uint32_t base;
-/* SEV hash table area size (in bytes) */
-uint32_t size;
-} SevHashTableDescriptor;
-
-/* hard code sha256 digest size */
-#define HASH_SIZE 32
-
-typedef struct QEMU_PACKED SevHashTableEntry {
-QemuUUID guid;
-uint16_t len;
-uint8_t hash[HASH_SIZE];
-} SevHashTableEntry;
-
-typedef struct QEMU_PACKED SevHashTable {
-QemuUUID guid;
-uint16_t len;
-SevHashTableEntry cmdline;
-SevHashTableEntry initrd;
-SevHashTableEntry kernel;
-} SevHashTable;
-
-/*
- * Data encrypted by sev_encrypt_flash() must be padded to a multiple of
- * 16 bytes.
- */
-typedef struct QEMU_PACKED PaddedSevHashTable {
-SevHashTable ht;
-uint8_t padding[ROUND_UP(sizeof(SevHashTable), 16) - sizeof(SevHashTable)];
-} PaddedSevHashTable;
-
-QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
-
 static Error *sev_mig_blocker;
 
 static const char *const sev_fw_errlist[] = {
-- 
2.45.1




[PULL 36/45] i386/sev: Invoke launch_updata_data() for SEV class

2024-06-03 Thread Paolo Bonzini
Add launch_update_data() in SevCommonStateClass and
invoke as sev_launch_update_data() for SEV object.

Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-26-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 7b5c4b4874d..8834cf9441a 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -74,6 +74,7 @@ struct SevCommonStateClass {
 /* public */
 int (*launch_start)(SevCommonState *sev_common);
 void (*launch_finish)(SevCommonState *sev_common);
+int (*launch_update_data)(SevCommonState *sev_common, hwaddr gpa, uint8_t 
*ptr, uint64_t len);
 int (*kvm_init)(ConfidentialGuestSupport *cgs, Error **errp);
 };
 
@@ -929,7 +930,7 @@ out:
 }
 
 static int
-sev_launch_update_data(SevGuestState *sev_guest, uint8_t *addr, uint64_t len)
+sev_launch_update_data(SevCommonState *sev_common, hwaddr gpa, uint8_t *addr, 
uint64_t len)
 {
 int ret, fw_error;
 struct kvm_sev_launch_update_data update;
@@ -941,7 +942,7 @@ sev_launch_update_data(SevGuestState *sev_guest, uint8_t 
*addr, uint64_t len)
 update.uaddr = (uintptr_t)addr;
 update.len = len;
 trace_kvm_sev_launch_update_data(addr, len);
-ret = sev_ioctl(SEV_COMMON(sev_guest)->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
+ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
 &update, &fw_error);
 if (ret) {
 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
@@ -1487,6 +1488,7 @@ int
 sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp)
 {
 SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(sev_common);
 
 if (!sev_common) {
 return 0;
@@ -1494,7 +1496,9 @@ sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, 
Error **errp)
 
 /* if SEV is in update state then encrypt the data else do nothing */
 if (sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) {
-int ret = sev_launch_update_data(SEV_GUEST(sev_common), ptr, len);
+int ret;
+
+ret = klass->launch_update_data(sev_common, gpa, ptr, len);
 if (ret < 0) {
 error_setg(errp, "SEV: Failed to encrypt pflash rom");
 return ret;
@@ -1968,6 +1972,7 @@ sev_guest_class_init(ObjectClass *oc, void *data)
 
 klass->launch_start = sev_launch_start;
 klass->launch_finish = sev_launch_finish;
+klass->launch_update_data = sev_launch_update_data;
 klass->kvm_init = sev_kvm_init;
 x86_klass->kvm_type = sev_kvm_type;
 
-- 
2.45.1




[PULL 26/45] i386/sev: Don't return launch measurements for SEV-SNP guests

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

For SEV-SNP guests, launch measurement is queried from within the guest
during attestation, so don't attempt to return it as part of
query-sev-launch-measure.

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-13-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 6525b3c1a0e..c3daaf1ad50 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -795,7 +795,9 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 
 static char *sev_get_launch_measurement(void)
 {
-SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
+ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
+SevGuestState *sev_guest =
+(SevGuestState *)object_dynamic_cast(OBJECT(cgs), TYPE_SEV_GUEST);
 
 if (sev_guest &&
 SEV_COMMON(sev_guest)->state >= SEV_STATE_LAUNCH_SECRET) {
-- 
2.45.1




[PULL 44/45] hw/i386/sev: Use guest_memfd for legacy ROMs

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

Current SNP guest kernels will attempt to access these regions with
with C-bit set, so guest_memfd is needed to handle that. Otherwise,
kvm_convert_memory() will fail when the guest kernel tries to access it
and QEMU attempts to call KVM_SET_MEMORY_ATTRIBUTES to set these ranges
to private.

Whether guests should actually try to access ROM regions in this way (or
need to deal with legacy ROM regions at all), is a separate issue to be
addressed on kernel side, but current SNP guest kernels will exhibit
this behavior and so this handling is needed to allow QEMU to continue
running existing SNP guest kernels.

Signed-off-by: Michael Roth 
[pankaj: Added sev_snp_enabled() check]
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-28-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 hw/i386/pc.c   | 14 ++
 hw/i386/pc_sysfw.c | 19 +--
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 7b638da7aaa..0469af00a78 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -62,6 +62,7 @@
 #include "hw/mem/memory-device.h"
 #include "e820_memory_layout.h"
 #include "trace.h"
+#include "sev.h"
 #include CONFIG_DEVICES
 
 #ifdef CONFIG_XEN_EMU
@@ -1022,10 +1023,15 @@ void pc_memory_init(PCMachineState *pcms,
 pc_system_firmware_init(pcms, rom_memory);
 
 option_rom_mr = g_malloc(sizeof(*option_rom_mr));
-memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
-   &error_fatal);
-if (pcmc->pci_enabled) {
-memory_region_set_readonly(option_rom_mr, true);
+if (machine_require_guest_memfd(machine)) {
+memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
+   PC_ROM_SIZE, &error_fatal);
+} else {
+memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
+   &error_fatal);
+if (pcmc->pci_enabled) {
+memory_region_set_readonly(option_rom_mr, true);
+}
 }
 memory_region_add_subregion_overlap(rom_memory,
 PC_ROM_MIN_VGA,
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 7cdbafc8d22..ef80281d28b 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -40,8 +40,8 @@
 
 #define FLASH_SECTOR_SIZE 4096
 
-static void pc_isa_bios_init(MemoryRegion *isa_bios, MemoryRegion *rom_memory,
- MemoryRegion *flash_mem)
+static void pc_isa_bios_init(PCMachineState *pcms, MemoryRegion *isa_bios,
+ MemoryRegion *rom_memory, MemoryRegion *flash_mem)
 {
 int isa_bios_size;
 uint64_t flash_size;
@@ -51,8 +51,13 @@ static void pc_isa_bios_init(MemoryRegion *isa_bios, 
MemoryRegion *rom_memory,
 
 /* map the last 128KB of the BIOS in ISA space */
 isa_bios_size = MIN(flash_size, 128 * KiB);
-memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
-   &error_fatal);
+if (machine_require_guest_memfd(MACHINE(pcms))) {
+memory_region_init_ram_guest_memfd(isa_bios, NULL, "isa-bios",
+   isa_bios_size, &error_fatal);
+} else {
+memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
+   &error_fatal);
+}
 memory_region_add_subregion_overlap(rom_memory,
 0x10 - isa_bios_size,
 isa_bios,
@@ -65,7 +70,9 @@ static void pc_isa_bios_init(MemoryRegion *isa_bios, 
MemoryRegion *rom_memory,
((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
isa_bios_size);
 
-memory_region_set_readonly(isa_bios, true);
+if (!machine_require_guest_memfd(current_machine)) {
+memory_region_set_readonly(isa_bios, true);
+}
 }
 
 static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
@@ -191,7 +198,7 @@ static void pc_system_flash_map(PCMachineState *pcms,
 x86_isa_bios_init(&x86ms->isa_bios, rom_memory, flash_mem,
   true);
 } else {
-pc_isa_bios_init(&x86ms->isa_bios, rom_memory, flash_mem);
+pc_isa_bios_init(pcms, &x86ms->isa_bios, rom_memory, 
flash_mem);
 }
 
 /* Encrypt the pflash boot ROM */
-- 
2.45.1




[PULL 38/45] i386/kvm: Add KVM_EXIT_HYPERCALL handling for KVM_HC_MAP_GPA_RANGE

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

KVM_HC_MAP_GPA_RANGE will be used to send requests to userspace for
private/shared memory attribute updates requested by the guest.
Implement handling for that use-case along with some basic
infrastructure for enabling specific hypercall events.

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-31-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/kvm/kvm_i386.h   |  1 +
 target/i386/kvm/kvm.c| 55 
 target/i386/kvm/trace-events |  1 +
 3 files changed, 57 insertions(+)

diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 6b44844d95d..34fc60774b8 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -33,6 +33,7 @@
 bool kvm_has_smm(void);
 bool kvm_enable_x2apic(void);
 bool kvm_hv_vpindex_settable(void);
+bool kvm_enable_hypercall(uint64_t enable_mask);
 
 bool kvm_enable_sgx_provisioning(KVMState *s);
 bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 23a003aaa7e..ede3ef1225f 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -21,6 +21,7 @@
 #include 
 
 #include 
+#include 
 #include "standard-headers/asm-x86/kvm_para.h"
 #include "hw/xen/interface/arch-x86/cpuid.h"
 
@@ -209,6 +210,13 @@ int kvm_get_vm_type(MachineState *ms)
 return kvm_type;
 }
 
+bool kvm_enable_hypercall(uint64_t enable_mask)
+{
+KVMState *s = KVM_STATE(current_accel());
+
+return !kvm_vm_enable_cap(s, KVM_CAP_EXIT_HYPERCALL, 0, enable_mask);
+}
+
 bool kvm_has_smm(void)
 {
 return kvm_vm_check_extension(kvm_state, KVM_CAP_X86_SMM);
@@ -5322,6 +5330,50 @@ static bool host_supports_vmx(void)
 return ecx & CPUID_EXT_VMX;
 }
 
+/*
+ * Currently the handling here only supports use of KVM_HC_MAP_GPA_RANGE
+ * to service guest-initiated memory attribute update requests so that
+ * KVM_SET_MEMORY_ATTRIBUTES can update whether or not a page should be
+ * backed by the private memory pool provided by guest_memfd, and as such
+ * is only applicable to guest_memfd-backed guests (e.g. SNP/TDX).
+ *
+ * Other other use-cases for KVM_HC_MAP_GPA_RANGE, such as for SEV live
+ * migration, are not implemented here currently.
+ *
+ * For the guest_memfd use-case, these exits will generally be synthesized
+ * by KVM based on platform-specific hypercalls, like GHCB requests in the
+ * case of SEV-SNP, and not issued directly within the guest though the
+ * KVM_HC_MAP_GPA_RANGE hypercall. So in this case, KVM_HC_MAP_GPA_RANGE is
+ * not actually advertised to guests via the KVM CPUID feature bit, as
+ * opposed to SEV live migration where it would be. Since it is unlikely the
+ * SEV live migration use-case would be useful for guest-memfd backed guests,
+ * because private/shared page tracking is already provided through other
+ * means, these 2 use-cases should be treated as being mutually-exclusive.
+ */
+static int kvm_handle_hc_map_gpa_range(struct kvm_run *run)
+{
+uint64_t gpa, size, attributes;
+
+if (!machine_require_guest_memfd(current_machine))
+return -EINVAL;
+
+gpa = run->hypercall.args[0];
+size = run->hypercall.args[1] * TARGET_PAGE_SIZE;
+attributes = run->hypercall.args[2];
+
+trace_kvm_hc_map_gpa_range(gpa, size, attributes, run->hypercall.flags);
+
+return kvm_convert_memory(gpa, size, attributes & 
KVM_MAP_GPA_RANGE_ENCRYPTED);
+}
+
+static int kvm_handle_hypercall(struct kvm_run *run)
+{
+if (run->hypercall.nr == KVM_HC_MAP_GPA_RANGE)
+return kvm_handle_hc_map_gpa_range(run);
+
+return -EINVAL;
+}
+
 #define VMX_INVALID_GUEST_STATE 0x8021
 
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
@@ -5417,6 +5469,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run 
*run)
 ret = kvm_xen_handle_exit(cpu, &run->xen);
 break;
 #endif
+case KVM_EXIT_HYPERCALL:
+ret = kvm_handle_hypercall(run);
+break;
 default:
 fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
 ret = -1;
diff --git a/target/i386/kvm/trace-events b/target/i386/kvm/trace-events
index b365a8e8e28..74a6234ff7f 100644
--- a/target/i386/kvm/trace-events
+++ b/target/i386/kvm/trace-events
@@ -5,6 +5,7 @@ kvm_x86_fixup_msi_error(uint32_t gsi) "VT-d failed to remap 
interrupt for GSI %"
 kvm_x86_add_msi_route(int virq) "Adding route entry for virq %d"
 kvm_x86_remove_msi_route(int virq) "Removing route entry for virq %d"
 kvm_x86_update_msi_routes(int num) "Updated %d MSI routes"
+kvm_hc_map_gpa_range(uint64_t gpa, uint64_t size, uint64_t attributes, 
uint64_t flags) "gpa 0x%" PRIx64 " size 0x%" PRIx64 " attributes 0x%" PRIx64 " 
flags 0x%" PRIx64
 
 # xen-emu.c
 kvm_xen_hypercall(int cpu, uint8_t cpl, uint64_t input, uint64_t a0, uint64_t 
a1, uint64_t a2, uint64_t ret) "xen_hypercall: cpu %d cpl %d input %" PRIu64 " 
a0 0x%" PRIx64 " a1 0x%" PRIx64 " a2 0x%" PRI

[PULL 18/45] i386/sev: Introduce "sev-common" type to encapsulate common SEV state

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

Currently all SEV/SEV-ES functionality is managed through a single
'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
same approach won't work well since some of the properties/state
managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
rely on a new QOM type with its own set of properties/state.

To prepare for this, this patch moves common state into an abstract
'sev-common' parent type to encapsulate properties/state that are
common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
properties/state in the current 'sev-guest' type. This should not
affect current behavior or command-line options.

As part of this patch, some related changes are also made:

  - a static 'sev_guest' variable is currently used to keep track of
the 'sev-guest' instance. SEV-SNP would similarly introduce an
'sev_snp_guest' static variable. But these instances are now
available via qdev_get_machine()->cgs, so switch to using that
instead and drop the static variable.

  - 'sev_guest' is currently used as the name for the static variable
holding a pointer to the 'sev-guest' instance. Re-purpose the name
as a local variable referring the 'sev-guest' instance, and use
that consistently throughout the code so it can be easily
distinguished from sev-common/sev-snp-guest instances.

  - 'sev' is generally used as the name for local variables holding a
pointer to the 'sev-guest' instance. In cases where that now points
to common state, use the name 'sev_common'; in cases where that now
points to state specific to 'sev-guest' instance, use the name
'sev_guest'

In order to enable kernel-hashes for SNP, pull it from
SevGuestProperties to its parent SevCommonProperties so
it will be available for both SEV and SNP.

Signed-off-by: Michael Roth 
Co-developed-by: Dov Murik 
Signed-off-by: Dov Murik 
Acked-by: Markus Armbruster  (QAPI schema)
Co-developed-by: Pankaj Gupta 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-5-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 qapi/qom.json |  40 ++--
 target/i386/sev.h |   3 +
 target/i386/sev.c | 493 ++
 3 files changed, 303 insertions(+), 233 deletions(-)

diff --git a/qapi/qom.json b/qapi/qom.json
index 38dde6d785a..056b38f491b 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -875,20 +875,12 @@
   'data': { '*filename': 'str' } }
 
 ##
-# @SevGuestProperties:
+# @SevCommonProperties:
 #
-# Properties for sev-guest objects.
+# Properties common to objects that are derivatives of sev-common.
 #
 # @sev-device: SEV device to use (default: "/dev/sev")
 #
-# @dh-cert-file: guest owners DH certificate (encoded with base64)
-#
-# @session-file: guest owners session parameters (encoded with base64)
-#
-# @policy: SEV policy value (default: 0x1)
-#
-# @handle: SEV firmware handle (default: 0)
-#
 # @cbitpos: C-bit location in page table entry (default: 0)
 #
 # @reduced-phys-bits: number of bits in physical addresses that become
@@ -898,6 +890,27 @@
 # designated guest firmware page for measured boot with -kernel
 # (default: false) (since 6.2)
 #
+# Since: 9.1
+##
+{ 'struct': 'SevCommonProperties',
+  'data': { '*sev-device': 'str',
+'*cbitpos': 'uint32',
+'reduced-phys-bits': 'uint32',
+'*kernel-hashes': 'bool' } }
+
+##
+# @SevGuestProperties:
+#
+# Properties for sev-guest objects.
+#
+# @dh-cert-file: guest owners DH certificate (encoded with base64)
+#
+# @session-file: guest owners session parameters (encoded with base64)
+#
+# @policy: SEV policy value (default: 0x1)
+#
+# @handle: SEV firmware handle (default: 0)
+#
 # @legacy-vm-type: Use legacy KVM_SEV_INIT KVM interface for creating the VM.
 #  The newer KVM_SEV_INIT2 interface syncs additional vCPU
 #  state when initializing the VMSA structures, which will
@@ -909,14 +922,11 @@
 # Since: 2.12
 ##
 { 'struct': 'SevGuestProperties',
-  'data': { '*sev-device': 'str',
-'*dh-cert-file': 'str',
+  'base': 'SevCommonProperties',
+  'data': { '*dh-cert-file': 'str',
 '*session-file': 'str',
 '*policy': 'uint32',
 '*handle': 'uint32',
-'*cbitpos': 'uint32',
-'reduced-phys-bits': 'uint32',
-'*kernel-hashes': 'bool',
 '*legacy-vm-type': 'bool' } }
 
 ##
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 9e10d09539a..668374eef31 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -20,6 +20,9 @@
 
 #include "exec/confidential-guest-support.h"
 
+#define TYPE_SEV_COMMON "sev-common"
+#define TYPE_SEV_GUEST "sev-guest"
+
 #define SEV_POLICY_NODBG0x1
 #define SEV_POLICY_NOKS 0x2
 #define SEV_POLICY_ES   0x4
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 67ed32e5ea9..33e606eea00 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -40,9 +40,36 @

[PULL 14/45] linux-headers: Update to current kvm/next

2024-06-03 Thread Paolo Bonzini
From: Pankaj Gupta 

This updates kernel headers to commit 6f627b425378 ("KVM: SVM: Add module
parameter to enable SEV-SNP", 2024-05-12).  The SNP host patches will
be included in Linux 6.11, to be released next July.

Also brings in an linux-headers/linux/vhost.h fix from v6.9-rc4.

Co-developed-by: Michael Roth 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-3-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 linux-headers/asm-loongarch/kvm.h |  4 +++
 linux-headers/asm-riscv/kvm.h |  1 +
 linux-headers/asm-x86/kvm.h   | 52 ++-
 linux-headers/linux/vhost.h   | 15 -
 4 files changed, 64 insertions(+), 8 deletions(-)

diff --git a/linux-headers/asm-loongarch/kvm.h 
b/linux-headers/asm-loongarch/kvm.h
index 109785922cf..f9abef38231 100644
--- a/linux-headers/asm-loongarch/kvm.h
+++ b/linux-headers/asm-loongarch/kvm.h
@@ -17,6 +17,8 @@
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 #define KVM_DIRTY_LOG_PAGE_OFFSET  64
 
+#define KVM_GUESTDBG_USE_SW_BP 0x0001
+
 /*
  * for KVM_GET_REGS and KVM_SET_REGS
  */
@@ -72,6 +74,8 @@ struct kvm_fpu {
 
 #define KVM_REG_LOONGARCH_COUNTER  (KVM_REG_LOONGARCH_KVM | 
KVM_REG_SIZE_U64 | 1)
 #define KVM_REG_LOONGARCH_VCPU_RESET   (KVM_REG_LOONGARCH_KVM | 
KVM_REG_SIZE_U64 | 2)
+/* Debugging: Special instruction for software breakpoint */
+#define KVM_REG_LOONGARCH_DEBUG_INST   (KVM_REG_LOONGARCH_KVM | 
KVM_REG_SIZE_U64 | 3)
 
 #define LOONGARCH_REG_SHIFT3
 #define LOONGARCH_REG_64(TYPE, REG)(TYPE | KVM_REG_SIZE_U64 | (REG << 
LOONGARCH_REG_SHIFT))
diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h
index b1c503c2959..e878e7cc397 100644
--- a/linux-headers/asm-riscv/kvm.h
+++ b/linux-headers/asm-riscv/kvm.h
@@ -167,6 +167,7 @@ enum KVM_RISCV_ISA_EXT_ID {
KVM_RISCV_ISA_EXT_ZFA,
KVM_RISCV_ISA_EXT_ZTSO,
KVM_RISCV_ISA_EXT_ZACAS,
+   KVM_RISCV_ISA_EXT_SSCOFPMF,
KVM_RISCV_ISA_EXT_MAX,
 };
 
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 31c95c2dfe4..1c8f9182348 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -695,6 +695,11 @@ enum sev_cmd_id {
/* Second time is the charm; improved versions of the above ioctls.  */
KVM_SEV_INIT2,
 
+   /* SNP-specific commands */
+   KVM_SEV_SNP_LAUNCH_START = 100,
+   KVM_SEV_SNP_LAUNCH_UPDATE,
+   KVM_SEV_SNP_LAUNCH_FINISH,
+
KVM_SEV_NR_MAX,
 };
 
@@ -709,7 +714,9 @@ struct kvm_sev_cmd {
 struct kvm_sev_init {
__u64 vmsa_features;
__u32 flags;
-   __u32 pad[9];
+   __u16 ghcb_version;
+   __u16 pad1;
+   __u32 pad2[8];
 };
 
 struct kvm_sev_launch_start {
@@ -820,6 +827,48 @@ struct kvm_sev_receive_update_data {
__u32 pad2;
 };
 
+struct kvm_sev_snp_launch_start {
+   __u64 policy;
+   __u8 gosvw[16];
+   __u16 flags;
+   __u8 pad0[6];
+   __u64 pad1[4];
+};
+
+/* Kept in sync with firmware values for simplicity. */
+#define KVM_SEV_SNP_PAGE_TYPE_NORMAL   0x1
+#define KVM_SEV_SNP_PAGE_TYPE_ZERO 0x3
+#define KVM_SEV_SNP_PAGE_TYPE_UNMEASURED   0x4
+#define KVM_SEV_SNP_PAGE_TYPE_SECRETS  0x5
+#define KVM_SEV_SNP_PAGE_TYPE_CPUID0x6
+
+struct kvm_sev_snp_launch_update {
+   __u64 gfn_start;
+   __u64 uaddr;
+   __u64 len;
+   __u8 type;
+   __u8 pad0;
+   __u16 flags;
+   __u32 pad1;
+   __u64 pad2[4];
+};
+
+#define KVM_SEV_SNP_ID_BLOCK_SIZE  96
+#define KVM_SEV_SNP_ID_AUTH_SIZE   4096
+#define KVM_SEV_SNP_FINISH_DATA_SIZE   32
+
+struct kvm_sev_snp_launch_finish {
+   __u64 id_block_uaddr;
+   __u64 id_auth_uaddr;
+   __u8 id_block_en;
+   __u8 auth_key_en;
+   __u8 vcek_disabled;
+   __u8 host_data[KVM_SEV_SNP_FINISH_DATA_SIZE];
+   __u8 pad0[3];
+   __u16 flags;
+   __u64 pad1[4];
+};
+
 #define KVM_X2APIC_API_USE_32BIT_IDS(1ULL << 0)
 #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
 
@@ -870,5 +919,6 @@ struct kvm_hyperv_eventfd {
 #define KVM_X86_SW_PROTECTED_VM1
 #define KVM_X86_SEV_VM 2
 #define KVM_X86_SEV_ES_VM  3
+#define KVM_X86_SNP_VM 4
 
 #endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h
index bea69739061..b95dd84eef2 100644
--- a/linux-headers/linux/vhost.h
+++ b/linux-headers/linux/vhost.h
@@ -179,12 +179,6 @@
 /* Get the config size */
 #define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32)
 
-/* Get the count of all virtqueues */
-#define VHOST_VDPA_GET_VQS_COUNT   _IOR(VHOST_VIRTIO, 0x80, __u32)
-
-/* Get the number of virtqueue groups. */
-#define VHOST_VDPA_GET_GROUP_NUM   _IOR(VHOST_VIRTIO, 0x81, __u32)
-
 /* Get the number of address spaces. */
 #define VHOST_VDPA_GET_AS_NUM  _IOR(VHOST_VIRTIO, 0x7A, unsigned int)
 
@@ -228,10 +222,1

[PULL 23/45] i386/sev: Add sev_kvm_init() override for SEV class

2024-06-03 Thread Paolo Bonzini
From: Pankaj Gupta 

Some aspects of the init routine SEV are specific to SEV and not
applicable for SNP guests, so move the SEV-specific bits into
separate class method and retain only the common functionality.

Co-developed-by: Michael Roth 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-10-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 72 +--
 1 file changed, 51 insertions(+), 21 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 4edfedc1393..5519de1c6b2 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -73,6 +73,7 @@ struct SevCommonStateClass {
 /* public */
 int (*launch_start)(SevCommonState *sev_common);
 void (*launch_finish)(SevCommonState *sev_common);
+int (*kvm_init)(ConfidentialGuestSupport *cgs, Error **errp);
 };
 
 /**
@@ -882,7 +883,7 @@ out:
 return sev_common->kvm_type;
 }
 
-static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 {
 SevCommonState *sev_common = SEV_COMMON(cgs);
 char *devname;
@@ -892,12 +893,6 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 struct sev_user_data_status status = {};
 SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(cgs);
 
-ret = ram_block_discard_disable(true);
-if (ret) {
-error_report("%s: cannot disable RAM discard", __func__);
-return -1;
-}
-
 sev_common->state = SEV_STATE_UNINIT;
 
 host_cpuid(0x801F, 0, NULL, &ebx, NULL, NULL);
@@ -911,7 +906,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 if (host_cbitpos != sev_common->cbitpos) {
 error_setg(errp, "%s: cbitpos check failed, host '%d' requested '%d'",
__func__, host_cbitpos, sev_common->cbitpos);
-goto err;
+return -1;
 }
 
 /*
@@ -924,7 +919,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 error_setg(errp, "%s: reduced_phys_bits check failed,"
" it should be in the range of 1 to 63, requested '%d'",
__func__, sev_common->reduced_phys_bits);
-goto err;
+return -1;
 }
 
 devname = object_property_get_str(OBJECT(sev_common), "sev-device", NULL);
@@ -933,7 +928,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 error_setg(errp, "%s: Failed to open %s '%s'", __func__,
devname, strerror(errno));
 g_free(devname);
-goto err;
+return -1;
 }
 g_free(devname);
 
@@ -943,7 +938,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 error_setg(errp, "%s: failed to get platform status ret=%d "
"fw_error='%d: %s'", __func__, ret, fw_error,
fw_error_to_str(fw_error));
-goto err;
+return -1;
 }
 sev_common->build_id = status.build;
 sev_common->api_major = status.api_major;
@@ -953,7 +948,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 if (!kvm_kernel_irqchip_allowed()) {
 error_setg(errp, "%s: SEV-ES guests require in-kernel irqchip"
"support", __func__);
-goto err;
+return -1;
 }
 }
 
@@ -962,7 +957,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 error_setg(errp, "%s: guest policy requires SEV-ES, but "
  "host SEV-ES support unavailable",
  __func__);
-goto err;
+return -1;
 }
 }
 
@@ -980,25 +975,59 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 if (ret) {
 error_setg(errp, "%s: failed to initialize ret=%d fw_error=%d '%s'",
__func__, ret, fw_error, fw_error_to_str(fw_error));
-goto err;
+return -1;
 }
 
 ret = klass->launch_start(sev_common);
 if (ret) {
 error_setg(errp, "%s: failed to create encryption context", __func__);
-goto err;
+return -1;
+}
+
+if (klass->kvm_init && klass->kvm_init(cgs, errp)) {
+return -1;
 }
 
-ram_block_notifier_add(&sev_ram_notifier);
-qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
 qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
 
 cgs->ready = true;
 
 return 0;
-err:
-ram_block_discard_disable(false);
-return -1;
+}
+
+static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+ int ret;
+
+/*
+ * SEV/SEV-ES rely on pinned memory to back guest RAM so discarding
+ * isn't actually possible. With SNP, only guest_memfd pages are used
+ * for private guest memory, so discarding of shared memory is still
+ * possible..
+ */

[PULL 13/45] update-linux-headers: move pvpanic.h to correct directory

2024-06-03 Thread Paolo Bonzini
Linux has , not .  Use the same
directory for QEMU's include/standard-headers/ copy.

Reviewed-by: Thomas Huth 
Signed-off-by: Paolo Bonzini 
---
 include/standard-headers/{linux => misc}/pvpanic.h | 0
 hw/misc/pvpanic-isa.c  | 2 +-
 hw/misc/pvpanic-pci.c  | 2 +-
 hw/misc/pvpanic.c  | 2 +-
 scripts/update-linux-headers.sh| 6 --
 5 files changed, 7 insertions(+), 5 deletions(-)
 rename include/standard-headers/{linux => misc}/pvpanic.h (100%)

diff --git a/include/standard-headers/linux/pvpanic.h 
b/include/standard-headers/misc/pvpanic.h
similarity index 100%
rename from include/standard-headers/linux/pvpanic.h
rename to include/standard-headers/misc/pvpanic.h
diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c
index ccec50f61bb..b4f84c41109 100644
--- a/hw/misc/pvpanic-isa.c
+++ b/hw/misc/pvpanic-isa.c
@@ -21,7 +21,7 @@
 #include "hw/misc/pvpanic.h"
 #include "qom/object.h"
 #include "hw/isa/isa.h"
-#include "standard-headers/linux/pvpanic.h"
+#include "standard-headers/misc/pvpanic.h"
 #include "hw/acpi/acpi_aml_interface.h"
 
 OBJECT_DECLARE_SIMPLE_TYPE(PVPanicISAState, PVPANIC_ISA_DEVICE)
diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c
index 83be95d0d24..4d44a881dad 100644
--- a/hw/misc/pvpanic-pci.c
+++ b/hw/misc/pvpanic-pci.c
@@ -21,7 +21,7 @@
 #include "hw/misc/pvpanic.h"
 #include "qom/object.h"
 #include "hw/pci/pci_device.h"
-#include "standard-headers/linux/pvpanic.h"
+#include "standard-headers/misc/pvpanic.h"
 
 OBJECT_DECLARE_SIMPLE_TYPE(PVPanicPCIState, PVPANIC_PCI_DEVICE)
 
diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c
index 1540e9091a4..80289ecf5fe 100644
--- a/hw/misc/pvpanic.c
+++ b/hw/misc/pvpanic.c
@@ -21,7 +21,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/misc/pvpanic.h"
 #include "qom/object.h"
-#include "standard-headers/linux/pvpanic.h"
+#include "standard-headers/misc/pvpanic.h"
 
 static void handle_event(int event)
 {
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index 57a48837aa4..7e93acb3b5f 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -231,10 +231,12 @@ for i in "$hdrdir"/include/linux/*virtio*.h \
  "$hdrdir/include/linux/const.h" \
  "$hdrdir/include/linux/kernel.h" \
  "$hdrdir/include/linux/vhost_types.h" \
- "$hdrdir/include/linux/sysinfo.h" \
- "$hdrdir/include/misc/pvpanic.h"; do
+ "$hdrdir/include/linux/sysinfo.h"; do
 cp_portable "$i" "$output/include/standard-headers/linux"
 done
+mkdir -p "$output/include/standard-headers/misc"
+cp_portable "$hdrdir/include/misc/pvpanic.h" \
+"$output/include/standard-headers/misc"
 mkdir -p "$output/include/standard-headers/drm"
 cp_portable "$hdrdir/include/drm/drm_fourcc.h" \
 "$output/include/standard-headers/drm"
-- 
2.45.1




[PULL 24/45] i386/sev: Add snp_kvm_init() override for SNP class

2024-06-03 Thread Paolo Bonzini
From: Pankaj Gupta 

SNP does not support SMM and requires guest_memfd for
private guest memory, so add SNP specific kvm_init()
functionality in snp_kvm_init() class method.

Signed-off-by: Michael Roth 
Co-developed-by: Pankaj Gupta 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-11-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 24 +++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 5519de1c6b2..6525b3c1a0e 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -885,12 +885,12 @@ out:
 
 static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 {
-SevCommonState *sev_common = SEV_COMMON(cgs);
 char *devname;
 int ret, fw_error, cmd;
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
+SevCommonState *sev_common = SEV_COMMON(cgs);
 SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(cgs);
 
 sev_common->state = SEV_STATE_UNINIT;
@@ -1030,6 +1030,21 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 return 0;
 }
 
+static int sev_snp_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+MachineState *ms = MACHINE(qdev_get_machine());
+X86MachineState *x86ms = X86_MACHINE(ms);
+
+if (x86ms->smm == ON_OFF_AUTO_AUTO) {
+x86ms->smm = ON_OFF_AUTO_OFF;
+} else if (x86ms->smm == ON_OFF_AUTO_ON) {
+error_setg(errp, "SEV-SNP does not support SMM.");
+return -1;
+}
+
+return 0;
+}
+
 int
 sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
 {
@@ -1752,6 +1767,10 @@ sev_snp_guest_set_host_data(Object *obj, const char 
*value, Error **errp)
 static void
 sev_snp_guest_class_init(ObjectClass *oc, void *data)
 {
+SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
+
+klass->kvm_init = sev_snp_kvm_init;
+
 object_class_property_add(oc, "policy", "uint64",
   sev_snp_guest_get_policy,
   sev_snp_guest_set_policy, NULL, NULL);
@@ -1778,8 +1797,11 @@ sev_snp_guest_class_init(ObjectClass *oc, void *data)
 static void
 sev_snp_guest_instance_init(Object *obj)
 {
+ConfidentialGuestSupport *cgs = CONFIDENTIAL_GUEST_SUPPORT(obj);
 SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
 
+cgs->require_guest_memfd = true;
+
 /* default init/start/finish params for kvm */
 sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
 }
-- 
2.45.1




[PULL 27/45] i386/sev: Add a class method to determine KVM VM type for SNP guests

2024-06-03 Thread Paolo Bonzini
SEV guests can use either KVM_X86_DEFAULT_VM, KVM_X86_SEV_VM,
or KVM_X86_SEV_ES_VM depending on the configuration and what
the host kernel supports. SNP guests on the other hand can only
ever use KVM_X86_SNP_VM, so split determination of VM type out
into a separate class method that can be set accordingly for
sev-guest vs. sev-snp-guest objects and add handling for SNP.

Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-14-pankaj.gu...@amd.com>
[Remove unnecessary function pointer declaration. - Paolo]
Signed-off-by: Paolo Bonzini 
---
 target/i386/kvm/kvm.c |  1 +
 target/i386/sev.c | 15 ---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 6c864e4611f..23a003aaa7e 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -167,6 +167,7 @@ static const char *vm_type_name[] = {
 [KVM_X86_DEFAULT_VM] = "default",
 [KVM_X86_SEV_VM] = "SEV",
 [KVM_X86_SEV_ES_VM] = "SEV-ES",
+[KVM_X86_SNP_VM] = "SEV-SNP",
 };
 
 bool kvm_is_vm_type_supported(int type)
diff --git a/target/i386/sev.c b/target/i386/sev.c
index c3daaf1ad50..072cc4f8530 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -885,6 +885,11 @@ out:
 return sev_common->kvm_type;
 }
 
+static int sev_snp_kvm_type(X86ConfidentialGuest *cg)
+{
+return KVM_X86_SNP_VM;
+}
+
 static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 {
 char *devname;
@@ -894,6 +899,8 @@ static int sev_common_kvm_init(ConfidentialGuestSupport 
*cgs, Error **errp)
 struct sev_user_data_status status = {};
 SevCommonState *sev_common = SEV_COMMON(cgs);
 SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(cgs);
+X86ConfidentialGuestClass *x86_klass =
+   X86_CONFIDENTIAL_GUEST_GET_CLASS(cgs);
 
 sev_common->state = SEV_STATE_UNINIT;
 
@@ -964,7 +971,7 @@ static int sev_common_kvm_init(ConfidentialGuestSupport 
*cgs, Error **errp)
 }
 
 trace_kvm_sev_init();
-if (sev_kvm_type(X86_CONFIDENTIAL_GUEST(sev_common)) == 
KVM_X86_DEFAULT_VM) {
+if (x86_klass->kvm_type(X86_CONFIDENTIAL_GUEST(sev_common)) == 
KVM_X86_DEFAULT_VM) {
 cmd = sev_es_enabled() ? KVM_SEV_ES_INIT : KVM_SEV_INIT;
 
 ret = sev_ioctl(sev_common->sev_fd, cmd, NULL, &fw_error);
@@ -1441,10 +1448,8 @@ static void
 sev_common_class_init(ObjectClass *oc, void *data)
 {
 ConfidentialGuestSupportClass *klass = 
CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
-X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
 
 klass->kvm_init = sev_common_kvm_init;
-x86_klass->kvm_type = sev_kvm_type;
 
 object_class_property_add_str(oc, "sev-device",
   sev_common_get_sev_device,
@@ -1529,10 +1534,12 @@ static void
 sev_guest_class_init(ObjectClass *oc, void *data)
 {
 SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
+X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
 
 klass->launch_start = sev_launch_start;
 klass->launch_finish = sev_launch_finish;
 klass->kvm_init = sev_kvm_init;
+x86_klass->kvm_type = sev_kvm_type;
 
 object_class_property_add_str(oc, "dh-cert-file",
   sev_guest_get_dh_cert_file,
@@ -1770,8 +1777,10 @@ static void
 sev_snp_guest_class_init(ObjectClass *oc, void *data)
 {
 SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
+X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
 
 klass->kvm_init = sev_snp_kvm_init;
+x86_klass->kvm_type = sev_snp_kvm_type;
 
 object_class_property_add(oc, "policy", "uint64",
   sev_snp_guest_get_policy,
-- 
2.45.1




[PULL 39/45] i386/sev: Enable KVM_HC_MAP_GPA_RANGE hcall for SNP guests

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

KVM will forward GHCB page-state change requests to userspace in the
form of KVM_HC_MAP_GPA_RANGE, so make sure the hypercall handling is
enabled for SNP guests.

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-32-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index eaf5fc6c6b5..abb63062ac6 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -14,6 +14,7 @@
 #include "qemu/osdep.h"
 
 #include 
+#include 
 #include 
 
 #include 
@@ -758,6 +759,10 @@ sev_snp_launch_start(SevCommonState *sev_common)
 trace_kvm_sev_snp_launch_start(start->policy,
sev_snp_guest->guest_visible_workarounds);
 
+if (!kvm_enable_hypercall(BIT_ULL(KVM_HC_MAP_GPA_RANGE))) {
+return 1;
+}
+
 rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START,
start, &fw_error);
 if (rc < 0) {
-- 
2.45.1




[PULL 28/45] i386/sev: Update query-sev QAPI format to handle SEV-SNP

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

Most of the current 'query-sev' command is relevant to both legacy
SEV/SEV-ES guests and SEV-SNP guests, with 2 exceptions:

  - 'policy' is a 64-bit field for SEV-SNP, not 32-bit, and
the meaning of the bit positions has changed
  - 'handle' is not relevant to SEV-SNP

To address this, this patch adds a new 'sev-type' field that can be
used as a discriminator to select between SEV and SEV-SNP-specific
fields/formats without breaking compatibility for existing management
tools (so long as management tools that add support for launching
SEV-SNP guest update their handling of query-sev appropriately).

The corresponding HMP command has also been fixed up similarly.

Signed-off-by: Michael Roth 
Co-developed-by:Pankaj Gupta 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-15-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 qapi/misc-target.json | 72 ++-
 target/i386/sev.h |  3 ++
 target/i386/sev.c | 57 +-
 3 files changed, 97 insertions(+), 35 deletions(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 4e0a6492a9a..2d7d4d89bd5 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -47,6 +47,50 @@
'send-update', 'receive-update' ],
   'if': 'TARGET_I386' }
 
+##
+# @SevGuestType:
+#
+# An enumeration indicating the type of SEV guest being run.
+#
+# @sev: The guest is a legacy SEV or SEV-ES guest.
+#
+# @sev-snp: The guest is an SEV-SNP guest.
+#
+# Since: 6.2
+##
+{ 'enum': 'SevGuestType',
+  'data': [ 'sev', 'sev-snp' ],
+  'if': 'TARGET_I386' }
+
+##
+# @SevGuestInfo:
+#
+# Information specific to legacy SEV/SEV-ES guests.
+#
+# @policy: SEV policy value
+#
+# @handle: SEV firmware handle
+#
+# Since: 2.12
+##
+{ 'struct': 'SevGuestInfo',
+  'data': { 'policy': 'uint32',
+'handle': 'uint32' },
+  'if': 'TARGET_I386' }
+
+##
+# @SevSnpGuestInfo:
+#
+# Information specific to SEV-SNP guests.
+#
+# @snp-policy: SEV-SNP policy value
+#
+# Since: 9.1
+##
+{ 'struct': 'SevSnpGuestInfo',
+  'data': { 'snp-policy': 'uint64' },
+  'if': 'TARGET_I386' }
+
 ##
 # @SevInfo:
 #
@@ -60,25 +104,25 @@
 #
 # @build-id: SEV FW build id
 #
-# @policy: SEV policy value
-#
 # @state: SEV guest state
 #
-# @handle: SEV firmware handle
+# @sev-type: Type of SEV guest being run
 #
 # Since: 2.12
 ##
-{ 'struct': 'SevInfo',
-'data': { 'enabled': 'bool',
-  'api-major': 'uint8',
-  'api-minor' : 'uint8',
-  'build-id' : 'uint8',
-  'policy' : 'uint32',
-  'state' : 'SevState',
-  'handle' : 'uint32'
-},
-  'if': 'TARGET_I386'
-}
+{ 'union': 'SevInfo',
+  'base': { 'enabled': 'bool',
+'api-major': 'uint8',
+'api-minor' : 'uint8',
+'build-id' : 'uint8',
+'state' : 'SevState',
+'sev-type' : 'SevGuestType' },
+  'discriminator': 'sev-type',
+  'data': {
+  'sev': 'SevGuestInfo',
+  'sev-snp': 'SevSnpGuestInfo' },
+  'if': 'TARGET_I386' }
+
 
 ##
 # @query-sev:
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 94295ee74f7..5dc4767b1e9 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -31,6 +31,9 @@
 #define SEV_POLICY_DOMAIN   0x10
 #define SEV_POLICY_SEV  0x20
 
+#define SEV_SNP_POLICY_SMT  0x1
+#define SEV_SNP_POLICY_DBG  0x8
+
 typedef struct SevKernelLoaderContext {
 char *setup_data;
 size_t setup_size;
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 072cc4f8530..43d1c48bd9e 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -363,25 +363,27 @@ static SevInfo *sev_get_info(void)
 {
 SevInfo *info;
 SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
-SevGuestState *sev_guest =
-(SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
- TYPE_SEV_GUEST);
 
 info = g_new0(SevInfo, 1);
 info->enabled = sev_enabled();
 
 if (info->enabled) {
-if (sev_guest) {
-info->handle = sev_guest->handle;
-}
 info->api_major = sev_common->api_major;
 info->api_minor = sev_common->api_minor;
 info->build_id = sev_common->build_id;
 info->state = sev_common->state;
-/* we only report the lower 32-bits of policy for SNP, ok for now... */
-info->policy =
-(uint32_t)object_property_get_uint(OBJECT(sev_common),
-   "policy", NULL);
+
+if (sev_snp_enabled()) {
+info->sev_type = SEV_GUEST_TYPE_SEV_SNP;
+info->u.sev_snp.snp_policy =
+object_property_get_uint(OBJECT(sev_common), "policy", NULL);
+} else {
+info->sev_type = SEV_GUEST_TYPE_SEV;
+info->u.sev.handle = SEV_GUEST(sev_common)->handle;
+info->u.sev.policy =
+(uint32_t)

[PULL 25/45] i386/cpu: Set SEV-SNP CPUID bit when SNP enabled

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

SNP guests will rely on this bit to determine certain feature support.

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-12-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/cpu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index bc2dceb647f..914bef442c7 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6979,6 +6979,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 if (sev_enabled()) {
 *eax = 0x2;
 *eax |= sev_es_enabled() ? 0x8 : 0;
+*eax |= sev_snp_enabled() ? 0x10 : 0;
 *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
 *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */
 }
-- 
2.45.1




[PULL 17/45] i386/sev: Replace error_report with error_setg

2024-06-03 Thread Paolo Bonzini
From: Pankaj Gupta 

Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-2-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index d30b68c11e4..67ed32e5ea9 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -952,13 +952,13 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 
 if (sev_es_enabled()) {
 if (!kvm_kernel_irqchip_allowed()) {
-error_report("%s: SEV-ES guests require in-kernel irqchip support",
- __func__);
+error_setg(errp, "%s: SEV-ES guests require in-kernel irqchip"
+   "support", __func__);
 goto err;
 }
 
 if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
-error_report("%s: guest policy requires SEV-ES, but "
+error_setg(errp, "%s: guest policy requires SEV-ES, but "
  "host SEV-ES support unavailable",
  __func__);
 goto err;
-- 
2.45.1




[PULL 03/45] meson: assume x86-64-v2 baseline ISA

2024-06-03 Thread Paolo Bonzini
x86-64-v2 processors were released in 2008, assume that we have one.
Unfortunately there is no GCC flag to enable all the features
without disabling what came after; so enable them one by one.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 meson.build | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/meson.build b/meson.build
index 63866071445..d80203f1cde 100644
--- a/meson.build
+++ b/meson.build
@@ -336,9 +336,13 @@ if host_arch == 'i386' and not cc.links('''
   qemu_common_flags = ['-march=i486'] + qemu_common_flags
 endif
 
-# ??? Only extremely old AMD cpus do not have cmpxchg16b.
-# If we truly care, we should simply detect this case at
-# runtime and generate the fallback to serial emulation.
+# Assume x86-64-v2 (minus CMPXCHG16B for 32-bit code)
+if host_arch == 'i386'
+  qemu_common_flags = ['-mfpmath=sse'] + qemu_common_flags
+endif
+if host_arch in ['i386', 'x86_64']
+  qemu_common_flags = ['-mpopcnt', '-msse4.2'] + qemu_common_flags
+endif
 if host_arch == 'x86_64'
   qemu_common_flags = ['-mcx16'] + qemu_common_flags
 endif
-- 
2.45.1




[PULL 32/45] hw/i386/sev: Add function to get SEV metadata from OVMF header

2024-06-03 Thread Paolo Bonzini
From: Brijesh Singh 

A recent version of OVMF expanded the reset vector GUID list to add
SEV-specific metadata GUID. The SEV metadata describes the reserved
memory regions such as the secrets and CPUID page used during the SEV-SNP
guest launch.

The pc_system_get_ovmf_sev_metadata_ptr() is used to retieve the SEV
metadata pointer from the OVMF GUID list.

Signed-off-by: Brijesh Singh 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-19-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 include/hw/i386/pc.h  | 26 ++
 target/i386/sev.h |  2 ++
 hw/i386/pc_sysfw.c|  4 
 target/i386/sev-sysemu-stub.c |  4 
 target/i386/sev.c | 32 
 5 files changed, 68 insertions(+)

diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index ad9c3d9ba84..c653b8eeb24 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -164,6 +164,32 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int 
level);
 #define PCI_HOST_ABOVE_4G_MEM_SIZE "above-4g-mem-size"
 #define PCI_HOST_PROP_SMM_RANGES   "smm-ranges"
 
+typedef enum {
+SEV_DESC_TYPE_UNDEF,
+/* The section contains the region that must be validated by the VMM. */
+SEV_DESC_TYPE_SNP_SEC_MEM,
+/* The section contains the SNP secrets page */
+SEV_DESC_TYPE_SNP_SECRETS,
+/* The section contains address that can be used as a CPUID page */
+SEV_DESC_TYPE_CPUID,
+
+} ovmf_sev_metadata_desc_type;
+
+typedef struct __attribute__((__packed__)) OvmfSevMetadataDesc {
+uint32_t base;
+uint32_t len;
+ovmf_sev_metadata_desc_type type;
+} OvmfSevMetadataDesc;
+
+typedef struct __attribute__((__packed__)) OvmfSevMetadata {
+uint8_t signature[4];
+uint32_t len;
+uint32_t version;
+uint32_t num_desc;
+OvmfSevMetadataDesc descs[];
+} OvmfSevMetadata;
+
+OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void);
 
 void pc_pci_as_mapping_init(MemoryRegion *system_memory,
 MemoryRegion *pci_address_space);
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 5dc4767b1e9..cc12824dd65 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -66,4 +66,6 @@ int sev_inject_launch_secret(const char *hdr, const char 
*secret,
 int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size);
 void sev_es_set_reset_vector(CPUState *cpu);
 
+void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size);
+
 #endif
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index ac88ad4eb91..9b8671c4412 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -260,6 +260,10 @@ void x86_firmware_configure(void *ptr, int size)
 pc_system_parse_ovmf_flash(ptr, size);
 
 if (sev_enabled()) {
+
+/* Copy the SEV metadata table (if it exists) */
+pc_system_parse_sev_metadata(ptr, size);
+
 ret = sev_es_save_reset_vector(ptr, size);
 if (ret) {
 error_report("failed to locate and/or save reset vector");
diff --git a/target/i386/sev-sysemu-stub.c b/target/i386/sev-sysemu-stub.c
index 96e1c15cc3f..fc1c57c4113 100644
--- a/target/i386/sev-sysemu-stub.c
+++ b/target/i386/sev-sysemu-stub.c
@@ -67,3 +67,7 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict)
 {
 monitor_printf(mon, "SEV is not available in this QEMU\n");
 }
+
+void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size)
+{
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index e84e4395a53..17281bb2c74 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -597,6 +597,38 @@ SevCapability *qmp_query_sev_capabilities(Error **errp)
 return sev_get_capabilities(errp);
 }
 
+static OvmfSevMetadata *ovmf_sev_metadata_table;
+
+#define OVMF_SEV_META_DATA_GUID "dc886566-984a-4798-A75e-5585a7bf67cc"
+typedef struct __attribute__((__packed__)) OvmfSevMetadataOffset {
+uint32_t offset;
+} OvmfSevMetadataOffset;
+
+OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void)
+{
+return ovmf_sev_metadata_table;
+}
+
+void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size)
+{
+OvmfSevMetadata *metadata;
+OvmfSevMetadataOffset  *data;
+
+if (!pc_system_ovmf_table_find(OVMF_SEV_META_DATA_GUID, (uint8_t **)&data,
+   NULL)) {
+return;
+}
+
+metadata = (OvmfSevMetadata *)(flash_ptr + flash_size - data->offset);
+if (memcmp(metadata->signature, "ASEV", 4) != 0 ||
+metadata->len < sizeof(OvmfSevMetadata) ||
+metadata->len > flash_size - data->offset) {
+return;
+}
+
+ovmf_sev_metadata_table = g_memdup2(metadata, metadata->len);
+}
+
 static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
 Error **errp)
 {
-- 
2.45.1




[PULL 40/45] i386/sev: Extract build_kernel_loader_hashes

2024-06-03 Thread Paolo Bonzini
From: Dov Murik 

Extract the building of the kernel hashes table out from
sev_add_kernel_loader_hashes() to allow building it in
other memory areas (for SNP support).

No functional change intended.

Signed-off-by: Dov Murik 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-22-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 102 ++
 1 file changed, 58 insertions(+), 44 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index abb63062ac6..73f94067155 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1754,45 +1754,16 @@ static const QemuUUID sev_cmdline_entry_guid = {
 0x4d, 0x36, 0xab, 0x2a)
 };
 
-/*
- * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
- * which is included in SEV's initial memory measurement.
- */
-bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
+static bool build_kernel_loader_hashes(PaddedSevHashTable *padded_ht,
+   SevKernelLoaderContext *ctx,
+   Error **errp)
 {
-uint8_t *data;
-SevHashTableDescriptor *area;
 SevHashTable *ht;
-PaddedSevHashTable *padded_ht;
 uint8_t cmdline_hash[HASH_SIZE];
 uint8_t initrd_hash[HASH_SIZE];
 uint8_t kernel_hash[HASH_SIZE];
 uint8_t *hashp;
 size_t hash_len = HASH_SIZE;
-hwaddr mapped_len = sizeof(*padded_ht);
-MemTxAttrs attrs = { 0 };
-bool ret = true;
-SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
-
-/*
- * Only add the kernel hashes if the sev-guest configuration explicitly
- * stated kernel-hashes=on.
- */
-if (!sev_common->kernel_hashes) {
-return false;
-}
-
-if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
-error_setg(errp, "SEV: kernel specified but guest firmware "
- "has no hashes table GUID");
-return false;
-}
-area = (SevHashTableDescriptor *)data;
-if (!area->base || area->size < sizeof(PaddedSevHashTable)) {
-error_setg(errp, "SEV: guest firmware hashes table area is invalid "
- "(base=0x%x size=0x%x)", area->base, area->size);
-return false;
-}
 
 /*
  * Calculate hash of kernel command-line with the terminating null byte. If
@@ -1829,16 +1800,6 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext 
*ctx, Error **errp)
 }
 assert(hash_len == HASH_SIZE);
 
-/*
- * Populate the hashes table in the guest's memory at the OVMF-designated
- * area for the SEV hashes table
- */
-padded_ht = address_space_map(&address_space_memory, area->base,
-  &mapped_len, true, attrs);
-if (!padded_ht || mapped_len != sizeof(*padded_ht)) {
-error_setg(errp, "SEV: cannot map hashes table guest memory area");
-return false;
-}
 ht = &padded_ht->ht;
 
 ht->guid = sev_hash_table_header_guid;
@@ -1859,8 +1820,61 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext 
*ctx, Error **errp)
 /* zero the excess data so the measurement can be reliably calculated */
 memset(padded_ht->padding, 0, sizeof(padded_ht->padding));
 
-if (sev_encrypt_flash(area->base, (uint8_t *)padded_ht,
-  sizeof(*padded_ht), errp) < 0) {
+return true;
+}
+
+/*
+ * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
+ * which is included in SEV's initial memory measurement.
+ */
+bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
+{
+uint8_t *data;
+SevHashTableDescriptor *area;
+PaddedSevHashTable *padded_ht;
+hwaddr mapped_len = sizeof(*padded_ht);
+MemTxAttrs attrs = { 0 };
+bool ret = true;
+SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+
+/*
+ * Only add the kernel hashes if the sev-guest configuration explicitly
+ * stated kernel-hashes=on.
+ */
+if (!sev_common->kernel_hashes) {
+return false;
+}
+
+if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
+error_setg(errp, "SEV: kernel specified but guest firmware "
+ "has no hashes table GUID");
+return false;
+}
+
+area = (SevHashTableDescriptor *)data;
+if (!area->base || area->size < sizeof(PaddedSevHashTable)) {
+error_setg(errp, "SEV: guest firmware hashes table area is invalid "
+ "(base=0x%x size=0x%x)", area->base, area->size);
+return false;
+}
+
+/*
+ * Populate the hashes table in the guest's memory at the OVMF-designated
+ * area for the SEV hashes table
+ */
+padded_ht = address_space_map(&address_space_memory, area->base,
+  &mapped_len, true, attrs);

[PULL 33/45] i386/sev: Add support for populating OVMF metadata pages

2024-06-03 Thread Paolo Bonzini
From: Brijesh Singh 

OVMF reserves various pages so they can be pre-initialized/validated
prior to launching the guest. Add support for populating these pages
with the expected content.

Signed-off-by: Brijesh Singh 
Signed-off-by: Michael Roth 
Co-developed-by: Pankaj Gupta 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-20-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 74 +++
 1 file changed, 74 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 17281bb2c74..c57534fca2b 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1003,15 +1003,89 @@ sev_launch_finish(SevCommonState *sev_common)
 migrate_add_blocker(&sev_mig_blocker, &error_fatal);
 }
 
+static int
+snp_launch_update_data(uint64_t gpa, void *hva, uint32_t len, int type)
+{
+SevLaunchUpdateData *data;
+
+data = g_new0(SevLaunchUpdateData, 1);
+data->gpa = gpa;
+data->hva = hva;
+data->len = len;
+data->type = type;
+
+QTAILQ_INSERT_TAIL(&launch_update, data, next);
+
+return 0;
+}
+
+static int
+snp_metadata_desc_to_page_type(int desc_type)
+{
+switch (desc_type) {
+/* Add the umeasured prevalidated pages as a zero page */
+case SEV_DESC_TYPE_SNP_SEC_MEM: return KVM_SEV_SNP_PAGE_TYPE_ZERO;
+case SEV_DESC_TYPE_SNP_SECRETS: return KVM_SEV_SNP_PAGE_TYPE_SECRETS;
+case SEV_DESC_TYPE_CPUID: return KVM_SEV_SNP_PAGE_TYPE_CPUID;
+default:
+ return KVM_SEV_SNP_PAGE_TYPE_ZERO;
+}
+}
+
+static void
+snp_populate_metadata_pages(SevSnpGuestState *sev_snp,
+OvmfSevMetadata *metadata)
+{
+OvmfSevMetadataDesc *desc;
+int type, ret, i;
+void *hva;
+MemoryRegion *mr = NULL;
+
+for (i = 0; i < metadata->num_desc; i++) {
+desc = &metadata->descs[i];
+
+type = snp_metadata_desc_to_page_type(desc->type);
+
+hva = gpa2hva(&mr, desc->base, desc->len, NULL);
+if (!hva) {
+error_report("%s: Failed to get HVA for GPA 0x%x sz 0x%x",
+ __func__, desc->base, desc->len);
+exit(1);
+}
+
+ret = snp_launch_update_data(desc->base, hva, desc->len, type);
+if (ret) {
+error_report("%s: Failed to add metadata page gpa 0x%x+%x type %d",
+ __func__, desc->base, desc->len, desc->type);
+exit(1);
+}
+}
+}
+
 static void
 sev_snp_launch_finish(SevCommonState *sev_common)
 {
 int ret, error;
 Error *local_err = NULL;
+OvmfSevMetadata *metadata;
 SevLaunchUpdateData *data;
 SevSnpGuestState *sev_snp = SEV_SNP_GUEST(sev_common);
 struct kvm_sev_snp_launch_finish *finish = &sev_snp->kvm_finish_conf;
 
+/*
+ * To boot the SNP guest, the hypervisor is required to populate the CPUID
+ * and Secrets page before finalizing the launch flow. The location of
+ * the secrets and CPUID page is available through the OVMF metadata GUID.
+ */
+metadata = pc_system_get_ovmf_sev_metadata_ptr();
+if (metadata == NULL) {
+error_report("%s: Failed to locate SEV metadata header", __func__);
+exit(1);
+}
+
+/* Populate all the metadata pages */
+snp_populate_metadata_pages(sev_snp, metadata);
+
 QTAILQ_FOREACH(data, &launch_update, next) {
 ret = sev_snp_launch_update(sev_snp, data);
 if (ret) {
-- 
2.45.1




[PULL 35/45] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled

2024-06-03 Thread Paolo Bonzini
From: Brijesh Singh 

As with SEV, an SNP guest requires that the BIOS be part of the initial
encrypted/measured guest payload. Extend sev_encrypt_flash() to handle
the SNP case and plumb through the GPA of the BIOS location since this
is needed for SNP.

Signed-off-by: Brijesh Singh 
Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-25-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 include/hw/i386/x86.h |  2 +-
 target/i386/sev.h |  2 +-
 hw/i386/pc_sysfw.c| 12 +++-
 hw/i386/x86-common.c  |  2 +-
 target/i386/sev-sysemu-stub.c |  2 +-
 target/i386/sev.c |  5 +++--
 6 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index b006f16b8d3..d43cb3908e6 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -154,6 +154,6 @@ void ioapic_init_gsi(GSIState *gsi_state, Object *parent);
 DeviceState *ioapic_init_secondary(GSIState *gsi_state);
 
 /* pc_sysfw.c */
-void x86_firmware_configure(void *ptr, int size);
+void x86_firmware_configure(hwaddr gpa, void *ptr, int size);
 
 #endif
diff --git a/target/i386/sev.h b/target/i386/sev.h
index cc12824dd65..858005a119c 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -59,7 +59,7 @@ uint32_t sev_get_cbit_position(void);
 uint32_t sev_get_reduced_phys_bits(void);
 bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp);
 
-int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp);
+int sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp);
 int sev_inject_launch_secret(const char *hdr, const char *secret,
  uint64_t gpa, Error **errp);
 
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 9b8671c4412..7cdbafc8d22 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -148,6 +148,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
 assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
 for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
+hwaddr gpa;
+
 system_flash = pcms->flash[i];
 blk = pflash_cfi01_get_blk(system_flash);
 if (!blk) {
@@ -177,11 +179,11 @@ static void pc_system_flash_map(PCMachineState *pcms,
 }
 
 total_size += size;
+gpa = 0x1ULL - total_size; /* where the flash is mapped */
 qdev_prop_set_uint32(DEVICE(system_flash), "num-blocks",
  size / FLASH_SECTOR_SIZE);
 sysbus_realize_and_unref(SYS_BUS_DEVICE(system_flash), &error_fatal);
-sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0,
-0x1ULL - total_size);
+sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0, gpa);
 
 if (i == 0) {
 flash_mem = pflash_cfi01_get_memory(system_flash);
@@ -196,7 +198,7 @@ static void pc_system_flash_map(PCMachineState *pcms,
 if (sev_enabled()) {
 flash_ptr = memory_region_get_ram_ptr(flash_mem);
 flash_size = memory_region_size(flash_mem);
-x86_firmware_configure(flash_ptr, flash_size);
+x86_firmware_configure(gpa, flash_ptr, flash_size);
 }
 }
 }
@@ -249,7 +251,7 @@ void pc_system_firmware_init(PCMachineState *pcms,
 pc_system_flash_cleanup_unused(pcms);
 }
 
-void x86_firmware_configure(void *ptr, int size)
+void x86_firmware_configure(hwaddr gpa, void *ptr, int size)
 {
 int ret;
 
@@ -270,6 +272,6 @@ void x86_firmware_configure(void *ptr, int size)
 exit(1);
 }
 
-sev_encrypt_flash(ptr, size, &error_fatal);
+sev_encrypt_flash(gpa, ptr, size, &error_fatal);
 }
 }
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index ee9046d9a80..f41cb0a6a8b 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -1013,7 +1013,7 @@ void x86_bios_rom_init(X86MachineState *x86ms, const char 
*default_firmware,
  */
 void *ptr = memory_region_get_ram_ptr(&x86ms->bios);
 load_image_size(filename, ptr, bios_size);
-x86_firmware_configure(ptr, bios_size);
+x86_firmware_configure(0x1ULL - bios_size, ptr, bios_size);
 } else {
 memory_region_set_readonly(&x86ms->bios, !isapc_ram_fw);
 ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
diff --git a/target/i386/sev-sysemu-stub.c b/target/i386/sev-sysemu-stub.c
index fc1c57c4113..d5bf886e799 100644
--- a/target/i386/sev-sysemu-stub.c
+++ b/target/i386/sev-sysemu-stub.c
@@ -42,7 +42,7 @@ void qmp_sev_inject_launch_secret(const char *packet_header, 
const char *secret,
 error_setg(errp, "SEV is not available in this QEMU");
 }
 
-int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
+int sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp)
 {
 g_assert_not_reached();
 }
diff --git a/target/i386/sev.c b/target/i386/sev.c
index

[PULL 34/45] i386/sev: Add support for SNP CPUID validation

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

SEV-SNP firmware allows a special guest page to be populated with a
table of guest CPUID values so that they can be validated through
firmware before being loaded into encrypted guest memory where they can
be used in place of hypervisor-provided values[1].

As part of SEV-SNP guest initialization, use this interface to validate
the CPUID entries reported by KVM_GET_CPUID2 prior to initial guest
start and populate the CPUID page reserved by OVMF with the resulting
encrypted data.

[1] SEV SNP Firmware ABI Specification, Rev. 0.8, 8.13.2.6

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-21-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 164 +-
 1 file changed, 162 insertions(+), 2 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index c57534fca2b..06401f0526f 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -200,6 +200,36 @@ static const char *const sev_fw_errlist[] = {
 
 #define SEV_FW_MAX_ERROR  ARRAY_SIZE(sev_fw_errlist)
 
+/*  doesn't expose this, so re-use the max from kvm.c */
+#define KVM_MAX_CPUID_ENTRIES 100
+
+typedef struct KvmCpuidInfo {
+struct kvm_cpuid2 cpuid;
+struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES];
+} KvmCpuidInfo;
+
+#define SNP_CPUID_FUNCTION_MAXCOUNT 64
+#define SNP_CPUID_FUNCTION_UNKNOWN 0x
+
+typedef struct {
+uint32_t eax_in;
+uint32_t ecx_in;
+uint64_t xcr0_in;
+uint64_t xss_in;
+uint32_t eax;
+uint32_t ebx;
+uint32_t ecx;
+uint32_t edx;
+uint64_t reserved;
+} __attribute__((packed)) SnpCpuidFunc;
+
+typedef struct {
+uint32_t count;
+uint32_t reserved1;
+uint64_t reserved2;
+SnpCpuidFunc entries[SNP_CPUID_FUNCTION_MAXCOUNT];
+} __attribute__((packed)) SnpCpuidInfo;
+
 static int
 sev_ioctl(int fd, int cmd, void *data, int *error)
 {
@@ -788,6 +818,35 @@ out:
 return ret;
 }
 
+static void
+sev_snp_cpuid_report_mismatches(SnpCpuidInfo *old,
+SnpCpuidInfo *new)
+{
+size_t i;
+
+if (old->count != new->count) {
+error_report("SEV-SNP: CPUID validation failed due to count mismatch,"
+ "provided: %d, expected: %d", old->count, new->count);
+return;
+}
+
+for (i = 0; i < old->count; i++) {
+SnpCpuidFunc *old_func, *new_func;
+
+old_func = &old->entries[i];
+new_func = &new->entries[i];
+
+if (memcmp(old_func, new_func, sizeof(SnpCpuidFunc))) {
+error_report("SEV-SNP: CPUID validation failed for function 0x%x, 
index: 0x%x"
+ "provided: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 
0x%08x"
+ "expected: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 
0x%08x",
+ old_func->eax_in, old_func->ecx_in,
+ old_func->eax, old_func->ebx, old_func->ecx, 
old_func->edx,
+ new_func->eax, new_func->ebx, new_func->ecx, 
new_func->edx);
+}
+}
+}
+
 static const char *
 snp_page_type_to_str(int type)
 {
@@ -806,6 +865,7 @@ sev_snp_launch_update(SevSnpGuestState *sev_snp_guest,
   SevLaunchUpdateData *data)
 {
 int ret, fw_error;
+SnpCpuidInfo snp_cpuid_info;
 struct kvm_sev_snp_launch_update update = {0};
 
 if (!data->hva || !data->len) {
@@ -815,6 +875,11 @@ sev_snp_launch_update(SevSnpGuestState *sev_snp_guest,
 return 1;
 }
 
+if (data->type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
+/* Save a copy for comparison in case the LAUNCH_UPDATE fails */
+memcpy(&snp_cpuid_info, data->hva, sizeof(snp_cpuid_info));
+}
+
 update.uaddr = (__u64)(unsigned long)data->hva;
 update.gfn_start = data->gpa >> TARGET_PAGE_BITS;
 update.len = data->len;
@@ -842,6 +907,11 @@ sev_snp_launch_update(SevSnpGuestState *sev_snp_guest,
 if (ret && ret != -EAGAIN) {
 error_report("SNP_LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
  ret, fw_error, fw_error_to_str(fw_error));
+
+if (data->type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
+sev_snp_cpuid_report_mismatches(&snp_cpuid_info, data->hva);
+error_report("SEV-SNP: failed update CPUID page");
+}
 break;
 }
 }
@@ -1004,7 +1074,8 @@ sev_launch_finish(SevCommonState *sev_common)
 }
 
 static int
-snp_launch_update_data(uint64_t gpa, void *hva, uint32_t len, int type)
+snp_launch_update_data(uint64_t gpa, void *hva,
+   uint32_t len, int type)
 {
 SevLaunchUpdateData *data;
 
@@ -1019,6 +1090,90 @@ snp_launch_update_data(uint64_t gpa, void *hva, uint32_t 
len, int type)
 return 0;
 }
 
+static int
+sev_snp_cpuid_info_fill(SnpCpuidInfo *snp_cpuid_info,
+const KvmCpuidInfo *kvm_cpuid_info)
+{
+size_t i;
+
+if (kvm_cpuid_info->cpuid.nent > SNP

[PULL 19/45] i386/sev: Move sev_launch_update to separate class method

2024-06-03 Thread Paolo Bonzini
From: Pankaj Gupta 

When sev-snp-guest objects are introduced there will be a number of
differences in how the launch data is handled compared to the existing
sev-guest object. Move sev_launch_start() to a class method to make it
easier to implement SNP-specific launch update functionality later.

Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-6-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.c | 13 ++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 33e606eea00..b2aa0d6f99b 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -69,6 +69,8 @@ struct SevCommonState {
 struct SevCommonStateClass {
 X86ConfidentialGuestClass parent_class;
 
+/* public */
+int (*launch_start)(SevCommonState *sev_common);
 };
 
 /**
@@ -632,16 +634,16 @@ sev_read_file_base64(const char *filename, guchar **data, 
gsize *len)
 }
 
 static int
-sev_launch_start(SevGuestState *sev_guest)
+sev_launch_start(SevCommonState *sev_common)
 {
 gsize sz;
 int ret = 1;
 int fw_error, rc;
+SevGuestState *sev_guest = SEV_GUEST(sev_common);
 struct kvm_sev_launch_start start = {
 .handle = sev_guest->handle, .policy = sev_guest->policy
 };
 guchar *session = NULL, *dh_cert = NULL;
-SevCommonState *sev_common = SEV_COMMON(sev_guest);
 
 if (sev_guest->session_file) {
 if (sev_read_file_base64(sev_guest->session_file, &session, &sz) < 0) {
@@ -862,6 +864,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
+SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(cgs);
 
 ret = ram_block_discard_disable(true);
 if (ret) {
@@ -952,7 +955,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
 goto err;
 }
 
-sev_launch_start(SEV_GUEST(sev_common));
+ret = klass->launch_start(sev_common);
 if (ret) {
 error_setg(errp, "%s: failed to create encryption context", __func__);
 goto err;
@@ -1451,6 +1454,10 @@ static void sev_guest_set_legacy_vm_type(Object *obj, 
bool value, Error **errp)
 static void
 sev_guest_class_init(ObjectClass *oc, void *data)
 {
+SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
+
+klass->launch_start = sev_launch_start;
+
 object_class_property_add_str(oc, "dh-cert-file",
   sev_guest_get_dh_cert_file,
   sev_guest_set_dh_cert_file);
-- 
2.45.1




[PULL 11/45] target/i386: fix xsave.flat from kvm-unit-tests

2024-06-03 Thread Paolo Bonzini
xsave.flat checks that "executing the XSETBV instruction causes a general-
protection fault (#GP) if ECX = 0 and EAX[2:1] has the value 10b".  QEMU allows
that option, so the test fails.  Add the condition.

Cc: qemu-sta...@nongnu.org
Fixes: 892544317fe ("target/i386: implement XSAVE and XRSTOR of AVX registers", 
2022-10-18)
Reported-by: Thomas Huth 
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/fpu_helper.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index e322293371c..e1b850f3fc2 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -3142,6 +3142,11 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, 
uint64_t mask)
 goto do_gpf;
 }
 
+/* SSE can be disabled, but only if AVX is disabled too.  */
+if ((mask & (XSTATE_SSE_MASK | XSTATE_YMM_MASK)) == XSTATE_YMM_MASK) {
+goto do_gpf;
+}
+
 /* Disallow enabling unimplemented features.  */
 cpu_x86_cpuid(env, 0x0d, 0, &ena_lo, &dummy, &dummy, &ena_hi);
 ena = ((uint64_t)ena_hi << 32) | ena_lo;
-- 
2.45.1




[PULL 22/45] i386/sev: Add a sev_snp_enabled() helper

2024-06-03 Thread Paolo Bonzini
From: Michael Roth 

Add a simple helper to check if the current guest type is SNP. Also have
SNP-enabled imply that SEV-ES is enabled as well, and fix up any places
where the sev_es_enabled() check is expecting a pure/non-SNP guest.

Signed-off-by: Michael Roth 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-9-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/sev.h |  2 ++
 target/i386/sev.c | 13 -
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.h b/target/i386/sev.h
index bedc667eeba..94295ee74f7 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -45,9 +45,11 @@ typedef struct SevKernelLoaderContext {
 #ifdef CONFIG_SEV
 bool sev_enabled(void);
 bool sev_es_enabled(void);
+bool sev_snp_enabled(void);
 #else
 #define sev_enabled() 0
 #define sev_es_enabled() 0
+#define sev_snp_enabled() 0
 #endif
 
 uint32_t sev_get_cbit_position(void);
diff --git a/target/i386/sev.c b/target/i386/sev.c
index a81b3228d4c..4edfedc1393 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -325,12 +325,21 @@ sev_enabled(void)
 return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON);
 }
 
+bool
+sev_snp_enabled(void)
+{
+ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
+
+return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_SNP_GUEST);
+}
+
 bool
 sev_es_enabled(void)
 {
 ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
 
-return sev_enabled() && (SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
+return sev_snp_enabled() ||
+(sev_enabled() && SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
 }
 
 uint32_t
@@ -946,7 +955,9 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
"support", __func__);
 goto err;
 }
+}
 
+if (sev_es_enabled() && !sev_snp_enabled()) {
 if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
 error_setg(errp, "%s: guest policy requires SEV-ES, but "
  "host SEV-ES support unavailable",
-- 
2.45.1




[PULL 07/45] host/i386: assume presence of POPCNT

2024-06-03 Thread Paolo Bonzini
QEMU now requires an x86-64-v2 host, which has the POPCNT instruction.
Use it freely in TCG-generated code.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 host/include/i386/host/cpuinfo.h | 1 -
 tcg/i386/tcg-target.h| 5 ++---
 util/cpuinfo-i386.c  | 1 -
 3 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/host/include/i386/host/cpuinfo.h b/host/include/i386/host/cpuinfo.h
index 72f6fad61e5..c1e94d75ce1 100644
--- a/host/include/i386/host/cpuinfo.h
+++ b/host/include/i386/host/cpuinfo.h
@@ -11,7 +11,6 @@
 #define CPUINFO_ALWAYS  (1u << 0)  /* so cpuinfo is nonzero */
 #define CPUINFO_MOVBE   (1u << 2)
 #define CPUINFO_LZCNT   (1u << 3)
-#define CPUINFO_POPCNT  (1u << 4)
 #define CPUINFO_BMI1(1u << 5)
 #define CPUINFO_BMI2(1u << 6)
 #define CPUINFO_AVX1(1u << 9)
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 2f67a97e059..ecc69827287 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -111,7 +111,6 @@ typedef enum {
 #endif
 
 #define have_bmi1 (cpuinfo & CPUINFO_BMI1)
-#define have_popcnt   (cpuinfo & CPUINFO_POPCNT)
 #define have_avx1 (cpuinfo & CPUINFO_AVX1)
 #define have_avx2 (cpuinfo & CPUINFO_AVX2)
 #define have_movbe(cpuinfo & CPUINFO_MOVBE)
@@ -143,7 +142,7 @@ typedef enum {
 #define TCG_TARGET_HAS_nor_i32  0
 #define TCG_TARGET_HAS_clz_i32  1
 #define TCG_TARGET_HAS_ctz_i32  1
-#define TCG_TARGET_HAS_ctpop_i32have_popcnt
+#define TCG_TARGET_HAS_ctpop_i321
 #define TCG_TARGET_HAS_deposit_i32  1
 #define TCG_TARGET_HAS_extract_i32  1
 #define TCG_TARGET_HAS_sextract_i32 1
@@ -178,7 +177,7 @@ typedef enum {
 #define TCG_TARGET_HAS_nor_i64  0
 #define TCG_TARGET_HAS_clz_i64  1
 #define TCG_TARGET_HAS_ctz_i64  1
-#define TCG_TARGET_HAS_ctpop_i64have_popcnt
+#define TCG_TARGET_HAS_ctpop_i641
 #define TCG_TARGET_HAS_deposit_i64  1
 #define TCG_TARGET_HAS_extract_i64  1
 #define TCG_TARGET_HAS_sextract_i64 0
diff --git a/util/cpuinfo-i386.c b/util/cpuinfo-i386.c
index 6d474a6259a..8f2694d88f2 100644
--- a/util/cpuinfo-i386.c
+++ b/util/cpuinfo-i386.c
@@ -35,7 +35,6 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
 __cpuid(1, a, b, c, d);
 
 info |= (c & bit_MOVBE ? CPUINFO_MOVBE : 0);
-info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
 info |= (c & bit_PCLMUL ? CPUINFO_PCLMUL : 0);
 
 /* NOTE: our AES support requires SSSE3 (PSHUFB) as well. */
-- 
2.45.1




[PULL 09/45] target/i386: fix memory opsize for Mov to/from Seg

2024-06-03 Thread Paolo Bonzini
From: Xinyu Li 

This commit fixes an issue with MOV instructions (0x8C and 0x8E)
involving segment registers; MOV to segment register's source is
16-bit, while MOV from segment register has to explicitly set the
memory operand size to 16 bits.  Introduce a new flag
X86_SPECIAL_Op0_Mw to handle this specification correctly.

Signed-off-by: Xinyu Li 
Message-ID: <20240602100528.2135717-1-lixinyu...@ict.ac.cn>
Fixes: 5e9e21bcc4d ("target/i386: move 60-BF opcodes to new decoder", 
2024-05-07)
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/decode-new.h |  3 +++
 target/i386/tcg/decode-new.c.inc | 13 +++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/target/i386/tcg/decode-new.h b/target/i386/tcg/decode-new.h
index 51ef0e621b9..1f90cf96407 100644
--- a/target/i386/tcg/decode-new.h
+++ b/target/i386/tcg/decode-new.h
@@ -203,6 +203,9 @@ typedef enum X86InsnSpecial {
 /* When loaded into s->T0, register operand 1 is zero/sign extended.  */
 X86_SPECIAL_SExtT0,
 X86_SPECIAL_ZExtT0,
+
+/* Memory operand size of MOV from segment register is MO_16 */
+X86_SPECIAL_Op0_Mw,
 } X86InsnSpecial;
 
 /*
diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
index 0ec849b0035..0ff0866e8f3 100644
--- a/target/i386/tcg/decode-new.c.inc
+++ b/target/i386/tcg/decode-new.c.inc
@@ -202,6 +202,7 @@
 #define avx_movx .special = X86_SPECIAL_AVXExtMov,
 #define sextT0 .special = X86_SPECIAL_SExtT0,
 #define zextT0 .special = X86_SPECIAL_ZExtT0,
+#define op0_Mw .special = X86_SPECIAL_Op0_Mw,
 
 #define vex1 .vex_class = 1,
 #define vex1_rep3 .vex_class = 1, .vex_special = X86_VEX_REPScalar,
@@ -1576,9 +1577,10 @@ static const X86OpEntry opcodes_root[256] = {
 [0x89] = X86_OP_ENTRY3(MOV, E,v, G,v, None, None),
 [0x8A] = X86_OP_ENTRY3(MOV, G,b, E,b, None, None),
 [0x8B] = X86_OP_ENTRY3(MOV, G,v, E,v, None, None),
-[0x8C] = X86_OP_ENTRY3(MOV, E,v, S,w, None, None),
+/* Missing in Table A-2: memory destination is always 16-bit.  */
+[0x8C] = X86_OP_ENTRY3(MOV, E,v, S,w, None, None, op0_Mw),
 [0x8D] = X86_OP_ENTRY3(LEA, G,v, M,v, None, None, noseg),
-[0x8E] = X86_OP_ENTRY3(MOV, S,w, E,v, None, None),
+[0x8E] = X86_OP_ENTRY3(MOV, S,w, E,w, None, None),
 [0x8F] = X86_OP_GROUPw(group1A, E,v),
 
 [0x98] = X86_OP_ENTRY1(CBW,0,v), /* rAX */
@@ -2514,6 +2516,13 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
 s->override = -1;
 break;
 
+case X86_SPECIAL_Op0_Mw:
+assert(decode.op[0].unit == X86_OP_INT);
+if (decode.op[0].has_ea) {
+decode.op[0].ot = MO_16;
+}
+break;
+
 default:
 break;
 }
-- 
2.45.1




[PULL 15/45] update-linux-headers: import linux/kvm_para.h header

2024-06-03 Thread Paolo Bonzini
Right now QEMU is importing arch/x86/include/uapi/asm/kvm_para.h
because it includes definitions for kvmclock and for KVM CPUID
bits.  However, other definitions for KVM hypercall values and return
codes are included in include/uapi/linux/kvm_para.h and they will be
used by SEV-SNP.

To ensure that it is possible to include both  and
"standard-headers/asm-x86/kvm_para.h" without conflicts, provide
linux/kvm_para.h as a portable header too, and forward linux-headers/
files to those in include/standard-headers.  Note that 
will include architecture-specific definitions as well, but
"standard-headers/linux/kvm_para.h" will not because it can be used in
architecture-independent files.

This could easily be extended to other architectures, but right now
they do not need any symbol in their specific kvm_para.h files.

Reviewed-by: Thomas Huth 
Signed-off-by: Paolo Bonzini 
---
 include/standard-headers/linux/kvm_para.h | 38 +++
 linux-headers/asm-x86/kvm_para.h  |  1 +
 linux-headers/linux/kvm_para.h|  2 ++
 scripts/update-linux-headers.sh   | 22 -
 4 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 include/standard-headers/linux/kvm_para.h
 create mode 100644 linux-headers/asm-x86/kvm_para.h
 create mode 100644 linux-headers/linux/kvm_para.h

diff --git a/include/standard-headers/linux/kvm_para.h 
b/include/standard-headers/linux/kvm_para.h
new file mode 100644
index 000..015c1663021
--- /dev/null
+++ b/include/standard-headers/linux/kvm_para.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_KVM_PARA_H
+#define __LINUX_KVM_PARA_H
+
+/*
+ * This header file provides a method for making a hypercall to the host
+ * Architectures should define:
+ * - kvm_hypercall0, kvm_hypercall1...
+ * - kvm_arch_para_features
+ * - kvm_para_available
+ */
+
+/* Return values for hypercalls */
+#define KVM_ENOSYS 1000
+#define KVM_EFAULT EFAULT
+#define KVM_EINVAL EINVAL
+#define KVM_E2BIG  E2BIG
+#define KVM_EPERM  EPERM
+#define KVM_EOPNOTSUPP 95
+
+#define KVM_HC_VAPIC_POLL_IRQ  1
+#define KVM_HC_MMU_OP  2
+#define KVM_HC_FEATURES3
+#define KVM_HC_PPC_MAP_MAGIC_PAGE  4
+#define KVM_HC_KICK_CPU5
+#define KVM_HC_MIPS_GET_CLOCK_FREQ 6
+#define KVM_HC_MIPS_EXIT_VM7
+#define KVM_HC_MIPS_CONSOLE_OUTPUT 8
+#define KVM_HC_CLOCK_PAIRING   9
+#define KVM_HC_SEND_IPI10
+#define KVM_HC_SCHED_YIELD 11
+#define KVM_HC_MAP_GPA_RANGE   12
+
+/*
+ * hypercalls use architecture specific
+ */
+
+#endif /* __LINUX_KVM_PARA_H */
diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h
new file mode 100644
index 000..1d3e0e0b07a
--- /dev/null
+++ b/linux-headers/asm-x86/kvm_para.h
@@ -0,0 +1 @@
+#include "standard-headers/asm-x86/kvm_para.h"
diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
new file mode 100644
index 000..6a1e672259c
--- /dev/null
+++ b/linux-headers/linux/kvm_para.h
@@ -0,0 +1,2 @@
+#include "standard-headers/linux/kvm_para.h"
+#include 
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index 7e93acb3b5f..c34ac6454ef 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -63,6 +63,7 @@ cp_portable() {
  -e 'linux/kernel' \
  -e 'linux/sysinfo' \
  -e 'asm/setup_data.h' \
+ -e 'asm/kvm_para.h' \
  > /dev/null
 then
 echo "Unexpected #include in input file $f".
@@ -70,6 +71,15 @@ cp_portable() {
 fi
 
 header=$(basename "$f");
+
+if test -z "$arch"; then
+# Let users of include/standard-headers/linux/ headers pick the
+# asm-* header that they care about
+arch_cmd='/]*\)>/d'
+else
+arch_cmd='s/]*\)>/"standard-headers\/asm-'$arch'\/\1"/'
+fi
+
 sed -e 's/__aligned_u64/__u64 __attribute__((aligned(8)))/g' \
 -e 's/__u\([0-9][0-9]*\)/uint\1_t/g' \
 -e 's/u\([0-9][0-9]*\)/uint\1_t/g' \
@@ -78,7 +88,7 @@ cp_portable() {
 -e 's/__be\([0-9][0-9]*\)/uint\1_t/g' \
 -e 's/"\(input-event-codes\.h\)"/"standard-headers\/linux\/\1"/' \
 -e 's/]*\)>/"standard-headers\/linux\/\1"/' \
--e 's/]*\)>/"standard-headers\/asm-'$arch'\/\1"/' \
+-e "$arch_cmd" \
 -e 's/__bitwise//' \
 -e 's/__attribute__((packed))/QEMU_PACKED/' \
 -e 's/__inline__/inline/' \
@@ -158,7 +168,12 @@ EOF
 cp "$hdrdir/include/asm/unistd_32.h" "$output/linux-headers/asm-x86/"
 cp "$hdrdir/include/asm/unistd_x32.h" "$output/linux-headers/asm-x86/"
 cp "$hdrdir/include/asm/un

[PULL 16/45] machine: allow early use of machine_require_guest_memfd

2024-06-03 Thread Paolo Bonzini
Ask the ConfidentialGuestSupport object whether to use guest_memfd
for KVM-backend private memory.  This bool can be set in instance_init
(or user_complete) so that it is available when the machine is created.

Signed-off-by: Paolo Bonzini 
---
 include/exec/confidential-guest-support.h | 5 +
 include/hw/boards.h   | 1 -
 hw/core/machine.c | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/include/exec/confidential-guest-support.h 
b/include/exec/confidential-guest-support.h
index e5b188cffbf..02dc4e518f0 100644
--- a/include/exec/confidential-guest-support.h
+++ b/include/exec/confidential-guest-support.h
@@ -31,6 +31,11 @@ OBJECT_DECLARE_TYPE(ConfidentialGuestSupport,
 struct ConfidentialGuestSupport {
 Object parent;
 
+/*
+ * True if the machine should use guest_memfd for RAM.
+ */
+bool require_guest_memfd;
+
 /*
  * ready: flag set by CGS initialization code once it's ready to
  *start executing instructions in a potentially-secure
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 2fa800f11ae..73ad319d7da 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -375,7 +375,6 @@ struct MachineState {
 char *dt_compatible;
 bool dump_guest_core;
 bool mem_merge;
-bool require_guest_memfd;
 bool usb;
 bool usb_disabled;
 char *firmware;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 17292b13e62..77a356f232f 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1216,7 +1216,7 @@ bool machine_mem_merge(MachineState *machine)
 
 bool machine_require_guest_memfd(MachineState *machine)
 {
-return machine->require_guest_memfd;
+return machine->cgs && machine->cgs->require_guest_memfd;
 }
 
 static char *cpu_slot_to_string(const CPUArchId *cpu)
-- 
2.45.1




[PULL 21/45] i386/sev: Introduce 'sev-snp-guest' object

2024-06-03 Thread Paolo Bonzini
From: Brijesh Singh 

SEV-SNP support relies on a different set of properties/state than the
existing 'sev-guest' object. This patch introduces the 'sev-snp-guest'
object, which can be used to configure an SEV-SNP guest. For example,
a default-configured SEV-SNP guest with no additional information
passed in for use with attestation:

  -object sev-snp-guest,id=sev0

or a fully-specified SEV-SNP guest where all spec-defined binary
blobs are passed in as base64-encoded strings:

  -object sev-snp-guest,id=sev0, \
policy=0x3, \
init-flags=0, \
id-block=YWFhYWFhYWFhYWFhYWFhCg==, \
id-auth=CxHK/OKLkXGn/KpAC7Wl1FSiisWDbGTEKz..., \
author-key-enabled=on, \
host-data=LNkCWBRC5CcdGXirbNUV1OrsR28s..., \
guest-visible-workarounds=AA==, \

See the QAPI schema updates included in this patch for more usage
details.

In some cases these blobs may be up to 4096 characters, but this is
generally well below the default limit for linux hosts where
command-line sizes are defined by the sysconf-configurable ARG_MAX
value, which defaults to 2097152 characters for Ubuntu hosts, for
example.

Signed-off-by: Brijesh Singh 
Co-developed-by: Michael Roth 
Acked-by: Markus Armbruster  (for QAPI schema)
Signed-off-by: Michael Roth 
Co-developed-by: Pankaj Gupta 
Signed-off-by: Pankaj Gupta 
Message-ID: <20240530111643.1091816-8-pankaj.gu...@amd.com>
Signed-off-by: Paolo Bonzini 
---
 docs/system/i386/amd-memory-encryption.rst |  70 +-
 qapi/qom.json  |  58 +
 target/i386/sev.h  |   1 +
 target/i386/sev.c  | 253 +
 4 files changed, 380 insertions(+), 2 deletions(-)

diff --git a/docs/system/i386/amd-memory-encryption.rst 
b/docs/system/i386/amd-memory-encryption.rst
index e9bc142bc13..748f5094baf 100644
--- a/docs/system/i386/amd-memory-encryption.rst
+++ b/docs/system/i386/amd-memory-encryption.rst
@@ -25,8 +25,8 @@ support for notifying a guest's operating system when certain 
types of VMEXITs
 are about to occur. This allows the guest to selectively share information with
 the hypervisor to satisfy the requested function.
 
-Launching
--
+Launching (SEV and SEV-ES)
+--
 
 Boot images (such as bios) must be encrypted before a guest can be booted. The
 ``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images: 
``LAUNCH_START``,
@@ -161,6 +161,72 @@ The value of GCTX.LD is
 If kernel hashes are not used, or SEV-ES is disabled, use empty blobs for
 ``kernel_hashes_blob`` and ``vmsas_blob`` as needed.
 
+Launching (SEV-SNP)
+---
+Boot images (such as bios) must be encrypted before a guest can be booted. The
+``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images:
+``SNP_LAUNCH_START``, ``SNP_LAUNCH_UPDATE``, and ``SNP_LAUNCH_FINISH``. These
+three commands communicate with SEV-SNP firmware to generate a fresh memory
+encryption key for the VM, encrypt the boot images for a successful launch. For
+more details on the SEV-SNP firmware interfaces used by these commands please
+see the SEV-SNP Firmware ABI.
+
+``SNP_LAUNCH_START`` is called first to create a cryptographic launch context
+within the firmware. To create this context, the guest owner must provide a
+guest policy and other parameters as described in the SEV-SNP firmware
+specification. The launch parameters should be specified as described in the
+QAPI schema for the sev-snp-guest object.
+
+The ``SNP_LAUNCH_START`` uses the following parameters, which can be configured
+by the corresponding parameters documented in the QAPI schema for the
+'sev-snp-guest' object.
+
+++---+--+-+
+| key   | type  | default  | meaning  |
++---+-+
+| policy| hex   | 0x3  | a 64-bit guest policy|
++---+-+
+| guest-visible-workarounds | string| 0| 16-byte base64 encoded string|
+|   |   |  | for guest OS visible |
+|   |   |  | workarounds. |
++---+-+
+
+``SNP_LAUNCH_UPDATE`` encrypts the memory region using the cryptographic 
context
+created via the ``SNP_LAUNCH_START`` command. If required, this command can be
+called multiple times to encrypt different memory regions. The command also
+calculates the measurement of the memory contents as it encrypts.
+
+``SNP_LAUNCH_FINISH`` finalizes the guest launch flow. Optionally, while
+finalizing the launch the firmware can perform checks on the launch digest
+computing through the ``SNP_LAUNCH_UPDATE``. To perform the check the user must
+supply the id block, authentication blob and host data that s

[PULL 12/45] update-linux-headers: fix forwarding to asm-generic headers

2024-06-03 Thread Paolo Bonzini
Afer commit 3efc75ad9d9 ("scripts/update-linux-headers.sh: Remove
temporary directory inbetween", 2024-05-29), updating linux-headers/
results in errors such as

   cp: cannot stat '/tmp/tmp.1A1Eejh1UE/headers/include/asm/bitsperlong.h': No 
such file or directory

because Loongarch does not have an asm/bitsperlong.h file and uses the
generic version.  Before commit 3efc75ad9d9, the missing file would
incorrectly cause stale files to be included in linux-headers/.  The files
were never committed to qemu.git, but were wrong nevertheless. The build
would just use the system version of the files, which is opposite to
the idea of importing Linux header files into QEMU's tree.

Create forwarding headers, resembling the ones that are generated during a
kernel build by scripts/Makefile.asm-generic, if a file is only installed
under include/asm-generic/.

Reviewed-by: Thomas Huth 
Signed-off-by: Paolo Bonzini 
---
 scripts/update-linux-headers.sh | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index 23afe8c08ad..57a48837aa4 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -118,7 +118,14 @@ for arch in $ARCHLIST; do
 rm -rf "$output/linux-headers/asm-$arch"
 mkdir -p "$output/linux-headers/asm-$arch"
 for header in kvm.h unistd.h bitsperlong.h mman.h; do
-cp "$hdrdir/include/asm/$header" "$output/linux-headers/asm-$arch"
+if test -f "$hdrdir/include/asm/$header"; then
+cp "$hdrdir/include/asm/$header" "$output/linux-headers/asm-$arch"
+elif test -f "$hdrdir/include/asm-generic/$header"; then
+# not installed as , but used as such in kernel 
sources
+cat <$output/linux-headers/asm-$arch/$header
+#include 
+EOF
+fi
 done
 
 if [ $arch = mips ]; then
-- 
2.45.1




[PULL 04/45] host/i386: assume presence of CMOV

2024-06-03 Thread Paolo Bonzini
QEMU now requires an x86-64-v2 host, which always has CMOV.
Use it freely in TCG generated code.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 host/include/i386/host/cpuinfo.h |  1 -
 util/cpuinfo-i386.c  |  1 -
 tcg/i386/tcg-target.c.inc| 15 +--
 3 files changed, 1 insertion(+), 16 deletions(-)

diff --git a/host/include/i386/host/cpuinfo.h b/host/include/i386/host/cpuinfo.h
index 9386c749881..81771733eaa 100644
--- a/host/include/i386/host/cpuinfo.h
+++ b/host/include/i386/host/cpuinfo.h
@@ -9,7 +9,6 @@
 /* Digested version of  */
 
 #define CPUINFO_ALWAYS  (1u << 0)  /* so cpuinfo is nonzero */
-#define CPUINFO_CMOV(1u << 1)
 #define CPUINFO_MOVBE   (1u << 2)
 #define CPUINFO_LZCNT   (1u << 3)
 #define CPUINFO_POPCNT  (1u << 4)
diff --git a/util/cpuinfo-i386.c b/util/cpuinfo-i386.c
index 18ab747a6d2..90f92a42dc8 100644
--- a/util/cpuinfo-i386.c
+++ b/util/cpuinfo-i386.c
@@ -34,7 +34,6 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
 if (max >= 1) {
 __cpuid(1, a, b, c, d);
 
-info |= (d & bit_CMOV ? CPUINFO_CMOV : 0);
 info |= (d & bit_SSE2 ? CPUINFO_SSE2 : 0);
 info |= (c & bit_MOVBE ? CPUINFO_MOVBE : 0);
 info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index 59235b4f387..9a54ef7f8db 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -157,12 +157,6 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind 
kind, int slot)
 #define SOFTMMU_RESERVE_REGS \
 (tcg_use_softmmu ? (1 << TCG_REG_L0) | (1 << TCG_REG_L1) : 0)
 
-/* For 64-bit, we always know that CMOV is available.  */
-#if TCG_TARGET_REG_BITS == 64
-# define have_cmov  true
-#else
-# define have_cmov  (cpuinfo & CPUINFO_CMOV)
-#endif
 #define have_bmi2   (cpuinfo & CPUINFO_BMI2)
 #define have_lzcnt  (cpuinfo & CPUINFO_LZCNT)
 
@@ -1815,14 +1809,7 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg 
*args,
 static void tcg_out_cmov(TCGContext *s, int jcc, int rexw,
  TCGReg dest, TCGReg v1)
 {
-if (have_cmov) {
-tcg_out_modrm(s, OPC_CMOVCC | jcc | rexw, dest, v1);
-} else {
-TCGLabel *over = gen_new_label();
-tcg_out_jxx(s, jcc ^ 1, over, 1);
-tcg_out_mov(s, TCG_TYPE_I32, dest, v1);
-tcg_out_label(s, over);
-}
+tcg_out_modrm(s, OPC_CMOVCC | jcc | rexw, dest, v1);
 }
 
 static void tcg_out_movcond(TCGContext *s, int rexw, TCGCond cond,
-- 
2.45.1




[PULL 02/45] host/i386: nothing looks at CPUINFO_SSE4

2024-06-03 Thread Paolo Bonzini
The only user was the SSE4.1 variant of buffer_is_zero, which has
been removed; code to compute CPUINFO_SSE4 is dead.

Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 host/include/i386/host/cpuinfo.h | 1 -
 util/cpuinfo-i386.c  | 1 -
 2 files changed, 2 deletions(-)

diff --git a/host/include/i386/host/cpuinfo.h b/host/include/i386/host/cpuinfo.h
index b89e6d2e55a..9386c749881 100644
--- a/host/include/i386/host/cpuinfo.h
+++ b/host/include/i386/host/cpuinfo.h
@@ -16,7 +16,6 @@
 #define CPUINFO_BMI1(1u << 5)
 #define CPUINFO_BMI2(1u << 6)
 #define CPUINFO_SSE2(1u << 7)
-#define CPUINFO_SSE4(1u << 8)
 #define CPUINFO_AVX1(1u << 9)
 #define CPUINFO_AVX2(1u << 10)
 #define CPUINFO_AVX512F (1u << 11)
diff --git a/util/cpuinfo-i386.c b/util/cpuinfo-i386.c
index 9fddb18303d..18ab747a6d2 100644
--- a/util/cpuinfo-i386.c
+++ b/util/cpuinfo-i386.c
@@ -36,7 +36,6 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
 
 info |= (d & bit_CMOV ? CPUINFO_CMOV : 0);
 info |= (d & bit_SSE2 ? CPUINFO_SSE2 : 0);
-info |= (c & bit_SSE4_1 ? CPUINFO_SSE4 : 0);
 info |= (c & bit_MOVBE ? CPUINFO_MOVBE : 0);
 info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
 info |= (c & bit_PCLMUL ? CPUINFO_PCLMUL : 0);
-- 
2.45.1




[PULL 08/45] target/i386: fix SSE and SSE2 feature check

2024-06-03 Thread Paolo Bonzini
From: Xinyu Li 

Features check of CPUID_SSE and CPUID_SSE2 should use cpuid_features,
rather than cpuid_ext_features.

Signed-off-by: Xinyu Li 
Reviewed-by: Zhao Liu 
Message-ID: <20240602100904.2137939-1-lixinyu...@ict.ac.cn>
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/decode-new.c.inc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
index 27dc1bb146b..0ec849b0035 100644
--- a/target/i386/tcg/decode-new.c.inc
+++ b/target/i386/tcg/decode-new.c.inc
@@ -2041,9 +2041,9 @@ static bool has_cpuid_feature(DisasContext *s, 
X86CPUIDFeature cpuid)
 case X86_FEAT_PCLMULQDQ:
 return (s->cpuid_ext_features & CPUID_EXT_PCLMULQDQ);
 case X86_FEAT_SSE:
-return (s->cpuid_ext_features & CPUID_SSE);
+return (s->cpuid_features & CPUID_SSE);
 case X86_FEAT_SSE2:
-return (s->cpuid_ext_features & CPUID_SSE2);
+return (s->cpuid_features & CPUID_SSE2);
 case X86_FEAT_SSE3:
 return (s->cpuid_ext_features & CPUID_EXT_SSE3);
 case X86_FEAT_SSSE3:
-- 
2.45.1




[PULL 06/45] host/i386: assume presence of SSSE3

2024-06-03 Thread Paolo Bonzini
QEMU now requires an x86-64-v2 host, which has SSSE3 instructions
(notably, PSHUFB which is used by QEMU's AES implementation).
Do not bother checking it.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 util/cpuinfo-i386.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/util/cpuinfo-i386.c b/util/cpuinfo-i386.c
index ca74ef04f54..6d474a6259a 100644
--- a/util/cpuinfo-i386.c
+++ b/util/cpuinfo-i386.c
@@ -38,8 +38,8 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
 info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
 info |= (c & bit_PCLMUL ? CPUINFO_PCLMUL : 0);
 
-/* Our AES support requires PSHUFB as well. */
-info |= ((c & bit_AES) && (c & bit_SSSE3) ? CPUINFO_AES : 0);
+/* NOTE: our AES support requires SSSE3 (PSHUFB) as well. */
+info |= (c & bit_AES) ? CPUINFO_AES : 0;
 
 /* For AVX features, we must check available and usable. */
 if ((c & bit_AVX) && (c & bit_OSXSAVE)) {
-- 
2.45.1




[PULL 01/45] virtio-blk: remove SCSI passthrough functionality

2024-06-03 Thread Paolo Bonzini
The legacy SCSI passthrough functionality has never been enabled for
VIRTIO 1.0 and was deprecated more than four years ago.

Get rid of it---almost, because QEMU is advertising it unconditionally
for legacy virtio-blk devices.  Just parse the header and return a
nonzero status.

Signed-off-by: Paolo Bonzini 
---
 docs/about/deprecated.rst   |  10 --
 docs/about/removed-features.rst |   8 ++
 hw/block/virtio-blk.c   | 166 +++-
 hw/core/machine.c   |   2 -
 4 files changed, 19 insertions(+), 167 deletions(-)

diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 40585ca7d55..4980d721cf4 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -296,16 +296,6 @@ Device options
 Emulated device options
 '''
 
-``-device virtio-blk,scsi=on|off`` (since 5.0)
-^^
-
-The virtio-blk SCSI passthrough feature is a legacy VIRTIO feature.  VIRTIO 1.0
-and later do not support it because the virtio-scsi device was introduced for
-full SCSI support.  Use virtio-scsi instead when SCSI passthrough is required.
-
-Note this also applies to ``-device virtio-blk-pci,scsi=on|off``, which is an
-alias.
-
 ``-device nvme-ns,eui64-default=on|off`` (since 7.1)
 
 
diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst
index fba0cfb0b02..ae6269eb562 100644
--- a/docs/about/removed-features.rst
+++ b/docs/about/removed-features.rst
@@ -510,6 +510,14 @@ than zero.
 
 Removed along with the ``compression`` migration capability.
 
+``-device virtio-blk,scsi=on|off`` (since 9.1)
+''
+
+The virtio-blk SCSI passthrough feature is a legacy VIRTIO feature.  VIRTIO 1.0
+and later do not support it because the virtio-scsi device was introduced for
+full SCSI support.  Use virtio-scsi instead when SCSI passthrough is required.
+
+
 User-mode emulator command line arguments
 -
 
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index bb86e65f652..73bdfd6122a 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -172,57 +172,6 @@ static void virtio_blk_discard_write_zeroes_complete(void 
*opaque, int ret)
 virtio_blk_free_request(req);
 }
 
-#ifdef __linux__
-
-typedef struct {
-VirtIOBlockReq *req;
-struct sg_io_hdr hdr;
-} VirtIOBlockIoctlReq;
-
-static void virtio_blk_ioctl_complete(void *opaque, int status)
-{
-VirtIOBlockIoctlReq *ioctl_req = opaque;
-VirtIOBlockReq *req = ioctl_req->req;
-VirtIOBlock *s = req->dev;
-VirtIODevice *vdev = VIRTIO_DEVICE(s);
-struct virtio_scsi_inhdr *scsi;
-struct sg_io_hdr *hdr;
-
-scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
-
-if (status) {
-status = VIRTIO_BLK_S_UNSUPP;
-virtio_stl_p(vdev, &scsi->errors, 255);
-goto out;
-}
-
-hdr = &ioctl_req->hdr;
-/*
- * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi)
- * clear the masked_status field [hence status gets cleared too, see
- * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED
- * status has occurred.  However they do set DRIVER_SENSE in driver_status
- * field. Also a (sb_len_wr > 0) indicates there is a sense buffer.
- */
-if (hdr->status == 0 && hdr->sb_len_wr > 0) {
-hdr->status = CHECK_CONDITION;
-}
-
-virtio_stl_p(vdev, &scsi->errors,
- hdr->status | (hdr->msg_status << 8) |
- (hdr->host_status << 16) | (hdr->driver_status << 24));
-virtio_stl_p(vdev, &scsi->residual, hdr->resid);
-virtio_stl_p(vdev, &scsi->sense_len, hdr->sb_len_wr);
-virtio_stl_p(vdev, &scsi->data_len, hdr->dxfer_len);
-
-out:
-virtio_blk_req_complete(req, status);
-virtio_blk_free_request(req);
-g_free(ioctl_req);
-}
-
-#endif
-
 static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *vq)
 {
 VirtIOBlockReq *req = virtqueue_pop(vq, sizeof(VirtIOBlockReq));
@@ -233,20 +182,14 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock 
*s, VirtQueue *vq)
 return req;
 }
 
-static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
 {
-int status = VIRTIO_BLK_S_OK;
-struct virtio_scsi_inhdr *scsi = NULL;
+int status;
+struct virtio_scsi_inhdr *scsi;
 VirtIOBlock *blk = req->dev;
 VirtIODevice *vdev = VIRTIO_DEVICE(blk);
 VirtQueueElement *elem = &req->elem;
 
-#ifdef __linux__
-int i;
-VirtIOBlockIoctlReq *ioctl_req;
-BlockAIOCB *acb;
-#endif
-
 /*
  * We require at least one output segment each for the virtio_blk_outhdr
  * and the SCSI command block.
@@ -262,95 +205,16 @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
 /*
  * The scsi inhdr is placed in the second-to-la

[PULL 00/45] mostly i386 patches for 2024-06-04

2024-06-03 Thread Paolo Bonzini
The following changes since commit 3b2fe44bb7f605f179e5e7feb2c13c2eb3abbb80:

  Merge tag 'pull-request-2024-05-29' of https://gitlab.com/thuth/qemu into 
staging (2024-05-29 08:38:20 -0700)

are available in the Git repository at:

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

for you to fetch changes up to ba849076b6fc2290275ce7491547f6ae831cd2aa:

  hw/i386: Add support for loading BIOS using guest_memfd (2024-06-04 08:40:46 
+0200)


* virtio-blk: remove SCSI passthrough functionality
* require x86-64-v2 baseline ISA
* SEV-SNP host support
* fix xsave.flat with TCG
* fixes for CPUID checks done by TCG


Brijesh Singh (6):
  i386/sev: Introduce 'sev-snp-guest' object
  i386/sev: Add the SNP launch start context
  i386/sev: Add handling to encrypt/finalize guest launch data
  hw/i386/sev: Add function to get SEV metadata from OVMF header
  i386/sev: Add support for populating OVMF metadata pages
  hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled

Dov Murik (3):
  i386/sev: Extract build_kernel_loader_hashes
  i386/sev: Reorder struct declarations
  i386/sev: Allow measured direct kernel boot on SNP

Michael Roth (11):
  i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  i386/sev: Add a sev_snp_enabled() helper
  i386/cpu: Set SEV-SNP CPUID bit when SNP enabled
  i386/sev: Don't return launch measurements for SEV-SNP guests
  i386/sev: Update query-sev QAPI format to handle SEV-SNP
  i386/sev: Set CPU state to protected once SNP guest payload is finalized
  i386/sev: Add support for SNP CPUID validation
  i386/kvm: Add KVM_EXIT_HYPERCALL handling for KVM_HC_MAP_GPA_RANGE
  i386/sev: Enable KVM_HC_MAP_GPA_RANGE hcall for SNP guests
  hw/i386/sev: Use guest_memfd for legacy ROMs
  hw/i386: Add support for loading BIOS using guest_memfd

Pankaj Gupta (7):
  linux-headers: Update to current kvm/next
  i386/sev: Replace error_report with error_setg
  i386/sev: Move sev_launch_update to separate class method
  i386/sev: Move sev_launch_finish to separate class method
  i386/sev: Add sev_kvm_init() override for SEV class
  i386/sev: Add snp_kvm_init() override for SNP class
  i386/sev: Invoke launch_updata_data() for SNP class

Paolo Bonzini (14):
  virtio-blk: remove SCSI passthrough functionality
  host/i386: nothing looks at CPUINFO_SSE4
  meson: assume x86-64-v2 baseline ISA
  host/i386: assume presence of CMOV
  host/i386: assume presence of SSE2
  host/i386: assume presence of SSSE3
  host/i386: assume presence of POPCNT
  target/i386: fix xsave.flat from kvm-unit-tests
  update-linux-headers: fix forwarding to asm-generic headers
  update-linux-headers: move pvpanic.h to correct directory
  update-linux-headers: import linux/kvm_para.h header
  machine: allow early use of machine_require_guest_memfd
  i386/sev: Add a class method to determine KVM VM type for SNP guests
  i386/sev: Invoke launch_updata_data() for SEV class

Xiaoyao Li (1):
  memory: Introduce memory_region_init_ram_guest_memfd()

Xinyu Li (2):
  target/i386: fix SSE and SSE2 feature check
  target/i386: fix memory opsize for Mov to/from Seg

Zhao Liu (1):
  target/i386/tcg: Fix RDPID feature check

 docs/about/deprecated.rst  |   10 -
 docs/about/removed-features.rst|8 +
 docs/system/i386/amd-memory-encryption.rst |   70 +-
 meson.build|   10 +-
 qapi/misc-target.json  |   72 +-
 qapi/qom.json  |   98 +-
 host/include/i386/host/cpuinfo.h   |4 -
 include/exec/confidential-guest-support.h  |5 +
 include/exec/memory.h  |6 +
 include/hw/boards.h|1 -
 include/hw/i386/pc.h   |   28 +
 include/hw/i386/x86.h  |2 +-
 include/standard-headers/linux/kvm_para.h  |   38 +
 include/standard-headers/{linux => misc}/pvpanic.h |0
 linux-headers/asm-loongarch/kvm.h  |4 +
 linux-headers/asm-riscv/kvm.h  |1 +
 linux-headers/asm-x86/kvm.h|   52 +-
 linux-headers/asm-x86/kvm_para.h   |1 +
 linux-headers/linux/kvm_para.h |2 +
 linux-headers/linux/vhost.h|   15 +-
 target/i386/kvm/kvm_i386.h |1 +
 target/i386/sev.h  |   13 +-
 target/i386/tcg/decode-new.h   |3 +
 tcg/i386/tcg-target.h  |5 +-
 hw/block/virtio-blk.c

Re: [PATCH v5 0/4] RISC-V: Modularize common match conditions for trigger

2024-06-03 Thread Alistair Francis
On Tue, Jun 4, 2024 at 2:42 PM Alvin Chang via  wrote:
>
> According to RISC-V Debug specification ratified version 0.13 [1]
> (also applied to version 1.0 [2] but it has not been ratified yet), the
> enabled privilege levels of the trigger is common match conditions for
> all the types of the trigger.
>
> This series modularize the code for checking the privilege levels of
> type 2/3/6 triggers by implementing functions trigger_common_match()
> and trigger_priv_match().
>
> Additional match conditions, such as CSR tcontrol and textra, can be
> further implemented into trigger_common_match() in the future.
>
> [1]: https://github.com/riscv/riscv-debug-spec/releases/tag/task_group_vote
> [2]: https://github.com/riscv/riscv-debug-spec/releases/tag/1.0.0-rc1-asciidoc
>
> Changes from v4:
> - Rebasing on riscv-to-apply.next
>
> Changes from v3:
> - Change this series to target Debug Spec. version 0.13
>
> Changes from v2:
> - Explicitly mention the targeting version of RISC-V Debug Spec.
>
> Changes from v1:
> - Fix typo
> - Add commit description for changing behavior of looping the triggers
>   when we check type 2 triggers.
>
> Alvin Chang (4):
>   target/riscv: Add functions for common matching conditions of trigger
>   target/riscv: Apply modularized matching conditions for breakpoint
>   target/riscv: Apply modularized matching conditions for watchpoint
>   target/riscv: Apply modularized matching conditions for icount trigger

Thanks!

Applied to riscv-to-apply.next

Alistair

>
>  target/riscv/debug.c | 129 ---
>  1 file changed, 85 insertions(+), 44 deletions(-)
>
> --
> 2.34.1
>
>



Re: [PATCH 1/4] hw/dma: Enhance error handling in loading description

2024-06-03 Thread Fea Wang
Hi Edgar,
Thank you for recommending to me. I will make the change in the next
version of the patch series.

Sincerely,
Fea

On Mon, Jun 3, 2024 at 6:19 PM Edgar E. Iglesias 
wrote:

> On Mon, Jun 3, 2024 at 7:47 AM Fea.Wang  wrote:
>
>> Loading a description from memory may cause a bus-error. In this
>> case, the DMA should stop working, set the error flag, and return
>> the error value.
>>
>> Signed-off-by: Fea.Wang 
>>
>
>
> Hi Fea,
>
> I've got a couple of small comments:
>
>
> ---
>>  hw/dma/xilinx_axidma.c | 16 ++--
>>  1 file changed, 14 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
>> index 0ae056ed06..4b475e5484 100644
>> --- a/hw/dma/xilinx_axidma.c
>> +++ b/hw/dma/xilinx_axidma.c
>> @@ -71,8 +71,10 @@ enum {
>>  enum {
>>  DMASR_HALTED = 1,
>>  DMASR_IDLE  = 2,
>> +DMASR_SLVERR = 1 << 5,
>>
>
> We should also add DMASR_DECERR = 1 << 6
>
>
>>  DMASR_IOC_IRQ  = 1 << 12,
>>  DMASR_DLY_IRQ  = 1 << 13,
>> +DMASR_ERR_IRQ  = 1 << 14,
>>
>>  DMASR_IRQ_MASK = 7 << 12
>>  };
>> @@ -190,17 +192,27 @@ static inline int streamid_from_addr(hwaddr addr)
>>  return sid;
>>  }
>>
>> -static void stream_desc_load(struct Stream *s, hwaddr addr)
>> +static MemTxResult stream_desc_load(struct Stream *s, hwaddr addr)
>>  {
>>  struct SDesc *d = &s->desc;
>>
>> -address_space_read(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED, d,
>> sizeof *d);
>> +MemTxResult result = address_space_read(&s->dma->as,
>> +addr, MEMTXATTRS_UNSPECIFIED,
>> +d, sizeof *d);
>> +if (result != MEMTX_OK) {
>> +s->regs[R_DMACR] &= ~DMACR_RUNSTOP;
>> +s->regs[R_DMASR] |= DMASR_HALTED;
>> +s->regs[R_DMASR] |= DMASR_SLVERR;
>>
>
> ... and map MEMTX_DECODE_ERROR to DMASR_DECERR and everything else to
> SLVERR, for example:
> if (result == MEMTX_DECODE_ERROR) {
> s->regs[R_DMASR] |= DMASR_DECERR;
> } else {
> s->regs[R_DMASR] |= DMASR_SLVERR;
> }
>
>
>> +s->regs[R_DMASR] |= DMASR_ERR_IRQ;
>> +return result;
>> +}
>>
>>  /* Convert from LE into host endianness.  */
>>  d->buffer_address = le64_to_cpu(d->buffer_address);
>>  d->nxtdesc = le64_to_cpu(d->nxtdesc);
>>  d->control = le32_to_cpu(d->control);
>>  d->status = le32_to_cpu(d->status);
>> +return result;
>>  }
>>
>>  static void stream_desc_store(struct Stream *s, hwaddr addr)
>> --
>> 2.34.1
>>
>>


Re: [PATCH v5 37/65] i386/tdvf: Introduce function to parse TDVF metadata

2024-06-03 Thread Duan, Zhenzhong



On 2/29/2024 2:36 PM, Xiaoyao Li wrote:

From: Isaku Yamahata 

TDX VM needs to boot with its specialized firmware, Trusted Domain
Virtual Firmware (TDVF). QEMU needs to parse TDVF and map it in TD
guest memory prior to running the TDX VM.

A TDVF Metadata in TDVF image describes the structure of firmware.
QEMU refers to it to setup memory for TDVF. Introduce function
tdvf_parse_metadata() to parse the metadata from TDVF image and store
the info of each TDVF section.

TDX metadata is located by a TDX metadata offset block, which is a
GUID-ed structure. The data portion of the GUID structure contains
only an 4-byte field that is the offset of TDX metadata to the end
of firmware file.

Select X86_FW_OVMF when TDX is enable to leverage existing functions
to parse and search OVMF's GUID-ed structures.

Signed-off-by: Isaku Yamahata 
Co-developed-by: Xiaoyao Li 
Signed-off-by: Xiaoyao Li 
Acked-by: Gerd Hoffmann 

---
Changes in v1:
  - rename tdvf_parse_section_entry() to
tdvf_parse_and_check_section_entry()
Changes in RFC v4:
  - rename TDX_METADATA_GUID to TDX_METADATA_OFFSET_GUID
---
  hw/i386/Kconfig|   1 +
  hw/i386/meson.build|   1 +
  hw/i386/tdvf.c | 199 +
  include/hw/i386/tdvf.h |  51 +++
  4 files changed, 252 insertions(+)
  create mode 100644 hw/i386/tdvf.c
  create mode 100644 include/hw/i386/tdvf.h

diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index c0ccf50ac3ef..4e6c8905f077 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -12,6 +12,7 @@ config SGX
  
  config TDX

  bool
+select X86_FW_OVMF
  depends on KVM
  
  config PC

diff --git a/hw/i386/meson.build b/hw/i386/meson.build
index b9c1ca39cb05..f09441c1ea54 100644
--- a/hw/i386/meson.build
+++ b/hw/i386/meson.build
@@ -28,6 +28,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files(
'port92.c'))
  i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'),
  if_false: 
files('pc_sysfw_ovmf-stubs.c'))
+i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c'))
  
  subdir('kvm')

  subdir('xen')
diff --git a/hw/i386/tdvf.c b/hw/i386/tdvf.c
new file mode 100644
index ..ff51f40088f0
--- /dev/null
+++ b/hw/i386/tdvf.c
@@ -0,0 +1,199 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+
+ * Copyright (c) 2020 Intel Corporation
+ * Author: Isaku Yamahata 
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that 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 "qemu/error-report.h"
+
+#include "hw/i386/pc.h"
+#include "hw/i386/tdvf.h"
+#include "sysemu/kvm.h"
+
+#define TDX_METADATA_OFFSET_GUID"e47a6535-984a-4798-865e-4685a7bf8ec2"
+#define TDX_METADATA_VERSION1
+#define TDVF_SIGNATURE  0x46564454 /* TDVF as little endian */
+
+typedef struct {
+uint32_t DataOffset;
+uint32_t RawDataSize;
+uint64_t MemoryAddress;
+uint64_t MemoryDataSize;
+uint32_t Type;
+uint32_t Attributes;
+} TdvfSectionEntry;
+
+typedef struct {
+uint32_t Signature;
+uint32_t Length;
+uint32_t Version;
+uint32_t NumberOfSectionEntries;
+TdvfSectionEntry SectionEntries[];
+} TdvfMetadata;
+
+struct tdx_metadata_offset {
+uint32_t offset;
+};
+
+static TdvfMetadata *tdvf_get_metadata(void *flash_ptr, int size)
+{
+TdvfMetadata *metadata;
+uint32_t offset = 0;
+uint8_t *data;
+
+if ((uint32_t) size != size) {
+return NULL;
+}
+
+if (pc_system_ovmf_table_find(TDX_METADATA_OFFSET_GUID, &data, NULL)) {
+offset = size - le32_to_cpu(((struct tdx_metadata_offset 
*)data)->offset);
+
+if (offset + sizeof(*metadata) > size) {
+return NULL;
+}
+} else {
+error_report("Cannot find TDX_METADATA_OFFSET_GUID");
+return NULL;
+}
+
+metadata = flash_ptr + offset;
+
+/* Finally, verify the signature to determine if this is a TDVF image. */
+metadata->Signature = le32_to_cpu(metadata->Signature);
+if (metadata->Signature != TDVF_SIGNATURE) {
+error_report("Invalid TDVF signature in metadata!");
+return NULL;
+}
+
+/* Sanity check that the TDVF doesn't overlap its own metadata. */
+metadata->Length = le32_to_cpu(metadata->Length);
+if (offset + metadata->Length > size) {
+return NULL;
+}
+
+/* Only version 1

Re: [PATCH v2 1/3] stdvga: fix screen blanking

2024-06-03 Thread Marc-André Lureau
Hi

On Mon, Jun 3, 2024 at 7:18 PM Gerd Hoffmann  wrote:
>
> In case the display surface uses a shared buffer (i.e. uses vga vram
> directly instead of a shadow) go unshare the buffer before clearing it.
>
> This avoids vga memory corruption, which in turn fixes unblanking not
> working properly with X11.
>
> Cc: qemu-sta...@nongnu.org
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2067
> Signed-off-by: Gerd Hoffmann 
> ---
>  hw/display/vga.c | 6 ++
>  1 file changed, 6 insertions(+)
>
> diff --git a/hw/display/vga.c b/hw/display/vga.c
> index 30facc6c8e33..474b6b14c327 100644
> --- a/hw/display/vga.c
> +++ b/hw/display/vga.c
> @@ -1762,6 +1762,12 @@ static void vga_draw_blank(VGACommonState *s, int 
> full_update)
>  if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
>  return;
>
> +if (is_buffer_shared(surface)) {

Perhaps the suggestion to rename the function (in the following patch)
should instead be surface_is_allocated() ? that would match the actual
flag check. But callers would have to ! the result. Wdyt?

> +/* unshare buffer, otherwise the blanking corrupts vga vram */
> +surface = qemu_create_displaysurface(s->last_scr_width, 
> s->last_scr_height);
> +dpy_gfx_replace_surface(s->con, surface);

Ok, this looks safer than calling "resize".

thanks

> +}
> +
>  w = s->last_scr_width * surface_bytes_per_pixel(surface);
>  d = surface_data(surface);
>  for(i = 0; i < s->last_scr_height; i++) {
> --
> 2.45.1
>




Re: [PATCH v2 00/37] target/sparc: Implement VIS4

2024-06-03 Thread Mark Cave-Ayland

On 28/05/2024 22:29, Mark Cave-Ayland wrote:


On 26/05/2024 20:42, Richard Henderson wrote:


Now tested with RISU, using a Solaris M8 host as reference.
This exposed a few bugs in the existing VIS1 support as well,
so fix those before anything else.  It also exposed a few bugs
in the implementation of VIS3, so fixes squashed there as well.


r~


Richard Henderson (37):
   target/sparc: Fix ARRAY8
   target/sparc: Rewrite gen_edge
   target/sparc: Fix do_dc
   target/sparc: Fix helper_fmul8ulx16
   target/sparc: Perform DFPREG/QFPREG in decodetree
   target/sparc: Remove gen_dest_fpr_D
   target/sparc: Remove cpu_fpr[]
   target/sparc: Use gvec for VIS1 parallel add/sub
   target/sparc: Implement FMAf extension
   target/sparc: Add feature bits for VIS 3
   target/sparc: Implement ADDXC, ADDXCcc
   target/sparc: Implement CMASK instructions
   target/sparc: Implement FCHKSM16
   target/sparc: Implement FHADD, FHSUB, FNHADD, FNADD, FNMUL
   target/sparc: Implement FLCMP
   target/sparc: Implement FMEAN16
   target/sparc: Implement FPADD64, FPSUB64
   target/sparc: Implement FPADDS, FPSUBS
   target/sparc: Implement FPCMPEQ8, FPCMPNE8, FPCMPULE8, FPCMPUGT8
   target/sparc: Implement FSLL, FSRL, FSRA, FSLAS
   target/sparc: Implement LDXEFSR
   target/sparc: Implement LZCNT
   target/sparc: Implement MOVsTOw, MOVdTOx, MOVwTOs, MOVxTOd
   target/sparc: Implement PDISTN
   target/sparc: Implement UMULXHI
   target/sparc: Implement XMULX
   target/sparc: Enable VIS3 feature bit
   target/sparc: Implement IMA extension
   target/sparc: Add feature bit for VIS4
   target/sparc: Implement FALIGNDATAi
   target/sparc: Implement 8-bit FPADD, FPADDS, and FPADDUS
   target/sparc: Implement VIS4 comparisons
   target/sparc: Implement FPMIN, FPMAX
   target/sparc: Implement SUBXC, SUBXCcc
   target/sparc: Implement MWAIT
   target/sparc: Implement monitor ASIs
   target/sparc: Enable VIS4 feature bit

  target/sparc/asi.h |   4 +
  target/sparc/helper.h  |  27 +-
  target/sparc/cpu-feature.h.inc |   4 +
  target/sparc/insns.decode  | 338 
  linux-user/elfload.c   |   3 +
  target/sparc/cpu.c |  12 +
  target/sparc/fop_helper.c  | 136 +
  target/sparc/ldst_helper.c |   4 +
  target/sparc/translate.c   | 938 ++---
  target/sparc/vis_helper.c  | 392 +++---
  fpu/softfloat-specialize.c.inc |  31 ++
  11 files changed, 1558 insertions(+), 331 deletions(-)


Thanks - I'll give this series a quick run over my test images over the next few days 
just to make sure there are no regressions (unlikely as I don't have much in the way 
of current VIS test cases) and report back.


This series passes all my sun4u boot tests so:

Tested-by: Mark Cave-Ayland 

I don't have any other pending patches so feel free to take this via your TCG branch 
if you would like it merged in the near future.



ATB,

Mark.




[PATCH v3 6/6] target/riscv: Reserve exception codes for sw-check and hw-err

2024-06-03 Thread Fea.Wang
Based on the priv-1.13.0, add the exception codes for Software-check and
Hardware-error.

Signed-off-by: Fea.Wang 
Reviewed-by: Frank Chang 
Reviewed-by: LIU Zhiwei 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu_bits.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index f888025c59..f037f727d9 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -673,6 +673,8 @@ typedef enum RISCVException {
 RISCV_EXCP_INST_PAGE_FAULT = 0xc, /* since: priv-1.10.0 */
 RISCV_EXCP_LOAD_PAGE_FAULT = 0xd, /* since: priv-1.10.0 */
 RISCV_EXCP_STORE_PAGE_FAULT = 0xf, /* since: priv-1.10.0 */
+RISCV_EXCP_SW_CHECK = 0x12, /* since: priv-1.13.0 */
+RISCV_EXCP_HW_ERR = 0x13, /* since: priv-1.13.0 */
 RISCV_EXCP_INST_GUEST_PAGE_FAULT = 0x14,
 RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT = 0x15,
 RISCV_EXCP_VIRT_INSTRUCTION_FAULT = 0x16,
-- 
2.34.1




[PATCH v3 4/6] target/riscv: Add 'P1P13' bit in SMSTATEEN0

2024-06-03 Thread Fea.Wang
Based on privilege 1.13 spec, there should be a bit56 for 'P1P13' in
mstateen0 that controls access to the hedeleg.

Signed-off-by: Fea.Wang 
Reviewed-by: Frank Chang 
Reviewed-by: Weiwei Li 
---
 target/riscv/cpu_bits.h | 1 +
 target/riscv/csr.c  | 8 
 2 files changed, 9 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 74318a925c..28bd3fb0b4 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -315,6 +315,7 @@
 #define SMSTATEEN0_CS   (1ULL << 0)
 #define SMSTATEEN0_FCSR (1ULL << 1)
 #define SMSTATEEN0_JVT  (1ULL << 2)
+#define SMSTATEEN0_P1P13(1ULL << 56)
 #define SMSTATEEN0_HSCONTXT (1ULL << 57)
 #define SMSTATEEN0_IMSIC(1ULL << 58)
 #define SMSTATEEN0_AIA  (1ULL << 59)
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 58ef7079dc..3dcfb343fe 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2245,6 +2245,10 @@ static RISCVException write_mstateen0(CPURISCVState 
*env, int csrno,
 wr_mask |= SMSTATEEN0_FCSR;
 }
 
+if (env->priv_ver >= PRIV_VERSION_1_13_0) {
+wr_mask |= SMSTATEEN0_P1P13;
+}
+
 return write_mstateen(env, csrno, wr_mask, new_val);
 }
 
@@ -2280,6 +2284,10 @@ static RISCVException write_mstateen0h(CPURISCVState 
*env, int csrno,
 {
 uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
 
+if (env->priv_ver >= PRIV_VERSION_1_13_0) {
+wr_mask |= SMSTATEEN0_P1P13;
+}
+
 return write_mstateenh(env, csrno, wr_mask, new_val);
 }
 
-- 
2.34.1




[PATCH v3 1/6] target/riscv: Reuse the conversion function of priv_spec

2024-06-03 Thread Fea.Wang
From: Jim Shu 

Public the conversion function of priv_spec in cpu.h, so that tcg-cpu.c
could also use it.

Signed-off-by: Jim Shu 
Signed-off-by: Fea.Wang 
Reviewed-by: Frank Chang 
Reviewed-by: LIU Zhiwei 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu.c |  2 +-
 target/riscv/cpu.h |  1 +
 target/riscv/tcg/tcg-cpu.c | 13 -
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index cee6fc4a9a..e9e69b9863 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1786,7 +1786,7 @@ static int priv_spec_from_str(const char *priv_spec_str)
 return priv_version;
 }
 
-static const char *priv_spec_to_str(int priv_version)
+const char *priv_spec_to_str(int priv_version)
 {
 switch (priv_version) {
 case PRIV_VERSION_1_10_0:
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 12d8b5344a..94600b91fa 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -829,4 +829,5 @@ const char *satp_mode_str(uint8_t satp_mode, bool 
is_32_bit);
 /* Implemented in th_csr.c */
 void th_register_custom_csrs(RISCVCPU *cpu);
 
+const char *priv_spec_to_str(int priv_version);
 #endif /* RISCV_CPU_H */
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 683f604d9f..60fe0fd060 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -76,16 +76,11 @@ static void riscv_cpu_write_misa_bit(RISCVCPU *cpu, 
uint32_t bit,
 
 static const char *cpu_priv_ver_to_str(int priv_ver)
 {
-switch (priv_ver) {
-case PRIV_VERSION_1_10_0:
-return "v1.10.0";
-case PRIV_VERSION_1_11_0:
-return "v1.11.0";
-case PRIV_VERSION_1_12_0:
-return "v1.12.0";
-}
+const char *priv_spec_str = priv_spec_to_str(priv_ver);
 
-g_assert_not_reached();
+g_assert(priv_spec_str);
+
+return priv_spec_str;
 }
 
 static void riscv_cpu_synchronize_from_tb(CPUState *cs,
-- 
2.34.1




[PATCH v3 3/6] target/riscv: Support the version for ss1p13

2024-06-03 Thread Fea.Wang
Add RISC-V privilege 1.13 support.

Signed-off-by: Fea.Wang 
Signed-off-by: Fea.Wang 
Reviewed-by: Frank Chang 
Reviewed-by: Weiwei Li 
Reviewed-by: LIU Zhiwei 
---
 target/riscv/cpu.c | 6 +-
 target/riscv/tcg/tcg-cpu.c | 4 
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e9e69b9863..02c1e12a03 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1775,7 +1775,9 @@ static int priv_spec_from_str(const char *priv_spec_str)
 {
 int priv_version = -1;
 
-if (!g_strcmp0(priv_spec_str, PRIV_VER_1_12_0_STR)) {
+if (!g_strcmp0(priv_spec_str, PRIV_VER_1_13_0_STR)) {
+priv_version = PRIV_VERSION_1_13_0;
+} else if (!g_strcmp0(priv_spec_str, PRIV_VER_1_12_0_STR)) {
 priv_version = PRIV_VERSION_1_12_0;
 } else if (!g_strcmp0(priv_spec_str, PRIV_VER_1_11_0_STR)) {
 priv_version = PRIV_VERSION_1_11_0;
@@ -1795,6 +1797,8 @@ const char *priv_spec_to_str(int priv_version)
 return PRIV_VER_1_11_0_STR;
 case PRIV_VERSION_1_12_0:
 return PRIV_VER_1_12_0_STR;
+case PRIV_VERSION_1_13_0:
+return PRIV_VER_1_13_0_STR;
 default:
 return NULL;
 }
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 60fe0fd060..595d3b5b8f 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -318,6 +318,10 @@ static void riscv_cpu_update_named_features(RISCVCPU *cpu)
 cpu->cfg.has_priv_1_12 = true;
 }
 
+if (cpu->env.priv_ver >= PRIV_VERSION_1_13_0) {
+cpu->cfg.has_priv_1_13 = true;
+}
+
 /* zic64b is 1.12 or later */
 cpu->cfg.ext_zic64b = cpu->cfg.cbom_blocksize == 64 &&
   cpu->cfg.cbop_blocksize == 64 &&
-- 
2.34.1




[PATCH v3 5/6] target/riscv: Add MEDELEGH, HEDELEGH csrs for RV32

2024-06-03 Thread Fea.Wang
Based on privileged spec 1.13, the RV32 needs to implement MEDELEGH
and HEDELEGH for exception codes 32-47 for reserving and exception codes
48-63 for custom use. Add the CSR number though the implementation is
just reading zero and writing ignore. Besides, for accessing HEDELEGH, it
should be controlled by mstateen0 'P1P13' bit.

Signed-off-by: Fea.Wang 
Reviewed-by: Frank Chang 
Reviewed-by: LIU Zhiwei 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu_bits.h |  2 ++
 target/riscv/csr.c  | 31 +++
 2 files changed, 33 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 28bd3fb0b4..f888025c59 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -156,6 +156,8 @@
 
 /* 32-bit only */
 #define CSR_MSTATUSH0x310
+#define CSR_MEDELEGH0x312
+#define CSR_HEDELEGH0x612
 
 /* Machine Trap Handling */
 #define CSR_MSCRATCH0x340
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 3dcfb343fe..d480feb94d 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -3222,6 +3222,33 @@ static RISCVException write_hedeleg(CPURISCVState *env, 
int csrno,
 return RISCV_EXCP_NONE;
 }
 
+static RISCVException read_hedelegh(CPURISCVState *env, int csrno,
+   target_ulong *val)
+{
+RISCVException ret;
+ret = smstateen_acc_ok(env, 0, SMSTATEEN0_P1P13);
+if (ret != RISCV_EXCP_NONE) {
+return ret;
+}
+
+/* Reserved, now read zero */
+*val = 0;
+return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hedelegh(CPURISCVState *env, int csrno,
+target_ulong val)
+{
+RISCVException ret;
+ret = smstateen_acc_ok(env, 0, SMSTATEEN0_P1P13);
+if (ret != RISCV_EXCP_NONE) {
+return ret;
+}
+
+/* Reserved, now write ignore */
+return RISCV_EXCP_NONE;
+}
+
 static RISCVException rmw_hvien64(CPURISCVState *env, int csrno,
 uint64_t *ret_val,
 uint64_t new_val, uint64_t wr_mask)
@@ -4626,6 +4653,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
 
 [CSR_MSTATUSH]= { "mstatush",   any32, read_mstatush,
   write_mstatush   },
+[CSR_MEDELEGH]= { "medelegh",   any32, read_zero, write_ignore,
+  .min_priv_ver = PRIV_VERSION_1_13_0  },
+[CSR_HEDELEGH]= { "hedelegh",   hmode32, read_hedelegh, write_hedelegh,
+  .min_priv_ver = PRIV_VERSION_1_13_0  },
 
 /* Machine Trap Handling */
 [CSR_MSCRATCH] = { "mscratch", any,  read_mscratch, write_mscratch,
-- 
2.34.1




[PATCH] qtest/x86/numa-test: do not use the obsolete 'pentium' cpu

2024-06-03 Thread Ani Sinha
'pentium' cpu is old and obsolete and should be avoided for running tests if
its not strictly needed. Use 'max' cpu instead for generic non-cpu specific
numa test.

CC: th...@redhat.com
Signed-off-by: Ani Sinha 
---
 tests/qtest/numa-test.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c
index 7aa262dbb9..f01f19592d 100644
--- a/tests/qtest/numa-test.c
+++ b/tests/qtest/numa-test.c
@@ -125,7 +125,8 @@ static void pc_numa_cpu(const void *data)
 QTestState *qts;
 g_autofree char *cli = NULL;
 
-cli = make_cli(data, "-cpu pentium -machine 
smp.cpus=8,smp.sockets=2,smp.cores=2,smp.threads=2 "
+cli = make_cli(data,
+"-cpu max -machine smp.cpus=8,smp.sockets=2,smp.cores=2,smp.threads=2 "
 "-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 "
 "-numa cpu,node-id=1,socket-id=0 "
 "-numa cpu,node-id=0,socket-id=1,core-id=0 "
-- 
2.42.0




[PATCH v3 0/6] target/riscv: Support RISC-V privilege 1.13 spec

2024-06-03 Thread Fea.Wang
Based on the change log for the RISC-V privilege 1.13 spec, add the
support for ss1p13.

base-commit: 915758c537b5fe09575291f4acd87e2d377a93de

* Correct the mstateen0 for P1P13 in commit message
* Refactor commit by splitting to two commits

[v2]
* Check HEDELEGH by hmode32 instead of any32
* Remove unnecessary code
* Refine calling functions

[v1]

Ref:https://github.com/riscv/riscv-isa-manual/blob/a7d93c9/src/priv-preface.adoc?plain=1#L40-L72

Lists what to do without clarification or document format.
* Redefined misa.MXL to be read-only, making MXLEN a constant.(Skip, 
implementation ignored)
* Added the constraint that SXLEN≥UXLEN.(Skip, implementation ignored)
* Defined the misa.V field to reflect that the V extension has been 
implemented.(Skip, existed) 
* Defined the RV32-only medelegh and hedelegh CSRs.(Done in these patches)
* Defined the misaligned atomicity granule PMA, superseding the proposed Zam 
extension..(Skip, implementation ignored)
* Allocated interrupt 13 for Sscofpmf LCOFI interrupt.(Skip, existed) 
* Defined hardware error and software check exception codes.(Done in these 
patches)
* Specified synchronization requirements when changing the PBMTE fields in 
menvcfg and henvcfg.(Skip, implementation ignored)
* Incorporated Svade and Svadu extension specifications.(Skip, existed) 


Fea.Wang (5):
  target/riscv: Define macros and variables for ss1p13
  target/riscv: Support the version for ss1p13
  target/riscv: Add 'P1P13' bit in SMSTATEEN0
  target/riscv: Add MEDELEGH, HEDELEGH csrs for RV32
  target/riscv: Reserve exception codes for sw-check and hw-err

Jim Shu (1):
  target/riscv: Reuse the conversion function of priv_spec

 target/riscv/cpu.c |  8 ++--
 target/riscv/cpu.h |  5 -
 target/riscv/cpu_bits.h|  5 +
 target/riscv/cpu_cfg.h |  1 +
 target/riscv/csr.c | 39 ++
 target/riscv/tcg/tcg-cpu.c | 17 -
 6 files changed, 63 insertions(+), 12 deletions(-)

-- 
2.34.1




[PATCH v3 2/6] target/riscv: Define macros and variables for ss1p13

2024-06-03 Thread Fea.Wang
Add macros and variables for RISC-V privilege 1.13 support.

Signed-off-by: Fea.Wang 
Reviewed-by: Frank Chang 
Reviewed-by: Weiwei Li 
Reviewed-by: LIU Zhiwei 
---
 target/riscv/cpu.h | 4 +++-
 target/riscv/cpu_cfg.h | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 94600b91fa..4d73486ea2 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -96,12 +96,14 @@ extern RISCVCPUProfile *riscv_profiles[];
 #define PRIV_VER_1_10_0_STR "v1.10.0"
 #define PRIV_VER_1_11_0_STR "v1.11.0"
 #define PRIV_VER_1_12_0_STR "v1.12.0"
+#define PRIV_VER_1_13_0_STR "v1.13.0"
 enum {
 PRIV_VERSION_1_10_0 = 0,
 PRIV_VERSION_1_11_0,
 PRIV_VERSION_1_12_0,
+PRIV_VERSION_1_13_0,
 
-PRIV_VERSION_LATEST = PRIV_VERSION_1_12_0,
+PRIV_VERSION_LATEST = PRIV_VERSION_1_13_0,
 };
 
 #define VEXT_VERSION_1_00_0 0x0001
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index e1e4f32698..fb7eebde52 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -136,6 +136,7 @@ struct RISCVCPUConfig {
  * TCG always implement/can't be user disabled,
  * based on spec version.
  */
+bool has_priv_1_13;
 bool has_priv_1_12;
 bool has_priv_1_11;
 
-- 
2.34.1




Re: [PATCH] hw/core: Rename CpuTopology to CPUTopology

2024-06-03 Thread Zhao Liu
On Tue, Jun 04, 2024 at 07:29:15AM +0200, Markus Armbruster wrote:
> Date: Tue, 04 Jun 2024 07:29:15 +0200
> From: Markus Armbruster 
> Subject: Re: [PATCH] hw/core: Rename CpuTopology to CPUTopology
> 
> Zhao Liu  writes:
> 
> > On Mon, Jun 03, 2024 at 01:54:15PM +0200, Markus Armbruster wrote:
> >> Date: Mon, 03 Jun 2024 13:54:15 +0200
> >> From: Markus Armbruster 
> >> Subject: Re: [PATCH] hw/core: Rename CpuTopology to CPUTopology
> >> 
> >> Zhao Liu  writes:
> >> 
> >> > Use CPUTopology to honor the generic style of CPU capitalization
> >> > abbreviations.
> >> >
> >> > Signed-off-by: Zhao Liu 
> >> 
> >> Is CPUFoo really more common than CpuFoo?  It isn't in the qapi
> >> schema...
> >
> > Hi Markus, do you think this style needs to be standardized?
> >
> > All-caps cases, like the widely used CPUState.
> >
> > And the common structures declared in include/qemu/typedefs.h, are all
> > using CPU, not Cpu...
> >
> > If you feel this is necessary, I'd be happy to help more places change
> > their names to standardize their style...
> 
> The situation is unfortunate[*].  The renaming cure could be worse than
> the disease, though.
> 
> In a situation like this, settling for local consistency is often the
> least bad.  machine.json is locally consistent: it consistently uses
> CpuFoo.
> 
> 
> [*] We suck at systematic, disciplined naming.

I see, by local consistency principle, my another patch (adding topology
enumeration in machine.json) should use Cpu...

The CpuTopology that this patch modifies is located in include/hw/boards.h,
where that looks as if this file prefers to use CPUs (defining the
CPUArchIdList and CPUArchId). And there's also another case for all-caps,
SMPCompatProps (using SMP not Smp). So I feel like this patch change
still makes sense... Sorry if I'm being a bit obsessive.

The most confusing thing in include/hw/boards.h is this structure:

typedef struct CPUArchId {
...
CpuInstanceProperties props;
CPUState *cpu;
...
} CPUArchId;

CPU and Cpu are mixed together, but this is also explained by the local
consistency principle, since the CpuInstanceProperties belong to
machine.json. ;-)




Re: [PATCH v5 13/17] aspeed/soc: Add AST2700 support

2024-06-03 Thread Cédric Le Goater

On 6/4/24 07:44, Jamin Lin wrote:

Initial definitions for a simple machine using an AST2700 SOC (Cortex-a35 CPU).

AST2700 SOC and its interrupt controller are too complex to handle
in the common Aspeed SoC framework. We introduce a new ast2700
class with instance_init and realize handlers.

AST2700 is a 64 bits quad core cpus and support 8 watchdog.
Update maximum ASPEED_CPUS_NUM to 4 and ASPEED_WDTS_NUM to 8.
In addition, update AspeedSocState to support scuio, sli, sliio and intc.

Add TYPE_ASPEED27X0_SOC machine type.

The SDMC controller is unlocked at SPL stage.
At present, only supports to emulate booting
start from u-boot stage. Set SDMC controller
unlocked by default.

In INTC, each interrupt of INT 128 to INT 136 combines 32 interrupts.
It connect GICINT IRQ GPIO-OUTPUT pins to GIC device with irq 128 to 136.
And, if a device irq is 128 to 136, its irq GPIO-OUTPUT pin is connected to
GICINT or-gates instead of GIC device.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 



Reviewed-by: Cédric Le Goater 

Thanks,

C.



---
  hw/arm/aspeed_ast27x0.c | 563 
  hw/arm/meson.build  |   1 +
  include/hw/arm/aspeed_soc.h |  28 +-
  3 files changed, 590 insertions(+), 2 deletions(-)
  create mode 100644 hw/arm/aspeed_ast27x0.c

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
new file mode 100644
index 00..29e75072c4
--- /dev/null
+++ b/hw/arm/aspeed_ast27x0.c
@@ -0,0 +1,563 @@
+/*
+ * ASPEED SoC 27x0 family
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Implementation extracted from the AST2600 and adapted for AST27x0.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/aspeed_soc.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "hw/i2c/aspeed_i2c.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/intc/arm_gicv3.h"
+#include "qapi/qmp/qlist.h"
+
+static const hwaddr aspeed_soc_ast2700_memmap[] = {
+[ASPEED_DEV_SPI_BOOT]  =  0x4,
+[ASPEED_DEV_SRAM]  =  0x1000,
+[ASPEED_DEV_SDMC]  =  0x12C0,
+[ASPEED_DEV_SCU]   =  0x12C02000,
+[ASPEED_DEV_SCUIO] =  0x14C02000,
+[ASPEED_DEV_UART0] =  0X14C33000,
+[ASPEED_DEV_UART1] =  0X14C33100,
+[ASPEED_DEV_UART2] =  0X14C33200,
+[ASPEED_DEV_UART3] =  0X14C33300,
+[ASPEED_DEV_UART4] =  0X12C1A000,
+[ASPEED_DEV_UART5] =  0X14C33400,
+[ASPEED_DEV_UART6] =  0X14C33500,
+[ASPEED_DEV_UART7] =  0X14C33600,
+[ASPEED_DEV_UART8] =  0X14C33700,
+[ASPEED_DEV_UART9] =  0X14C33800,
+[ASPEED_DEV_UART10]=  0X14C33900,
+[ASPEED_DEV_UART11]=  0X14C33A00,
+[ASPEED_DEV_UART12]=  0X14C33B00,
+[ASPEED_DEV_WDT]   =  0x14C37000,
+[ASPEED_DEV_VUART] =  0X14C3,
+[ASPEED_DEV_FMC]   =  0x1400,
+[ASPEED_DEV_SPI0]  =  0x1401,
+[ASPEED_DEV_SPI1]  =  0x1402,
+[ASPEED_DEV_SPI2]  =  0x1403,
+[ASPEED_DEV_SDRAM] =  0x4,
+[ASPEED_DEV_MII1]  =  0x1404,
+[ASPEED_DEV_MII2]  =  0x14040008,
+[ASPEED_DEV_MII3]  =  0x14040010,
+[ASPEED_DEV_ETH1]  =  0x1405,
+[ASPEED_DEV_ETH2]  =  0x1406,
+[ASPEED_DEV_ETH3]  =  0x1407,
+[ASPEED_DEV_EMMC]  =  0x1209,
+[ASPEED_DEV_INTC]  =  0x1210,
+[ASPEED_DEV_SLI]   =  0x12C17000,
+[ASPEED_DEV_SLIIO] =  0x14C1E000,
+[ASPEED_GIC_DIST]  =  0x1220,
+[ASPEED_GIC_REDIST]=  0x1228,
+};
+
+#define AST2700_MAX_IRQ 288
+
+/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
+static const int aspeed_soc_ast2700_irqmap[] = {
+[ASPEED_DEV_UART0] = 132,
+[ASPEED_DEV_UART1] = 132,
+[ASPEED_DEV_UART2] = 132,
+[ASPEED_DEV_UART3] = 132,
+[ASPEED_DEV_UART4] = 8,
+[ASPEED_DEV_UART5] = 132,
+[ASPEED_DEV_UART6] = 132,
+[ASPEED_DEV_UART7] = 132,
+[ASPEED_DEV_UART8] = 132,
+[ASPEED_DEV_UART9] = 132,
+[ASPEED_DEV_UART10]= 132,
+[ASPEED_DEV_UART11]= 132,
+[ASPEED_DEV_UART12]= 132,
+[ASPEED_DEV_FMC]   = 131,
+[ASPEED_DEV_SDMC]  = 0,
+[ASPEED_DEV_SCU]   = 12,
+[ASPEED_DEV_ADC]   = 130,
+[ASPEED_DEV_XDMA]  = 5,
+[ASPEED_DEV_EMMC]  = 15,
+[ASPEED_DEV_GPIO]  = 11,
+[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_RTC]   = 13,
+[ASPEED_DEV_TIMER1]= 16,
+[ASPEED_DEV_TIMER2]= 17,
+[ASPEED_DEV_TIMER3]= 18,
+[ASPEED_DEV_TIMER4]= 19,
+[ASPEED_DEV_TIMER5]= 20,
+[ASPEED_DEV_TIMER6]= 21,
+[ASPEED_DEV_TIMER7]= 22,
+[ASPEED_DEV_TIMER8]= 23,
+[ASPEED_DEV_WDT]   = 131,
+[ASPEED_DEV_PWM]   = 131,
+[ASPEE

Re: [PATCH v5 15/17] aspeed/soc: fix incorrect dram size for AST2700

2024-06-03 Thread Cédric Le Goater

On 6/4/24 07:44, Jamin Lin wrote:

AST2700 dram size calculation is not back compatible AST2600.
According to the DDR capacity hardware behavior,
if users write the data to the address which is beyond the ram size,
it would write the data to the "address % ram_size".
For example:
a. sdram base address "0x4 "
b. sdram size 1 GiB
The available address range is from "0x4 " to "0x4 3FFF".
If users write 0x12345678 to address "0x5 ",
the value of DRAM address 0 (base address 0x4 ) will be 0x12345678.

Add aspeed_soc_ast2700_dram_init to calculate the dram size and add
memory I/O whose address range is from "max_ram_size - ram_size" to max_ram_size
and its read/write handler to emulate DDR capacity hardware behavior.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 



Reviewed-by: Cédric Le Goater 

Thanks,

C.



---
  hw/arm/aspeed_ast27x0.c | 87 -
  include/hw/arm/aspeed_soc.h |  2 +
  2 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 29e75072c4..b6876b4862 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -20,6 +20,7 @@
  #include "sysemu/sysemu.h"
  #include "hw/intc/arm_gicv3.h"
  #include "qapi/qmp/qlist.h"
+#include "qemu/log.h"
  
  static const hwaddr aspeed_soc_ast2700_memmap[] = {

  [ASPEED_DEV_SPI_BOOT]  =  0x4,
@@ -191,6 +192,90 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState 
*s, int dev)
  return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
  }
  
+static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,

+unsigned int size)
+{
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM read out of ram size, addr:0x%" PRIx64 "\n",
+   __func__, addr);
+return 0;
+}
+
+static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data,
+unsigned int size)
+{
+AspeedSoCState *s = ASPEED_SOC(opaque);
+ram_addr_t ram_size;
+MemTxResult result;
+
+ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
+&error_abort);
+
+/*
+ * Emulate ddr capacity hardware behavior.
+ * If writes the data to the address which is beyond the ram size,
+ * it would write the data to the "address % ram_size".
+ */
+result = address_space_write(&s->dram_as, addr % ram_size,
+ MEMTXATTRS_UNSPECIFIED, &data, 4);
+if (result != MEMTX_OK) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM write failed, addr:0x%" HWADDR_PRIx
+  ", data :0x%" PRIx64  "\n",
+  __func__, addr % ram_size, data);
+}
+}
+
+static const MemoryRegionOps aspeed_ram_capacity_ops = {
+.read = aspeed_ram_capacity_read,
+.write = aspeed_ram_capacity_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 8,
+},
+};
+
+/*
+ * SDMC should be realized first to get correct RAM size and max size
+ * values
+ */
+static bool aspeed_soc_ast2700_dram_init(DeviceState *dev, Error **errp)
+{
+ram_addr_t ram_size, max_ram_size;
+Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
+AspeedSoCState *s = ASPEED_SOC(dev);
+AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
+&error_abort);
+max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), "max-ram-size",
+&error_abort);
+
+memory_region_init(&s->dram_container, OBJECT(s), "ram-container",
+   ram_size);
+memory_region_add_subregion(&s->dram_container, 0, s->dram_mr);
+address_space_init(&s->dram_as, s->dram_mr, "dram");
+
+/*
+ * Add a memory region beyond the RAM region to emulate
+ * ddr capacity hardware behavior.
+ */
+if (ram_size < max_ram_size) {
+memory_region_init_io(&a->dram_empty, OBJECT(s),
+  &aspeed_ram_capacity_ops, s,
+  "ram-empty", max_ram_size - ram_size);
+
+memory_region_add_subregion(s->memory,
+sc->memmap[ASPEED_DEV_SDRAM] + ram_size,
+&a->dram_empty);
+}
+
+memory_region_add_subregion(s->memory,
+  sc->memmap[ASPEED_DEV_SDRAM], &s->dram_container);
+return true;
+}
+
  static void aspeed_soc_ast2700_init(Object *obj)
  {
  Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
@@ -461,7 +546,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
  sc->memmap[ASPEED_DEV_SDMC]);
  
  /* RAM */

-if (!aspeed_soc_dram_init(s, errp)) {
+if (!aspeed

Re: [PATCH v5 10/17] aspeed/smc: Add AST2700 support

2024-06-03 Thread Cédric Le Goater

On 6/4/24 07:44, Jamin Lin wrote:

AST2700 fmc/spi controller's address decoding unit is 64KB
and only bits [31:16] are used for decoding. Introduce seg_to_reg
and reg_to_seg handlers for ast2700 fmc/spi controller.
In addition, adds ast2700 fmc, spi0, spi1, and spi2 class init handler.

AST2700 is a 64 bits quad core CPUs(Cortex-a35). Introduce a new
"aspeed_2700_smc_flash_ops" and set its valid "max_access_size"
8 for 64 bits data format access.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 



Reviewed-by: Cédric Le Goater 

Thanks,

C.



---
  hw/ssi/aspeed_smc.c | 234 +++-
  1 file changed, 233 insertions(+), 1 deletion(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 129d06690d..49205ab76d 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -185,7 +185,7 @@
   *   0: 4 bytes
   *   0x1FC: 32M bytes
   *
- * DMA length is from 1 byte to 32MB (AST2600, AST10x0)
+ * DMA length is from 1 byte to 32MB (AST2600, AST10x0 and AST2700)
   *   0: 1 byte
   *   0x1FF: 32M bytes
   */
@@ -1938,6 +1938,234 @@ static const TypeInfo aspeed_1030_spi2_info = {
  .class_init = aspeed_1030_spi2_class_init,
  };
  
+/*

+ * The FMC Segment Registers of the AST2700 have a 64KB unit.
+ * Only bits [31:16] are used for decoding.
+ */
+#define AST2700_SEG_ADDR_MASK 0x
+
+static uint32_t aspeed_2700_smc_segment_to_reg(const AspeedSMCState *s,
+   const AspeedSegments *seg)
+{
+uint32_t reg = 0;
+
+/* Disabled segments have a nil register */
+if (!seg->size) {
+return 0;
+}
+
+reg |= (seg->addr & AST2700_SEG_ADDR_MASK) >> 16; /* start offset */
+reg |= (seg->addr + seg->size - 1) & AST2700_SEG_ADDR_MASK; /* end offset 
*/
+return reg;
+}
+
+static void aspeed_2700_smc_reg_to_segment(const AspeedSMCState *s,
+   uint32_t reg, AspeedSegments *seg)
+{
+uint32_t start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK;
+uint32_t end_offset = reg & AST2700_SEG_ADDR_MASK;
+AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+
+if (reg) {
+seg->addr = asc->flash_window_base + start_offset;
+seg->size = end_offset + (64 * KiB) - start_offset;
+} else {
+seg->addr = asc->flash_window_base;
+seg->size = 0;
+}
+}
+
+static const uint32_t aspeed_2700_fmc_resets[ASPEED_SMC_R_MAX] = {
+[R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 |
+CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1),
+[R_CE_CTRL] = 0xaa00,
+[R_CTRL0] = 0x406b0641,
+[R_CTRL1] = 0x0400,
+[R_CTRL2] = 0x0400,
+[R_CTRL3] = 0x0400,
+[R_SEG_ADDR0] = 0x0800,
+[R_SEG_ADDR1] = 0x1800,
+[R_SEG_ADDR2] = 0x,
+[R_SEG_ADDR3] = 0x,
+[R_DUMMY_DATA] = 0x0001,
+[R_DMA_DRAM_ADDR_HIGH] = 0x,
+[R_TIMINGS] = 0x007b,
+};
+
+static const MemoryRegionOps aspeed_2700_smc_flash_ops = {
+.read = aspeed_smc_flash_read,
+.write = aspeed_smc_flash_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 8,
+},
+};
+
+static const AspeedSegments aspeed_2700_fmc_segments[] = {
+{ 0x0, 128 * MiB }, /* start address is readonly */
+{ 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
+{ 256 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
+{ 0x0, 0 }, /* disabled */
+};
+
+static void aspeed_2700_fmc_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
+
+dc->desc   = "Aspeed 2700 FMC Controller";
+asc->r_conf= R_CONF;
+asc->r_ce_ctrl = R_CE_CTRL;
+asc->r_ctrl0   = R_CTRL0;
+asc->r_timings = R_TIMINGS;
+asc->nregs_timings = 3;
+asc->conf_enable_w0= CONF_ENABLE_W0;
+asc->cs_num_max= 3;
+asc->segments  = aspeed_2700_fmc_segments;
+asc->segment_addr_mask = 0x;
+asc->resets= aspeed_2700_fmc_resets;
+asc->flash_window_base = 0x1;
+asc->flash_window_size = 1 * GiB;
+asc->features  = ASPEED_SMC_FEATURE_DMA |
+ ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+asc->dma_flash_mask= 0x2FFC;
+asc->dma_dram_mask = 0xFFFC;
+asc->dma_start_length  = 1;
+asc->nregs = ASPEED_SMC_R_MAX;
+asc->segment_to_reg= aspeed_2700_smc_segment_to_reg;
+asc->reg_to_segment= aspeed_2700_smc_reg_to_segment;
+asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_2700_smc_flash_ops;
+}
+
+static const TypeInfo aspeed_2700_fmc_info = {
+.name =  "aspeed.fmc-ast2700",
+.parent = TYPE_ASPEED_SMC,
+.class_init = aspeed_2700_fmc_class_init,
+};
+
+static const AspeedSegm

Re: [PATCH v5 09/17] aspeed/smc: support different memory region ops for SMC flash region

2024-06-03 Thread Cédric Le Goater

On 6/4/24 07:44, Jamin Lin wrote:

It set "aspeed_smc_flash_ops" struct which containing
read and write callbacks to be used when I/O is performed
on the SMC flash region. And it set the valid max_access_size 4
by default for all ASPEED SMC models.

However, the valid max_access_size 4 only support 32 bits CPUs.
To support all ASPEED SMC model, introduce a new
"const MemoryRegionOps *" attribute in AspeedSMCClass and
use it in aspeed_smc_flash_realize function.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 


Reviewed-by: Cédric Le Goater 

Thanks,

C.



---
  hw/ssi/aspeed_smc.c | 14 +-
  include/hw/ssi/aspeed_smc.h |  1 +
  2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index df0c63469c..129d06690d 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -1316,7 +1316,7 @@ static void aspeed_smc_flash_realize(DeviceState *dev, 
Error **errp)
   * Use the default segment value to size the memory region. This
   * can be changed by FW at runtime.
   */
-memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_flash_ops,
+memory_region_init_io(&s->mmio, OBJECT(s), s->asc->reg_ops,
s, name, s->asc->segments[s->cs].size);
  sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
  }
@@ -1391,6 +1391,7 @@ static void aspeed_2400_smc_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2400_smc_info = {

@@ -1441,6 +1442,7 @@ static void aspeed_2400_fmc_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2400_fmc_info = {

@@ -1480,6 +1482,7 @@ static void aspeed_2400_spi1_class_init(ObjectClass 
*klass, void *data)
  asc->reg_to_segment= aspeed_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_smc_dma_ctrl;
  asc->addr_width= aspeed_2400_spi1_addr_width;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2400_spi1_info = {

@@ -1525,6 +1528,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2500_fmc_info = {

@@ -1560,6 +1564,7 @@ static void aspeed_2500_spi1_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2500_spi1_info = {

@@ -1595,6 +1600,7 @@ static void aspeed_2500_spi2_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2500_spi2_info = {

@@ -1682,6 +1688,7 @@ static void aspeed_2600_fmc_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_2600_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_2600_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2600_fmc_info = {

@@ -1721,6 +1728,7 @@ static void aspeed_2600_spi1_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_2600_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_2600_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2600_spi1_info = {

@@ -1761,6 +1769,7 @@ static void aspeed_2600_spi2_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_2600_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_2600_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
  }
  
  static const TypeInfo aspeed_2600_spi2_info = {

@@ -1843,6 +1852,7 @@ static void aspeed_1030_fmc_class_init(ObjectClass 
*klass, void *data)
  asc->segment_to_reg= aspeed_1030_smc_segment_to_reg;
  asc->reg_to_segment= aspeed_1030_smc_reg_to_segment;
  asc->dma_ctrl  = aspeed_2600

Re: [PATCH v5 05/17] aspeed/sdmc: Add AST2700 support

2024-06-03 Thread Cédric Le Goater

On 6/4/24 07:44, Jamin Lin wrote:

The SDRAM memory controller(DRAMC) controls the access to external
DDR4 and DDR5 SDRAM and power up to DDR4 and DDR5 PHY.

The DRAM memory controller of AST2700 is not backward compatible
to previous chips such AST2600, AST2500 and AST2400.

Max memory is now 8GiB on the AST2700. Introduce new
aspeed_2700_sdmc and class with read/write operation and
reset handlers.

Define DRAMC necessary protected registers and
unprotected registers for AST2700 and increase
the register set to 0x1000.

Add unlocked property to change controller protected status.

Incrementing the version of vmstate to 2.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 


Reviewed-by: Cédric Le Goater 


Thanks,

C.




---
  hw/misc/aspeed_sdmc.c | 194 +-
  include/hw/misc/aspeed_sdmc.h |   5 +-
  2 files changed, 195 insertions(+), 4 deletions(-)

diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 873d67c592..93e2e29ead 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -27,6 +27,7 @@
  #define   PROT_SOFTLOCKED0x00
  
  #define   PROT_KEY_UNLOCK 0xFC600309

+#define   PROT_2700_KEY_UNLOCK  0x1688A8A8
  #define   PROT_KEY_HARDLOCK   0xDEADDEAD /* AST2600 */
  
  /* Configuration Register */

@@ -54,6 +55,46 @@
  #define R_DRAM_TIME   (0x8c / 4)
  #define R_ECC_ERR_INJECT  (0xb4 / 4)
  
+/* AST2700 Register */

+#define R_2700_PROT (0x00 / 4)
+#define R_INT_STATUS(0x04 / 4)
+#define R_INT_CLEAR (0x08 / 4)
+#define R_INT_MASK  (0x0c / 4)
+#define R_MAIN_CONF (0x10 / 4)
+#define R_MAIN_CONTROL  (0x14 / 4)
+#define R_MAIN_STATUS   (0x18 / 4)
+#define R_ERR_STATUS(0x1c / 4)
+#define R_ECC_FAIL_STATUS   (0x78 / 4)
+#define R_ECC_FAIL_ADDR (0x7c / 4)
+#define R_ECC_TESTING_CONTROL   (0x80 / 4)
+#define R_PROT_REGION_LOCK_STATUS   (0x94 / 4)
+#define R_TEST_FAIL_ADDR(0xd4 / 4)
+#define R_TEST_FAIL_D0  (0xd8 / 4)
+#define R_TEST_FAIL_D1  (0xdc / 4)
+#define R_TEST_FAIL_D2  (0xe0 / 4)
+#define R_TEST_FAIL_D3  (0xe4 / 4)
+#define R_DBG_STATUS(0xf4 / 4)
+#define R_PHY_INTERFACE_STATUS  (0xf8 / 4)
+#define R_GRAPHIC_MEM_BASE_ADDR (0x10c / 4)
+#define R_PORT0_INTERFACE_MONITOR0  (0x240 / 4)
+#define R_PORT0_INTERFACE_MONITOR1  (0x244 / 4)
+#define R_PORT0_INTERFACE_MONITOR2  (0x248 / 4)
+#define R_PORT1_INTERFACE_MONITOR0  (0x2c0 / 4)
+#define R_PORT1_INTERFACE_MONITOR1  (0x2c4 / 4)
+#define R_PORT1_INTERFACE_MONITOR2  (0x2c8 / 4)
+#define R_PORT2_INTERFACE_MONITOR0  (0x340 / 4)
+#define R_PORT2_INTERFACE_MONITOR1  (0x344 / 4)
+#define R_PORT2_INTERFACE_MONITOR2  (0x348 / 4)
+#define R_PORT3_INTERFACE_MONITOR0  (0x3c0 / 4)
+#define R_PORT3_INTERFACE_MONITOR1  (0x3c4 / 4)
+#define R_PORT3_INTERFACE_MONITOR2  (0x3c8 / 4)
+#define R_PORT4_INTERFACE_MONITOR0  (0x440 / 4)
+#define R_PORT4_INTERFACE_MONITOR1  (0x444 / 4)
+#define R_PORT4_INTERFACE_MONITOR2  (0x448 / 4)
+#define R_PORT5_INTERFACE_MONITOR0  (0x4c0 / 4)
+#define R_PORT5_INTERFACE_MONITOR1  (0x4c4 / 4)
+#define R_PORT5_INTERFACE_MONITOR2  (0x4c8 / 4)
+
  /*
   * Configuration register Ox4 (for Aspeed AST2400 SOC)
   *
@@ -101,6 +142,19 @@
   ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |\
   ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
  
+/*

+ * Main Configuration register Ox10 (for Aspeed AST2700 SOC and higher)
+ *
+ */
+#define ASPEED_SDMC_AST2700_RESERVED0x2082 /* 31:16, 13, 7, 1 */
+#define ASPEED_SDMC_AST2700_DATA_SCRAMBLE   (1 << 8)
+#define ASPEED_SDMC_AST2700_ECC_ENABLE  (1 << 6)
+#define ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE(1 << 5)
+#define ASPEED_SDMC_AST2700_DRAM_SIZE(x)((x & 0x7) << 2)
+
+#define ASPEED_SDMC_AST2700_READONLY_MASK   \
+ (ASPEED_SDMC_AST2700_RESERVED)
+
  static uint64_t aspeed_sdmc_read(void *opaque, hwaddr addr, unsigned size)
  {
  AspeedSDMCState *s = ASPEED_SDMC(opaque);
@@ -216,7 +270,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error 
**errp)
  AspeedSDMCState *s = ASPEED_SDMC(dev);
  AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
  
-assert(asc->max_ram_size < 4 * GiB); /* 32-bit address bus */

+assert(asc->max_ram_size < 4 * GiB || asc->is_bus64bit);
  s->max_ram_size = asc->max_ram_size;
  
  memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,

@@ -226,8 +280,8 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error 
**errp)
  
  static const VMStateDescription vmstate_aspeed_sdmc = {

  .name = "aspeed.sdmc",
-.version_id = 1,
-.minimum_version_id = 1,
+.version_id = 2,
+.minimum_version_id = 2,
  .fields = (const VMStateField[]) {
  VMSTATE_UINT32_ARRAY(regs, AspeedSDMCState, ASPEED_SDMC_NR_REGS),
  VMSTATE_END_OF_LIST()
@@ -236,6

Re: [PATCH 2/2] target/ppc/cpu_init: Synchronize HASHKEYR with KVM for migration

2024-06-03 Thread Nicholas Piggin
On Mon Jun 3, 2024 at 9:53 PM AEST, Shivaprasad G Bhat wrote:
> The patch enables HASHKEYR migration by hooking with the
> "KVM one reg" ID KVM_REG_PPC_HASHKEYR.
>
> Signed-off-by: Shivaprasad G Bhat 
> ---
>  linux-headers/asm-powerpc/kvm.h |1 +
>  target/ppc/cpu_init.c   |4 ++--
>  2 files changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
> index fcb947f656..23a0af739c 100644
> --- a/linux-headers/asm-powerpc/kvm.h
> +++ b/linux-headers/asm-powerpc/kvm.h
> @@ -646,6 +646,7 @@ struct kvm_ppc_cpu_char {
>  #define KVM_REG_PPC_DAWR1(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc4)
>  #define KVM_REG_PPC_DAWRX1   (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc5)
>  #define KVM_REG_PPC_DEXCR(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc6)
> +#define KVM_REG_PPC_HASHKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc7)
>  
>  /* Transactional Memory checkpointed state:
>   * This is all GPRs, all VSX regs and a subset of SPRs
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index b1422c2eab..cee0a609eb 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -5805,10 +5805,10 @@ static void register_power10_hash_sprs(CPUPPCState 
> *env)
>  ((uint64_t)g_rand_int(rand) << 32) | (uint64_t)g_rand_int(rand);
>  g_rand_free(rand);
>  #endif
> -spr_register(env, SPR_HASHKEYR, "HASHKEYR",
> +spr_register_kvm(env, SPR_HASHKEYR, "HASHKEYR",
>  SPR_NOACCESS, SPR_NOACCESS,
>  &spr_read_generic, &spr_write_generic,
> -hashkeyr_initial_value);
> +KVM_REG_PPC_HASHKEYR, hashkeyr_initial_value);
>  spr_register_hv(env, SPR_HASHPKEYR, "HASHPKEYR",
>  SPR_NOACCESS, SPR_NOACCESS,
>  SPR_NOACCESS, SPR_NOACCESS,

Hmm... now that I look at it, the hashpkey value also needs to be set
in the machine and migrated, right? That looks broken. I *think* if we
make this spr_register_kvm_hv, and you will also need to add a KVM
API for the register, that should get it working becuse SPRs will
be migrated for us.

Thanks,
Nick



Re: [PATCH v2] chardev: add path option for pty backend

2024-06-03 Thread Marc-André Lureau
On Tue, Jun 4, 2024 at 1:22 AM Octavian Purdila  wrote:
>
> Add path option to the pty char backend which will create a symbolic
> link to the given path that points to the allocated PTY.
>
> This avoids having to make QMP or HMP monitor queries to find out what
> the new PTY device path is.
>
> Based on patch from Paulo Neves:
>
> https://patchew.org/QEMU/1548509635-15776-1-git-send-email-ptsne...@gmail.com/
>
> Tested with the following invocations that the link is created and
> removed when qemu stops:
>
>   qemu-system-x86_64 -nodefaults -mon chardev=compat_monitor \
>   -chardev pty,path=test,id=compat_monitor0
>
>   qemu-system-x86_64 -nodefaults -monitor pty:test
>
> Also tested that when a link path is not passed invocations still work, e.g.:
>
>   qemu-system-x86_64 -monitor pty
>
> Co-authored-by: Paulo Neves 
> Signed-off-by: Paulo Neves 
> [OP: rebase and address original patch review comments]
> Signed-off-by: Octavian Purdila 
> ---
> Changes since v1:
>
>  * Keep the original Signed-off-by from Paulo and add one line
> description with further changes
>
>  * Update commit message with justification for why the new
> functionality is useful
>
>  * Don't close master_fd when symlink creation fails to avoid double
> close
>
>  * Update documentation for clarity
>
>  chardev/char-pty.c | 33 +
>  chardev/char.c |  5 +
>  qapi/char.json |  4 ++--
>  qemu-options.hx| 24 ++--
>  4 files changed, 58 insertions(+), 8 deletions(-)
>
> diff --git a/chardev/char-pty.c b/chardev/char-pty.c
> index cc2f7617fe..b5a4eb59fc 100644
> --- a/chardev/char-pty.c
> +++ b/chardev/char-pty.c
> @@ -29,6 +29,7 @@
>  #include "qemu/sockets.h"
>  #include "qemu/error-report.h"
>  #include "qemu/module.h"
> +#include "qemu/option.h"
>  #include "qemu/qemu-print.h"
>
>  #include "chardev/char-io.h"
> @@ -41,6 +42,7 @@ struct PtyChardev {
>
>  int connected;
>  GSource *timer_src;
> +char *symlink_path;
>  };
>  typedef struct PtyChardev PtyChardev;
>
> @@ -204,6 +206,12 @@ static void char_pty_finalize(Object *obj)
>  Chardev *chr = CHARDEV(obj);
>  PtyChardev *s = PTY_CHARDEV(obj);
>
> +/* unlink symlink */
> +if (s->symlink_path) {
> +unlink(s->symlink_path);
> +g_free(s->symlink_path);
> +}
> +
>  pty_chr_state(chr, 0);
>  object_unref(OBJECT(s->ioc));
>  pty_chr_timer_cancel(s);
> @@ -330,6 +338,7 @@ static void char_pty_open(Chardev *chr,
>  int master_fd, slave_fd;
>  char pty_name[PATH_MAX];
>  char *name;
> +char *symlink_path = backend->u.pty.data->device;
>
>  master_fd = qemu_openpty_raw(&slave_fd, pty_name);
>  if (master_fd < 0) {
> @@ -354,12 +363,36 @@ static void char_pty_open(Chardev *chr,
>  g_free(name);
>  s->timer_src = NULL;
>  *be_opened = false;
> +
> +/* create symbolic link */
> +if (symlink_path) {
> +int res = symlink(pty_name, symlink_path);
> +
> +if (res != 0) {
> +error_setg_errno(errp, errno, "Failed to create PTY symlink");
> +} else {
> +s->symlink_path = g_strdup(symlink_path);
> +}
> +}
> +}
> +
> +static void char_pty_parse(QemuOpts *opts, ChardevBackend *backend,
> +   Error **errp)
> +{
> +const char *path = qemu_opt_get(opts, "path");
> +ChardevHostdev *dev;
> +
> +backend->type = CHARDEV_BACKEND_KIND_PTY;
> +dev = backend->u.pty.data = g_new0(ChardevHostdev, 1);
> +qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
> +dev->device = path ? g_strdup(path) : NULL;

minor nit, g_strdup(NULL) returns NULL. Get rid of "?:" if you send a v3.

>  }
>
>  static void char_pty_class_init(ObjectClass *oc, void *data)
>  {
>  ChardevClass *cc = CHARDEV_CLASS(oc);
>
> +cc->parse = char_pty_parse;
>  cc->open = char_pty_open;
>  cc->chr_write = char_pty_chr_write;
>  cc->chr_update_read_handler = pty_chr_update_read_handler;
> diff --git a/chardev/char.c b/chardev/char.c
> index 3c43fb1278..404c6b8a4f 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -428,6 +428,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const 
> char *filename,
>  qemu_opt_set(opts, "path", p, &error_abort);
>  return opts;
>  }
> +if (strstart(filename, "pty:", &p)) {
> +qemu_opt_set(opts, "backend", "pty", &error_abort);
> +qemu_opt_set(opts, "path", p, &error_abort);
> +return opts;
> +}
>  if (strstart(filename, "tcp:", &p) ||
>  strstart(filename, "telnet:", &p) ||
>  strstart(filename, "tn3270:", &p) ||
> diff --git a/qapi/char.json b/qapi/char.json
> index 777dde55d9..4c74bfc437 100644
> --- a/qapi/char.json
> +++ b/qapi/char.json
> @@ -509,7 +509,7 @@
>  ##
>  # @ChardevHostdevWrapper:
>  #
> -# @data: Configuration info for device and pipe chardevs
> +# @data: Configuration info for device, pty and pipe chardevs

[PATCH v5 03/17] aspeed/sdmc: remove redundant macros

2024-06-03 Thread Jamin Lin via
These macros are no longer used for ASPEED SOCs, so removes them.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/misc/aspeed_sdmc.c | 15 ---
 1 file changed, 15 deletions(-)

diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 64cd1a81dc..74279bbe8e 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -76,10 +76,6 @@
 #define ASPEED_SDMC_VGA_32MB0x2
 #define ASPEED_SDMC_VGA_64MB0x3
 #define ASPEED_SDMC_DRAM_SIZE(x)(x & 0x3)
-#define ASPEED_SDMC_DRAM_64MB   0x0
-#define ASPEED_SDMC_DRAM_128MB  0x1
-#define ASPEED_SDMC_DRAM_256MB  0x2
-#define ASPEED_SDMC_DRAM_512MB  0x3
 
 #define ASPEED_SDMC_READONLY_MASK   \
 (ASPEED_SDMC_RESERVED | ASPEED_SDMC_VGA_COMPAT |\
@@ -100,17 +96,6 @@
 #define ASPEED_SDMC_CACHE_ENABLE(1 << 10) /* differs from AST2400 */
 #define ASPEED_SDMC_DRAM_TYPE   (1 << 4)  /* differs from AST2400 */
 
-/* DRAM size definitions differs */
-#define ASPEED_SDMC_AST2500_128MB   0x0
-#define ASPEED_SDMC_AST2500_256MB   0x1
-#define ASPEED_SDMC_AST2500_512MB   0x2
-#define ASPEED_SDMC_AST2500_1024MB  0x3
-
-#define ASPEED_SDMC_AST2600_256MB   0x0
-#define ASPEED_SDMC_AST2600_512MB   0x1
-#define ASPEED_SDMC_AST2600_1024MB  0x2
-#define ASPEED_SDMC_AST2600_2048MB  0x3
-
 #define ASPEED_SDMC_AST2500_READONLY_MASK   \
 (ASPEED_SDMC_HW_VERSION(0xf) | ASPEED_SDMC_CACHE_INITIAL_DONE | \
  ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |\
-- 
2.25.1




[PATCH v5 08/17] aspeed/smc: support 64 bits dma dram address

2024-06-03 Thread Jamin Lin via
AST2700 support the maximum dram size is 8GiB
and has a "DMA DRAM Side Address High Part(0x7C)"
register to support 64 bits dma dram address.
Add helper routines functions to compute the dma dram
address, new features and update trace-event
to support 64 bits dram address.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/ssi/aspeed_smc.c | 51 ++---
 hw/ssi/trace-events |  2 +-
 2 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 0b8488a113..df0c63469c 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -132,6 +132,9 @@
 #define   FMC_WDT2_CTRL_BOOT_SOURCE  BIT(4) /* O: primary 1: alternate */
 #define   FMC_WDT2_CTRL_EN   BIT(0)
 
+/* DMA DRAM Side Address High Part (AST2700) */
+#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
+
 /* DMA Control/Status Register */
 #define R_DMA_CTRL(0x80 / 4)
 #define   DMA_CTRL_REQUEST  (1 << 31)
@@ -187,6 +190,7 @@
  *   0x1FF: 32M bytes
  */
 #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
+#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
 #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
 #define DMA_LENGTH(val) ((val) & 0x01FF)
 
@@ -207,6 +211,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[];
 #define ASPEED_SMC_FEATURE_DMA   0x1
 #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
 #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
+#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
 
 static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
 {
@@ -218,6 +223,11 @@ static inline bool aspeed_smc_has_wdt_control(const 
AspeedSMCClass *asc)
 return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
 }
 
+static inline bool aspeed_smc_has_dma64(const AspeedSMCClass *asc)
+{
+return !!(asc->features & ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
+}
+
 #define aspeed_smc_error(fmt, ...)  \
 qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__)
 
@@ -747,6 +757,8 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, 
unsigned int size)
 (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
 (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR) ||
 (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR) ||
+(aspeed_smc_has_dma(asc) && aspeed_smc_has_dma64(asc) &&
+ addr == R_DMA_DRAM_ADDR_HIGH) ||
 (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
 (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM) ||
 (addr >= R_SEG_ADDR0 &&
@@ -847,6 +859,12 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState 
*s)
 }
 }
 
+static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s)
+{
+return s->regs[R_DMA_DRAM_ADDR] |
+((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32);
+}
+
 static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
 {
 AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
@@ -903,24 +921,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
 
 static void aspeed_smc_dma_rw(AspeedSMCState *s)
 {
+AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+uint64_t dma_dram_offset;
+uint64_t dma_dram_addr;
 MemTxResult result;
 uint32_t dma_len;
 uint32_t data;
 
 dma_len = aspeed_smc_dma_len(s);
+dma_dram_addr = aspeed_smc_dma_dram_addr(s);
+
+if (aspeed_smc_has_dma64(asc)) {
+dma_dram_offset = dma_dram_addr - s->dram_base;
+} else {
+dma_dram_offset = dma_dram_addr;
+}
 
 trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
 "write" : "read",
 s->regs[R_DMA_FLASH_ADDR],
-s->regs[R_DMA_DRAM_ADDR],
+dma_dram_offset,
 dma_len);
 while (dma_len) {
 if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
-data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
+data = address_space_ldl_le(&s->dram_as, dma_dram_offset,
 MEMTXATTRS_UNSPECIFIED, &result);
 if (result != MEMTX_OK) {
-aspeed_smc_error("DRAM read failed @%08x",
- s->regs[R_DMA_DRAM_ADDR]);
+aspeed_smc_error("DRAM read failed @%" PRIx64,
+ dma_dram_offset);
 return;
 }
 
@@ -940,11 +968,11 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
 return;
 }
 
-address_space_stl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
+address_space_stl_le(&s->dram_as, dma_dram_offset,
  data, MEMTXATTRS_UNSPECIFIED, &result);
 if (result != MEMTX_OK) {
-aspeed_smc_error("DRAM write failed @%08x",
- s->regs[R_DMA_DR

[PATCH v5 16/17] test/avocado/machine_aspeed.py: Add AST2700 test case

2024-06-03 Thread Jamin Lin via
Add a test case to test Aspeed OpenBMC SDK v09.01 on AST2700 board.

It loads u-boot-nodtb.bin, u-boot.dtb, tfa and optee-os
images to dram first which base address is 0x4.
Then, boot and launch 4 cpu cores.

```
qemu-system-aarch64 -machine ast2700-evb
-device loader,force-raw=on,addr=0x4,file=workdir/u-boot-nodtb.bin \
-device 
loader,force-raw=on,addr=uboot_dtb_load_addr,file=workdir/u-boot.dtb\
-device loader,force-raw=on,addr=0x43000,file=workdir/bl31.bin\
-device loader,force-raw=on,addr=0x43008,file=workdir/optee/tee-raw.bin\
-device loader,cpu-num=0,addr=0x43000 \
-device loader,cpu-num=1,addr=0x43000 \
-device loader,cpu-num=2,addr=0x43000 \
-device loader,cpu-num=3,addr=0x43000 \
-smp 4 \
-drive file=workdir/image-bmc,format=raw,if=mtd
```

A test image is downloaded from the ASPEED Forked OpenBMC GitHub release 
repository :
https://github.com/AspeedTech-BMC/openbmc/releases/

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 tests/avocado/machine_aspeed.py | 62 +
 1 file changed, 62 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index cec0181424..3a20644fb2 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -311,6 +311,17 @@ def do_test_arm_aspeed_sdk_start(self, image):
 self, 'boot', '## Loading kernel from FIT Image')
 self.wait_for_console_pattern('Starting kernel ...')
 
+def do_test_aarch64_aspeed_sdk_start(self, image):
+self.vm.set_console()
+self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw')
+
+self.vm.launch()
+
+self.wait_for_console_pattern('U-Boot 2023.10')
+self.wait_for_console_pattern('## Loading kernel from FIT Image')
+self.wait_for_console_pattern('Starting kernel ...')
+self.wait_for_console_pattern("systemd[1]: Hostname set to")
+
 @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on 
GitLab')
 
 def test_arm_ast2500_evb_sdk(self):
@@ -375,3 +386,54 @@ def test_arm_ast2600_evb_sdk(self):
  'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
 year = time.strftime("%Y")
 self.ssh_command_output_contains('/sbin/hwclock -f /dev/rtc1', year);
+
+def test_aarch64_ast2700_evb_sdk_v09_01(self):
+"""
+:avocado: tags=arch:aarch64
+:avocado: tags=machine:ast2700-evb
+"""
+
+image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
+ 'download/v09.01/ast2700-default-obmc.tar.gz')
+image_hash = 
'b1cc0fd73c7650d34c9c8459a243f52a91e9e27144b8608b2645ab19461d1e07'
+image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+  algorithm='sha256')
+archive.extract(image_path, self.workdir)
+
+num_cpu = 4
+image_dir = self.workdir + '/ast2700-default/'
+uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin')
+uboot_dtb_load_addr = hex(0x4 + uboot_size)
+
+load_images_list = [
+{
+'addr': '0x4',
+'file': image_dir + 'u-boot-nodtb.bin'
+},
+{
+'addr': str(uboot_dtb_load_addr),
+'file': image_dir + 'u-boot.dtb'
+},
+{
+'addr': '0x43000',
+'file': image_dir + 'bl31.bin'
+},
+{
+'addr': '0x43008',
+'file': image_dir + 'optee/tee-raw.bin'
+}
+]
+
+for load_image in load_images_list:
+addr = load_image['addr']
+file = load_image['file']
+self.vm.add_args('-device',
+ f'loader,force-raw=on,addr={addr},file={file}')
+
+for i in range(num_cpu):
+self.vm.add_args('-device',
+ f'loader,addr=0x43000,cpu-num={i}')
+
+self.vm.add_args('-smp', str(num_cpu))
+self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
+
-- 
2.25.1




RE: [PATCH v6 18/19] intel_iommu: Implement [set|unset]_iommu_device() callbacks

2024-06-03 Thread Duan, Zhenzhong


>-Original Message-
>From: Eric Auger 
>Subject: Re: [PATCH v6 18/19] intel_iommu: Implement
>[set|unset]_iommu_device() callbacks
>
>
>
>On 6/3/24 08:10, Zhenzhong Duan wrote:
>> From: Yi Liu 
>>
>> Implement [set|unset]_iommu_device() callbacks in Intel vIOMMU.
>> In set call, a new structure VTDHostIOMMUDevice which holds
>> a reference to HostIOMMUDevice is stored in hash table
>> indexed by PCI BDF.
>>
>> Signed-off-by: Yi Liu 
>> Signed-off-by: Yi Sun 
>> Signed-off-by: Zhenzhong Duan 
>> ---
>>  hw/i386/intel_iommu_internal.h |  9 
>>  include/hw/i386/intel_iommu.h  |  2 +
>>  hw/i386/intel_iommu.c  | 76
>++
>>  3 files changed, 87 insertions(+)
>>
>> diff --git a/hw/i386/intel_iommu_internal.h
>b/hw/i386/intel_iommu_internal.h
>> index f8cf99bddf..b800d62ca0 100644
>> --- a/hw/i386/intel_iommu_internal.h
>> +++ b/hw/i386/intel_iommu_internal.h
>> @@ -28,6 +28,7 @@
>>  #ifndef HW_I386_INTEL_IOMMU_INTERNAL_H
>>  #define HW_I386_INTEL_IOMMU_INTERNAL_H
>>  #include "hw/i386/intel_iommu.h"
>> +#include "sysemu/host_iommu_device.h"
>>
>>  /*
>>   * Intel IOMMU register specification
>> @@ -537,4 +538,12 @@ typedef struct VTDRootEntry VTDRootEntry;
>>  #define VTD_SL_IGN_COM  0xbff0ULL
>>  #define VTD_SL_TM   (1ULL << 62)
>>
>> +
>> +typedef struct VTDHostIOMMUDevice {
>> +IntelIOMMUState *iommu_state;
>> +PCIBus *bus;
>> +uint8_t devfn;
>> +HostIOMMUDevice *dev;
>> +QLIST_ENTRY(VTDHostIOMMUDevice) next;
>> +} VTDHostIOMMUDevice;
>>  #endif
>> diff --git a/include/hw/i386/intel_iommu.h
>b/include/hw/i386/intel_iommu.h
>> index 7d694b0813..2bbde41e45 100644
>> --- a/include/hw/i386/intel_iommu.h
>> +++ b/include/hw/i386/intel_iommu.h
>> @@ -293,6 +293,8 @@ struct IntelIOMMUState {
>>  /* list of registered notifiers */
>>  QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers;
>>
>> +GHashTable *vtd_host_iommu_dev; /* VTDHostIOMMUDevice
>*/
>> +
>>  /* interrupt remapping */
>>  bool intr_enabled;  /* Whether guest enabled IR */
>>  dma_addr_t intr_root;   /* Interrupt remapping table pointer */
>> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
>> index 519063c8f8..747c988bc4 100644
>> --- a/hw/i386/intel_iommu.c
>> +++ b/hw/i386/intel_iommu.c
>> @@ -237,6 +237,13 @@ static gboolean vtd_as_equal(gconstpointer v1,
>gconstpointer v2)
>> (key1->pasid == key2->pasid);
>>  }
>>
>> +static gboolean vtd_as_idev_equal(gconstpointer v1, gconstpointer v2)
>> +{
>> +const struct vtd_as_key *key1 = v1;
>> +const struct vtd_as_key *key2 = v2;
>> +
>> +return (key1->bus == key2->bus) && (key1->devfn == key2->devfn);
>> +}
>>  /*
>>   * Note that we use pointer to PCIBus as the key, so hashing/shifting
>>   * based on the pointer value is intended. Note that we deal with
>> @@ -3812,6 +3819,70 @@ VTDAddressSpace
>*vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
>>  return vtd_dev_as;
>>  }
>>
>> +static bool vtd_dev_set_iommu_device(PCIBus *bus, void *opaque, int
>devfn,
>> + HostIOMMUDevice *hiod, Error **errp)
>> +{
>> +IntelIOMMUState *s = opaque;
>> +VTDHostIOMMUDevice *vtd_hdev;
>> +struct vtd_as_key key = {
>> +.bus = bus,
>> +.devfn = devfn,
>> +};
>> +struct vtd_as_key *new_key;
>> +
>> +assert(hiod);
>> +
>> +vtd_iommu_lock(s);
>> +
>> +vtd_hdev = g_hash_table_lookup(s->vtd_host_iommu_dev, &key);
>> +
>> +if (vtd_hdev) {
>> +error_setg(errp, "IOMMUFD device already exist");
>> +vtd_iommu_unlock(s);
>> +return false;
>> +}
>> +
>> +vtd_hdev = g_malloc0(sizeof(VTDHostIOMMUDevice));
>> +vtd_hdev->bus = bus;
>> +vtd_hdev->devfn = (uint8_t)devfn;
>> +vtd_hdev->iommu_state = s;
>> +vtd_hdev->dev = hiod;
>I am still not totally clear about why we couldn't reuse VTDAddressSpace
>instance for this bus/devid. Is it a matter of aliased versus non
>aliased bus/devfn, or a matter of pasid diff. An AddressSpace could back
>an assigned device in which case a HostIOMMUDevice could be added to
>this latter. I think this should be explained in the commit msg

Yes, as you said, it's a matter of aliased vs non aliased BDF.

VTDAddressSpace is per aliased BDF while VTDHostIOMMUDevice is per non aliased 
BDF.
There can be multiple assigned devices under same virtual iommu group and share 
same 
VTDAddressSpace, but they have their own VTDHostIOMMUDevice.

Will refine commit msg.

Thanks
Zhenzhong

>
>Eric
>> +
>> +new_key = g_malloc(sizeof(*new_key));
>> +new_key->bus = bus;
>> +new_key->devfn = devfn;
>> +
>> +object_ref(hiod);
>> +g_hash_table_insert(s->vtd_host_iommu_dev, new_key, vtd_hdev);
>> +
>> +vtd_iommu_unlock(s);
>> +
>> +return true;
>> +}
>> +
>> +static void vtd_dev_unset_iommu_device(PCIBus *bus, void *opaque, int
>devfn)
>> +{
>> +IntelIOMMUState *

[PATCH v5 04/17] aspeed/sdmc: fix coding style

2024-06-03 Thread Jamin Lin via
Fix coding style issues from checkpatch.pl

Test command:
scripts/checkpatch.pl --no-tree -f hw/misc/aspeed_sdmc.c

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/misc/aspeed_sdmc.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 74279bbe8e..873d67c592 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -296,7 +296,8 @@ static void aspeed_2400_sdmc_write(AspeedSDMCState *s, 
uint32_t reg,
uint32_t data)
 {
 if (reg == R_PROT) {
-s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : 
PROT_SOFTLOCKED;
+s->regs[reg] =
+(data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
 return;
 }
 
@@ -354,7 +355,8 @@ static void aspeed_2500_sdmc_write(AspeedSDMCState *s, 
uint32_t reg,
uint32_t data)
 {
 if (reg == R_PROT) {
-s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : 
PROT_SOFTLOCKED;
+s->regs[reg] =
+(data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
 return;
 }
 
@@ -434,8 +436,9 @@ static void aspeed_2600_sdmc_write(AspeedSDMCState *s, 
uint32_t reg,
 }
 
 if (s->regs[R_PROT] == PROT_HARDLOCKED) {
-qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked until system 
reset!\n",
-__func__);
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: SDMC is locked until system reset!\n",
+  __func__);
 return;
 }
 
-- 
2.25.1




[PATCH v5 07/17] aspeed/smc: support dma start length and 1 byte length unit

2024-06-03 Thread Jamin Lin via
DMA length is from 1 byte to 32MB for AST2600 and AST10x0
and DMA length is from 4 bytes to 32MB for AST2500.

In other words, if "R_DMA_LEN" is 0, it should move at least 1 byte
data for AST2600 and AST10x0 and 4 bytes data for AST2500.
To support all ASPEED SOCs, adds dma_start_length parameter to store
the start length, add helper routines function to compute the dma length
and update DMA_LENGTH mask to "1FF" to support dma 1 byte
length unit for AST2600 and AST1030.
Currently, only supports dma length 4 bytes aligned.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/ssi/aspeed_smc.c | 43 ++---
 include/hw/ssi/aspeed_smc.h |  1 +
 2 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index fe1cd96b80..0b8488a113 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -178,13 +178,17 @@
  * DMA flash addresses should be 4 bytes aligned and the valid address
  * range is 0x2000 - 0x2FFF.
  *
- * DMA length is from 4 bytes to 32MB
+ * DMA length is from 4 bytes to 32MB (AST2500)
  *   0: 4 bytes
- *   0x7F: 32M bytes
+ *   0x1FC: 32M bytes
+ *
+ * DMA length is from 1 byte to 32MB (AST2600, AST10x0)
+ *   0: 1 byte
+ *   0x1FF: 32M bytes
  */
 #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
 #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
-#define DMA_LENGTH(val) ((val) & 0x01FC)
+#define DMA_LENGTH(val) ((val) & 0x01FF)
 
 /* Flash opcodes. */
 #define SPI_OP_READ   0x03/* Read data bytes (low frequency) */
@@ -843,6 +847,13 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState 
*s)
 }
 }
 
+static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
+{
+AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+
+return QEMU_ALIGN_UP(s->regs[R_DMA_LEN] + asc->dma_start_length, 4);
+}
+
 /*
  * Accumulate the result of the reads to provide a checksum that will
  * be used to validate the read timing settings.
@@ -850,6 +861,7 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState 
*s)
 static void aspeed_smc_dma_checksum(AspeedSMCState *s)
 {
 MemTxResult result;
+uint32_t dma_len;
 uint32_t data;
 
 if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
@@ -861,7 +873,9 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
 aspeed_smc_dma_calibration(s);
 }
 
-while (s->regs[R_DMA_LEN]) {
+dma_len = aspeed_smc_dma_len(s);
+
+while (dma_len) {
 data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR],
 MEMTXATTRS_UNSPECIFIED, &result);
 if (result != MEMTX_OK) {
@@ -877,7 +891,8 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
  */
 s->regs[R_DMA_CHECKSUM] += data;
 s->regs[R_DMA_FLASH_ADDR] += 4;
-s->regs[R_DMA_LEN] -= 4;
+dma_len -= 4;
+s->regs[R_DMA_LEN] = dma_len;
 }
 
 if (s->inject_failure && aspeed_smc_inject_read_failure(s)) {
@@ -889,14 +904,17 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
 static void aspeed_smc_dma_rw(AspeedSMCState *s)
 {
 MemTxResult result;
+uint32_t dma_len;
 uint32_t data;
 
+dma_len = aspeed_smc_dma_len(s);
+
 trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
 "write" : "read",
 s->regs[R_DMA_FLASH_ADDR],
 s->regs[R_DMA_DRAM_ADDR],
-s->regs[R_DMA_LEN]);
-while (s->regs[R_DMA_LEN]) {
+dma_len);
+while (dma_len) {
 if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
 data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
 MEMTXATTRS_UNSPECIFIED, &result);
@@ -937,7 +955,8 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
  */
 s->regs[R_DMA_FLASH_ADDR] += 4;
 s->regs[R_DMA_DRAM_ADDR] += 4;
-s->regs[R_DMA_LEN] -= 4;
+dma_len -= 4;
+s->regs[R_DMA_LEN] = dma_len;
 s->regs[R_DMA_CHECKSUM] += data;
 }
 }
@@ -1382,6 +1401,7 @@ static void aspeed_2400_fmc_class_init(ObjectClass 
*klass, void *data)
 asc->features  = ASPEED_SMC_FEATURE_DMA;
 asc->dma_flash_mask= 0x0FFC;
 asc->dma_dram_mask = 0x1FFC;
+asc->dma_start_length  = 4;
 asc->nregs = ASPEED_SMC_R_MAX;
 asc->segment_to_reg= aspeed_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_smc_reg_to_segment;
@@ -1465,6 +1485,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass 
*klass, void *data)
 asc->features  = ASPEED_SMC_FEATURE_DMA;
 asc->dma_flash_mask= 0x0FFC;
 asc->dma_dram_mask = 0x3FFC;
+asc->dma_start_length  = 4;
 asc->nregs = ASPEED_SMC_R_MAX;
 asc->segment_to_reg= aspeed_smc_seg

[PATCH v5 05/17] aspeed/sdmc: Add AST2700 support

2024-06-03 Thread Jamin Lin via
The SDRAM memory controller(DRAMC) controls the access to external
DDR4 and DDR5 SDRAM and power up to DDR4 and DDR5 PHY.

The DRAM memory controller of AST2700 is not backward compatible
to previous chips such AST2600, AST2500 and AST2400.

Max memory is now 8GiB on the AST2700. Introduce new
aspeed_2700_sdmc and class with read/write operation and
reset handlers.

Define DRAMC necessary protected registers and
unprotected registers for AST2700 and increase
the register set to 0x1000.

Add unlocked property to change controller protected status.

Incrementing the version of vmstate to 2.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
---
 hw/misc/aspeed_sdmc.c | 194 +-
 include/hw/misc/aspeed_sdmc.h |   5 +-
 2 files changed, 195 insertions(+), 4 deletions(-)

diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 873d67c592..93e2e29ead 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -27,6 +27,7 @@
 #define   PROT_SOFTLOCKED0x00
 
 #define   PROT_KEY_UNLOCK 0xFC600309
+#define   PROT_2700_KEY_UNLOCK  0x1688A8A8
 #define   PROT_KEY_HARDLOCK   0xDEADDEAD /* AST2600 */
 
 /* Configuration Register */
@@ -54,6 +55,46 @@
 #define R_DRAM_TIME   (0x8c / 4)
 #define R_ECC_ERR_INJECT  (0xb4 / 4)
 
+/* AST2700 Register */
+#define R_2700_PROT (0x00 / 4)
+#define R_INT_STATUS(0x04 / 4)
+#define R_INT_CLEAR (0x08 / 4)
+#define R_INT_MASK  (0x0c / 4)
+#define R_MAIN_CONF (0x10 / 4)
+#define R_MAIN_CONTROL  (0x14 / 4)
+#define R_MAIN_STATUS   (0x18 / 4)
+#define R_ERR_STATUS(0x1c / 4)
+#define R_ECC_FAIL_STATUS   (0x78 / 4)
+#define R_ECC_FAIL_ADDR (0x7c / 4)
+#define R_ECC_TESTING_CONTROL   (0x80 / 4)
+#define R_PROT_REGION_LOCK_STATUS   (0x94 / 4)
+#define R_TEST_FAIL_ADDR(0xd4 / 4)
+#define R_TEST_FAIL_D0  (0xd8 / 4)
+#define R_TEST_FAIL_D1  (0xdc / 4)
+#define R_TEST_FAIL_D2  (0xe0 / 4)
+#define R_TEST_FAIL_D3  (0xe4 / 4)
+#define R_DBG_STATUS(0xf4 / 4)
+#define R_PHY_INTERFACE_STATUS  (0xf8 / 4)
+#define R_GRAPHIC_MEM_BASE_ADDR (0x10c / 4)
+#define R_PORT0_INTERFACE_MONITOR0  (0x240 / 4)
+#define R_PORT0_INTERFACE_MONITOR1  (0x244 / 4)
+#define R_PORT0_INTERFACE_MONITOR2  (0x248 / 4)
+#define R_PORT1_INTERFACE_MONITOR0  (0x2c0 / 4)
+#define R_PORT1_INTERFACE_MONITOR1  (0x2c4 / 4)
+#define R_PORT1_INTERFACE_MONITOR2  (0x2c8 / 4)
+#define R_PORT2_INTERFACE_MONITOR0  (0x340 / 4)
+#define R_PORT2_INTERFACE_MONITOR1  (0x344 / 4)
+#define R_PORT2_INTERFACE_MONITOR2  (0x348 / 4)
+#define R_PORT3_INTERFACE_MONITOR0  (0x3c0 / 4)
+#define R_PORT3_INTERFACE_MONITOR1  (0x3c4 / 4)
+#define R_PORT3_INTERFACE_MONITOR2  (0x3c8 / 4)
+#define R_PORT4_INTERFACE_MONITOR0  (0x440 / 4)
+#define R_PORT4_INTERFACE_MONITOR1  (0x444 / 4)
+#define R_PORT4_INTERFACE_MONITOR2  (0x448 / 4)
+#define R_PORT5_INTERFACE_MONITOR0  (0x4c0 / 4)
+#define R_PORT5_INTERFACE_MONITOR1  (0x4c4 / 4)
+#define R_PORT5_INTERFACE_MONITOR2  (0x4c8 / 4)
+
 /*
  * Configuration register Ox4 (for Aspeed AST2400 SOC)
  *
@@ -101,6 +142,19 @@
  ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |\
  ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
 
+/*
+ * Main Configuration register Ox10 (for Aspeed AST2700 SOC and higher)
+ *
+ */
+#define ASPEED_SDMC_AST2700_RESERVED0x2082 /* 31:16, 13, 7, 1 */
+#define ASPEED_SDMC_AST2700_DATA_SCRAMBLE   (1 << 8)
+#define ASPEED_SDMC_AST2700_ECC_ENABLE  (1 << 6)
+#define ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE(1 << 5)
+#define ASPEED_SDMC_AST2700_DRAM_SIZE(x)((x & 0x7) << 2)
+
+#define ASPEED_SDMC_AST2700_READONLY_MASK   \
+ (ASPEED_SDMC_AST2700_RESERVED)
+
 static uint64_t aspeed_sdmc_read(void *opaque, hwaddr addr, unsigned size)
 {
 AspeedSDMCState *s = ASPEED_SDMC(opaque);
@@ -216,7 +270,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error 
**errp)
 AspeedSDMCState *s = ASPEED_SDMC(dev);
 AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
 
-assert(asc->max_ram_size < 4 * GiB); /* 32-bit address bus */
+assert(asc->max_ram_size < 4 * GiB || asc->is_bus64bit);
 s->max_ram_size = asc->max_ram_size;
 
 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
@@ -226,8 +280,8 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error 
**errp)
 
 static const VMStateDescription vmstate_aspeed_sdmc = {
 .name = "aspeed.sdmc",
-.version_id = 1,
-.minimum_version_id = 1,
+.version_id = 2,
+.minimum_version_id = 2,
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32_ARRAY(regs, AspeedSDMCState, ASPEED_SDMC_NR_REGS),
 VMSTATE_END_OF_LIST()
@@ -236,6 +290,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
 
 static Property aspeed_sdmc_properties[] = {
 DEFINE_

[PATCH v5 17/17] docs:aspeed: Add AST2700 Evaluation board

2024-06-03 Thread Jamin Lin via
Add AST2700 Evaluation board and its boot command.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 docs/system/arm/aspeed.rst | 39 ++
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
index b2dea54eed..cd9559e3e2 100644
--- a/docs/system/arm/aspeed.rst
+++ b/docs/system/arm/aspeed.rst
@@ -1,11 +1,12 @@
-Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``)
-==
+Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``, 
``ast2700-evb``)
+===
 
 The QEMU Aspeed machines model BMCs of various OpenPOWER systems and
 Aspeed evaluation boards. They are based on different releases of the
 Aspeed SoC : the AST2400 integrating an ARM926EJ-S CPU (400MHz), the
-AST2500 with an ARM1176JZS CPU (800MHz) and more recently the AST2600
-with dual cores ARM Cortex-A7 CPUs (1.2GHz).
+AST2500 with an ARM1176JZS CPU (800MHz), the AST2600
+with dual cores ARM Cortex-A7 CPUs (1.2GHz) and more recently the AST2700
+with quad cores ARM Cortex-A35 64 bits CPUs (1.6GHz)
 
 The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C,
 etc.
@@ -38,6 +39,10 @@ AST2600 SoC based machines :
 - ``qcom-dc-scm-v1-bmc``   Qualcomm DC-SCM V1 BMC
 - ``qcom-firework-bmc``Qualcomm Firework BMC
 
+AST2700 SoC based machines :
+
+- ``ast2700-evb``  Aspeed AST2700 Evaluation board (Cortex-A35)
+
 Supported devices
 -
 
@@ -66,6 +71,7 @@ Supported devices
  * eMMC Boot Controller (dummy)
  * PECI Controller (minimal)
  * I3C Controller
+ * Internal Bridge Controller (SLI dummy)
 
 
 Missing devices
@@ -95,6 +101,10 @@ or directly from the OpenBMC GitHub release repository :
 
https://github.com/openbmc/openbmc/releases
 
+or directly from the ASPEED Forked OpenBMC GitHub release repository :
+
+   https://github.com/AspeedTech-BMC/openbmc/releases
+
 To boot a kernel directly from a Linux build tree:
 
 .. code-block:: bash
@@ -164,6 +174,27 @@ under Linux), use :
 
   -M ast2500-evb,bmc-console=uart3
 
+
+Boot the AST2700 machine from the flash image, use an MTD drive :
+
+.. code-block:: bash
+
+  IMGDIR=ast2700-default
+  UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin)
+
+  $ qemu-system-aarch64 -M ast2700-evb \
+   -device 
loader,force-raw=on,addr=0x4,file=${IMGDIR}/u-boot-nodtb.bin \
+   -device loader,force-raw=on,addr=$((0x4 + 
${UBOOT_SIZE})),file=${IMGDIR}/u-boot.dtb \
+   -device loader,force-raw=on,addr=0x43000,file=${IMGDIR}/bl31.bin \
+   -device 
loader,force-raw=on,addr=0x43008,file=${IMGDIR}/optee/tee-raw.bin \
+   -device loader,cpu-num=0,addr=0x43000 \
+   -device loader,cpu-num=1,addr=0x43000 \
+   -device loader,cpu-num=2,addr=0x43000 \
+   -device loader,cpu-num=3,addr=0x43000 \
+   -smp 4 \
+   -drive file=${IMGDIR}/image-bmc,format=raw,if=mtd \
+   -nographic
+
 Aspeed minibmc family boards (``ast1030-evb``)
 ==
 
-- 
2.25.1




RE: [PATCH v6 19/19] intel_iommu: Check compatibility with host IOMMU capabilities

2024-06-03 Thread Duan, Zhenzhong


>-Original Message-
>From: Eric Auger 
>Subject: Re: [PATCH v6 19/19] intel_iommu: Check compatibility with host
>IOMMU capabilities
>
>Hi Zhenzhong,
>
>On 6/3/24 08:10, Zhenzhong Duan wrote:
>> If check fails, host device (either VFIO or VDPA device) is not
>> compatible with current vIOMMU config and should not be passed to
>> guest.
>>
>> Only aw_bits is checked for now, we don't care other capabilities
>we don't care about other caps

Will do.

Thanks
Zhenzhong

>> before scalable modern mode is introduced.
>>
>> Signed-off-by: Yi Liu 
>> Signed-off-by: Zhenzhong Duan 
>> ---
>>  hw/i386/intel_iommu.c | 29 +
>>  1 file changed, 29 insertions(+)
>>
>> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
>> index 747c988bc4..d8202a77dd 100644
>> --- a/hw/i386/intel_iommu.c
>> +++ b/hw/i386/intel_iommu.c
>> @@ -3819,6 +3819,30 @@ VTDAddressSpace
>*vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
>>  return vtd_dev_as;
>>  }
>>
>> +static bool vtd_check_hdev(IntelIOMMUState *s, HostIOMMUDevice
>*hiod,
>> +   Error **errp)
>> +{
>> +HostIOMMUDeviceClass *hiodc =
>HOST_IOMMU_DEVICE_GET_CLASS(hiod);
>> +int ret;
>> +
>> +if (!hiodc->get_cap) {
>> +error_setg(errp, ".get_cap() not implemented");
>> +return false;
>> +}
>> +
>> +/* Common checks */
>> +ret = hiodc->get_cap(hiod, HOST_IOMMU_DEVICE_CAP_AW_BITS,
>errp);
>> +if (ret < 0) {
>> +return false;
>> +}
>> +if (s->aw_bits > ret) {
>> +error_setg(errp, "aw-bits %d > host aw-bits %d", s->aw_bits, ret);
>> +return false;
>> +}
>> +
>> +return true;
>> +}
>> +
>>  static bool vtd_dev_set_iommu_device(PCIBus *bus, void *opaque, int
>devfn,
>>   HostIOMMUDevice *hiod, Error **errp)
>>  {
>> @@ -3842,6 +3866,11 @@ static bool
>vtd_dev_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>  return false;
>>  }
>>
>> +if (!vtd_check_hdev(s, hiod, errp)) {
>> +vtd_iommu_unlock(s);
>> +return false;
>> +}
>> +
>>  vtd_hdev = g_malloc0(sizeof(VTDHostIOMMUDevice));
>>  vtd_hdev->bus = bus;
>>  vtd_hdev->devfn = (uint8_t)devfn;
>Eric



[PATCH v5 12/17] aspeed/intc: Add AST2700 support

2024-06-03 Thread Jamin Lin via
AST2700 interrupt controller(INTC) provides hardware interrupt interfaces
to interrupt of processors PSP, SSP and TSP. In INTC, each interrupt of
INT 128 to INT136 combines 32 interrupts.

Introduce a new aspeed_intc class with instance_init and realize handlers.

So far, this model only supports GICINT128 to GICINT136.
It creates 9 GICINT or-gates to connect 32 interrupts sources
from GICINT128 to GICINT136 as IRQ GPIO-OUTPUT pins.
Then, this model registers IRQ handler with its IRQ GPIO-INPUT pins which
connect to GICINT or-gates. And creates 9 GICINT IRQ GPIO-OUTPUT pins which
connect to GIC device with GIC IRQ 128 to 136.

If one interrupt source from GICINT128 to GICINT136
set irq, the OR-GATE irq callback function is called and set irq to INTC by
OR-GATE GPIO-OUTPUT pins. Then, the INTC irq callback function is called and
set irq to GIC by its GICINT IRQ GPIO-OUTPUT pins. Finally, the GIC irq
callback function is called and set irq to CPUs and
CPUs execute Interrupt Service Routine (ISR).

Block diagram of GICINT132:

GICINT132
  ETH1+---+
+>+0 3|
  ETH2|  4|
+>+1 5|
  ETH3|  6|
+>+219|  INTC  
GIC
  UART0   | 20|+--+
+>+721||  |
+--+
  UART1   | 22||orgate0 +> 
output_pin0+--->+GIC128|
+>+823||  ||
  |
  UART2   | 24||orgate1 +> 
output_pin1+--->+GIC129|
+>+925||  ||
  |
  UART3   | 26||orgate2 +> 
output_pin2+--->+GIC130|
+->10   27||  ||
  |
  UART5   | 28||orgate3 +> 
output_pin3+--->+GIC131|
+>+11   29||  ||
  |
  UART6   |   +--->+orgate4 +> 
output_pin4+--->+GIC132|
+>+12   30||  ||
  |
  UART7   | 31||orgate5 +> 
output_pin5+--->+GIC133|
+>+13 ||  ||
  |
  UART8   |  OR[0:31] ||orgate6 +> 
output_pin6+--->+GIC134|
-->14 ||  ||
  |
  UART9   |   ||orgate7 +> 
output_pin7+--->+GIC135|
->+15 ||  ||
  |
  UART10  |   ||orgate8 +> 
output_pin8+--->+GIC136|
->+16 ||  |
+--+
  UART11  |   |+--+
+>+17 |
  UART12  |   |
+->18 |
  |   |
  |   |
  |   |
  +---+

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
---
 hw/intc/aspeed_intc.c | 360 ++
 hw/intc/meson.build   |   1 +
 hw/intc/trace-events  |  13 ++
 include/hw/intc/aspeed_intc.h |  44 +
 4 files changed, 418 insertions(+)
 create mode 100644 hw/intc/aspeed_intc.c
 create mode 100644 include/hw/intc/aspeed_intc.h

diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c
new file mode 100644
index 00..e232361791
--- /dev/null
+++ b/hw/intc/aspeed_intc.c
@@ -0,0 +1,360 @@
+/*
+ * ASPEED INTC Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/intc/aspeed_intc.h"
+#include "hw/irq.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/registerfields.h"
+#include "qapi/error.h"
+
+/* INTC Registers */
+REG32(GICINT128_EN, 0x1000)
+REG32(GICINT128_STATUS, 0x1004)
+REG32(GICINT129_EN, 0x1100)
+REG32(GICINT129_STATUS, 0x1104)
+REG32(GICINT130_EN, 0x1200)
+REG32(GICINT130_STATUS, 0x1204)
+REG32(GICINT131_EN, 0x1300)
+REG32(GICINT131_STATUS, 0x1304)
+REG32(GICINT132_EN, 0x1400)
+REG32(GICINT132_STATUS, 0x1404)
+REG32(GICINT133_EN, 0x1500)
+REG32(GICINT133_STATUS, 0x1504)
+REG32(GICINT134_EN, 0x1600)
+REG32(GICINT134_STATUS, 0x1604)
+REG32(GICINT135_EN, 0x1700)
+REG32(GICINT135_STATUS, 0x1704)
+REG32(GICINT136_EN, 0x1800)
+REG32(GICINT136_STATUS, 0x1804)
+
+#define GICINT_STATUS_BASE R_GICINT128_STATUS
+
+static void aspeed_intc_update(AspeedINTCState *s, int irq

Re: [PATCH v2] chardev: add path option for pty backend

2024-06-03 Thread Marc-André Lureau
On Tue, Jun 4, 2024 at 1:22 AM Octavian Purdila  wrote:
>
> Add path option to the pty char backend which will create a symbolic
> link to the given path that points to the allocated PTY.
>
> This avoids having to make QMP or HMP monitor queries to find out what
> the new PTY device path is.
>
> Based on patch from Paulo Neves:
>
> https://patchew.org/QEMU/1548509635-15776-1-git-send-email-ptsne...@gmail.com/
>
> Tested with the following invocations that the link is created and
> removed when qemu stops:
>
>   qemu-system-x86_64 -nodefaults -mon chardev=compat_monitor \
>   -chardev pty,path=test,id=compat_monitor0
>
>   qemu-system-x86_64 -nodefaults -monitor pty:test
>
> Also tested that when a link path is not passed invocations still work, e.g.:
>
>   qemu-system-x86_64 -monitor pty
>
> Co-authored-by: Paulo Neves 
> Signed-off-by: Paulo Neves 
> [OP: rebase and address original patch review comments]
> Signed-off-by: Octavian Purdila 

Reviewed-by: Marc-André Lureau 

> ---
> Changes since v1:
>
>  * Keep the original Signed-off-by from Paulo and add one line
> description with further changes
>
>  * Update commit message with justification for why the new
> functionality is useful
>
>  * Don't close master_fd when symlink creation fails to avoid double
> close
>
>  * Update documentation for clarity
>
>  chardev/char-pty.c | 33 +
>  chardev/char.c |  5 +
>  qapi/char.json |  4 ++--
>  qemu-options.hx| 24 ++--
>  4 files changed, 58 insertions(+), 8 deletions(-)
>
> diff --git a/chardev/char-pty.c b/chardev/char-pty.c
> index cc2f7617fe..b5a4eb59fc 100644
> --- a/chardev/char-pty.c
> +++ b/chardev/char-pty.c
> @@ -29,6 +29,7 @@
>  #include "qemu/sockets.h"
>  #include "qemu/error-report.h"
>  #include "qemu/module.h"
> +#include "qemu/option.h"
>  #include "qemu/qemu-print.h"
>
>  #include "chardev/char-io.h"
> @@ -41,6 +42,7 @@ struct PtyChardev {
>
>  int connected;
>  GSource *timer_src;
> +char *symlink_path;
>  };
>  typedef struct PtyChardev PtyChardev;
>
> @@ -204,6 +206,12 @@ static void char_pty_finalize(Object *obj)
>  Chardev *chr = CHARDEV(obj);
>  PtyChardev *s = PTY_CHARDEV(obj);
>
> +/* unlink symlink */
> +if (s->symlink_path) {
> +unlink(s->symlink_path);
> +g_free(s->symlink_path);
> +}
> +
>  pty_chr_state(chr, 0);
>  object_unref(OBJECT(s->ioc));
>  pty_chr_timer_cancel(s);
> @@ -330,6 +338,7 @@ static void char_pty_open(Chardev *chr,
>  int master_fd, slave_fd;
>  char pty_name[PATH_MAX];
>  char *name;
> +char *symlink_path = backend->u.pty.data->device;
>
>  master_fd = qemu_openpty_raw(&slave_fd, pty_name);
>  if (master_fd < 0) {
> @@ -354,12 +363,36 @@ static void char_pty_open(Chardev *chr,
>  g_free(name);
>  s->timer_src = NULL;
>  *be_opened = false;
> +
> +/* create symbolic link */
> +if (symlink_path) {
> +int res = symlink(pty_name, symlink_path);
> +
> +if (res != 0) {
> +error_setg_errno(errp, errno, "Failed to create PTY symlink");
> +} else {
> +s->symlink_path = g_strdup(symlink_path);
> +}
> +}
> +}
> +
> +static void char_pty_parse(QemuOpts *opts, ChardevBackend *backend,
> +   Error **errp)
> +{
> +const char *path = qemu_opt_get(opts, "path");
> +ChardevHostdev *dev;
> +
> +backend->type = CHARDEV_BACKEND_KIND_PTY;
> +dev = backend->u.pty.data = g_new0(ChardevHostdev, 1);
> +qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
> +dev->device = path ? g_strdup(path) : NULL;
>  }
>
>  static void char_pty_class_init(ObjectClass *oc, void *data)
>  {
>  ChardevClass *cc = CHARDEV_CLASS(oc);
>
> +cc->parse = char_pty_parse;
>  cc->open = char_pty_open;
>  cc->chr_write = char_pty_chr_write;
>  cc->chr_update_read_handler = pty_chr_update_read_handler;
> diff --git a/chardev/char.c b/chardev/char.c
> index 3c43fb1278..404c6b8a4f 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -428,6 +428,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const 
> char *filename,
>  qemu_opt_set(opts, "path", p, &error_abort);
>  return opts;
>  }
> +if (strstart(filename, "pty:", &p)) {
> +qemu_opt_set(opts, "backend", "pty", &error_abort);
> +qemu_opt_set(opts, "path", p, &error_abort);
> +return opts;
> +}
>  if (strstart(filename, "tcp:", &p) ||
>  strstart(filename, "telnet:", &p) ||
>  strstart(filename, "tn3270:", &p) ||
> diff --git a/qapi/char.json b/qapi/char.json
> index 777dde55d9..4c74bfc437 100644
> --- a/qapi/char.json
> +++ b/qapi/char.json
> @@ -509,7 +509,7 @@
>  ##
>  # @ChardevHostdevWrapper:
>  #
> -# @data: Configuration info for device and pipe chardevs
> +# @data: Configuration info for device, pty and pipe chardevs
>  #
>  # Since: 1.4
>  ##
> @@ -650,7 +65

[PATCH v5 13/17] aspeed/soc: Add AST2700 support

2024-06-03 Thread Jamin Lin via
Initial definitions for a simple machine using an AST2700 SOC (Cortex-a35 CPU).

AST2700 SOC and its interrupt controller are too complex to handle
in the common Aspeed SoC framework. We introduce a new ast2700
class with instance_init and realize handlers.

AST2700 is a 64 bits quad core cpus and support 8 watchdog.
Update maximum ASPEED_CPUS_NUM to 4 and ASPEED_WDTS_NUM to 8.
In addition, update AspeedSocState to support scuio, sli, sliio and intc.

Add TYPE_ASPEED27X0_SOC machine type.

The SDMC controller is unlocked at SPL stage.
At present, only supports to emulate booting
start from u-boot stage. Set SDMC controller
unlocked by default.

In INTC, each interrupt of INT 128 to INT 136 combines 32 interrupts.
It connect GICINT IRQ GPIO-OUTPUT pins to GIC device with irq 128 to 136.
And, if a device irq is 128 to 136, its irq GPIO-OUTPUT pin is connected to
GICINT or-gates instead of GIC device.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 563 
 hw/arm/meson.build  |   1 +
 include/hw/arm/aspeed_soc.h |  28 +-
 3 files changed, 590 insertions(+), 2 deletions(-)
 create mode 100644 hw/arm/aspeed_ast27x0.c

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
new file mode 100644
index 00..29e75072c4
--- /dev/null
+++ b/hw/arm/aspeed_ast27x0.c
@@ -0,0 +1,563 @@
+/*
+ * ASPEED SoC 27x0 family
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Implementation extracted from the AST2600 and adapted for AST27x0.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/aspeed_soc.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "hw/i2c/aspeed_i2c.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/intc/arm_gicv3.h"
+#include "qapi/qmp/qlist.h"
+
+static const hwaddr aspeed_soc_ast2700_memmap[] = {
+[ASPEED_DEV_SPI_BOOT]  =  0x4,
+[ASPEED_DEV_SRAM]  =  0x1000,
+[ASPEED_DEV_SDMC]  =  0x12C0,
+[ASPEED_DEV_SCU]   =  0x12C02000,
+[ASPEED_DEV_SCUIO] =  0x14C02000,
+[ASPEED_DEV_UART0] =  0X14C33000,
+[ASPEED_DEV_UART1] =  0X14C33100,
+[ASPEED_DEV_UART2] =  0X14C33200,
+[ASPEED_DEV_UART3] =  0X14C33300,
+[ASPEED_DEV_UART4] =  0X12C1A000,
+[ASPEED_DEV_UART5] =  0X14C33400,
+[ASPEED_DEV_UART6] =  0X14C33500,
+[ASPEED_DEV_UART7] =  0X14C33600,
+[ASPEED_DEV_UART8] =  0X14C33700,
+[ASPEED_DEV_UART9] =  0X14C33800,
+[ASPEED_DEV_UART10]=  0X14C33900,
+[ASPEED_DEV_UART11]=  0X14C33A00,
+[ASPEED_DEV_UART12]=  0X14C33B00,
+[ASPEED_DEV_WDT]   =  0x14C37000,
+[ASPEED_DEV_VUART] =  0X14C3,
+[ASPEED_DEV_FMC]   =  0x1400,
+[ASPEED_DEV_SPI0]  =  0x1401,
+[ASPEED_DEV_SPI1]  =  0x1402,
+[ASPEED_DEV_SPI2]  =  0x1403,
+[ASPEED_DEV_SDRAM] =  0x4,
+[ASPEED_DEV_MII1]  =  0x1404,
+[ASPEED_DEV_MII2]  =  0x14040008,
+[ASPEED_DEV_MII3]  =  0x14040010,
+[ASPEED_DEV_ETH1]  =  0x1405,
+[ASPEED_DEV_ETH2]  =  0x1406,
+[ASPEED_DEV_ETH3]  =  0x1407,
+[ASPEED_DEV_EMMC]  =  0x1209,
+[ASPEED_DEV_INTC]  =  0x1210,
+[ASPEED_DEV_SLI]   =  0x12C17000,
+[ASPEED_DEV_SLIIO] =  0x14C1E000,
+[ASPEED_GIC_DIST]  =  0x1220,
+[ASPEED_GIC_REDIST]=  0x1228,
+};
+
+#define AST2700_MAX_IRQ 288
+
+/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
+static const int aspeed_soc_ast2700_irqmap[] = {
+[ASPEED_DEV_UART0] = 132,
+[ASPEED_DEV_UART1] = 132,
+[ASPEED_DEV_UART2] = 132,
+[ASPEED_DEV_UART3] = 132,
+[ASPEED_DEV_UART4] = 8,
+[ASPEED_DEV_UART5] = 132,
+[ASPEED_DEV_UART6] = 132,
+[ASPEED_DEV_UART7] = 132,
+[ASPEED_DEV_UART8] = 132,
+[ASPEED_DEV_UART9] = 132,
+[ASPEED_DEV_UART10]= 132,
+[ASPEED_DEV_UART11]= 132,
+[ASPEED_DEV_UART12]= 132,
+[ASPEED_DEV_FMC]   = 131,
+[ASPEED_DEV_SDMC]  = 0,
+[ASPEED_DEV_SCU]   = 12,
+[ASPEED_DEV_ADC]   = 130,
+[ASPEED_DEV_XDMA]  = 5,
+[ASPEED_DEV_EMMC]  = 15,
+[ASPEED_DEV_GPIO]  = 11,
+[ASPEED_DEV_GPIO_1_8V] = 130,
+[ASPEED_DEV_RTC]   = 13,
+[ASPEED_DEV_TIMER1]= 16,
+[ASPEED_DEV_TIMER2]= 17,
+[ASPEED_DEV_TIMER3]= 18,
+[ASPEED_DEV_TIMER4]= 19,
+[ASPEED_DEV_TIMER5]= 20,
+[ASPEED_DEV_TIMER6]= 21,
+[ASPEED_DEV_TIMER7]= 22,
+[ASPEED_DEV_TIMER8]= 23,
+[ASPEED_DEV_WDT]   = 131,
+[ASPEED_DEV_PWM]   = 131,
+[ASPEED_DEV_LPC]   = 128,
+[ASPEED_DEV_IBT]   = 128,
+[ASPEED_DEV_I2C]   = 13

[PATCH v5 06/17] aspeed/smc: correct device description

2024-06-03 Thread Jamin Lin via
Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/ssi/aspeed_smc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 7075bc9d61..fe1cd96b80 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -1449,7 +1449,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass 
*klass, void *data)
 DeviceClass *dc = DEVICE_CLASS(klass);
 AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
 
-dc->desc   = "Aspeed 2600 FMC Controller";
+dc->desc   = "Aspeed 2500 FMC Controller";
 asc->r_conf= R_CONF;
 asc->r_ce_ctrl = R_CE_CTRL;
 asc->r_ctrl0   = R_CTRL0;
@@ -1487,7 +1487,7 @@ static void aspeed_2500_spi1_class_init(ObjectClass 
*klass, void *data)
 DeviceClass *dc = DEVICE_CLASS(klass);
 AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
 
-dc->desc   = "Aspeed 2600 SPI1 Controller";
+dc->desc   = "Aspeed 2500 SPI1 Controller";
 asc->r_conf= R_CONF;
 asc->r_ce_ctrl = R_CE_CTRL;
 asc->r_ctrl0   = R_CTRL0;
@@ -1522,7 +1522,7 @@ static void aspeed_2500_spi2_class_init(ObjectClass 
*klass, void *data)
 DeviceClass *dc = DEVICE_CLASS(klass);
 AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
 
-dc->desc   = "Aspeed 2600 SPI2 Controller";
+dc->desc   = "Aspeed 2500 SPI2 Controller";
 asc->r_conf= R_CONF;
 asc->r_ce_ctrl = R_CE_CTRL;
 asc->r_ctrl0   = R_CTRL0;
-- 
2.25.1




[PATCH v5 14/17] aspeed: Add an AST2700 eval board

2024-06-03 Thread Jamin Lin via
AST2700 CPU is ARM Cortex-A35 which is 64 bits.
Add TARGET_AARCH64 to build this machine.

According to the design of ast2700, it has a bootmcu(riscv-32) which
is used for executing SPL.
Then, CPUs(cortex-a35) execute u-boot, kernel and rofs.

Currently, qemu not support emulate two CPU architectures
at the same machine. Therefore, qemu will only support
to emulate CPU(cortex-a35) side for ast2700

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/arm/aspeed.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 93ca87fda2..40dc0e4c76 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -178,6 +178,12 @@ struct AspeedMachineState {
 #define AST2600_EVB_HW_STRAP1 0x00C0
 #define AST2600_EVB_HW_STRAP2 0x0003
 
+#ifdef TARGET_AARCH64
+/* AST2700 evb hardware value */
+#define AST2700_EVB_HW_STRAP1 0x00C0
+#define AST2700_EVB_HW_STRAP2 0x0003
+#endif
+
 /* Tacoma hardware value */
 #define TACOMA_BMC_HW_STRAP1  0x
 #define TACOMA_BMC_HW_STRAP2  0x0040
@@ -1588,6 +1594,26 @@ static void 
aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
 aspeed_machine_class_init_cpus_defaults(mc);
 }
 
+#ifdef TARGET_AARCH64
+static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
+{
+MachineClass *mc = MACHINE_CLASS(oc);
+AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+mc->desc = "Aspeed AST2700 EVB (Cortex-A35)";
+amc->soc_name  = "ast2700-a0";
+amc->hw_strap1 = AST2700_EVB_HW_STRAP1;
+amc->hw_strap2 = AST2700_EVB_HW_STRAP2;
+amc->fmc_model = "w25q01jvq";
+amc->spi_model = "w25q512jv";
+amc->num_cs= 2;
+amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
+amc->uart_default = ASPEED_DEV_UART12;
+mc->default_ram_size = 1 * GiB;
+aspeed_machine_class_init_cpus_defaults(mc);
+}
+#endif
+
 static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc,
  void *data)
 {
@@ -1711,6 +1737,12 @@ static const TypeInfo aspeed_machine_types[] = {
 .name   = MACHINE_TYPE_NAME("ast1030-evb"),
 .parent = TYPE_ASPEED_MACHINE,
 .class_init = aspeed_minibmc_machine_ast1030_evb_class_init,
+#ifdef TARGET_AARCH64
+}, {
+.name  = MACHINE_TYPE_NAME("ast2700-evb"),
+.parent= TYPE_ASPEED_MACHINE,
+.class_init= aspeed_machine_ast2700_evb_class_init,
+#endif
 }, {
 .name  = TYPE_ASPEED_MACHINE,
 .parent= TYPE_MACHINE,
-- 
2.25.1




[PATCH v5 15/17] aspeed/soc: fix incorrect dram size for AST2700

2024-06-03 Thread Jamin Lin via
AST2700 dram size calculation is not back compatible AST2600.
According to the DDR capacity hardware behavior,
if users write the data to the address which is beyond the ram size,
it would write the data to the "address % ram_size".
For example:
a. sdram base address "0x4 "
b. sdram size 1 GiB
The available address range is from "0x4 " to "0x4 3FFF".
If users write 0x12345678 to address "0x5 ",
the value of DRAM address 0 (base address 0x4 ) will be 0x12345678.

Add aspeed_soc_ast2700_dram_init to calculate the dram size and add
memory I/O whose address range is from "max_ram_size - ram_size" to max_ram_size
and its read/write handler to emulate DDR capacity hardware behavior.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
---
 hw/arm/aspeed_ast27x0.c | 87 -
 include/hw/arm/aspeed_soc.h |  2 +
 2 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 29e75072c4..b6876b4862 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -20,6 +20,7 @@
 #include "sysemu/sysemu.h"
 #include "hw/intc/arm_gicv3.h"
 #include "qapi/qmp/qlist.h"
+#include "qemu/log.h"
 
 static const hwaddr aspeed_soc_ast2700_memmap[] = {
 [ASPEED_DEV_SPI_BOOT]  =  0x4,
@@ -191,6 +192,90 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState 
*s, int dev)
 return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
 }
 
+static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
+unsigned int size)
+{
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM read out of ram size, addr:0x%" PRIx64 "\n",
+   __func__, addr);
+return 0;
+}
+
+static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data,
+unsigned int size)
+{
+AspeedSoCState *s = ASPEED_SOC(opaque);
+ram_addr_t ram_size;
+MemTxResult result;
+
+ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
+&error_abort);
+
+/*
+ * Emulate ddr capacity hardware behavior.
+ * If writes the data to the address which is beyond the ram size,
+ * it would write the data to the "address % ram_size".
+ */
+result = address_space_write(&s->dram_as, addr % ram_size,
+ MEMTXATTRS_UNSPECIFIED, &data, 4);
+if (result != MEMTX_OK) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: DRAM write failed, addr:0x%" HWADDR_PRIx
+  ", data :0x%" PRIx64  "\n",
+  __func__, addr % ram_size, data);
+}
+}
+
+static const MemoryRegionOps aspeed_ram_capacity_ops = {
+.read = aspeed_ram_capacity_read,
+.write = aspeed_ram_capacity_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 8,
+},
+};
+
+/*
+ * SDMC should be realized first to get correct RAM size and max size
+ * values
+ */
+static bool aspeed_soc_ast2700_dram_init(DeviceState *dev, Error **errp)
+{
+ram_addr_t ram_size, max_ram_size;
+Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
+AspeedSoCState *s = ASPEED_SOC(dev);
+AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
+&error_abort);
+max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), "max-ram-size",
+&error_abort);
+
+memory_region_init(&s->dram_container, OBJECT(s), "ram-container",
+   ram_size);
+memory_region_add_subregion(&s->dram_container, 0, s->dram_mr);
+address_space_init(&s->dram_as, s->dram_mr, "dram");
+
+/*
+ * Add a memory region beyond the RAM region to emulate
+ * ddr capacity hardware behavior.
+ */
+if (ram_size < max_ram_size) {
+memory_region_init_io(&a->dram_empty, OBJECT(s),
+  &aspeed_ram_capacity_ops, s,
+  "ram-empty", max_ram_size - ram_size);
+
+memory_region_add_subregion(s->memory,
+sc->memmap[ASPEED_DEV_SDRAM] + ram_size,
+&a->dram_empty);
+}
+
+memory_region_add_subregion(s->memory,
+  sc->memmap[ASPEED_DEV_SDRAM], &s->dram_container);
+return true;
+}
+
 static void aspeed_soc_ast2700_init(Object *obj)
 {
 Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
@@ -461,7 +546,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, 
Error **errp)
 sc->memmap[ASPEED_DEV_SDMC]);
 
 /* RAM */
-if (!aspeed_soc_dram_init(s, errp)) {
+if (!aspeed_soc_ast2700_dram_init(dev, errp)) {
 return;
 }
 
diff --git a/include/hw/arm/aspeed_soc.h b/i

[PATCH v5 10/17] aspeed/smc: Add AST2700 support

2024-06-03 Thread Jamin Lin via
AST2700 fmc/spi controller's address decoding unit is 64KB
and only bits [31:16] are used for decoding. Introduce seg_to_reg
and reg_to_seg handlers for ast2700 fmc/spi controller.
In addition, adds ast2700 fmc, spi0, spi1, and spi2 class init handler.

AST2700 is a 64 bits quad core CPUs(Cortex-a35). Introduce a new
"aspeed_2700_smc_flash_ops" and set its valid "max_access_size"
8 for 64 bits data format access.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
---
 hw/ssi/aspeed_smc.c | 234 +++-
 1 file changed, 233 insertions(+), 1 deletion(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 129d06690d..49205ab76d 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -185,7 +185,7 @@
  *   0: 4 bytes
  *   0x1FC: 32M bytes
  *
- * DMA length is from 1 byte to 32MB (AST2600, AST10x0)
+ * DMA length is from 1 byte to 32MB (AST2600, AST10x0 and AST2700)
  *   0: 1 byte
  *   0x1FF: 32M bytes
  */
@@ -1938,6 +1938,234 @@ static const TypeInfo aspeed_1030_spi2_info = {
 .class_init = aspeed_1030_spi2_class_init,
 };
 
+/*
+ * The FMC Segment Registers of the AST2700 have a 64KB unit.
+ * Only bits [31:16] are used for decoding.
+ */
+#define AST2700_SEG_ADDR_MASK 0x
+
+static uint32_t aspeed_2700_smc_segment_to_reg(const AspeedSMCState *s,
+   const AspeedSegments *seg)
+{
+uint32_t reg = 0;
+
+/* Disabled segments have a nil register */
+if (!seg->size) {
+return 0;
+}
+
+reg |= (seg->addr & AST2700_SEG_ADDR_MASK) >> 16; /* start offset */
+reg |= (seg->addr + seg->size - 1) & AST2700_SEG_ADDR_MASK; /* end offset 
*/
+return reg;
+}
+
+static void aspeed_2700_smc_reg_to_segment(const AspeedSMCState *s,
+   uint32_t reg, AspeedSegments *seg)
+{
+uint32_t start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK;
+uint32_t end_offset = reg & AST2700_SEG_ADDR_MASK;
+AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+
+if (reg) {
+seg->addr = asc->flash_window_base + start_offset;
+seg->size = end_offset + (64 * KiB) - start_offset;
+} else {
+seg->addr = asc->flash_window_base;
+seg->size = 0;
+}
+}
+
+static const uint32_t aspeed_2700_fmc_resets[ASPEED_SMC_R_MAX] = {
+[R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 |
+CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1),
+[R_CE_CTRL] = 0xaa00,
+[R_CTRL0] = 0x406b0641,
+[R_CTRL1] = 0x0400,
+[R_CTRL2] = 0x0400,
+[R_CTRL3] = 0x0400,
+[R_SEG_ADDR0] = 0x0800,
+[R_SEG_ADDR1] = 0x1800,
+[R_SEG_ADDR2] = 0x,
+[R_SEG_ADDR3] = 0x,
+[R_DUMMY_DATA] = 0x0001,
+[R_DMA_DRAM_ADDR_HIGH] = 0x,
+[R_TIMINGS] = 0x007b,
+};
+
+static const MemoryRegionOps aspeed_2700_smc_flash_ops = {
+.read = aspeed_smc_flash_read,
+.write = aspeed_smc_flash_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 8,
+},
+};
+
+static const AspeedSegments aspeed_2700_fmc_segments[] = {
+{ 0x0, 128 * MiB }, /* start address is readonly */
+{ 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
+{ 256 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
+{ 0x0, 0 }, /* disabled */
+};
+
+static void aspeed_2700_fmc_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
+
+dc->desc   = "Aspeed 2700 FMC Controller";
+asc->r_conf= R_CONF;
+asc->r_ce_ctrl = R_CE_CTRL;
+asc->r_ctrl0   = R_CTRL0;
+asc->r_timings = R_TIMINGS;
+asc->nregs_timings = 3;
+asc->conf_enable_w0= CONF_ENABLE_W0;
+asc->cs_num_max= 3;
+asc->segments  = aspeed_2700_fmc_segments;
+asc->segment_addr_mask = 0x;
+asc->resets= aspeed_2700_fmc_resets;
+asc->flash_window_base = 0x1;
+asc->flash_window_size = 1 * GiB;
+asc->features  = ASPEED_SMC_FEATURE_DMA |
+ ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+asc->dma_flash_mask= 0x2FFC;
+asc->dma_dram_mask = 0xFFFC;
+asc->dma_start_length  = 1;
+asc->nregs = ASPEED_SMC_R_MAX;
+asc->segment_to_reg= aspeed_2700_smc_segment_to_reg;
+asc->reg_to_segment= aspeed_2700_smc_reg_to_segment;
+asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_2700_smc_flash_ops;
+}
+
+static const TypeInfo aspeed_2700_fmc_info = {
+.name =  "aspeed.fmc-ast2700",
+.parent = TYPE_ASPEED_SMC,
+.class_init = aspeed_2700_fmc_class_init,
+};
+
+static const AspeedSegments aspeed_2700_spi0_segments[] = {
+{ 0x0, 128 * MiB }, /* start address is readonly */
+   

[PATCH v5 09/17] aspeed/smc: support different memory region ops for SMC flash region

2024-06-03 Thread Jamin Lin via
It set "aspeed_smc_flash_ops" struct which containing
read and write callbacks to be used when I/O is performed
on the SMC flash region. And it set the valid max_access_size 4
by default for all ASPEED SMC models.

However, the valid max_access_size 4 only support 32 bits CPUs.
To support all ASPEED SMC model, introduce a new
"const MemoryRegionOps *" attribute in AspeedSMCClass and
use it in aspeed_smc_flash_realize function.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
---
 hw/ssi/aspeed_smc.c | 14 +-
 include/hw/ssi/aspeed_smc.h |  1 +
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index df0c63469c..129d06690d 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -1316,7 +1316,7 @@ static void aspeed_smc_flash_realize(DeviceState *dev, 
Error **errp)
  * Use the default segment value to size the memory region. This
  * can be changed by FW at runtime.
  */
-memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_flash_ops,
+memory_region_init_io(&s->mmio, OBJECT(s), s->asc->reg_ops,
   s, name, s->asc->segments[s->cs].size);
 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
 }
@@ -1391,6 +1391,7 @@ static void aspeed_2400_smc_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2400_smc_info = {
@@ -1441,6 +1442,7 @@ static void aspeed_2400_fmc_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2400_fmc_info = {
@@ -1480,6 +1482,7 @@ static void aspeed_2400_spi1_class_init(ObjectClass 
*klass, void *data)
 asc->reg_to_segment= aspeed_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_smc_dma_ctrl;
 asc->addr_width= aspeed_2400_spi1_addr_width;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2400_spi1_info = {
@@ -1525,6 +1528,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2500_fmc_info = {
@@ -1560,6 +1564,7 @@ static void aspeed_2500_spi1_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2500_spi1_info = {
@@ -1595,6 +1600,7 @@ static void aspeed_2500_spi2_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2500_spi2_info = {
@@ -1682,6 +1688,7 @@ static void aspeed_2600_fmc_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_2600_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_2600_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2600_fmc_info = {
@@ -1721,6 +1728,7 @@ static void aspeed_2600_spi1_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_2600_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_2600_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2600_spi1_info = {
@@ -1761,6 +1769,7 @@ static void aspeed_2600_spi2_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_2600_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_2600_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_2600_spi2_info = {
@@ -1843,6 +1852,7 @@ static void aspeed_1030_fmc_class_init(ObjectClass 
*klass, void *data)
 asc->segment_to_reg= aspeed_1030_smc_segment_to_reg;
 asc->reg_to_segment= aspeed_1030_smc_reg_to_segment;
 asc->dma_ctrl  = aspeed_2600_smc_dma_ctrl;
+asc->reg_ops   = &aspeed_smc_flash_ops;
 }
 
 static const TypeInfo aspeed_1030_fmc_info = {
@@ -1881,6 +1891,7 @@ static void aspee

[PATCH v5 01/17] aspeed/wdt: Add AST2700 support

2024-06-03 Thread Jamin Lin via
AST2700 wdt controller is similiar to AST2600's wdt, but
the AST2700 has 8 watchdogs, and they each have 0x80 of registers.
Introduce ast2700 object class and increase the number of regs(offset) of
ast2700 model.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/watchdog/wdt_aspeed.c | 24 
 include/hw/watchdog/wdt_aspeed.h |  3 ++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
index d70b656f8e..75685c5647 100644
--- a/hw/watchdog/wdt_aspeed.c
+++ b/hw/watchdog/wdt_aspeed.c
@@ -422,12 +422,36 @@ static const TypeInfo aspeed_1030_wdt_info = {
 .class_init = aspeed_1030_wdt_class_init,
 };
 
+static void aspeed_2700_wdt_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
+
+dc->desc = "ASPEED 2700 Watchdog Controller";
+awc->iosize = 0x80;
+awc->ext_pulse_width_mask = 0xf; /* TODO */
+awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1;
+awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
+awc->wdt_reload = aspeed_wdt_reload_1mhz;
+awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl;
+awc->default_status = 0x014FB180;
+awc->default_reload_value = 0x014FB180;
+}
+
+static const TypeInfo aspeed_2700_wdt_info = {
+.name = TYPE_ASPEED_2700_WDT,
+.parent = TYPE_ASPEED_WDT,
+.instance_size = sizeof(AspeedWDTState),
+.class_init = aspeed_2700_wdt_class_init,
+};
+
 static void wdt_aspeed_register_types(void)
 {
 type_register_static(&aspeed_wdt_info);
 type_register_static(&aspeed_2400_wdt_info);
 type_register_static(&aspeed_2500_wdt_info);
 type_register_static(&aspeed_2600_wdt_info);
+type_register_static(&aspeed_2700_wdt_info);
 type_register_static(&aspeed_1030_wdt_info);
 }
 
diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h
index e90ef86651..830b0a7936 100644
--- a/include/hw/watchdog/wdt_aspeed.h
+++ b/include/hw/watchdog/wdt_aspeed.h
@@ -19,9 +19,10 @@ OBJECT_DECLARE_TYPE(AspeedWDTState, AspeedWDTClass, 
ASPEED_WDT)
 #define TYPE_ASPEED_2400_WDT TYPE_ASPEED_WDT "-ast2400"
 #define TYPE_ASPEED_2500_WDT TYPE_ASPEED_WDT "-ast2500"
 #define TYPE_ASPEED_2600_WDT TYPE_ASPEED_WDT "-ast2600"
+#define TYPE_ASPEED_2700_WDT TYPE_ASPEED_WDT "-ast2700"
 #define TYPE_ASPEED_1030_WDT TYPE_ASPEED_WDT "-ast1030"
 
-#define ASPEED_WDT_REGS_MAX(0x30 / 4)
+#define ASPEED_WDT_REGS_MAX(0x80 / 4)
 
 struct AspeedWDTState {
 /*< private >*/
-- 
2.25.1




[PATCH v5 11/17] aspeed/scu: Add AST2700 support

2024-06-03 Thread Jamin Lin via
AST2700 have two SCU controllers which are SCU and SCUIO.
Both SCU and SCUIO registers are not compatible previous SOCs
, introduces new registers and adds ast2700 scu, sucio class init handler.

The pclk divider selection of SCUIO is defined in SCUIO280[20:18] and
the pclk divider selection of SCU is defined in SCU280[25:23].
Both of them are not compatible AST2600 SOCs, adds a get_apb_freq function
and trace-event for AST2700 SCU and SCUIO.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/misc/aspeed_scu.c | 306 ++-
 hw/misc/trace-events |   4 +
 include/hw/misc/aspeed_scu.h |  47 +-
 3 files changed, 351 insertions(+), 6 deletions(-)

diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 1ac04b6cb0..eb38ea8e19 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -134,6 +134,48 @@
 
 #define AST2600_CLK TO_REG(0x40)
 
+#define AST2700_SILICON_REV   TO_REG(0x00)
+#define AST2700_HW_STRAP1 TO_REG(0x10)
+#define AST2700_HW_STRAP1_CLR TO_REG(0x14)
+#define AST2700_HW_STRAP1_LOCKTO_REG(0x20)
+#define AST2700_HW_STRAP1_SEC1TO_REG(0x24)
+#define AST2700_HW_STRAP1_SEC2TO_REG(0x28)
+#define AST2700_HW_STRAP1_SEC3TO_REG(0x2C)
+
+#define AST2700_SCU_CLK_SEL_1   TO_REG(0x280)
+#define AST2700_SCU_HPLL_PARAM  TO_REG(0x300)
+#define AST2700_SCU_HPLL_EXT_PARAM  TO_REG(0x304)
+#define AST2700_SCU_DPLL_PARAM  TO_REG(0x308)
+#define AST2700_SCU_DPLL_EXT_PARAM  TO_REG(0x30c)
+#define AST2700_SCU_MPLL_PARAM  TO_REG(0x310)
+#define AST2700_SCU_MPLL_EXT_PARAM  TO_REG(0x314)
+#define AST2700_SCU_D1CLK_PARAM TO_REG(0x320)
+#define AST2700_SCU_D2CLK_PARAM TO_REG(0x330)
+#define AST2700_SCU_CRT1CLK_PARAM   TO_REG(0x340)
+#define AST2700_SCU_CRT2CLK_PARAM   TO_REG(0x350)
+#define AST2700_SCU_MPHYCLK_PARAM   TO_REG(0x360)
+#define AST2700_SCU_FREQ_CNTR   TO_REG(0x3b0)
+#define AST2700_SCU_CPU_SCRATCH_0   TO_REG(0x780)
+#define AST2700_SCU_CPU_SCRATCH_1   TO_REG(0x784)
+
+#define AST2700_SCUIO_CLK_STOP_CTL_1TO_REG(0x240)
+#define AST2700_SCUIO_CLK_STOP_CLR_1TO_REG(0x244)
+#define AST2700_SCUIO_CLK_STOP_CTL_2TO_REG(0x260)
+#define AST2700_SCUIO_CLK_STOP_CLR_2TO_REG(0x264)
+#define AST2700_SCUIO_CLK_SEL_1 TO_REG(0x280)
+#define AST2700_SCUIO_CLK_SEL_2 TO_REG(0x284)
+#define AST2700_SCUIO_HPLL_PARAMTO_REG(0x300)
+#define AST2700_SCUIO_HPLL_EXT_PARAMTO_REG(0x304)
+#define AST2700_SCUIO_APLL_PARAMTO_REG(0x310)
+#define AST2700_SCUIO_APLL_EXT_PARAMTO_REG(0x314)
+#define AST2700_SCUIO_DPLL_PARAMTO_REG(0x320)
+#define AST2700_SCUIO_DPLL_EXT_PARAMTO_REG(0x324)
+#define AST2700_SCUIO_DPLL_PARAM_READ   TO_REG(0x328)
+#define AST2700_SCUIO_DPLL_EXT_PARAM_READ TO_REG(0x32c)
+#define AST2700_SCUIO_UARTCLK_GEN   TO_REG(0x330)
+#define AST2700_SCUIO_HUARTCLK_GEN  TO_REG(0x334)
+#define AST2700_SCUIO_CLK_DUTY_MEAS_RST TO_REG(0x388)
+
 #define SCU_IO_REGION_SIZE 0x1000
 
 static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
@@ -244,6 +286,25 @@ static uint32_t 
aspeed_1030_scu_get_apb_freq(AspeedSCUState *s)
 / asc->apb_divider;
 }
 
+static uint32_t aspeed_2700_scu_get_apb_freq(AspeedSCUState *s)
+{
+AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
+uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCU_HPLL_PARAM]);
+
+return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2700_SCU_CLK_SEL_1]) + 1)
+   / asc->apb_divider;
+}
+
+static uint32_t aspeed_2700_scuio_get_apb_freq(AspeedSCUState *s)
+{
+AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
+uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCUIO_HPLL_PARAM]);
+
+return hpll /
+(SCUIO_AST2700_CLK_GET_PCLK_DIV(s->regs[AST2700_SCUIO_CLK_SEL_1]) + 1)
+/ asc->apb_divider;
+}
+
 static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
 {
 AspeedSCUState *s = ASPEED_SCU(opaque);
@@ -258,7 +319,8 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr 
offset, unsigned size)
 
 switch (reg) {
 case RNG_DATA:
-/* On hardware, RNG_DATA works regardless of
+/*
+ * On hardware, RNG_DATA works regardless of
  * the state of the enable bit in RNG_CTRL
  */
 s->regs[RNG_DATA] = aspeed_scu_get_random();
@@ -494,6 +556,9 @@ static uint32_t aspeed_silicon_revs[] = {
 AST2600_A3_SILICON_REV,
 AST1030_A0_SILICON_REV,
 AST1030_A1_SILICON_REV,
+AST2700_A0_SILICON_REV,
+AST2720_A0_SILICON_REV,
+AST2750_A0_SILICON_REV,
 };
 
 bool is_supported_silicon_rev(uint32_t silicon_rev)
@@ -783,6 +848,243 @@ static const TypeInfo aspeed_2600_scu_info = {
 .class_init = aspeed_2600_scu_class_init,
 };
 
+static uint64_t aspeed_ast2700_scu_read(void *opaque, hwaddr offset,
+unsigned size)
+{
+AspeedSCUState *s = ASPEED_SCU(opaque);
+int reg = TO_REG(offset);
+
+if (reg >= AS

[PATCH v5 02/17] aspeed/sli: Add AST2700 support

2024-06-03 Thread Jamin Lin via
AST2700 SLI engine is designed to accelerate the
throughput between cross-die connections.
It have CPU_SLI at CPU die and IO_SLI at IO die.

Introduce dummy AST2700 SLI and SLIIO models.

Signed-off-by: Troy Lee 
Signed-off-by: Jamin Lin 
Reviewed-by: Cédric Le Goater 
---
 hw/misc/aspeed_sli.c | 177 +++
 hw/misc/meson.build  |   3 +-
 hw/misc/trace-events |   7 ++
 include/hw/misc/aspeed_sli.h |  27 ++
 4 files changed, 213 insertions(+), 1 deletion(-)
 create mode 100644 hw/misc/aspeed_sli.c
 create mode 100644 include/hw/misc/aspeed_sli.h

diff --git a/hw/misc/aspeed_sli.c b/hw/misc/aspeed_sli.c
new file mode 100644
index 00..fe720ead50
--- /dev/null
+++ b/hw/misc/aspeed_sli.c
@@ -0,0 +1,177 @@
+/*
+ * ASPEED SLI Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-properties.h"
+#include "hw/misc/aspeed_sli.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+#define SLI_REGION_SIZE 0x500
+#define TO_REG(addr) ((addr) >> 2)
+
+static uint64_t aspeed_sli_read(void *opaque, hwaddr addr, unsigned int size)
+{
+AspeedSLIState *s = ASPEED_SLI(opaque);
+int reg = TO_REG(addr);
+
+if (reg >= ARRAY_SIZE(s->regs)) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+  __func__, addr);
+return 0;
+}
+
+trace_aspeed_sli_read(addr, size, s->regs[reg]);
+return s->regs[reg];
+}
+
+static void aspeed_sli_write(void *opaque, hwaddr addr, uint64_t data,
+  unsigned int size)
+{
+AspeedSLIState *s = ASPEED_SLI(opaque);
+int reg = TO_REG(addr);
+
+if (reg >= ARRAY_SIZE(s->regs)) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+  __func__, addr);
+return;
+}
+
+trace_aspeed_sli_write(addr, size, data);
+s->regs[reg] = data;
+}
+
+static uint64_t aspeed_sliio_read(void *opaque, hwaddr addr, unsigned int size)
+{
+AspeedSLIState *s = ASPEED_SLI(opaque);
+int reg = TO_REG(addr);
+
+if (reg >= ARRAY_SIZE(s->regs)) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+  __func__, addr);
+return 0;
+}
+
+trace_aspeed_sliio_read(addr, size, s->regs[reg]);
+return s->regs[reg];
+}
+
+static void aspeed_sliio_write(void *opaque, hwaddr addr, uint64_t data,
+  unsigned int size)
+{
+AspeedSLIState *s = ASPEED_SLI(opaque);
+int reg = TO_REG(addr);
+
+if (reg >= ARRAY_SIZE(s->regs)) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+  __func__, addr);
+return;
+}
+
+trace_aspeed_sliio_write(addr, size, data);
+s->regs[reg] = data;
+}
+
+static const MemoryRegionOps aspeed_sli_ops = {
+.read = aspeed_sli_read,
+.write = aspeed_sli_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 4,
+},
+};
+
+static const MemoryRegionOps aspeed_sliio_ops = {
+.read = aspeed_sliio_read,
+.write = aspeed_sliio_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 4,
+},
+};
+
+static void aspeed_sli_realize(DeviceState *dev, Error **errp)
+{
+AspeedSLIState *s = ASPEED_SLI(dev);
+SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sli_ops, s,
+  TYPE_ASPEED_SLI, SLI_REGION_SIZE);
+sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void aspeed_sliio_realize(DeviceState *dev, Error **errp)
+{
+AspeedSLIState *s = ASPEED_SLI(dev);
+SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sliio_ops, s,
+  TYPE_ASPEED_SLI, SLI_REGION_SIZE);
+sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void aspeed_sli_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+
+dc->desc = "Aspeed SLI Controller";
+dc->realize = aspeed_sli_realize;
+}
+
+static const TypeInfo aspeed_sli_info = {
+.name  = TYPE_ASPEED_SLI,
+.parent= TYPE_SYS_BUS_DEVICE,
+.instance_size = sizeof(AspeedSLIState),
+.class_init= aspeed_sli_class_init,
+.abstract  = true,
+};
+
+static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(klass);
+
+dc->desc = "AST2700 SLI Controller";
+}
+
+static void aspeed_2700_sliio_class_init(ObjectClass 

[PATCH v5 00/17] Add AST2700 support

2024-06-03 Thread Jamin Lin via
Changes from v1:
The patch series supports WDT, SDMC, SMC, SCU, SLI and INTC for AST2700 SoC.

Changes from v2:
- replace is_aarch64 with is_bus64bit for sdmc patch review.
- fix incorrect dram size for AST2700

Changes from v3:
- Add AST2700 Evaluation board in ASPEED document
- Add avocado test cases for AST2700 Evaluation board
- Fix reviewers review issues and add reviewers suggestions
- Implement INTC model GICINT 128 to GICINT136 for AST2700

Changes from v4:
- support 64 bits dma dram address associated with review issues
- support dma start length and 1 byte length unit associated with review issues
- refactor intc model to fix serial console stuck issue and associated with 
review issues

Changes from v5:
- sdmc: incrementing the version of vmstate to 2.
- smc: support different memory region ops for SMC flash region
   introduce a new "const MemoryRegionOps *" attribute in AspeedSMCClass and
   use it in aspeed_smc_flash_realize function.
- intc: fix associated with review issues
- dram size detect: change to use address space API and simplify with write
transaction on the DRAM memory region of the SoC.
- ast27x0_soc: update aspeed_soc_ast2700_gic function associated with review 
issues
   and rename to aspeed_soc_ast2700_gic_realize

Test Version:
qemu commit:
https://github.com/qemu/qemu/commit/74abb45dac6979e7ff76172b7f0a24e869405184
applied patch:
https://patchew.org/QEMU/20240527124315.35356-1-...@redhat.com/

Test steps:
1. Download the latest openbmc image for AST2700 from AspeedTech-BMC/openbmc
   repository, https://github.com/AspeedTech-BMC/openbmc/releases/tag/v09.01
   link: 
https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.01/ast2700-default-obmc.tar.gz
2. untar ast2700-default-obmc.tar.gz
   ```
   tar -xf ast2700-default-obmc.tar.gz
   ```
3. Run and the contents of scripts as following
IMGDIR=ast2700-default
UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin)
UBOOT_DTB_ADDR=$((0x4 + ${UBOOT_SIZE}))

qemu-system-aarch64 -M ast2700-evb -nographic\
 -device loader,addr=0x4,file=${IMGDIR}/u-boot-nodtb.bin,force-raw=on\
 -device loader,addr=${UBOOT_DTB_ADDR},file=${IMGDIR}/u-boot.dtb,force-raw=on\
 -device loader,addr=0x43000,file=${IMGDIR}/bl31.bin,force-raw=on\
 -device loader,addr=0x43008,file=${IMGDIR}/optee/tee-raw.bin,force-raw=on\
 -device loader,addr=0x43000,cpu-num=0\
 -device loader,addr=0x43000,cpu-num=1\
 -device loader,addr=0x43000,cpu-num=2\
 -device loader,addr=0x43000,cpu-num=3\
 -smp 4\
 -drive file=${IMGDIR}/image-bmc,format=raw,if=mtd\
 -serial mon:stdio\
 -snapshot

Jamin Lin (17):
  aspeed/wdt: Add AST2700 support
  aspeed/sli: Add AST2700 support
  aspeed/sdmc: remove redundant macros
  aspeed/sdmc: fix coding style
  aspeed/sdmc: Add AST2700 support
  aspeed/smc: correct device description
  aspeed/smc: support dma start length and 1 byte length unit
  aspeed/smc: support 64 bits dma dram address
  aspeed/smc: support different memory region ops for SMC flash region
  aspeed/smc: Add AST2700 support
  aspeed/scu: Add AST2700 support
  aspeed/intc: Add AST2700 support
  aspeed/soc: Add AST2700 support
  aspeed: Add an AST2700 eval board
  aspeed/soc: fix incorrect dram size for AST2700
  test/avocado/machine_aspeed.py: Add AST2700 test case
  docs:aspeed: Add AST2700 Evaluation board

 docs/system/arm/aspeed.rst   |  39 +-
 hw/arm/aspeed.c  |  32 ++
 hw/arm/aspeed_ast27x0.c  | 648 +++
 hw/arm/meson.build   |   1 +
 hw/intc/aspeed_intc.c| 360 +
 hw/intc/meson.build  |   1 +
 hw/intc/trace-events |  13 +
 hw/misc/aspeed_scu.c | 306 ++-
 hw/misc/aspeed_sdmc.c| 220 +--
 hw/misc/aspeed_sli.c | 177 +
 hw/misc/meson.build  |   3 +-
 hw/misc/trace-events |  11 +
 hw/ssi/aspeed_smc.c  | 346 -
 hw/ssi/trace-events  |   2 +-
 hw/watchdog/wdt_aspeed.c |  24 ++
 include/hw/arm/aspeed_soc.h  |  30 +-
 include/hw/intc/aspeed_intc.h|  44 +++
 include/hw/misc/aspeed_scu.h |  47 ++-
 include/hw/misc/aspeed_sdmc.h|   5 +-
 include/hw/misc/aspeed_sli.h |  27 ++
 include/hw/ssi/aspeed_smc.h  |   2 +
 include/hw/watchdog/wdt_aspeed.h |   3 +-
 tests/avocado/machine_aspeed.py  |  62 +++
 23 files changed, 2345 insertions(+), 58 deletions(-)
 create mode 100644 hw/arm/aspeed_ast27x0.c
 create mode 100644 hw/intc/aspeed_intc.c
 create mode 100644 hw/misc/aspeed_sli.c
 create mode 100644 include/hw/intc/aspeed_intc.h
 create mode 100644 include/hw/misc/aspeed_sli.h

-- 
2.25.1




RE: [PATCH v6 18/19] intel_iommu: Implement [set|unset]_iommu_device() callbacks

2024-06-03 Thread Duan, Zhenzhong


>-Original Message-
>From: Eric Auger 
>Subject: Re: [PATCH v6 18/19] intel_iommu: Implement
>[set|unset]_iommu_device() callbacks
>
>Hi Zhenzhong,
>
>On 6/3/24 08:10, Zhenzhong Duan wrote:
>> From: Yi Liu 
>>
>> Implement [set|unset]_iommu_device() callbacks in Intel vIOMMU.
>> In set call, a new structure VTDHostIOMMUDevice which holds
>> a reference to HostIOMMUDevice is stored in hash table
>> indexed by PCI BDF.
>maybe precise that this is not the aliased one?

Sure.

>>
>> Signed-off-by: Yi Liu 
>> Signed-off-by: Yi Sun 
>> Signed-off-by: Zhenzhong Duan 
>> ---
>>  hw/i386/intel_iommu_internal.h |  9 
>>  include/hw/i386/intel_iommu.h  |  2 +
>>  hw/i386/intel_iommu.c  | 76
>++
>>  3 files changed, 87 insertions(+)
>>
>> diff --git a/hw/i386/intel_iommu_internal.h
>b/hw/i386/intel_iommu_internal.h
>> index f8cf99bddf..b800d62ca0 100644
>> --- a/hw/i386/intel_iommu_internal.h
>> +++ b/hw/i386/intel_iommu_internal.h
>> @@ -28,6 +28,7 @@
>>  #ifndef HW_I386_INTEL_IOMMU_INTERNAL_H
>>  #define HW_I386_INTEL_IOMMU_INTERNAL_H
>>  #include "hw/i386/intel_iommu.h"
>> +#include "sysemu/host_iommu_device.h"
>>
>>  /*
>>   * Intel IOMMU register specification
>> @@ -537,4 +538,12 @@ typedef struct VTDRootEntry VTDRootEntry;
>>  #define VTD_SL_IGN_COM  0xbff0ULL
>>  #define VTD_SL_TM   (1ULL << 62)
>>
>> +
>> +typedef struct VTDHostIOMMUDevice {
>> +IntelIOMMUState *iommu_state;
>Why do you need the iommu_state?

It is used in nesting series.

>> +PCIBus *bus;
>> +uint8_t devfn;
>> +HostIOMMUDevice *dev;
>> +QLIST_ENTRY(VTDHostIOMMUDevice) next;
>> +} VTDHostIOMMUDevice;
>How VTD specific is it?

In nesting series, it has element iommu_state and errata
which are VTD specific.

>>  #endif
>> diff --git a/include/hw/i386/intel_iommu.h
>b/include/hw/i386/intel_iommu.h
>> index 7d694b0813..2bbde41e45 100644
>> --- a/include/hw/i386/intel_iommu.h
>> +++ b/include/hw/i386/intel_iommu.h
>> @@ -293,6 +293,8 @@ struct IntelIOMMUState {
>>  /* list of registered notifiers */
>>  QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers;
>>
>> +GHashTable *vtd_host_iommu_dev; /* VTDHostIOMMUDevice
>*/
>> +
>>  /* interrupt remapping */
>>  bool intr_enabled;  /* Whether guest enabled IR */
>>  dma_addr_t intr_root;   /* Interrupt remapping table pointer */
>> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
>> index 519063c8f8..747c988bc4 100644
>> --- a/hw/i386/intel_iommu.c
>> +++ b/hw/i386/intel_iommu.c
>> @@ -237,6 +237,13 @@ static gboolean vtd_as_equal(gconstpointer v1,
>gconstpointer v2)
>> (key1->pasid == key2->pasid);
>>  }
>>
>> +static gboolean vtd_as_idev_equal(gconstpointer v1, gconstpointer v2)
>> +{
>> +const struct vtd_as_key *key1 = v1;
>> +const struct vtd_as_key *key2 = v2;
>> +
>> +return (key1->bus == key2->bus) && (key1->devfn == key2->devfn);
>> +}
>can't you reuse the key with pasid?

s->vtd_host_iommu_dev isn't indexed by pasid but only BDF.
Maybe I'd better to define its own key struct, hash() and equal() functions.

>>  /*
>>   * Note that we use pointer to PCIBus as the key, so hashing/shifting
>>   * based on the pointer value is intended. Note that we deal with
>> @@ -3812,6 +3819,70 @@ VTDAddressSpace
>*vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
>>  return vtd_dev_as;
>>  }
>>
>> +static bool vtd_dev_set_iommu_device(PCIBus *bus, void *opaque, int
>devfn,
>> + HostIOMMUDevice *hiod, Error **errp)
>> +{
>> +IntelIOMMUState *s = opaque;
>> +VTDHostIOMMUDevice *vtd_hdev;
>> +struct vtd_as_key key = {
>> +.bus = bus,
>> +.devfn = devfn,
>> +};
>> +struct vtd_as_key *new_key;
>> +
>> +assert(hiod);
>> +
>> +vtd_iommu_lock(s);
>> +
>> +vtd_hdev = g_hash_table_lookup(s->vtd_host_iommu_dev, &key);
>> +
>> +if (vtd_hdev) {
>> +error_setg(errp, "IOMMUFD device already exist");
>s/IOMMUFD/Host IOMMU device?

Good catch, will fix.

Thanks
Zhenzhong

>> +vtd_iommu_unlock(s);
>> +return false;
>> +}
>> +
>> +vtd_hdev = g_malloc0(sizeof(VTDHostIOMMUDevice));
>> +vtd_hdev->bus = bus;
>> +vtd_hdev->devfn = (uint8_t)devfn;
>> +vtd_hdev->iommu_state = s;
>> +vtd_hdev->dev = hiod;
>> +
>> +new_key = g_malloc(sizeof(*new_key));
>> +new_key->bus = bus;
>> +new_key->devfn = devfn;
>> +
>> +object_ref(hiod);
>> +g_hash_table_insert(s->vtd_host_iommu_dev, new_key, vtd_hdev);
>> +
>> +vtd_iommu_unlock(s);
>> +
>> +return true;
>> +}
>> +
>> +static void vtd_dev_unset_iommu_device(PCIBus *bus, void *opaque, int
>devfn)
>> +{
>> +IntelIOMMUState *s = opaque;
>> +VTDHostIOMMUDevice *vtd_hdev;
>> +struct vtd_as_key key = {
>> +.bus = bus,
>> +.devfn = devfn,
>> +};
>> +
>> +vtd_iommu_lock(s);
>> +
>> +vtd_hdev = g_hash

Re: [PATCH] hw/core: Rename CpuTopology to CPUTopology

2024-06-03 Thread Markus Armbruster
Zhao Liu  writes:

> On Mon, Jun 03, 2024 at 01:54:15PM +0200, Markus Armbruster wrote:
>> Date: Mon, 03 Jun 2024 13:54:15 +0200
>> From: Markus Armbruster 
>> Subject: Re: [PATCH] hw/core: Rename CpuTopology to CPUTopology
>> 
>> Zhao Liu  writes:
>> 
>> > Use CPUTopology to honor the generic style of CPU capitalization
>> > abbreviations.
>> >
>> > Signed-off-by: Zhao Liu 
>> 
>> Is CPUFoo really more common than CpuFoo?  It isn't in the qapi
>> schema...
>
> Hi Markus, do you think this style needs to be standardized?
>
> All-caps cases, like the widely used CPUState.
>
> And the common structures declared in include/qemu/typedefs.h, are all
> using CPU, not Cpu...
>
> If you feel this is necessary, I'd be happy to help more places change
> their names to standardize their style...

The situation is unfortunate[*].  The renaming cure could be worse than
the disease, though.

In a situation like this, settling for local consistency is often the
least bad.  machine.json is locally consistent: it consistently uses
CpuFoo.


[*] We suck at systematic, disciplined naming.




Re: [PATCH 0/4] hw/s390x: Alias @dump-skeys -> @dump-s390-skey and deprecate

2024-06-03 Thread Markus Armbruster
"Dr. David Alan Gilbert"  writes:

> * Daniel P. Berrangé (berra...@redhat.com) wrote:
>> On Fri, May 31, 2024 at 06:47:45AM +0200, Thomas Huth wrote:
>> > On 30/05/2024 09.45, Philippe Mathieu-Daudé wrote:
>> > > We are trying to unify all qemu-system-FOO to a single binary.
>> > > In order to do that we need to remove QAPI target specific code.
>> > > 
>> > > @dump-skeys is only available on qemu-system-s390x. This series
>> > > rename it as @dump-s390-skey, making it available on other
>> > > binaries. We take care of backward compatibility via deprecation.
>> > > 
>> > > Philippe Mathieu-Daudé (4):
>> > >hw/s390x: Introduce the @dump-s390-skeys QMP command
>> > >hw/s390x: Introduce the 'dump_s390_skeys' HMP command
>> > >hw/s390x: Deprecate the HMP 'dump_skeys' command
>> > >hw/s390x: Deprecate the QMP @dump-skeys command
>> > 
>> > Why do we have to rename the command? Just for the sake of it? I think
>> > renaming HMP commands is maybe ok, but breaking the API in QMP is something
>> > you should consider twice.

PRO rename: the command's tie to S390 is them immediately obvious, which
may be useful when the command becomes available in qemu-systems capable
of running other targets.

CON rename: users need to adapt.

What are the users?  Not libvirt, as far as I can tell.

>> That was going to be my question too. Seems like its possible to simply
>> stub out the existing command for other targets.

That's going to happen whether we rename the commands or not.

> Are these commands really supposed to be stable, or are they just debug
> commands?  If they are debug, then add the x- and don't worry too much.

docs/devel/qapi-code-gen.rst:

Names beginning with ``x-`` used to signify "experimental".  This
convention has been replaced by special feature "unstable".

Feature "unstable" is what makes something unstable, and is what
machines should check.

An "x-" prefix may still be useful for humans.  Machines should *not*
key on the prefix.  It's unreliable anyway: InputBarrierProperties
member @x-origin is stable despite it's name.  Renames to gain or lose
the prefix may or may not be worth the bother.

Making an existing part of the interface unstable should be treated
similar to deprecating it: we keep it stable for at least the
deprecation period.  Not written policy, because we didn't consider such
changes when we documented our deprecation policy in
docs/about/deprecated.rst.

Alternative path to a renamed command (*if* we want that):

1. Make it unstable.

2. But keep it stable for two releases.

3. Rename.

[...]




[PATCH v5 3/4] target/riscv: Apply modularized matching conditions for watchpoint

2024-06-03 Thread Alvin Chang via
We have implemented trigger_common_match(), which checks if the enabled
privilege levels of the trigger match CPU's current privilege level.
Remove the related code in riscv_cpu_debug_check_watchpoint() and invoke
trigger_common_match() to check the privilege levels of the type 2 and
type 6 triggers for the watchpoints.

This commit also changes the behavior of looping the triggers. In
previous implementation, if we have a type 2 trigger and
env->virt_enabled is true, we directly return false to stop the loop.
Now we keep looping all the triggers until we find a matched trigger.

Only load/store bits and loaded/stored address should be further checked
in riscv_cpu_debug_check_watchpoint().

Signed-off-by: Alvin Chang 
Acked-by: Alistair Francis 
---
 target/riscv/debug.c | 26 ++
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 11125f333b..c290d6002e 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -901,13 +901,12 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, 
CPUWatchpoint *wp)
 for (i = 0; i < RV_MAX_TRIGGERS; i++) {
 trigger_type = get_trigger_type(env, i);
 
+if (!trigger_common_match(env, trigger_type, i)) {
+continue;
+}
+
 switch (trigger_type) {
 case TRIGGER_TYPE_AD_MATCH:
-/* type 2 trigger cannot be fired in VU/VS mode */
-if (env->virt_enabled) {
-return false;
-}
-
 ctrl = env->tdata1[i];
 addr = env->tdata2[i];
 flags = 0;
@@ -920,10 +919,7 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, 
CPUWatchpoint *wp)
 }
 
 if ((wp->flags & flags) && (wp->vaddr == addr)) {
-/* check U/S/M bit against current privilege level */
-if ((ctrl >> 3) & BIT(env->priv)) {
-return true;
-}
+return true;
 }
 break;
 case TRIGGER_TYPE_AD_MATCH6:
@@ -939,17 +935,7 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, 
CPUWatchpoint *wp)
 }
 
 if ((wp->flags & flags) && (wp->vaddr == addr)) {
-if (env->virt_enabled) {
-/* check VU/VS bit against current privilege level */
-if ((ctrl >> 23) & BIT(env->priv)) {
-return true;
-}
-} else {
-/* check U/S/M bit against current privilege level */
-if ((ctrl >> 3) & BIT(env->priv)) {
-return true;
-}
-}
+return true;
 }
 break;
 default:
-- 
2.34.1




[PATCH v5 4/4] target/riscv: Apply modularized matching conditions for icount trigger

2024-06-03 Thread Alvin Chang via
We have implemented trigger_common_match(), which checks if the enabled
privilege levels of the trigger match CPU's current privilege level. We
can invoke trigger_common_match() to check the privilege levels of the
type 3 triggers.

Signed-off-by: Alvin Chang 
Acked-by: Alistair Francis 
---
 target/riscv/debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index c290d6002e..0b5099ff9a 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -624,7 +624,7 @@ void helper_itrigger_match(CPURISCVState *env)
 if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
 continue;
 }
-if (check_itrigger_priv(env, i)) {
+if (!trigger_common_match(env, TRIGGER_TYPE_INST_CNT, i)) {
 continue;
 }
 count = itrigger_get_count(env, i);
-- 
2.34.1




[PATCH v5 1/4] target/riscv: Add functions for common matching conditions of trigger

2024-06-03 Thread Alvin Chang via
According to RISC-V Debug specification version 0.13 [1] (also applied
to version 1.0 [2] but it has not been ratified yet), there are several
common matching conditions before firing a trigger, including the
enabled privilege levels of the trigger.

This commit adds trigger_common_match() to prepare the common matching
conditions for the type 2/3/6 triggers. For now, we just implement
trigger_priv_match() to check if the enabled privilege levels of the
trigger match CPU's current privilege level.

[1]: https://github.com/riscv/riscv-debug-spec/releases/tag/task_group_vote
[2]: https://github.com/riscv/riscv-debug-spec/releases/tag/1.0.0-rc1-asciidoc

Signed-off-by: Alvin Chang 
Reviewed-by: Alistair Francis 
---
 target/riscv/debug.c | 70 
 1 file changed, 70 insertions(+)

diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index b110370ea6..05e001d041 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -241,6 +241,76 @@ static void do_trigger_action(CPURISCVState *env, 
target_ulong trigger_index)
 }
 }
 
+/*
+ * Check the privilege level of specific trigger matches CPU's current 
privilege
+ * level.
+ */
+static bool trigger_priv_match(CPURISCVState *env, trigger_type_t type,
+   int trigger_index)
+{
+target_ulong ctrl = env->tdata1[trigger_index];
+
+switch (type) {
+case TRIGGER_TYPE_AD_MATCH:
+/* type 2 trigger cannot be fired in VU/VS mode */
+if (env->virt_enabled) {
+return false;
+}
+/* check U/S/M bit against current privilege level */
+if ((ctrl >> 3) & BIT(env->priv)) {
+return true;
+}
+break;
+case TRIGGER_TYPE_AD_MATCH6:
+if (env->virt_enabled) {
+/* check VU/VS bit against current privilege level */
+if ((ctrl >> 23) & BIT(env->priv)) {
+return true;
+}
+} else {
+/* check U/S/M bit against current privilege level */
+if ((ctrl >> 3) & BIT(env->priv)) {
+return true;
+}
+}
+break;
+case TRIGGER_TYPE_INST_CNT:
+if (env->virt_enabled) {
+/* check VU/VS bit against current privilege level */
+if ((ctrl >> 25) & BIT(env->priv)) {
+return true;
+}
+} else {
+/* check U/S/M bit against current privilege level */
+if ((ctrl >> 6) & BIT(env->priv)) {
+return true;
+}
+}
+break;
+case TRIGGER_TYPE_INT:
+case TRIGGER_TYPE_EXCP:
+case TRIGGER_TYPE_EXT_SRC:
+qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n", type);
+break;
+case TRIGGER_TYPE_NO_EXIST:
+case TRIGGER_TYPE_UNAVAIL:
+qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exist\n",
+  type);
+break;
+default:
+g_assert_not_reached();
+}
+
+return false;
+}
+
+/* Common matching conditions for all types of the triggers. */
+static bool trigger_common_match(CPURISCVState *env, trigger_type_t type,
+ int trigger_index)
+{
+return trigger_priv_match(env, type, trigger_index);
+}
+
 /* type 2 trigger */
 
 static uint32_t type2_breakpoint_size(CPURISCVState *env, target_ulong ctrl)
-- 
2.34.1




[PATCH v5 2/4] target/riscv: Apply modularized matching conditions for breakpoint

2024-06-03 Thread Alvin Chang via
We have implemented trigger_common_match(), which checks if the enabled
privilege levels of the trigger match CPU's current privilege level.
Remove the related code in riscv_cpu_debug_check_breakpoint() and invoke
trigger_common_match() to check the privilege levels of the type 2 and
type 6 triggers for the breakpoints.

This commit also changes the behavior of looping the triggers. In
previous implementation, if we have a type 2 trigger and
env->virt_enabled is true, we directly return false to stop the loop.
Now we keep looping all the triggers until we find a matched trigger.

Only the execution bit and the executed PC should be futher checked in
riscv_cpu_debug_check_breakpoint().

Signed-off-by: Alvin Chang 
Reviewed-by: Alistair Francis 
---
 target/riscv/debug.c | 31 ---
 1 file changed, 8 insertions(+), 23 deletions(-)

diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 05e001d041..11125f333b 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -855,22 +855,18 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
 for (i = 0; i < RV_MAX_TRIGGERS; i++) {
 trigger_type = get_trigger_type(env, i);
 
+if (!trigger_common_match(env, trigger_type, i)) {
+continue;
+}
+
 switch (trigger_type) {
 case TRIGGER_TYPE_AD_MATCH:
-/* type 2 trigger cannot be fired in VU/VS mode */
-if (env->virt_enabled) {
-return false;
-}
-
 ctrl = env->tdata1[i];
 pc = env->tdata2[i];
 
 if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) {
-/* check U/S/M bit against current privilege level */
-if ((ctrl >> 3) & BIT(env->priv)) {
-env->badaddr = pc;
-return true;
-}
+env->badaddr = pc;
+return true;
 }
 break;
 case TRIGGER_TYPE_AD_MATCH6:
@@ -878,19 +874,8 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
 pc = env->tdata2[i];
 
 if ((ctrl & TYPE6_EXEC) && (bp->pc == pc)) {
-if (env->virt_enabled) {
-/* check VU/VS bit against current privilege level */
-if ((ctrl >> 23) & BIT(env->priv)) {
-env->badaddr = pc;
-return true;
-}
-} else {
-/* check U/S/M bit against current privilege level */
-if ((ctrl >> 3) & BIT(env->priv)) {
-env->badaddr = pc;
-return true;
-}
-}
+env->badaddr = pc;
+return true;
 }
 break;
 default:
-- 
2.34.1




[PATCH v5 0/4] RISC-V: Modularize common match conditions for trigger

2024-06-03 Thread Alvin Chang via
According to RISC-V Debug specification ratified version 0.13 [1]
(also applied to version 1.0 [2] but it has not been ratified yet), the
enabled privilege levels of the trigger is common match conditions for
all the types of the trigger.

This series modularize the code for checking the privilege levels of
type 2/3/6 triggers by implementing functions trigger_common_match()
and trigger_priv_match().

Additional match conditions, such as CSR tcontrol and textra, can be
further implemented into trigger_common_match() in the future.

[1]: https://github.com/riscv/riscv-debug-spec/releases/tag/task_group_vote
[2]: https://github.com/riscv/riscv-debug-spec/releases/tag/1.0.0-rc1-asciidoc

Changes from v4:
- Rebasing on riscv-to-apply.next 

Changes from v3:
- Change this series to target Debug Spec. version 0.13

Changes from v2:
- Explicitly mention the targeting version of RISC-V Debug Spec.

Changes from v1:
- Fix typo
- Add commit description for changing behavior of looping the triggers
  when we check type 2 triggers.

Alvin Chang (4):
  target/riscv: Add functions for common matching conditions of trigger
  target/riscv: Apply modularized matching conditions for breakpoint
  target/riscv: Apply modularized matching conditions for watchpoint
  target/riscv: Apply modularized matching conditions for icount trigger

 target/riscv/debug.c | 129 ---
 1 file changed, 85 insertions(+), 44 deletions(-)

-- 
2.34.1




RE: [PATCH v4 0/4] RISC-V: Modularize common match conditions for trigger

2024-06-03 Thread 張哲嘉
> -Original Message-
> From: Alistair Francis 
> Sent: Tuesday, June 4, 2024 9:58 AM
> To: Alvin Che-Chia Chang(張哲嘉) 
> Cc: qemu-ri...@nongnu.org; qemu-devel@nongnu.org;
> alistair.fran...@wdc.com; bin.m...@windriver.com; liwei1...@gmail.com;
> dbarb...@ventanamicro.com; zhiwei_...@linux.alibaba.com
> Subject: Re: [PATCH v4 0/4] RISC-V: Modularize common match conditions for
> trigger
>
> [EXTERNAL MAIL]
>
> On Thu, Mar 7, 2024 at 12:36 PM Alvin Che-Chia Chang(張哲嘉)
>  wrote:
> >
> > Hi Alistair,
> >
> > Please also take a look at this series, I guess it is ready to be applied, 
> > thanks!
>
> This is all acked now, do you mind rebasing on
> https://github.com/alistair23/qemu/tree/riscv-to-apply.next and sending a new
> version

Done, please check patch v5.
I also took care of Daniel's latest patch:
https://github.com/alistair23/qemu/commit/0099f6053410f5611796213b723e908cfc8055eb


BRs,
Alvin

>
> Alistair
>
> >
> >
> > BRs,
> > Alvin
> >
> > > -Original Message-
> > > From: Alvin Che-Chia Chang(張哲嘉) 
> > > Sent: Tuesday, February 27, 2024 9:24 AM
> > > To: qemu-ri...@nongnu.org; qemu-devel@nongnu.org
> > > Cc: alistair.fran...@wdc.com; bin.m...@windriver.com;
> > > liwei1...@gmail.com; dbarb...@ventanamicro.com;
> > > zhiwei_...@linux.alibaba.com; Alvin Che-Chia Chang(張哲嘉)
> > > 
> > > Subject: [PATCH v4 0/4] RISC-V: Modularize common match conditions
> > > for trigger
> > >
> > > According to RISC-V Debug specification ratified version 0.13 [1]
> > > (also applied to version 1.0 [2] but it has not been ratified yet),
> > > the enabled privilege levels of the trigger is common match conditions for
> all the types of the trigger.
> > >
> > > This series modularize the code for checking the privilege levels of
> > > type 2/3/6 triggers by implementing functions trigger_common_match()
> > > and trigger_priv_match().
> > >
> > > Additional match conditions, such as CSR tcontrol and textra, can be
> > > further implemented into trigger_common_match() in the future.
> > >
> > > [1]:
> > > https://github.com/riscv/riscv-debug-spec/releases/tag/task_group_vo
> > > te
> > > [2]:
> > > https://github.com/riscv/riscv-debug-spec/releases/tag/1.0.0-rc1-asc
> > > iidoc
> > >
> > > Changes from v3:
> > > - Change this series to target Debug Spec. version 0.13
> > >
> > > Changes from v2:
> > > - Explicitly mention the targeting version of RISC-V Debug Spec.
> > >
> > > Changes from v1:
> > > - Fix typo
> > > - Add commit description for changing behavior of looping the triggers
> > >   when we check type 2 triggers.
> > >
> > > Alvin Chang (4):
> > >   target/riscv: Add functions for common matching conditions of trigger
> > >   target/riscv: Apply modularized matching conditions for breakpoint
> > >   target/riscv: Apply modularized matching conditions for watchpoint
> > >   target/riscv: Apply modularized matching conditions for icount
> > > trigger
> > >
> > >  target/riscv/debug.c | 124
> > > +--
> > >  1 file changed, 83 insertions(+), 41 deletions(-)
> > >
> > > --
> > > 2.34.1
> >
> > CONFIDENTIALITY NOTICE:
> >
> > This e-mail (and its attachments) may contain confidential and legally
> privileged information or information protected from disclosure. If you are 
> not
> the intended recipient, you are hereby notified that any disclosure, copying,
> distribution, or use of the information contained herein is strictly 
> prohibited. In
> this case, please immediately notify the sender by return e-mail, delete the
> message (and any accompanying documents) and destroy all printed hard
> copies. Thank you for your cooperation.
> >
> > Copyright ANDES TECHNOLOGY CORPORATION - All Rights Reserved.
CONFIDENTIALITY NOTICE:

This e-mail (and its attachments) may contain confidential and legally 
privileged information or information protected from disclosure. If you are not 
the intended recipient, you are hereby notified that any disclosure, copying, 
distribution, or use of the information contained herein is strictly 
prohibited. In this case, please immediately notify the sender by return 
e-mail, delete the message (and any accompanying documents) and destroy all 
printed hard copies. Thank you for your cooperation.

Copyright ANDES TECHNOLOGY CORPORATION - All Rights Reserved.


  1   2   3   4   5   >