[XEN PATCH v3] tools/lsevtchn: Use errno macro to handle hypercall error cases
Currently, lsevtchn aborts its event channel enumeration when it hits its first hypercall error, namely: * When an event channel doesn't exist at the specified port * When the event channel is owned by Xen lsevtchn does not distinguish between different hypercall errors, which results in lsevtchn missing potential relevant event channels with higher port numbers. Use the errno macro to distinguish between hypercall errors, and continue event channel enumeration if the hypercall error is not critical to enumeration. Signed-off-by: Matthew Barnes --- tools/xcutils/lsevtchn.c | 14 +- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/xcutils/lsevtchn.c b/tools/xcutils/lsevtchn.c index d1710613ddc5..e4b3f88fe4ec 100644 --- a/tools/xcutils/lsevtchn.c +++ b/tools/xcutils/lsevtchn.c @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -24,7 +25,18 @@ int main(int argc, char **argv) status.port = port; rc = xc_evtchn_status(xch, ); if ( rc < 0 ) -break; +{ +if ( errno == ESRCH ) +{ +fprintf(stderr, "Domain ID '%d' does not correspond to valid domain.\n", domid); +break; +} + +if ( errno == EINVAL ) +break; + +continue; +} if ( status.status == EVTCHNSTAT_closed ) continue; -- 2.34.1
[XEN PATCH v2 1/2] evtchn: Add error status indicators for evtchn_status hypercall
When the evtchn_status hypercall fails, it is not possible to determine the cause of the error, since the library call returns -1 to the tool and not the errno. Because of this, lsevtchn is unable to determine whether to continue event channel enumeration upon an evtchn_status hypercall error. Add error status indicators for the eventchn_status hypercall for lsevtchn to terminate its loop on, and keep other errors as failed hypercalls. Signed-off-by: Matthew Barnes --- xen/common/event_channel.c | 12 +++- xen/include/public/event_channel.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index aceee0695f9f..0f11e71c3e6f 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -1030,7 +1030,17 @@ int evtchn_status(evtchn_status_t *status) d = rcu_lock_domain_by_any_id(dom); if ( d == NULL ) -return -ESRCH; +{ +status->status = EVTCHNSTAT_dom_invalid; +return 0; +} + +if ( !port_is_valid(d, port) ) +{ +status->status = EVTCHNSTAT_port_invalid; +rcu_unlock_domain(d); +return 0; +} chn = _evtchn_from_port(d, port); if ( !chn ) diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h index 0d91a1c4afab..29cbf43945b3 100644 --- a/xen/include/public/event_channel.h +++ b/xen/include/public/event_channel.h @@ -200,6 +200,8 @@ struct evtchn_status { #define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ #define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ #define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */ +#define EVTCHNSTAT_dom_invalid 6 /* Given domain ID is not a valid domain */ +#define EVTCHNSTAT_port_invalid 7 /* Given port is not within valid range */ uint32_t status; uint32_t vcpu; /* VCPU to which this channel is bound. */ union { -- 2.34.1
[XEN PATCH v2 0/2] Enumerate all allocated evtchns in lsevtchn
Currently, lsevtchn aborts its event channel enumeration when it hits its first hypercall error, namely: * When an event channel doesn't exist at the specified port * When the event channel is owned by Xen This results in lsevtchn missing potential relevant event channels with higher port numbers, since lsevtchn cannot determine the cause of hypercall errors. This patch adds error status indicators for the evtchn_status hypercall for when no further event channels will be yielded for higher port numbers, allowing lsevtchn to terminate when all event channels have been enumerated over. Matthew Barnes (2): evtchn: Add error status indicators for evtchn_status hypercall tools/lsevtchn: Use new status identifiers in loop tools/xcutils/lsevtchn.c | 11 ++- xen/common/event_channel.c | 12 +++- xen/include/public/event_channel.h | 2 ++ 3 files changed, 23 insertions(+), 2 deletions(-) -- 2.34.1
[XEN PATCH v2 2/2] tools/lsevtchn: Use new status identifiers in loop
lsevtchn terminates the loop when the hypercall returns an error, even if there are still event channels with higher port numbers to be enumerated over. Continue the loop even on hypercall errors, and use the new status identifiers for the evtchn_status hypercall, namely "port invalid" and "domain invalid", to determine when to break the loop. Signed-off-by: Matthew Barnes --- tools/xcutils/lsevtchn.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/xcutils/lsevtchn.c b/tools/xcutils/lsevtchn.c index d1710613ddc5..4a48620cd72a 100644 --- a/tools/xcutils/lsevtchn.c +++ b/tools/xcutils/lsevtchn.c @@ -24,11 +24,20 @@ int main(int argc, char **argv) status.port = port; rc = xc_evtchn_status(xch, ); if ( rc < 0 ) -break; +continue; if ( status.status == EVTCHNSTAT_closed ) continue; +if ( status.status == EVTCHNSTAT_dom_invalid ) +{ +printf("Domain ID '%d' does not correspond to valid domain.\n", domid); +break; +} + +if ( status.status == EVTCHNSTAT_port_invalid ) +break; + printf("%4d: VCPU %u: ", port, status.vcpu); switch ( status.status ) -- 2.34.1
[XEN PATCH 2/2] tools/lsevtchn: Use evtchn port upper bound for evtchn enumeration
lsevtchn terminates the loop when the hypercall returns an error, even if there are still event channels with higher port numbers to be enumerated over. Use the highest allocated event channel port number for a given domain to bound the loop so that all relevant event channels can be enumerated over. Signed-off-by: Matthew Barnes --- tools/xcutils/lsevtchn.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/xcutils/lsevtchn.c b/tools/xcutils/lsevtchn.c index d1710613ddc5..7f8ad7c8e7ce 100644 --- a/tools/xcutils/lsevtchn.c +++ b/tools/xcutils/lsevtchn.c @@ -11,6 +11,7 @@ int main(int argc, char **argv) xc_interface *xch; int domid, port, rc; xc_evtchn_status_t status; +xc_domaininfo_t info; domid = (argc > 1) ? strtol(argv[1], NULL, 10) : 0; @@ -18,13 +19,16 @@ int main(int argc, char **argv) if ( !xch ) errx(1, "failed to open control interface"); -for ( port = 0; ; port++ ) +if ( xc_domain_getinfo_single(xch, domid, ) < 0 ) +errx(1, "failed to fetch domain info"); + +for ( port = 0; port <= info.highest_evtchn_port; port++ ) { status.dom = domid; status.port = port; rc = xc_evtchn_status(xch, ); if ( rc < 0 ) -break; +continue; if ( status.status == EVTCHNSTAT_closed ) continue; -- 2.34.1
[XEN PATCH 0/2] Enumerate all allocated evtchns in lsevtchn
Currently, lsevtchn aborts its event channel enumeration when it hits its first hypercall error, namely: * When an event channel doesn't exist at the specified port * When the event channel is owned by Xen This results in lsevtchn missing potential relevant event channels with higher port numbers. This patch series adds the highest allocated event channel port for a given domain in the xen_domctl_getdomaininfo hypercall struct, and uses that value as an upper bound in the lsevtchn loop. Matthew Barnes (2): xen/domctl: Add highest allocated evtchn port to getdomaininfo tools/lsevtchn: Use evtchn port upper bound for evtchn enumeration tools/xcutils/lsevtchn.c| 8 ++-- xen/common/domctl.c | 1 + xen/include/public/domctl.h | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) -- 2.34.1
[XEN PATCH 1/2] xen/domctl: Add highest allocated evtchn port to getdomaininfo
For tools such as lsevtchn to enumerate through event channels, they need an upper bound on the port number. Add the highest allocated event channel port number for a domain in the xen_domctl_getdomaininfo struct, and populate it. The field is added above the padding to avoid implicit padding. Signed-off-by: Matthew Barnes --- xen/common/domctl.c | 1 + xen/include/public/domctl.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 43b0b074c3a6..1d1ee17f6f91 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -73,6 +73,7 @@ void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info) info->domain = d->domain_id; info->max_vcpu_id = XEN_INVALID_MAX_VCPU_ID; +info->highest_evtchn_port = read_atomic(>valid_evtchns); /* * - domain is marked as blocked only if all its vcpus are blocked diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index a33f9ec32b08..d28d29180c75 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -145,7 +145,8 @@ struct xen_domctl_getdomaininfo { xen_domain_handle_t handle; uint32_t cpupool; uint8_t gpaddr_bits; /* Guest physical address space size. */ -uint8_t pad2[7]; +uint8_t pad2[3]; +evtchn_port_t highest_evtchn_port; /* Highest allocated event channel port. Used for enumeration */ struct xen_arch_domainconfig arch_config; }; typedef struct xen_domctl_getdomaininfo xen_domctl_getdomaininfo_t; -- 2.34.1
Re: [XEN PATCH] tools: add x2APIC entries in MADT based on APIC ID
On Tue, Mar 26, 2024 at 05:15:46PM +0100, Jan Beulich wrote: > On 26.03.2024 16:57, Matthew Barnes wrote: > >>> This patch scans each APIC ID before constructing the MADT, and uses the > >>> x2APIC entry for each vCPU whose APIC ID exceeds the size limit imposed > >>> by regular APIC entries. > >> > >> It is my understanding that if you use any x2APIC entry, every CPU needs > >> to have one. > > > > In the ACPI 6.4 specification, section 5.2.12.12, the note says the > > following: > > > > [Compatibility note] On some legacy OSes, Logical processors with APIC ID > > values less than 255 (whether in XAPIC or X2APIC mode) must use the > > Processor > > Local APIC structure to convey their APIC information to OSPM, and those > > processors must be declared in the DSDT using the Processor() keyword. > > > > Therefore, even in X2APIC mode, it's better to represent processors with > > APIC > > ID values less than 255 with APIC entries for legacy reasons. > > Well, my reading of that is different: All CPUs need to have x2APIC entries > if one has, and CPUs with small enough APIC IDs _additionally_ need xAPIC > entries. That's what I've been observing on real hardware, too. Understood. Patch v2 will reflect this Matt
Re: [XEN PATCH] tools: add x2APIC entries in MADT based on APIC ID
> > This patch scans each APIC ID before constructing the MADT, and uses the > > x2APIC entry for each vCPU whose APIC ID exceeds the size limit imposed > > by regular APIC entries. > > It is my understanding that if you use any x2APIC entry, every CPU needs > to have one. In the ACPI 6.4 specification, section 5.2.12.12, the note says the following: [Compatibility note] On some legacy OSes, Logical processors with APIC ID values less than 255 (whether in XAPIC or X2APIC mode) must use the Processor Local APIC structure to convey their APIC information to OSPM, and those processors must be declared in the DSDT using the Processor() keyword. Therefore, even in X2APIC mode, it's better to represent processors with APIC ID values less than 255 with APIC entries for legacy reasons. > > @@ -134,27 +151,45 @@ static struct acpi_20_madt *construct_madt(struct > > acpi_ctxt *ctxt, > > io_apic->ioapic_id = config->ioapic_id; > > io_apic->ioapic_addr = config->ioapic_base_address; > > > > -lapic = (struct acpi_20_madt_lapic *)(io_apic + 1); > > +apicid_entry = io_apic + 1; > > } > > else > > -lapic = (struct acpi_20_madt_lapic *)(madt + 1); > > +apicid_entry = madt + 1; > > > > info->nr_cpus = hvminfo->nr_vcpus; > > -info->madt_lapic0_addr = ctxt->mem_ops.v2p(ctxt, lapic); > > +info->madt_lapic0_addr = ctxt->mem_ops.v2p(ctxt, apicid_entry); > > for ( i = 0; i < hvminfo->nr_vcpus; i++ ) > > { > > -memset(lapic, 0, sizeof(*lapic)); > > -lapic->type= ACPI_PROCESSOR_LOCAL_APIC; > > -lapic->length = sizeof(*lapic); > > -/* Processor ID must match processor-object IDs in the DSDT. */ > > -lapic->acpi_processor_id = i; > > -lapic->apic_id = config->lapic_id(i); > > -lapic->flags = (test_bit(i, hvminfo->vcpu_online) > > -? ACPI_LOCAL_APIC_ENABLED : 0); > > -lapic++; > > +uint32_t apic_id = config->lapic_id(i); > > +if ( apic_id < 255 ) > > Nit (here and below): This file uses hypervisor coding style. and hence a > blank line is wanted between declaration(s) and statement(s). I will add this in patch V2 > > +{ > > +struct acpi_20_madt_lapic *lapic = apicid_entry; > > +memset(lapic, 0, sizeof(*lapic)); > > +lapic->type= ACPI_PROCESSOR_LOCAL_APIC; > > +lapic->length = sizeof(*lapic); > > +/* Processor ID must match processor-object IDs in the DSDT. */ > > +lapic->acpi_processor_id = i; > > +lapic->apic_id = apic_id; > > +lapic->flags = (test_bit(i, hvminfo->vcpu_online) > > +? ACPI_LOCAL_APIC_ENABLED : 0); > > +apicid_entry = lapic + 1; > > +} > > +else > > +{ > > +struct acpi_20_madt_x2apic *x2apic = apicid_entry; > > +memset(x2apic, 0, sizeof(*x2apic)); > > +x2apic->type= ACPI_PROCESSOR_LOCAL_X2APIC; > > +x2apic->length = sizeof(*x2apic); > > +x2apic->apic_id = apic_id; > > +x2apic->flags = (test_bit(i, hvminfo->vcpu_online) > > +? ACPI_LOCAL_APIC_ENABLED : 0); > > Nit: Indentation off by 1. I will add this in patch V2 Matt
[XEN PATCH 2/2] x86: Refactor LBR feature to MSR_DEBUGCTL feature
Last Branch Record and Bus Lock Detect both belong to the same MSR. The same mechanism that restores LBR also restores BLD. Therefore, the name of the feature that enables this mechanism should reflect restoring the MSR, instead of one field. No functional change. Signed-off-by: Matthew Barnes --- xen/arch/x86/hvm/vmx/entry.S | 4 ++-- xen/arch/x86/include/asm/cpufeature.h | 2 +- xen/arch/x86/include/asm/cpufeatures.h | 2 +- xen/arch/x86/traps.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S index a0148f78584d..acfdc370289d 100644 --- a/xen/arch/x86/hvm/vmx/entry.S +++ b/xen/arch/x86/hvm/vmx/entry.S @@ -47,12 +47,12 @@ ENTRY(vmx_asm_vmexit_handler) /* Hardware clears MSR_DEBUGCTL on VMExit. Reinstate it if debugging Xen. */ mov host_msr_debugctl(%rip), %eax -.macro restore_lbr +.macro restore_msr_debugctl mov $MSR_IA32_DEBUGCTLMSR, %ecx xor %edx, %edx wrmsr .endm -ALTERNATIVE "", restore_lbr, X86_FEATURE_XEN_LBR +ALTERNATIVE "", restore_msr_debugctl, X86_FEATURE_XEN_MSR_DEBUGCTL mov %rsp,%rdi call vmx_vmexit_handler diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h index 9bc553681f4a..084501c76a03 100644 --- a/xen/arch/x86/include/asm/cpufeature.h +++ b/xen/arch/x86/include/asm/cpufeature.h @@ -223,7 +223,7 @@ static inline bool boot_cpu_has(unsigned int feat) #define cpu_has_aperfmperf boot_cpu_has(X86_FEATURE_APERFMPERF) #define cpu_has_lfence_dispatch boot_cpu_has(X86_FEATURE_LFENCE_DISPATCH) #define cpu_has_nscbboot_cpu_has(X86_FEATURE_NSCB) -#define cpu_has_xen_lbr boot_cpu_has(X86_FEATURE_XEN_LBR) +#define cpu_has_xen_msr_debugctl boot_cpu_has(X86_FEATURE_XEN_MSR_DEBUGCTL) #define cpu_has_xen_shstk (IS_ENABLED(CONFIG_XEN_SHSTK) && \ boot_cpu_has(X86_FEATURE_XEN_SHSTK)) #define cpu_has_xen_ibt (IS_ENABLED(CONFIG_XEN_IBT) && \ diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h index 7e8221fd85dd..060d7c1d5c9e 100644 --- a/xen/arch/x86/include/asm/cpufeatures.h +++ b/xen/arch/x86/include/asm/cpufeatures.h @@ -34,7 +34,7 @@ XEN_CPUFEATURE(SC_RSB_PV, X86_SYNTH(18)) /* RSB overwrite needed for PV XEN_CPUFEATURE(SC_RSB_HVM,X86_SYNTH(19)) /* RSB overwrite needed for HVM */ XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ -XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ +XEN_CPUFEATURE(XEN_MSR_DEBUGCTL, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL */ XEN_CPUFEATURE(SC_DIV,X86_SYNTH(23)) /* DIV scrub needed */ XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 7d8eee013d00..16bef5d76620 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1940,7 +1940,7 @@ void asmlinkage do_debug(struct cpu_user_regs *regs) return; /* #DB automatically disabled LBR. Reinstate it if debugging Xen. */ -if ( cpu_has_xen_lbr ) +if ( cpu_has_xen_msr_debugctl ) wrmsrl(MSR_IA32_DEBUGCTLMSR, host_msr_debugctl); if ( !guest_mode(regs) ) @@ -2129,10 +2129,10 @@ void percpu_traps_init(void) return; } -setup_force_cpu_cap(X86_FEATURE_XEN_LBR); +setup_force_cpu_cap(X86_FEATURE_XEN_MSR_DEBUGCTL); } -if ( cpu_has_xen_lbr ) +if ( cpu_has_xen_msr_debugctl ) { host_msr_debugctl |= IA32_DEBUGCTLMSR_LBR; wrmsrl(MSR_IA32_DEBUGCTLMSR, host_msr_debugctl); -- 2.34.1
[XEN PATCH 0/2] Enable Bus Lock Detect as rate limiter
Bus Lock Detect can be used to reduce the effects of DoS in case it happens. This patch series enables BLD from MSR_DEBUGCTL if available, and refines a mechanism to restore MSR_DEBUGCTL upon VMExit to support BLD as well as LBR. Said mechanism is also refactored to have a name that reflects generally restoring the MSR, instead of only one field. Matthew Barnes (2): x86: Enable BLD and handle #DB traps x86: Refactor LBR feature into general MSR_DEBUGCTL feature xen/arch/x86/cpu/common.c | 5 + xen/arch/x86/hvm/vmx/entry.S | 6 +++--- xen/arch/x86/include/asm/cpufeature.h | 2 +- xen/arch/x86/include/asm/cpufeatures.h | 2 +- xen/arch/x86/include/asm/debugreg.h| 1 + xen/arch/x86/include/asm/msr-index.h | 1 + xen/arch/x86/include/asm/msr.h | 2 ++ xen/arch/x86/msr.c | 2 ++ xen/arch/x86/traps.c | 16 +++- 9 files changed, 27 insertions(+), 10 deletions(-) -- 2.34.1
[XEN PATCH 1/2] x86: Enable BLD and handle #DB traps
Enable Bus Lock Detect if available, and handle #DB traps to reduce effects of DoS. The value to restore MSR_DEBUGCTL to after VMExit will now depend on whether BLD is enabled or not. Restore MSR_DEBUGCTL after being cleared by storing a copy of the register value in memory, instead of hard-coding it. Signed-off-by: Matthew Barnes --- xen/arch/x86/cpu/common.c| 5 + xen/arch/x86/hvm/vmx/entry.S | 2 +- xen/arch/x86/include/asm/debugreg.h | 1 + xen/arch/x86/include/asm/msr-index.h | 1 + xen/arch/x86/include/asm/msr.h | 2 ++ xen/arch/x86/msr.c | 2 ++ xen/arch/x86/traps.c | 10 -- 7 files changed, 20 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c index 28d7f34c4dbe..f11ac06f8292 100644 --- a/xen/arch/x86/cpu/common.c +++ b/xen/arch/x86/cpu/common.c @@ -623,6 +623,11 @@ void identify_cpu(struct cpuinfo_x86 *c) } setup_doitm(); + + if (cpu_has(c, X86_FEATURE_BLD)) { + host_msr_debugctl |= IA32_DEBUGCTLMSR_BLD; + wrmsrl(MSR_IA32_DEBUGCTLMSR, host_msr_debugctl); + } } /* leaf 0xb SMT level */ diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S index 1bead826caa3..a0148f78584d 100644 --- a/xen/arch/x86/hvm/vmx/entry.S +++ b/xen/arch/x86/hvm/vmx/entry.S @@ -46,8 +46,8 @@ ENTRY(vmx_asm_vmexit_handler) /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ /* Hardware clears MSR_DEBUGCTL on VMExit. Reinstate it if debugging Xen. */ +mov host_msr_debugctl(%rip), %eax .macro restore_lbr -mov $IA32_DEBUGCTLMSR_LBR, %eax mov $MSR_IA32_DEBUGCTLMSR, %ecx xor %edx, %edx wrmsr diff --git a/xen/arch/x86/include/asm/debugreg.h b/xen/arch/x86/include/asm/debugreg.h index 2bdaf5d9aa11..9c048ae215d6 100644 --- a/xen/arch/x86/include/asm/debugreg.h +++ b/xen/arch/x86/include/asm/debugreg.h @@ -19,6 +19,7 @@ #define DR_TRAP1(0x2) /* db1 */ #define DR_TRAP2(0x4) /* db2 */ #define DR_TRAP3(0x8) /* db3 */ +#define DR_TRAP11 (0x800) /* db11 */ #define DR_STEP (0x4000)/* single-step */ #define DR_SWITCH (0x8000)/* task switch */ #define DR_NOT_RTM (0x1) /* clear: #BP inside RTM region */ diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h index 92dd9fa4962c..2e397bd28c77 100644 --- a/xen/arch/x86/include/asm/msr-index.h +++ b/xen/arch/x86/include/asm/msr-index.h @@ -292,6 +292,7 @@ #define MSR_IA32_DEBUGCTLMSR 0x01d9 #define IA32_DEBUGCTLMSR_LBR (1<<0) /* Last Branch Record */ #define IA32_DEBUGCTLMSR_BTF (1<<1) /* Single Step on Branches */ +#define IA32_DEBUGCTLMSR_BLD (1<<2) /* Bus Lock Detect */ #define IA32_DEBUGCTLMSR_TR(1<<6) /* Trace Message Enable */ #define IA32_DEBUGCTLMSR_BTS (1<<7) /* Branch Trace Store */ #define IA32_DEBUGCTLMSR_BTINT (1<<8) /* Branch Trace Interrupt */ diff --git a/xen/arch/x86/include/asm/msr.h b/xen/arch/x86/include/asm/msr.h index 1d8ea9f26faa..9ff7dcc8ca8b 100644 --- a/xen/arch/x86/include/asm/msr.h +++ b/xen/arch/x86/include/asm/msr.h @@ -432,4 +432,6 @@ int init_vcpu_msr_policy(struct vcpu *v); int guest_rdmsr(struct vcpu *v, uint32_t msr, uint64_t *val); int guest_wrmsr(struct vcpu *v, uint32_t msr, uint64_t val); +extern uint32_t host_msr_debugctl; + #endif /* __ASM_MSR_H */ diff --git a/xen/arch/x86/msr.c b/xen/arch/x86/msr.c index 9babd441f9d4..7d9d162cb8b4 100644 --- a/xen/arch/x86/msr.c +++ b/xen/arch/x86/msr.c @@ -24,6 +24,8 @@ #include +uint32_t host_msr_debugctl; + DEFINE_PER_CPU(uint32_t, tsc_aux); int init_vcpu_msr_policy(struct vcpu *v) diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index d554c9d41edd..7d8eee013d00 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1936,9 +1936,12 @@ void asmlinkage do_debug(struct cpu_user_regs *regs) */ write_debugreg(6, X86_DR6_DEFAULT); +if ( !( dr6 & DR_TRAP11 ) ) +return; + /* #DB automatically disabled LBR. Reinstate it if debugging Xen. */ if ( cpu_has_xen_lbr ) -wrmsrl(MSR_IA32_DEBUGCTLMSR, IA32_DEBUGCTLMSR_LBR); +wrmsrl(MSR_IA32_DEBUGCTLMSR, host_msr_debugctl); if ( !guest_mode(regs) ) { @@ -2130,7 +2133,10 @@ void percpu_traps_init(void) } if ( cpu_has_xen_lbr ) -wrmsrl(MSR_IA32_DEBUGCTLMSR, IA32_DEBUGCTLMSR_LBR); +{ +host_msr_debugctl |= IA32_DEBUGCTLMSR_LBR; +wrmsrl(MSR_IA32_DEBUGCTLMSR, host_msr_debugctl); +} } /* Exception entries */ -- 2.34.1
[XEN PATCH] tools: add x2APIC entries in MADT based on APIC ID
libacpi is a tool that is used by libxl (for PVH guests) and hvmloader (for HVM guests) to construct ACPI tables for guests. Currently, libacpi only uses APIC entries to enumerate processors for guests in the MADT. The APIC ID field in APIC entries is an octet big, which is fine for xAPIC IDs, but not so for sufficiently large x2APIC IDs. This patch scans each APIC ID before constructing the MADT, and uses the x2APIC entry for each vCPU whose APIC ID exceeds the size limit imposed by regular APIC entries. Signed-off-by: Matthew Barnes --- tools/libacpi/acpi2_0.h | 13 +++ tools/libacpi/build.c | 75 ++--- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/tools/libacpi/acpi2_0.h b/tools/libacpi/acpi2_0.h index 6dfa939a8c0c..10e567686fe6 100644 --- a/tools/libacpi/acpi2_0.h +++ b/tools/libacpi/acpi2_0.h @@ -344,6 +344,7 @@ struct acpi_20_waet { #define ACPI_IO_SAPIC 0x06 #define ACPI_PROCESSOR_LOCAL_SAPIC 0x07 #define ACPI_PLATFORM_INTERRUPT_SOURCES 0x08 +#define ACPI_PROCESSOR_LOCAL_X2APIC 0x09 /* * APIC Structure Definitions. @@ -360,6 +361,18 @@ struct acpi_20_madt_lapic { uint32_t flags; }; +/* + * Processor Local x2APIC Structure Definition. + */ +struct acpi_20_madt_x2apic { +uint8_t type; /* Must refer to x2APIC type (0x09) */ +uint8_t length;/* Must be length of x2APIC struct in bytes (0x10) */ +uint16_t reserved; /* Must be zero */ +uint32_t apic_id; /* Processor's local x2APIC ID */ +uint32_t flags; /* Same as Local APIC flags */ +uint32_t acpi_processor_id; /* Refers to a processor device used to associate the X2APIC structure with */ +}; + /* * Local APIC Flags. All other bits are reserved and must be 0. */ diff --git a/tools/libacpi/build.c b/tools/libacpi/build.c index 2f29863db154..5b0fd6584b30 100644 --- a/tools/libacpi/build.c +++ b/tools/libacpi/build.c @@ -63,6 +63,27 @@ static void set_checksum( p[checksum_offset] = -sum; } +static unsigned calculate_madt_size(const struct acpi_config *config) +{ +uint32_t apic_id; +unsigned i, size; + +size = sizeof(struct acpi_20_madt); +size += sizeof(struct acpi_20_madt_intsrcovr) * 16; +size += sizeof(struct acpi_20_madt_ioapic); + +for ( i = 0; i < config->hvminfo->nr_vcpus; i++ ) +{ +apic_id = config->lapic_id(i); +if ( apic_id < 255 ) +size += sizeof(struct acpi_20_madt_lapic); +else +size += sizeof(struct acpi_20_madt_x2apic); +} + +return size; +} + static struct acpi_20_madt *construct_madt(struct acpi_ctxt *ctxt, const struct acpi_config *config, struct acpi_info *info) @@ -70,18 +91,14 @@ static struct acpi_20_madt *construct_madt(struct acpi_ctxt *ctxt, struct acpi_20_madt *madt; struct acpi_20_madt_intsrcovr *intsrcovr; struct acpi_20_madt_ioapic*io_apic; -struct acpi_20_madt_lapic *lapic; +void *apicid_entry; const struct hvm_info_table *hvminfo = config->hvminfo; -int i, sz; +unsigned i, sz; if ( config->lapic_id == NULL ) return NULL; -sz = sizeof(struct acpi_20_madt); -sz += sizeof(struct acpi_20_madt_intsrcovr) * 16; -sz += sizeof(struct acpi_20_madt_ioapic); -sz += sizeof(struct acpi_20_madt_lapic) * hvminfo->nr_vcpus; - +sz = calculate_madt_size(config); madt = ctxt->mem_ops.alloc(ctxt, sz, 16); if (!madt) return NULL; @@ -134,27 +151,45 @@ static struct acpi_20_madt *construct_madt(struct acpi_ctxt *ctxt, io_apic->ioapic_id = config->ioapic_id; io_apic->ioapic_addr = config->ioapic_base_address; -lapic = (struct acpi_20_madt_lapic *)(io_apic + 1); +apicid_entry = io_apic + 1; } else -lapic = (struct acpi_20_madt_lapic *)(madt + 1); +apicid_entry = madt + 1; info->nr_cpus = hvminfo->nr_vcpus; -info->madt_lapic0_addr = ctxt->mem_ops.v2p(ctxt, lapic); +info->madt_lapic0_addr = ctxt->mem_ops.v2p(ctxt, apicid_entry); for ( i = 0; i < hvminfo->nr_vcpus; i++ ) { -memset(lapic, 0, sizeof(*lapic)); -lapic->type= ACPI_PROCESSOR_LOCAL_APIC; -lapic->length = sizeof(*lapic); -/* Processor ID must match processor-object IDs in the DSDT. */ -lapic->acpi_processor_id = i; -lapic->apic_id = config->lapic_id(i); -lapic->flags = (test_bit(i, hvminfo->vcpu_online) -? ACPI_LOCAL_APIC_ENABLED : 0); -lapic++; +uint32_t apic_id = config->lapic_id(i); +if ( apic_id < 255 ) +{ +struct acpi_20_madt_lapic *lap