]> xenbits.xensource.com Git - pvdrivers/win/xenbus.git/commitdiff
Introduce DriverGet/PutNamedPages()
authorPaul Durrant <pdurrant@amazon.com>
Sat, 28 Nov 2020 17:38:29 +0000 (17:38 +0000)
committerPaul Durrant <pdurrant@amazon.com>
Thu, 3 Dec 2020 08:14:22 +0000 (08:14 +0000)
A subsequent patch will need a mechanism to allocate memory that persists
for the lifetime of the VM. Because it is possible for the XEN.SYS module
can be unloaded, references to the PFNs of the allocated buffer are stored
under a volatile registry key such that they can be re-discovered if XEN.SYS
is re-loaded.

DriverGetNamedPages() will either allocate or discover PFNs and wrap them in
an MDL which is then mapped and passed back to the caller.
DriverPutNamedPages() will unmap the PFNs but not free them (since they
will have been written into the registry by DriverGetNamedPages()).

NOTE: There is also a whitespace fix in the call to RegistryCreateSubKey()
      for the 'ParametersKey' in driver.c.

Signed-off-by: Paul Durrant <pdurrant@amazon.com>
src/xen/driver.c
src/xen/driver.h

index 9e4a18ef7dfdcac5ad3ecee37a8a5c9bc63d857f..4670539b488a4b4a6a4e030ba5a948d7175d7be6 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <ntddk.h>
 #include <procgrp.h>
+#include <ntstrsafe.h>
 #include <xen.h>
 
 #include "registry.h"
@@ -47,6 +48,7 @@
 #include "bug_check.h"
 #include "dbg_print.h"
 #include "assert.h"
+#include "util.h"
 #include "version.h"
 
 #define DEFAULT_XEN_LOG_LEVEL   LOG_LEVEL_CRITICAL
@@ -59,12 +61,31 @@ typedef struct _XEN_DRIVER {
     PLOG_DISPOSITION    XenDisposition;
     PLOG_DISPOSITION    QemuDisposition;
     HANDLE              UnplugKey;
+    HANDLE              MemoryKey;
 } XEN_DRIVER, *PXEN_DRIVER;
 
 static XEN_DRIVER   Driver;
 
+#define XEN_DRIVER_TAG  'VIRD'
+
 extern PULONG   InitSafeBootMode;
 
+static FORCEINLINE PVOID
+__DriverAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, XEN_DRIVER_TAG);
+}
+
+static FORCEINLINE VOID
+__DriverFree(
+    IN  PVOID   Buffer
+    )
+{
+    __FreePoolWithTag(Buffer, XEN_DRIVER_TAG);
+}
+
 static FORCEINLINE BOOLEAN
 __DriverSafeMode(
     VOID
@@ -97,6 +118,284 @@ DriverGetUnplugKey(
     return __DriverGetUnplugKey();
 }
 
+static FORCEINLINE VOID
+__DriverSetMemoryKey(
+    IN  HANDLE  Key
+    )
+{
+    Driver.MemoryKey = Key;
+}
+
+static FORCEINLINE HANDLE
+__DriverGetMemoryKey(
+    VOID
+    )
+{
+    return Driver.MemoryKey;
+}
+
+#define MAXNAMELEN 128
+
+static FORCEINLINE NTSTATUS
+__DriverSetPfnArray(
+    IN  PCHAR       Name,
+    IN  ULONG       Count,
+    IN  PFN_NUMBER  PfnArray[]
+    )
+{
+    HANDLE          Key = __DriverGetMemoryKey();
+    LONG            Index;
+    NTSTATUS        status;
+
+    Index = 0;
+    while (Index < (LONG)Count) {
+        CHAR    ValueName[MAXNAMELEN];
+        PVOID   Value;
+        ULONG   Length;
+
+        status = RtlStringCbPrintfA(ValueName,
+                                    MAXNAMELEN,
+                                    "%s_%u",
+                                    Name,
+                                    Index);
+        ASSERT(NT_SUCCESS(status));
+
+        Value = &PfnArray[Index];
+        Length = sizeof (PFN_NUMBER);
+
+        status = RegistryUpdateBinaryValue(Key,
+                                           ValueName,
+                                           Value,
+                                           Length);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+
+        Info("%s %p\n", ValueName, (PVOID)PfnArray[Index]);
+
+        Index++;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    while (--Index >= 0) {
+        CHAR    ValueName[MAXNAMELEN];
+
+        status = RtlStringCbPrintfA(ValueName,
+                                    MAXNAMELEN,
+                                    "%s_%u",
+                                    Name,
+                                    Index);
+        ASSERT(NT_SUCCESS(status));
+
+        (VOID) RegistryDeleteValue(Key, ValueName);
+    }
+
+    return status;
+}
+
+static FORCEINLINE NTSTATUS
+__DriverAllocatePfnArray(
+    IN  PCHAR           Name,
+    IN  ULONG           Count,
+    OUT PFN_NUMBER      PfnArray[]
+    )
+{
+    PHYSICAL_ADDRESS    LowAddress;
+    PHYSICAL_ADDRESS    HighAddress;
+    LARGE_INTEGER       SkipBytes;
+    SIZE_T              TotalBytes;
+    PMDL                Mdl;
+    NTSTATUS            status;
+
+    LowAddress.QuadPart = 0ull;
+    HighAddress.QuadPart = ~0ull;
+    SkipBytes.QuadPart = 0ull;
+    TotalBytes = PAGE_SIZE * Count;
+
+    Mdl = MmAllocatePagesForMdlEx(LowAddress,
+                                  HighAddress,
+                                  SkipBytes,
+                                  TotalBytes,
+                                  MmCached,
+                                  MM_ALLOCATE_FULLY_REQUIRED);
+
+    status = STATUS_NO_MEMORY;
+    if (Mdl == NULL)
+        goto fail1;
+
+    if (Mdl->ByteCount < TotalBytes)
+        goto fail2;
+
+    ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA |
+                             MDL_PARTIAL_HAS_BEEN_MAPPED |
+                             MDL_PARTIAL |
+                             MDL_PARENT_MAPPED_SYSTEM_VA |
+                             MDL_SOURCE_IS_NONPAGED_POOL |
+                             MDL_IO_SPACE)) == 0);
+
+    status = __DriverSetPfnArray(Name, Count, MmGetMdlPfnArray(Mdl));
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    RtlCopyMemory(PfnArray, MmGetMdlPfnArray(Mdl), sizeof (PFN_NUMBER) * Count);
+
+    ExFreePool(Mdl);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+    MmFreePagesFromMdl(Mdl);
+    ExFreePool(Mdl);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static FORCEINLINE NTSTATUS
+__DriverGetPfnArray(
+    IN  PCHAR       Name,
+    IN  ULONG       Count,
+    OUT PFN_NUMBER  PfnArray[]
+    )
+{
+    HANDLE          Key = __DriverGetMemoryKey();
+    ULONG           Index;
+    NTSTATUS        status;
+
+    for (Index = 0; Index < Count; Index++) {
+        CHAR    ValueName[MAXNAMELEN];
+        PVOID   Value;
+        ULONG   Length;
+
+        status = RtlStringCbPrintfA(ValueName,
+                                    MAXNAMELEN,
+                                    "%s_%u",
+                                    Name,
+                                    Index);
+        ASSERT(NT_SUCCESS(status));
+
+        status = RegistryQueryBinaryValue(Key,
+                                          ValueName,
+                                          &Value,
+                                          &Length);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+
+        status = STATUS_UNSUCCESSFUL;
+        if (Length != sizeof (PFN_NUMBER))
+            goto fail2;
+
+        PfnArray[Index] = *(PPFN_NUMBER)Value;
+
+        RegistryFreeBinaryValue(Value);
+
+        Info("%s %p\n", Name, (PVOID)PfnArray[Index]);
+    }
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+PMDL
+DriverGetNamedPages(
+    IN  PCHAR   Name,
+    IN  ULONG   Count
+    )
+{
+    ULONG       Size;
+    PMDL        Mdl;
+    PUCHAR      MdlMappedSystemVa;
+    NTSTATUS    status;
+
+    Size = sizeof (MDL) + (sizeof (PFN_NUMBER) * Count);
+    Mdl = __DriverAllocate(Size);
+
+    status = STATUS_NO_MEMORY;
+    if (Mdl == NULL)
+        goto fail1;
+
+#pragma warning(push)
+#pragma warning(disable:28145) // modifying struct MDL
+
+    Mdl->Size = (USHORT)Size;
+    Mdl->MdlFlags = MDL_PAGES_LOCKED;
+    Mdl->ByteCount = PAGE_SIZE * Count;
+
+#pragma warning(pop)
+
+    status = __DriverGetPfnArray(Name, Count, MmGetMdlPfnArray(Mdl));
+    if (!NT_SUCCESS(status)) {
+        if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+            status = __DriverAllocatePfnArray(Name, Count,
+                                              MmGetMdlPfnArray(Mdl));
+
+        if (!NT_SUCCESS(status))
+            goto fail2;
+    }
+
+    MdlMappedSystemVa = MmMapLockedPagesSpecifyCache(Mdl,
+                                                     KernelMode,
+                                                     MmCached,
+                                                     NULL,
+                                                     FALSE,
+                                                     NormalPagePriority);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (MdlMappedSystemVa == NULL)
+        goto fail3;
+
+    Mdl->StartVa = PAGE_ALIGN(MdlMappedSystemVa);
+
+    return Mdl;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+    __DriverFree(Mdl);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return NULL;
+}
+
+VOID
+DriverPutNamedPages(
+    IN  PMDL    Mdl
+    )
+{
+    PUCHAR         MdlMappedSystemVa;
+
+    ASSERT(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
+    MdlMappedSystemVa = Mdl->MappedSystemVa;
+
+    MmUnmapLockedPages(MdlMappedSystemVa, Mdl);
+
+    // DO NOT FREE PAGES
+
+    __DriverFree(Mdl);
+}
+
 XEN_API
 NTSTATUS
 XenTouch(
@@ -173,8 +472,9 @@ DllInitialize(
     )
 {
     HANDLE              ServiceKey;
-    HANDLE              UnplugKey;
     HANDLE              ParametersKey;
+    HANDLE              UnplugKey;
+    HANDLE              MemoryKey;
     LOG_LEVEL           LogLevel;
     NTSTATUS            status;
 
@@ -198,9 +498,9 @@ DllInitialize(
         goto fail3;
 
     status = RegistryCreateSubKey(ServiceKey,
-                                "Parameters",
-                                REG_OPTION_NON_VOLATILE,
-                                &ParametersKey);
+                                  "Parameters",
+                                  REG_OPTION_NON_VOLATILE,
+                                  &ParametersKey);
     if (!NT_SUCCESS(status))
         goto fail4;
 
@@ -249,31 +549,40 @@ DllInitialize(
 
     __DriverSetUnplugKey(UnplugKey);
 
+    status = RegistryCreateSubKey(ServiceKey,
+                                  "Memory",
+                                  REG_OPTION_VOLATILE,
+                                  &MemoryKey);
+    if (!NT_SUCCESS(status))
+        goto fail6;
+
+    __DriverSetMemoryKey(MemoryKey);
+
     HypercallInitialize();
 
     status = AcpiInitialize();
     if (!NT_SUCCESS(status))
-        goto fail6;
+        goto fail7;
 
     status = SystemInitialize();
     if (!NT_SUCCESS(status))
-        goto fail7;
+        goto fail8;
 
     status = BugCheckInitialize();
     if (!NT_SUCCESS(status))
-        goto fail8;
+        goto fail9;
 
     status = ModuleInitialize();
     if (!NT_SUCCESS(status))
-        goto fail9;
+        goto fail10;
 
     status = ProcessInitialize();
     if (!NT_SUCCESS(status))
-        goto fail10;
+        goto fail11;
 
     status = UnplugInitialize();
     if (!NT_SUCCESS(status))
-        goto fail11;
+        goto fail12;
 
     RegistryCloseKey(ParametersKey);
 
@@ -283,36 +592,42 @@ DllInitialize(
 
     return STATUS_SUCCESS;
 
+fail12:
+    Error("fail12\n");
+
+    ProcessTeardown();
+
 fail11:
     Error("fail11\n");
 
-    ProcessTeardown();
+    ModuleTeardown();
 
 fail10:
     Error("fail10\n");
 
-    ModuleTeardown();
+    BugCheckTeardown();
 
 fail9:
     Error("fail9\n");
 
-    BugCheckTeardown();
+    SystemTeardown();
 
 fail8:
     Error("fail8\n");
 
-    SystemTeardown();
+    AcpiTeardown();
 
 fail7:
     Error("fail7\n");
 
-    AcpiTeardown();
+    HypercallTeardown();
+
+    RegistryCloseKey(MemoryKey);
+    __DriverSetMemoryKey(NULL);
 
 fail6:
     Error("fail6\n");
 
-    HypercallTeardown();
-
     RegistryCloseKey(UnplugKey);
     __DriverSetUnplugKey(NULL);
 
@@ -355,6 +670,7 @@ DllUnload(
     VOID
     )
 {
+    HANDLE  MemoryKey;
     HANDLE  UnplugKey;
 
     Trace("====>\n");
@@ -373,6 +689,11 @@ DllUnload(
 
     HypercallTeardown();
 
+    MemoryKey = __DriverGetMemoryKey();
+
+    RegistryCloseKey(MemoryKey);
+    __DriverSetMemoryKey(NULL);
+
     UnplugKey = __DriverGetUnplugKey();
 
     RegistryCloseKey(UnplugKey);
index c4f7a6fb6f6de3711844bb47b971f3f72be2d097..8c39735147c6e3067a44d0853eee3ec171f4643d 100644 (file)
@@ -37,4 +37,15 @@ DriverGetUnplugKey(
     VOID
     );
 
+extern PMDL
+DriverGetNamedPages(
+    IN  PCHAR   Name,
+    IN  ULONG   Count
+    );
+
+extern VOID
+DriverPutNamedPages(
+    IN  PMDL    Mdl
+    );
+
 #endif  // _XEN_DRIVER_H