[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 5/8] tools/hvmloader: Retrieve (x2)APIC IDs from the APs themselves
On Fri, May 24, 2024 at 04:15:34PM +0100, Alejandro Vallejo wrote: > On 24/05/2024 08:21, Roger Pau Monné wrote: > > On Wed, May 08, 2024 at 01:39:24PM +0100, Alejandro Vallejo wrote: > >> Make it so the APs expose their own APIC IDs in a LUT. We can use that LUT > >> to > >> populate the MADT, decoupling the algorithm that relates CPU IDs and APIC > >> IDs > >> from hvmloader. > >> > >> While at this also remove ap_callin, as writing the APIC ID may serve the > >> same > >> purpose. > >> > >> Signed-off-by: Alejandro Vallejo <alejandro.vallejo@xxxxxxxxx> > >> --- > >> v2: > >> * New patch. Replaces adding cpu policy to hvmloader in v1. > >> --- > >> tools/firmware/hvmloader/config.h | 6 ++++- > >> tools/firmware/hvmloader/hvmloader.c | 4 +-- > >> tools/firmware/hvmloader/smp.c | 40 +++++++++++++++++++++++----- > >> tools/firmware/hvmloader/util.h | 5 ++++ > >> xen/arch/x86/include/asm/hvm/hvm.h | 1 + > >> 5 files changed, 47 insertions(+), 9 deletions(-) > >> > >> diff --git a/tools/firmware/hvmloader/config.h > >> b/tools/firmware/hvmloader/config.h > >> index c82adf6dc508..edf6fa9c908c 100644 > >> --- a/tools/firmware/hvmloader/config.h > >> +++ b/tools/firmware/hvmloader/config.h > >> @@ -4,6 +4,8 @@ > >> #include <stdint.h> > >> #include <stdbool.h> > >> > >> +#include <xen/hvm/hvm_info_table.h> > >> + > >> enum virtual_vga { VGA_none, VGA_std, VGA_cirrus, VGA_pt }; > >> extern enum virtual_vga virtual_vga; > >> > >> @@ -49,8 +51,10 @@ extern uint8_t ioapic_version; > >> > >> #define IOAPIC_ID 0x01 > >> > >> +extern uint32_t CPU_TO_X2APICID[HVM_MAX_VCPUS]; > >> + > >> #define LAPIC_BASE_ADDRESS 0xfee00000 > >> -#define LAPIC_ID(vcpu_id) ((vcpu_id) * 2) > >> +#define LAPIC_ID(vcpu_id) (CPU_TO_X2APICID[(vcpu_id)]) > >> > >> #define PCI_ISA_DEVFN 0x08 /* dev 1, fn 0 */ > >> #define PCI_ISA_IRQ_MASK 0x0c20U /* ISA IRQs 5,10,11 are PCI connected > >> */ > >> diff --git a/tools/firmware/hvmloader/hvmloader.c > >> b/tools/firmware/hvmloader/hvmloader.c > >> index c58841e5b556..1eba92229925 100644 > >> --- a/tools/firmware/hvmloader/hvmloader.c > >> +++ b/tools/firmware/hvmloader/hvmloader.c > >> @@ -342,11 +342,11 @@ int main(void) > >> > >> printf("CPU speed is %u MHz\n", get_cpu_mhz()); > >> > >> + smp_initialise(); > >> + > >> apic_setup(); > >> pci_setup(); > >> > >> - smp_initialise(); > >> - > >> perform_tests(); > >> > >> if ( bios->bios_info_setup ) > >> diff --git a/tools/firmware/hvmloader/smp.c > >> b/tools/firmware/hvmloader/smp.c > >> index a668f15d7e1f..4d75f239c2f5 100644 > >> --- a/tools/firmware/hvmloader/smp.c > >> +++ b/tools/firmware/hvmloader/smp.c > >> @@ -29,7 +29,34 @@ > >> > >> #include <xen/vcpu.h> > >> > >> -static int ap_callin, ap_cpuid; > >> +static int ap_cpuid; > >> + > >> +/** > >> + * Lookup table of x2APIC IDs. > >> + * > >> + * Each entry is populated its respective CPU as they come online. This > >> is required > >> + * for generating the MADT with minimal assumptions about ID > >> relationships. > >> + */ > >> +uint32_t CPU_TO_X2APICID[HVM_MAX_VCPUS]; > >> + > >> +static uint32_t read_apic_id(void) > >> +{ > >> + uint32_t apic_id; > >> + > >> + cpuid(1, NULL, &apic_id, NULL, NULL); > >> + apic_id >>= 24; > >> + > >> + /* > >> + * APIC IDs over 255 are represented by 255 in leaf 1 and are meant > >> to be > >> + * read from topology leaves instead. Xen exposes x2APIC IDs in leaf > >> 0xb, > >> + * but only if the x2APIC feature is present. If there are that many > >> CPUs > >> + * it's guaranteed to be there so we can avoid checking for it > >> specifically > >> + */ > >> + if ( apic_id == 255 ) > >> + cpuid(0xb, NULL, NULL, NULL, &apic_id); > >> + > >> + return apic_id; > >> +} > >> > >> static void ap_start(void) > >> { > >> @@ -37,12 +64,12 @@ static void ap_start(void) > >> cacheattr_init(); > >> printf("done.\n"); > >> > >> + wmb(); > >> + ACCESS_ONCE(CPU_TO_X2APICID[ap_cpuid]) = read_apic_id(); > > > > Further thinking about this: do we really need the wmb(), given the > > usage of ACCESS_ONCE()? > > > > wmb() is a compiler barrier, and the usage of volatile in > > ACCESS_ONCE() should already prevent any compiler re-ordering. > > > > Thanks, Roger. > > volatile reads/writes cannot be reordered with other volatile > reads/writes, but volatile reads/writes can be reordered with > non-volatile reads/writes, AFAIR. Right, I've read the C99 spec and it does indeed only guarantee the state of volatile objects to be as expected at sequence points. I think however this specific code would still be fine since the function calls are considered to have side-effects, and those must all be completed before the volatile access. > My intent here was to prevent the compiler omitting the write (though in > practice it didn't). I think the barrier is still required to prevent > reordering according to the spec. Yes, my understating is that you added the ACCESS_ONCE() to possibly prevent the compiler from re-ordering the CPU_TO_X2APICID[ap_cpuid]) = read_apic_id() after the 'hlt' loop? AFAICT the expressions in the `for` statement are considered sequence points, and the calling `read_apic_id()` could have side-effects, so the compiler won't be able to elide or move the setting of CPU_TO_X2APICID[] due to all side-effects of previous evaluations must be complete at sequence points. I'm fine with leaving the wmb() + ACCESS_ONCE(). Thanks, Roger.
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |