[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH v2] Map Local APIC IDs to Processor IDs through the MADT
To use the FIFO EVTCHN ABI the frontend code needs to know the vcpu id of the guest CPUs. This mapping is currently done by taking the the CPU local APIC ID and dividing by 2. This currently works on most Xen installations but Matt Wilson advises that this will not work on AWS. This patch introduces code to map and parse the ACPI RSDP, XSDT and MADT (APIC) tables such that the local APIC substructures present in the latter can be used to map local APIC ID to processor ID (which is identical to vcpu id). Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> Cc: Matt Wilson <msw@xxxxxxxxx> --- v2: - Add missing line into vs2013 vcxproj src/xen/acpi.c | 313 +++++++++++++++++++++++++++++++++++++++++++++++++ src/xen/acpi.h | 108 +++++++++++++++++ src/xen/driver.c | 28 +++-- src/xen/system.c | 117 +++++++++++++++++- vs2012/xen/xen.vcxproj | 1 + vs2013/xen/xen.vcxproj | 1 + 6 files changed, 556 insertions(+), 12 deletions(-) create mode 100644 src/xen/acpi.c create mode 100644 src/xen/acpi.h diff --git a/src/xen/acpi.c b/src/xen/acpi.c new file mode 100644 index 0000000..124dcb6 --- /dev/null +++ b/src/xen/acpi.c @@ -0,0 +1,313 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ntddk.h> +#include <stdarg.h> +#include <xen.h> +#include <util.h> + +#include "acpi.h" +#include "dbg_print.h" +#include "assert.h" + +#define XENBUS_ACPI_TAG 'IPCA' + +static ACPI_RSDP AcpiRsdp; +static PACPI_XSDT AcpiXsdt; + +static FORCEINLINE PVOID +__AcpiAllocate( + IN ULONG Length + ) +{ + return __AllocatePoolWithTag(NonPagedPool, Length, XENBUS_ACPI_TAG); +} + +static FORCEINLINE VOID +__AcpiFree( + IN PVOID Buffer + ) +{ + ExFreePoolWithTag(Buffer, XENBUS_ACPI_TAG); +} + +static BOOLEAN +AcpiVerifyChecksum( + IN PVOID Table, + IN ULONG Length + ) +{ + UCHAR Sum; + ULONG Index; + + Sum = 0; + for (Index = 0; Index < Length; Index++) + Sum += ((PUCHAR)Table)[Index]; + + return (Sum == 0) ? TRUE : FALSE; +} + +static NTSTATUS +AcpiFindRsdp( + VOID + ) +{ + PHYSICAL_ADDRESS Start; + PHYSICAL_ADDRESS End; + ULONG Length; + PUCHAR Data; + ULONG Offset; + PACPI_RSDP Rsdp; + NTSTATUS status; + + Trace("====>\n"); + + if (strncmp(AcpiRsdp.Signature, + "RSD PTR ", + sizeof (AcpiRsdp.Signature)) == 0) + goto done; + + Start.QuadPart = 0xE0000; + End.QuadPart = 0xFFFFF; + + Length = (ULONG)(End.QuadPart + 1 - Start.QuadPart); + + Data = MmMapIoSpace(Start, Length, MmCached); + + status = STATUS_UNSUCCESSFUL; + if (Data == NULL) + goto fail1; + + for (Offset = 0; + Offset + sizeof (ACPI_RSDP) < Length; + Offset += 16) { + Rsdp = (PACPI_RSDP)(Data + Offset); + + if (strncmp(Rsdp->Signature, + "RSD PTR ", + sizeof (Rsdp->Signature)) == 0 && + AcpiVerifyChecksum(Rsdp, sizeof (ACPI_RSDP))) + goto found; + } + + status = STATUS_UNSUCCESSFUL; + goto fail2; + +found: + Info("0x%p\n", Start.QuadPart + Offset); + + // Copy the table for reference + AcpiRsdp = *Rsdp; + + MmUnmapIoSpace(Data, Length); + +done: + Trace("<====\n"); + + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + + MmUnmapIoSpace(Data, Length); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +static NTSTATUS +AcpiGetXsdt( + VOID + ) +{ + PHYSICAL_ADDRESS Address; + PACPI_XSDT Xsdt; + NTSTATUS status; + + Trace("====>\n"); + + if (AcpiXsdt != NULL) + goto done; + + Address.QuadPart = AcpiRsdp.XsdtAddress; + + Info("0x%p\n", Address.QuadPart); + + Xsdt = MmMapIoSpace(Address, PAGE_SIZE, MmCached); + + status = STATUS_UNSUCCESSFUL; + if (Xsdt == NULL) + goto fail1; + + if (strncmp(Xsdt->Header.Signature, + "XSDT", + sizeof (Xsdt->Header.Signature)) != 0) + goto fail2; + + if (!AcpiVerifyChecksum(Xsdt, Xsdt->Header.Length)) + goto fail3; + + AcpiXsdt = __AcpiAllocate(Xsdt->Header.Length); + + status = STATUS_NO_MEMORY; + if (AcpiXsdt == NULL) + goto fail4; + + RtlCopyMemory(AcpiXsdt, Xsdt, Xsdt->Header.Length); + + MmUnmapIoSpace(Xsdt, PAGE_SIZE); + +done: + Trace("<====\n"); + + return STATUS_SUCCESS; + +fail4: + Error("fail4\n"); + +fail3: + Error("fail3\n"); + +fail2: + Error("fail2\n"); + + MmUnmapIoSpace(Xsdt, PAGE_SIZE); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +NTSTATUS +AcpiGetTable( + IN const CHAR *Signature, + OUT PVOID Buffer OPTIONAL, + IN OUT PULONG Length + ) +{ + ULONG Count; + ULONG Index; + PACPI_HEADER Header; + NTSTATUS status; + + status = AcpiGetXsdt(); + if (!NT_SUCCESS(status)) + goto fail1; + + Count = (AcpiXsdt->Header.Length - FIELD_OFFSET(ACPI_XSDT, Entry)) / + sizeof (ULONG64); + + for (Index = 0; Index < Count; Index++) { + PHYSICAL_ADDRESS Address; + + Address.QuadPart = AcpiXsdt->Entry[Index]; + + Header = MmMapIoSpace(Address, PAGE_SIZE, MmCached); + + status = STATUS_UNSUCCESSFUL; + if (Header == NULL) + goto fail2; + + if (strncmp(Header->Signature, + Signature, + sizeof (Header->Signature)) == 0 && + AcpiVerifyChecksum(Header, Header->Length)) + goto found; + + MmUnmapIoSpace(Header, PAGE_SIZE); + } + + status = STATUS_UNSUCCESSFUL; + goto fail3; + +found: + status = STATUS_BUFFER_OVERFLOW; + if (Buffer == NULL || Header->Length > *Length) { + *Length = Header->Length; + goto fail4; + } + + RtlCopyMemory(Buffer, Header, Header->Length); + + MmUnmapIoSpace(Header, PAGE_SIZE); + + return STATUS_SUCCESS; + +fail4: + MmUnmapIoSpace(Header, PAGE_SIZE); + +fail3: + if (status != STATUS_BUFFER_OVERFLOW) + Error("fail3\n"); + +fail2: + if (status != STATUS_BUFFER_OVERFLOW) + Error("fail2\n"); + +fail1: + if (status != STATUS_BUFFER_OVERFLOW) + Error("fail1 (%08x)\n", status); + + return status; +} + +NTSTATUS +AcpiInitialize( + VOID + ) +{ + NTSTATUS status; + + status = AcpiFindRsdp(); + if (!NT_SUCCESS(status)) + goto fail1; + + return STATUS_SUCCESS; + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +VOID +AcpiTeardown( + VOID + ) +{ + if (AcpiXsdt != NULL) { + __AcpiFree(AcpiXsdt); + AcpiXsdt = NULL; + } +} diff --git a/src/xen/acpi.h b/src/xen/acpi.h new file mode 100644 index 0000000..334f62a --- /dev/null +++ b/src/xen/acpi.h @@ -0,0 +1,108 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _XEN_ACPI_H +#define _XEN_ACPI_H + +#include <ntddk.h> + +#pragma pack(push, 1) + +typedef struct _ACPI_RSDP { + CHAR Signature[8]; + UCHAR Checksum; + CHAR OemID[6]; + UCHAR Revision; + ULONG RsdtAddress; + ULONG Length; + ULONG64 XsdtAddress; + UCHAR ExtendedChecksum; + UCHAR Reserved[3]; +} ACPI_RSDP, *PACPI_RSDP; + +typedef struct _ACPI_HEADER { + CHAR Signature[4]; + ULONG Length; + UCHAR Revision; + UCHAR Checksum; + CHAR OemID[6]; + CHAR OemTableID[8]; + ULONG OemRevision; + CHAR CreatorID[4]; + ULONG CreatorRevision; +} ACPI_HEADER, *PACPI_HEADER; + +typedef struct _ACPI_XSDT { + ACPI_HEADER Header; + ULONG64 Entry[1]; +} ACPI_XSDT, *PACPI_XSDT; + +typedef struct _ACPI_MADT { + ACPI_HEADER Header; + ULONG LocalAPICAddress; + ULONG Flags; +} ACPI_MADT, *PACPI_MADT; + +typedef struct _ACPI_MADT_HEADER { + UCHAR Type; + UCHAR Length; +} ACPI_MADT_HEADER, *PACPI_MADT_HEADER; + +#define ACPI_MADT_TYPE_LOCAL_APIC 0x00 + +typedef struct _ACPI_MADT_LOCAL_APIC { + ACPI_MADT_HEADER Header; + UCHAR ProcessorID; + UCHAR ApicID; + ULONG Flags; +} ACPI_MADT_LOCAL_APIC, *PACPI_MADT_LOCAL_APIC; + +#pragma pack(pop) + +extern NTSTATUS +AcpiInitialize( + VOID + ); + +extern NTSTATUS +AcpiGetTable( + IN const CHAR *Signature, + OUT PVOID Buffer OPTIONAL, + IN OUT PULONG Length + ); + +extern VOID +AcpiTeardown( + VOID + ); + +#endif // _XEN_ACPI_H + diff --git a/src/xen/driver.c b/src/xen/driver.c index fce75aa..a4e91aa 100644 --- a/src/xen/driver.c +++ b/src/xen/driver.c @@ -39,6 +39,7 @@ #include "module.h" #include "process.h" #include "system.h" +#include "acpi.h" #include "bug_check.h" #include "dbg_print.h" #include "assert.h" @@ -143,50 +144,59 @@ DllInitialize( MONTH, YEAR); - status = SystemInitialize(); + status = AcpiInitialize(); if (!NT_SUCCESS(status)) goto fail2; - status = HypercallInitialize(); + status = SystemInitialize(); if (!NT_SUCCESS(status)) goto fail3; - status = BugCheckInitialize(); + status = HypercallInitialize(); if (!NT_SUCCESS(status)) goto fail4; - status = ModuleInitialize(); + status = BugCheckInitialize(); if (!NT_SUCCESS(status)) goto fail5; - status = ProcessInitialize(); + status = ModuleInitialize(); if (!NT_SUCCESS(status)) goto fail6; + status = ProcessInitialize(); + if (!NT_SUCCESS(status)) + goto fail7; + done: Trace("<====\n"); return STATUS_SUCCESS; +fail7: + Error("fail7\n"); + + ModuleTeardown(); + fail6: Error("fail6\n"); - ModuleTeardown(); + BugCheckTeardown(); fail5: Error("fail5\n"); - BugCheckTeardown(); + HypercallTeardown(); fail4: Error("fail4\n"); - HypercallTeardown(); + SystemTeardown(); fail3: Error("fail3\n"); - SystemTeardown(); + AcpiTeardown(); fail2: Error("fail2\n"); diff --git a/src/xen/system.c b/src/xen/system.c index 1ac8123..0934ac8 100644 --- a/src/xen/system.c +++ b/src/xen/system.c @@ -40,23 +40,44 @@ #include "registry.h" #include "system.h" +#include "acpi.h" #include "dbg_print.h" #include "assert.h" +#define XEN_SYSTEM_TAG 'TSYS' + typedef struct _SYSTEM_CPU { ULONG Index; CHAR Manufacturer[13]; UCHAR ApicID; + UCHAR ProcessorID; } SYSTEM_CPU, *PSYSTEM_CPU; typedef struct _SYSTEM_CONTEXT { LONG References; + PACPI_MADT Madt; SYSTEM_CPU Cpu[MAXIMUM_PROCESSORS]; PVOID Handle; } SYSTEM_CONTEXT, *PSYSTEM_CONTEXT; static SYSTEM_CONTEXT SystemContext; +static FORCEINLINE PVOID +__SystemAllocate( + IN ULONG Length + ) +{ + return __AllocatePoolWithTag(NonPagedPool, Length, XEN_SYSTEM_TAG); +} + +static FORCEINLINE VOID +__SystemFree( + IN PVOID Buffer + ) +{ + ExFreePoolWithTag(Buffer, XEN_SYSTEM_TAG); +} + static FORCEINLINE const CHAR * __PlatformIdName( IN ULONG PlatformId @@ -233,6 +254,77 @@ fail1: return status; } +static NTSTATUS +SystemGetAcpiInformation( + VOID + ) +{ + PSYSTEM_CONTEXT Context = &SystemContext; + ULONG Length; + NTSTATUS status; + + status = AcpiGetTable("APIC", NULL, &Length); + if (status != STATUS_BUFFER_OVERFLOW) + goto fail1; + + Context->Madt = __SystemAllocate(Length); + + status = STATUS_NO_MEMORY; + if (Context->Madt == NULL) + goto fail2; + + status = AcpiGetTable("APIC", Context->Madt, &Length); + if (!NT_SUCCESS(status)) + goto fail3; + + return STATUS_SUCCESS; + +fail3: + Error("fail3\n"); + +fail2: + Error("fail2\n"); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +#pragma warning(push) +#pragma warning(disable:4715) + +static UCHAR +SystemApicIDToProcessorID( + IN UCHAR ApicID + ) +{ + PSYSTEM_CONTEXT Context = &SystemContext; + PACPI_MADT Madt = Context->Madt; + ULONG Offset; + + Offset = sizeof (ACPI_MADT); + while (Offset < Madt->Header.Length) { + PACPI_MADT_HEADER Header; + PACPI_MADT_LOCAL_APIC Apic; + + Header = (PACPI_MADT_HEADER)((PUCHAR)Madt + Offset); + Offset += Header->Length; + + if (Header->Type != ACPI_MADT_TYPE_LOCAL_APIC) + continue; + + Apic = CONTAINING_RECORD(Header, ACPI_MADT_LOCAL_APIC, Header); + + if (Apic->ApicID == ApicID) + return Apic->ProcessorID; + } + + BUG(__FUNCTION__); +} + +#pragma warning(pop) + KDEFERRED_ROUTINE SystemCpuInformation; VOID @@ -272,7 +364,11 @@ SystemCpuInformation( Cpu->ApicID = EBX >> 24; - Info("Local APIC ID: %02X\n", Cpu->ApicID); + Info("APIC ID: %02X\n", Cpu->ApicID); + + Cpu->ProcessorID = SystemApicIDToProcessorID(Cpu->ApicID); + + Info("PROCESSOR ID: %02X\n", Cpu->ProcessorID); Info("<==== (%u)\n", Cpu->Index); @@ -476,6 +572,10 @@ SystemInitialize( if (!NT_SUCCESS(status)) goto fail4; + status = SystemGetAcpiInformation(); + if (!NT_SUCCESS(status)) + goto fail5; + SystemGetCpuInformation(); status = SystemRegisterCallback(L"\\Callback\\PowerState", @@ -483,10 +583,16 @@ SystemInitialize( NULL, &Context->Handle); if (!NT_SUCCESS(status)) - goto fail5; + goto fail6; return STATUS_SUCCESS; +fail6: + Error("fail6\n"); + + __SystemFree(Context->Madt); + Context->Madt = NULL; + fail5: Error("fail5\n"); @@ -502,6 +608,8 @@ fail2: fail1: Error("fail1 (%08x)\n", status); + (VOID) InterlockedDecrement(&Context->References); + return status; } @@ -516,7 +624,7 @@ SystemVirtualCpuIndex( ASSERT3U(Index, <, MAXIMUM_PROCESSORS); - return Cpu->ApicID / 2; + return Cpu->ProcessorID; } VOID @@ -531,6 +639,9 @@ SystemTeardown( RtlZeroMemory(Context->Cpu, sizeof (SYSTEM_CPU) * MAXIMUM_PROCESSORS); + __SystemFree(Context->Madt); + Context->Madt = NULL; + (VOID) InterlockedDecrement(&Context->References); ASSERT(IsZeroMemory(Context, sizeof (SYSTEM_CONTEXT))); diff --git a/vs2012/xen/xen.vcxproj b/vs2012/xen/xen.vcxproj index 2f4d958..9efeaf1 100644 --- a/vs2012/xen/xen.vcxproj +++ b/vs2012/xen/xen.vcxproj @@ -96,6 +96,7 @@ <ClCompile Include="..\..\src\xen\bug_check.c" /> <ClCompile Include="..\..\src\xen\module.c" /> <ClCompile Include="..\..\src\xen\process.c" /> + <ClCompile Include="..\..\src\xen\acpi.c" /> <ClCompile Include="..\..\src\xen\system.c" /> </ItemGroup> <ItemGroup> diff --git a/vs2013/xen/xen.vcxproj b/vs2013/xen/xen.vcxproj index 81d50ea..7a09960 100644 --- a/vs2013/xen/xen.vcxproj +++ b/vs2013/xen/xen.vcxproj @@ -136,6 +136,7 @@ <ClCompile Include="..\..\src\xen\bug_check.c" /> <ClCompile Include="..\..\src\xen\module.c" /> <ClCompile Include="..\..\src\xen\process.c" /> + <ClCompile Include="..\..\src\xen\acpi.c" /> <ClCompile Include="..\..\src\xen\system.c" /> </ItemGroup> <ItemGroup> -- 2.1.1 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |