Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging

* fixes for i386 TCG paging
* fixes for Hyper-V enlightenments
* avoid uninitialized variable warning

# gpg: Signature made Fri 19 Mar 2021 14:38:12 GMT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini-gitlab/tags/for-upstream:
  tests/qtest: cleanup the testcase for bug 1878642
  hw/intc/i8259: Refactor pic_read_irq() to avoid uninitialized variable
  i386: Make migration fail when Hyper-V reenlightenment was enabled but 'user_tsc_khz' is unset
  i386: Fix 'hypercall_hypercall' typo
  target/i386: svm: do not discard high 32 bits of EXITINFO1
  target/i386: fail if toggling LA57 in 64-bit mode
  target/i386: allow modifying TCG phys-addr-bits
  qom: use qemu_printf to print help for user-creatable objects

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/docs/hyperv.txt b/docs/hyperv.txt
index 5df00da..e53c581 100644
--- a/docs/hyperv.txt
+++ b/docs/hyperv.txt
@@ -160,6 +160,11 @@
 with hv-frequencies, allows Hyper-V on KVM to pass stable clocksource (Reference
 TSC page) to its own guests.
 
+Note, KVM doesn't fully support re-enlightenment notifications and doesn't
+emulate TSC accesses after migration so 'tsc-frequency=' CPU option also has to
+be specified to make migration succeed. The destination host has to either have
+the same TSC frequency or support TSC scaling CPU feature.
+
 Recommended: hv-frequencies
 
 3.16. hv-evmcs
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index 344fd04..cc4e21f 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -176,10 +176,12 @@
 int pic_read_irq(DeviceState *d)
 {
     PICCommonState *s = PIC_COMMON(d);
-    int irq, irq2, intno;
+    int irq, intno;
 
     irq = pic_get_irq(s);
     if (irq >= 0) {
+        int irq2;
+
         if (irq == 2) {
             irq2 = pic_get_irq(slave_pic);
             if (irq2 >= 0) {
@@ -189,20 +191,18 @@
                 irq2 = 7;
             }
             intno = slave_pic->irq_base + irq2;
+            pic_intack(s, irq);
+            irq = irq2 + 8;
         } else {
             intno = s->irq_base + irq;
+            pic_intack(s, irq);
         }
-        pic_intack(s, irq);
     } else {
         /* spurious IRQ on host controller */
         irq = 7;
         intno = s->irq_base + irq;
     }
 
-    if (irq == 2) {
-        irq = irq2 + 8;
-    }
-
 #ifdef DEBUG_IRQ_LATENCY
     printf("IRQ%d latency=%0.3fus\n",
            irq,
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index b17aa57..c3324b0 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -17,6 +17,7 @@
 #include "qemu/qemu-print.h"
 #include "qapi/opts-visitor.h"
 #include "qemu/config-file.h"
+#include "qemu/qemu-print.h"
 
 bool user_creatable_complete(UserCreatable *uc, Error **errp)
 {
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ae9fd9f..6b3e946 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6785,21 +6785,14 @@
                     cpu->phys_bits = cpu->host_phys_bits_limit;
                 }
             }
-
-            if (cpu->phys_bits &&
-                (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS ||
-                cpu->phys_bits < 32)) {
-                error_setg(errp, "phys-bits should be between 32 and %u "
-                                 " (but is %u)",
-                                 TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits);
-                return;
-            }
-        } else {
-            if (cpu->phys_bits && cpu->phys_bits != TCG_PHYS_ADDR_BITS) {
-                error_setg(errp, "TCG only supports phys-bits=%u",
-                                  TCG_PHYS_ADDR_BITS);
-                return;
-            }
+        }
+        if (cpu->phys_bits &&
+            (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS ||
+            cpu->phys_bits < 32)) {
+            error_setg(errp, "phys-bits should be between 32 and %u "
+                             " (but is %u)",
+                             TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits);
+            return;
         }
         /* 0 means it was not explicitly set by the user (or by machine
          * compat_props or by the host code above). In this case, the default
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index b4b136c..570f916 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -290,7 +290,6 @@
 #define PG_GLOBAL_MASK   (1 << PG_GLOBAL_BIT)
 #define PG_PSE_PAT_MASK  (1 << PG_PSE_PAT_BIT)
 #define PG_ADDRESS_MASK  0x000ffffffffff000LL
-#define PG_HI_RSVD_MASK  (PG_ADDRESS_MASK & ~PHYS_ADDR_MASK)
 #define PG_HI_USER_MASK  0x7ff0000000000000LL
 #define PG_PKRU_MASK     (15ULL << PG_PKRU_BIT)
 #define PG_NX_MASK       (1ULL << PG_NX_BIT)
diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h
index 056a305..e30d64b 100644
--- a/target/i386/kvm/hyperv-proto.h
+++ b/target/i386/kvm/hyperv-proto.h
@@ -139,6 +139,7 @@
  * Reenlightenment notification MSRs
  */
 #define HV_X64_MSR_REENLIGHTENMENT_CONTROL      0x40000106
+#define HV_REENLIGHTENMENT_ENABLE_BIT           (1u << 16)
 #define HV_X64_MSR_TSC_EMULATION_CONTROL        0x40000107
 #define HV_X64_MSR_TSC_EMULATION_STATUS         0x40000108
 
diff --git a/target/i386/machine.c b/target/i386/machine.c
index 3967dfc..137604d 100644
--- a/target/i386/machine.c
+++ b/target/i386/machine.c
@@ -705,7 +705,7 @@
     return env->msr_hv_hypercall != 0 || env->msr_hv_guest_os_id != 0;
 }
 
-static const VMStateDescription vmstate_msr_hypercall_hypercall = {
+static const VMStateDescription vmstate_msr_hyperv_hypercall = {
     .name = "cpu/msr_hyperv_hypercall",
     .version_id = 1,
     .minimum_version_id = 1,
@@ -883,11 +883,31 @@
         env->msr_hv_tsc_emulation_status != 0;
 }
 
+static int hyperv_reenlightenment_post_load(void *opaque, int version_id)
+{
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
+
+    /*
+     * KVM doesn't fully support re-enlightenment notifications so we need to
+     * make sure TSC frequency doesn't change upon migration.
+     */
+    if ((env->msr_hv_reenlightenment_control & HV_REENLIGHTENMENT_ENABLE_BIT) &&
+        !env->user_tsc_khz) {
+        error_report("Guest enabled re-enlightenment notifications, "
+                     "'tsc-frequency=' has to be specified");
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
 static const VMStateDescription vmstate_msr_hyperv_reenlightenment = {
     .name = "cpu/msr_hyperv_reenlightenment",
     .version_id = 1,
     .minimum_version_id = 1,
     .needed = hyperv_reenlightenment_enable_needed,
+    .post_load = hyperv_reenlightenment_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_UINT64(env.msr_hv_reenlightenment_control, X86CPU),
         VMSTATE_UINT64(env.msr_hv_tsc_emulation_control, X86CPU),
@@ -1484,7 +1504,7 @@
         &vmstate_msr_ia32_feature_control,
         &vmstate_msr_architectural_pmu,
         &vmstate_mpx,
-        &vmstate_msr_hypercall_hypercall,
+        &vmstate_msr_hyperv_hypercall,
         &vmstate_msr_hyperv_vapic,
         &vmstate_msr_hyperv_time,
         &vmstate_msr_hyperv_crash,
diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c
index b7d6259..1e71e44 100644
--- a/target/i386/tcg/excp_helper.c
+++ b/target/i386/tcg/excp_helper.c
@@ -142,8 +142,9 @@
 static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
                         int *prot)
 {
-    CPUX86State *env = &X86_CPU(cs)->env;
-    uint64_t rsvd_mask = PG_HI_RSVD_MASK;
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+    uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
     uint64_t ptep, pte;
     uint64_t exit_info_1 = 0;
     target_ulong pde_addr, pte_addr;
@@ -358,7 +359,7 @@
     int error_code = 0;
     int is_dirty, prot, page_size, is_write, is_user;
     hwaddr paddr;
-    uint64_t rsvd_mask = PG_HI_RSVD_MASK;
+    uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
     uint32_t page_offset;
     target_ulong vaddr;
     uint32_t pkr;
diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h
index c133c63..bcdfca0 100644
--- a/target/i386/tcg/helper-tcg.h
+++ b/target/i386/tcg/helper-tcg.h
@@ -25,17 +25,13 @@
 /* Maximum instruction code size */
 #define TARGET_MAX_INSN_SIZE 16
 
-/*
- * XXX: This value should match the one returned by CPUID
- * and in exec.c
- */
-# if defined(TARGET_X86_64)
+#if defined(TARGET_X86_64)
 # define TCG_PHYS_ADDR_BITS 40
-# else
+#else
 # define TCG_PHYS_ADDR_BITS 36
-# endif
+#endif
 
-#define PHYS_ADDR_MASK MAKE_64BIT_MASK(0, TCG_PHYS_ADDR_BITS)
+QEMU_BUILD_BUG_ON(TCG_PHYS_ADDR_BITS > TARGET_PHYS_ADDR_SPACE_BITS);
 
 /**
  * x86_cpu_do_interrupt:
@@ -84,7 +80,7 @@
 /* svm_helper.c */
 void QEMU_NORETURN cpu_vmexit(CPUX86State *nenv, uint32_t exit_code,
                               uint64_t exit_info_1, uintptr_t retaddr);
-void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1);
+void do_vmexit(CPUX86State *env);
 
 /* seg_helper.c */
 void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index 90b87fd..a25428c 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -167,6 +167,10 @@
         cpu_x86_update_cr3(env, t0);
         break;
     case 4:
+        if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) &&
+            (env->hflags & HF_CS64_MASK)) {
+             raise_exception_ra(env, EXCP0D_GPF, GETPC());
+        }
         cpu_x86_update_cr4(env, t0);
         break;
     case 8:
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index 180d47f..d180a38 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -1305,9 +1305,9 @@
     /* successfully delivered */
     env->old_exception = -1;
 #else
-    if (cs->exception_index >= EXCP_VMEXIT) {
+    if (cs->exception_index == EXCP_VMEXIT) {
         assert(env->old_exception == -1);
-        do_vmexit(env, cs->exception_index - EXCP_VMEXIT, env->error_code);
+        do_vmexit(env);
     } else {
         do_interrupt_all(cpu, cs->exception_index,
                          env->exception_is_int,
diff --git a/target/i386/tcg/svm_helper.c b/target/i386/tcg/svm_helper.c
index 097bb9b..0145afc 100644
--- a/target/i386/tcg/svm_helper.c
+++ b/target/i386/tcg/svm_helper.c
@@ -621,15 +621,19 @@
                                                    control.exit_info_2)),
                   env->eip);
 
-    cs->exception_index = EXCP_VMEXIT + exit_code;
-    env->error_code = exit_info_1;
+    cs->exception_index = EXCP_VMEXIT;
+    x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
+             exit_code);
+
+    x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
+                                             control.exit_info_1), exit_info_1),
 
     /* remove any pending exception */
     env->old_exception = -1;
     cpu_loop_exit(cs);
 }
 
-void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
+void do_vmexit(CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
     uint32_t int_ctl;
@@ -762,11 +766,6 @@
                           env->vm_hsave + offsetof(struct vmcb, save.dr7));
 
     /* other setups */
-    x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
-             exit_code);
-    x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1),
-             exit_info_1);
-
     x86_stl_phys(cs,
              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
diff --git a/tests/qtest/fuzz-test.c b/tests/qtest/lpc-ich9-test.c
similarity index 71%
rename from tests/qtest/fuzz-test.c
rename to tests/qtest/lpc-ich9-test.c
index 00149ab..fe0bef9 100644
--- a/tests/qtest/fuzz-test.c
+++ b/tests/qtest/lpc-ich9-test.c
@@ -1,5 +1,5 @@
 /*
- * QTest testcase for fuzz case
+ * QTest testcases for ich9 case
  *
  * Copyright (c) 2020 Li Qiang <liq3ea@gmail.com>
  *
@@ -18,9 +18,11 @@
     s = qtest_init("-M pc-q35-5.0 "
                    "-nographic -monitor none -serial none");
 
-    qtest_outl(s, 0xcf8, 0x8400f841);
-    qtest_outl(s, 0xcfc, 0xebed205d);
-    qtest_outl(s, 0x5d02, 0xebed205d);
+    qtest_outl(s, 0xcf8, 0x8000f840); /* PMBASE */
+    qtest_outl(s, 0xcfc, 0x5d00);
+    qtest_outl(s, 0xcf8, 0x8000f844); /* ACPI_CTRL */
+    qtest_outl(s, 0xcfc, 0xeb);
+    qtest_outw(s, 0x5d02, 0x205d);
     qtest_quit(s);
 }
 
@@ -31,7 +33,7 @@
     g_test_init(&argc, &argv, NULL);
 
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qtest_add_func("fuzz/test_lp1878642_pci_bus_get_irq_level_assert",
+        qtest_add_func("ich9/test_lp1878642_pci_bus_get_irq_level_assert",
                        test_lp1878642_pci_bus_get_irq_level_assert);
     }
 
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 6e87107..9731606 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -57,6 +57,7 @@
   (config_all_devices.has_key('CONFIG_HDA') ? ['intel-hda-test'] : []) +                    \
   (config_all_devices.has_key('CONFIG_I82801B11') ? ['i82801b11-test'] : []) +             \
   (config_all_devices.has_key('CONFIG_IOH3420') ? ['ioh3420-test'] : []) +                  \
+  (config_all_devices.has_key('CONFIG_LPC_ICH9') ? ['lpc-ich9-test'] : []) +              \
   (config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) +            \
   (config_all_devices.has_key('CONFIG_USB_UHCI') and                                        \
    config_all_devices.has_key('CONFIG_USB_EHCI') ? ['usb-hcd-ehci-test'] : []) +            \
@@ -74,7 +75,6 @@
    'bios-tables-test',
    'rtc-test',
    'i440fx-test',
-   'fuzz-test',
    'fw_cfg-test',
    'device-plug-test',
    'drive_del-test',