Created
March 2, 2026 16:10
-
-
Save Mintsuki/25129025509e7f8e30521c1f7940aad4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff -ruN '--exclude=build' '--exclude=*.o' '--exclude=*.pyc' '--exclude=__pycache__' a/hw/intc/apic.c b/hw/intc/apic.c | |
| --- a/hw/intc/apic.c 2025-12-23 20:48:56.000000000 +0100 | |
| +++ b/hw/intc/apic.c 2026-03-02 00:44:42.007386449 +0100 | |
| @@ -41,6 +41,42 @@ | |
| static uint32_t max_apics; | |
| static uint32_t max_apic_words; | |
| +static const char *apic_reg_name(int index) | |
| +{ | |
| + switch (index) { | |
| + case 0x02: return "ID"; | |
| + case 0x03: return "VERSION"; | |
| + case 0x08: return "TPR"; | |
| + case 0x09: return "APR"; | |
| + case 0x0a: return "PPR"; | |
| + case 0x0b: return "EOI"; | |
| + case 0x0d: return "LDR"; | |
| + case 0x0e: return "DFR"; | |
| + case 0x0f: return "SIVR"; | |
| + case 0x10: case 0x11: case 0x12: case 0x13: | |
| + case 0x14: case 0x15: case 0x16: case 0x17: return "ISR"; | |
| + case 0x18: case 0x19: case 0x1a: case 0x1b: | |
| + case 0x1c: case 0x1d: case 0x1e: case 0x1f: return "TMR"; | |
| + case 0x20: case 0x21: case 0x22: case 0x23: | |
| + case 0x24: case 0x25: case 0x26: case 0x27: return "IRR"; | |
| + case 0x28: return "ESR"; | |
| + case 0x2f: return "LVT_CMCI"; | |
| + case 0x30: return "ICR_LO"; | |
| + case 0x31: return "ICR_HI"; | |
| + case 0x32: return "LVT_TIMER"; | |
| + case 0x33: return "LVT_THERMAL"; | |
| + case 0x34: return "LVT_PMC"; | |
| + case 0x35: return "LVT_LINT0"; | |
| + case 0x36: return "LVT_LINT1"; | |
| + case 0x37: return "LVT_ERROR"; | |
| + case 0x38: return "TIMER_ICR"; | |
| + case 0x39: return "TIMER_CCR"; | |
| + case 0x3e: return "TIMER_DCR"; | |
| + case 0x3f: return "SELF_IPI"; | |
| + default: return "???"; | |
| + } | |
| +} | |
| + | |
| #define TYPE_APIC "apic" | |
| /*This is reusing the APICCommonState typedef from APIC_COMMON */ | |
| DECLARE_INSTANCE_CHECKER(APICCommonState, APIC, | |
| @@ -312,6 +348,21 @@ | |
| return -1; | |
| } | |
| + /* When x2APIC is locked, reject clearing EXTD or EN (#GP) */ | |
| + if (s->x2apic_locked && | |
| + (s->apicbase & MSR_IA32_APICBASE_EXTD)) { | |
| + if (!(val & MSR_IA32_APICBASE_EXTD) || | |
| + !(val & MSR_IA32_APICBASE_ENABLE)) { | |
| + fprintf(stderr, "x2apic-locked: BLOCKED APICBASE write 0x%lx -> 0x%lx (#GP)\n", | |
| + (unsigned long)s->apicbase, (unsigned long)val); | |
| + return -1; | |
| + } | |
| + } | |
| + if (s->x2apic_locked) { | |
| + fprintf(stderr, "x2apic-locked: APICBASE write 0x%lx -> 0x%lx (allowed)\n", | |
| + (unsigned long)s->apicbase, (unsigned long)val); | |
| + } | |
| + | |
| /* | |
| * Transition into invalid state | |
| * (s->apicbase & MSR_IA32_APICBASE_ENABLE == 0) && | |
| @@ -874,6 +925,23 @@ | |
| return -1; | |
| } | |
| + /* When x2APIC is locked and in x2APIC mode, MMIO is not decoded */ | |
| + if (s->x2apic_locked && is_x2apic_mode(s)) { | |
| + int reg = (addr >> 4) & 0xff; | |
| + fprintf(stderr, "x2apic-locked: MMIO READ 0x%03lx %-10s cpu=%d apic_id=%u rip=0x%lx\n", | |
| + (unsigned long)addr, apic_reg_name(reg), | |
| + CPU(s->cpu)->cpu_index, s->initial_apic_id, | |
| + (unsigned long)s->cpu->env.eip); | |
| + if (s->x2apic_mce) { | |
| + cpu_x86_inject_mce(NULL, s->cpu, 0, | |
| + MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN | | |
| + MCI_STATUS_ADDRV, | |
| + MCG_STATUS_MCIP, | |
| + APIC_DEFAULT_ADDRESS | addr, 0, 0); | |
| + } | |
| + return 0xffffffff; | |
| + } | |
| + | |
| index = (addr >> 4) & 0xff; | |
| apic_register_read(s, index, &val); | |
| @@ -1070,6 +1138,24 @@ | |
| return; | |
| } | |
| + /* When x2APIC is locked and in x2APIC mode, MMIO writes are ignored */ | |
| + if (s->x2apic_locked && is_x2apic_mode(s)) { | |
| + int reg = (addr >> 4) & 0xff; | |
| + fprintf(stderr, "x2apic-locked: MMIO WRITE 0x%03lx %-10s val=0x%08x cpu=%d apic_id=%u rip=0x%lx\n", | |
| + (unsigned long)addr, apic_reg_name(reg), | |
| + (unsigned int)val, | |
| + CPU(s->cpu)->cpu_index, s->initial_apic_id, | |
| + (unsigned long)s->cpu->env.eip); | |
| + if (s->x2apic_mce) { | |
| + cpu_x86_inject_mce(NULL, s->cpu, 0, | |
| + MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN | | |
| + MCI_STATUS_ADDRV, | |
| + MCG_STATUS_MCIP, | |
| + APIC_DEFAULT_ADDRESS | addr, 0, 0); | |
| + } | |
| + return; | |
| + } | |
| + | |
| apic_register_write(s, index, val); | |
| } | |
| diff -ruN '--exclude=build' '--exclude=*.o' '--exclude=*.pyc' '--exclude=__pycache__' a/hw/intc/apic_common.c b/hw/intc/apic_common.c | |
| --- a/hw/intc/apic_common.c 2025-12-23 20:48:56.000000000 +0100 | |
| +++ b/hw/intc/apic_common.c 2026-03-01 22:12:42.663438222 +0100 | |
| @@ -60,6 +60,14 @@ | |
| } | |
| } | |
| +bool cpu_is_apic_x2apic_locked(APICCommonState *s) | |
| +{ | |
| + if (!s) { | |
| + return false; | |
| + } | |
| + return s->x2apic_locked; | |
| +} | |
| + | |
| bool cpu_is_apic_enabled(APICCommonState *s) | |
| { | |
| if (!s) { | |
| @@ -397,6 +405,8 @@ | |
| true), | |
| DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id, | |
| false), | |
| + DEFINE_PROP_BOOL("x2apic-locked", APICCommonState, x2apic_locked, false), | |
| + DEFINE_PROP_BOOL("x2apic-mce", APICCommonState, x2apic_mce, false), | |
| }; | |
| static void apic_common_get_id(Object *obj, Visitor *v, const char *name, | |
| diff -ruN '--exclude=build' '--exclude=*.o' '--exclude=*.pyc' '--exclude=__pycache__' a/include/hw/i386/apic.h b/include/hw/i386/apic.h | |
| --- a/include/hw/i386/apic.h 2025-12-23 20:48:56.000000000 +0100 | |
| +++ b/include/hw/i386/apic.h 2026-02-28 22:39:01.030027434 +0100 | |
| @@ -22,6 +22,7 @@ | |
| int apic_msr_read(APICCommonState *s, int index, uint64_t *val); | |
| int apic_msr_write(APICCommonState *s, int index, uint64_t val); | |
| bool is_x2apic_mode(APICCommonState *s); | |
| +bool cpu_is_apic_x2apic_locked(APICCommonState *s); | |
| /* pc.c */ | |
| APICCommonState *cpu_get_current_apic(void); | |
| diff -ruN '--exclude=build' '--exclude=*.o' '--exclude=*.pyc' '--exclude=__pycache__' a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h | |
| --- a/include/hw/i386/apic_internal.h 2025-12-23 20:48:56.000000000 +0100 | |
| +++ b/include/hw/i386/apic_internal.h 2026-02-28 22:54:48.567856717 +0100 | |
| @@ -188,6 +188,8 @@ | |
| DeviceState *vapic; | |
| hwaddr vapic_paddr; /* note: persistence via kvmvapic */ | |
| bool legacy_instance_id; | |
| + bool x2apic_locked; | |
| + bool x2apic_mce; | |
| uint32_t extended_log_dest; | |
| }; | |
| diff -ruN '--exclude=build' '--exclude=*.o' '--exclude=*.pyc' '--exclude=__pycache__' a/target/i386/cpu.c b/target/i386/cpu.c | |
| --- a/target/i386/cpu.c 2025-12-23 20:48:57.000000000 +0100 | |
| +++ b/target/i386/cpu.c 2026-03-01 21:43:29.659400482 +0100 | |
| @@ -44,6 +44,7 @@ | |
| #include "system/address-spaces.h" | |
| #include "hw/boards.h" | |
| #include "hw/i386/sgx-epc.h" | |
| +#include "hw/i386/apic.h" | |
| #endif | |
| #include "system/qtest.h" | |
| #include "tcg/tcg-cpu.h" | |
| @@ -1542,7 +1543,7 @@ | |
| "taa-no", NULL, NULL, NULL, | |
| NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no", | |
| NULL, "fb-clear", NULL, NULL, | |
| - "bhi-no", NULL, NULL, NULL, | |
| + "bhi-no", "xapic-disable", NULL, NULL, | |
| "pbrsb-no", NULL, "gds-no", "rfds-no", | |
| "rfds-clear", NULL, NULL, NULL, | |
| NULL, NULL, NULL, NULL, | |
| @@ -8043,6 +8044,11 @@ | |
| *ecx |= CPUID_7_0_ECX_OSPKE; | |
| } | |
| *edx = env->features[FEAT_7_0_EDX]; /* Feature flags */ | |
| +#ifndef CONFIG_USER_ONLY | |
| + if (cpu->apic_state && cpu_is_apic_x2apic_locked(cpu->apic_state)) { | |
| + *edx |= CPUID_7_0_EDX_ARCH_CAPABILITIES; | |
| + } | |
| +#endif | |
| } else if (count == 1) { | |
| *eax = env->features[FEAT_7_1_EAX]; | |
| *ecx = env->features[FEAT_7_1_ECX]; | |
| diff -ruN '--exclude=build' '--exclude=*.o' '--exclude=*.pyc' '--exclude=__pycache__' a/target/i386/cpu.h b/target/i386/cpu.h | |
| --- a/target/i386/cpu.h 2025-12-23 20:48:57.000000000 +0100 | |
| +++ b/target/i386/cpu.h 2026-02-28 22:38:31.776097461 +0100 | |
| @@ -1245,6 +1245,10 @@ | |
| #define MSR_ARCH_CAP_PBRSB_NO (1U << 24) | |
| #define MSR_ARCH_CAP_GDS_NO (1U << 26) | |
| #define MSR_ARCH_CAP_RFDS_NO (1U << 27) | |
| +#define MSR_ARCH_CAP_XAPIC_DISABLE (1U << 21) | |
| + | |
| +#define MSR_IA32_XAPIC_DISABLE_STATUS 0xBD | |
| +#define XAPIC_DISABLE_STATUS_LEGACY_DISABLED (1U << 0) | |
| #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) | |
| diff -ruN '--exclude=build' '--exclude=*.o' '--exclude=*.pyc' '--exclude=__pycache__' a/target/i386/tcg/system/misc_helper.c b/target/i386/tcg/system/misc_helper.c | |
| --- a/target/i386/tcg/system/misc_helper.c 2025-12-23 20:48:57.000000000 +0100 | |
| +++ b/target/i386/tcg/system/misc_helper.c 2026-03-01 22:12:56.801353315 +0100 | |
| @@ -294,6 +294,9 @@ | |
| env->msr_bndcfgs = val; | |
| cpu_sync_bndcs_hflags(env); | |
| break; | |
| + case MSR_IA32_XAPIC_DISABLE_STATUS: | |
| + /* Read-only MSR: #GP on any write */ | |
| + goto error; | |
| case MSR_APIC_START ... MSR_APIC_END: { | |
| int ret; | |
| int index = (uint32_t)env->regs[R_ECX] - MSR_APIC_START; | |
| @@ -472,6 +475,19 @@ | |
| val = cpu_x86_get_msr_core_thread_count(x86_cpu); | |
| break; | |
| } | |
| + case MSR_IA32_ARCH_CAPABILITIES: | |
| + val = env->features[FEAT_ARCH_CAPABILITIES]; | |
| + if (cpu_is_apic_x2apic_locked(x86_cpu->apic_state)) { | |
| + val |= MSR_ARCH_CAP_XAPIC_DISABLE; | |
| + } | |
| + break; | |
| + case MSR_IA32_XAPIC_DISABLE_STATUS: | |
| + val = 0; | |
| + if (cpu_is_apic_x2apic_locked(x86_cpu->apic_state) && | |
| + is_x2apic_mode(x86_cpu->apic_state)) { | |
| + val |= XAPIC_DISABLE_STATUS_LEGACY_DISABLED; | |
| + } | |
| + break; | |
| case MSR_APIC_START ... MSR_APIC_END: { | |
| int ret; | |
| int index = (uint32_t)env->regs[R_ECX] - MSR_APIC_START; | |
| @@ -497,6 +513,7 @@ | |
| val = 0; | |
| break; | |
| } | |
| + | |
| env->regs[R_EAX] = (uint32_t)(val); | |
| env->regs[R_EDX] = (uint32_t)(val >> 32); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment