[XEN PATCH v3] tools/lsevtchn: Use errno macro to handle hypercall error cases

2024-05-08 Thread Matthew Barnes
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

2024-04-29 Thread Matthew Barnes
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

2024-04-29 Thread Matthew Barnes
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

2024-04-29 Thread Matthew Barnes
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

2024-04-11 Thread Matthew Barnes
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

2024-04-11 Thread Matthew Barnes
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

2024-04-11 Thread Matthew Barnes
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

2024-03-26 Thread Matthew Barnes
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

2024-03-26 Thread Matthew Barnes
> > 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

2024-03-15 Thread Matthew Barnes
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

2024-03-15 Thread Matthew Barnes
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

2024-03-15 Thread Matthew Barnes
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

2024-03-13 Thread Matthew Barnes
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