/*++

Copyright (c) 2012 Minoca Corp. All Rights Reserved

Module Name:

    init.c

Abstract:

    This module contains code to initialize the I/O subsystem.

Author:

    Evan Green 16-Sep-2012

Environment:

    Kernel

--*/

//
// ------------------------------------------------------------------- Includes
//

#include <minoca/kernel/kernel.h>
#include <minoca/kernel/bootload.h>
#include <minoca/lib/bconf.h>
#include "iop.h"
#include "pagecach.h"

//
// ---------------------------------------------------------------- Definitions
//

//
// ------------------------------------------------------ Data Type Definitions
//

/*++

Structure Description:

    This structure defines the iteration context that initializes the physical
    address space arbiter.

Members:

    PreviousEnd - Stores the end of the previous descriptor.

    Status - Stores the final status code.

--*/

typedef struct _IO_INIT_PHYSICAL_MAP_ITERATOR {
    ULONGLONG PreviousEnd;
    KSTATUS Status;
} IO_INIT_PHYSICAL_MAP_ITERATOR, *PIO_INIT_PHYSICAL_MAP_ITERATOR;

//
// ----------------------------------------------- Internal Function Prototypes
//

KSTATUS
IopInitializeDeviceSupport (
    VOID
    );

KSTATUS
IopInitializeResourceAllocation (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    );

KSTATUS
IopInitializeBootDrivers (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    );

KSTATUS
IopInitializeDeviceDatabase (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    );

KSTATUS
IopCreateBootDevices (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    );

VOID
IopInitializePhysicalAddressArbiterIterator (
    PMEMORY_DESCRIPTOR_LIST DescriptorList,
    PMEMORY_DESCRIPTOR Descriptor,
    PVOID Context
    );

//
// -------------------------------------------------------------------- Globals
//

//
// ------------------------------------------------------------------ Functions
//

KSTATUS
IoInitialize (
    ULONG Phase,
    PKERNEL_INITIALIZATION_BLOCK Parameters
    )

/*++

Routine Description:

    This routine initializes the I/O subsystem.

Arguments:

    Phase - Supplies the initialization phase.

    Parameters - Supplies a pointer to the kernel's initialization information.

Return Value:

    Status code.

--*/

{

    PBOOT_ENTRY BootEntry;
    ULONG Flags;
    KSTATUS Status;
    UINTN SystemDirectorySize;

    INITIALIZE_LIST_HEAD(&IoDeviceList);
    IoDeviceListLock = KeCreateQueuedLock();
    if (IoDeviceListLock == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    //
    // Copy the boot information over.
    //

    if (Parameters->BootEntry != NULL) {
        BootEntry = Parameters->BootEntry;

        ASSERT((sizeof(IoBootInformation.SystemDiskIdentifier) ==
                sizeof(BootEntry->DiskId)) &&
               (sizeof(IoBootInformation.SystemPartitionIdentifier) ==
                sizeof(BootEntry->PartitionId)));

        RtlCopyMemory(&(IoBootInformation.SystemDiskIdentifier),
                      &(BootEntry->DiskId),
                      sizeof(IoBootInformation.SystemDiskIdentifier));

        RtlCopyMemory(&(IoBootInformation.SystemPartitionIdentifier),
                      &(BootEntry->PartitionId),
                      sizeof(IoBootInformation.SystemPartitionIdentifier));

        //
        // Copy the system directory path.
        //

        if (BootEntry->SystemPath != NULL) {
            SystemDirectorySize = RtlStringLength(BootEntry->SystemPath) + 1;
            IoSystemDirectoryPath = MmAllocateNonPagedPool(SystemDirectorySize,
                                                           IO_ALLOCATION_TAG);

            if (IoSystemDirectoryPath == NULL) {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto InitializeEnd;
            }

            RtlStringCopy(IoSystemDirectoryPath,
                          BootEntry->SystemPath,
                          SystemDirectorySize);
        }
    }

    RtlCopyMemory(&(IoBootInformation.BootTime),
                  &(Parameters->BootTime),
                  sizeof(SYSTEM_TIME));

    //
    // Create the Interfaces object directory.
    //

    IoInterfaceDirectory = ObCreateObject(ObjectDirectory,
                                          NULL,
                                          "Interface",
                                          sizeof("Interface"),
                                          sizeof(OBJECT_HEADER),
                                          NULL,
                                          OBJECT_FLAG_USE_NAME_DIRECTLY,
                                          IO_ALLOCATION_TAG);

    if (IoInterfaceDirectory == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    IoInterfaceLock = KeCreateQueuedLock();
    if (IoInterfaceLock == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    //
    // Create the IRP directory.
    //

    IoIrpDirectory = ObCreateObject(ObjectDirectory,
                                    NULL,
                                    "Irp",
                                    sizeof("Irp"),
                                    sizeof(OBJECT_HEADER),
                                    NULL,
                                    OBJECT_FLAG_USE_NAME_DIRECTLY,
                                    IO_ALLOCATION_TAG);

    if (IoIrpDirectory == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    //
    // Create the pipe directory.
    //

    IoPipeDirectory = ObCreateObject(ObjectDirectory,
                                     NULL,
                                     "Pipe",
                                     sizeof("Pipe"),
                                     sizeof(OBJECT_HEADER),
                                     NULL,
                                     OBJECT_FLAG_USE_NAME_DIRECTLY,
                                     FI_ALLOCATION_TAG);

    if (IoPipeDirectory == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    //
    // Create the shared memory object directory.
    //

    IoSharedMemoryObjectDirectory = ObCreateObject(
                                                 ObjectDirectory,
                                                 NULL,
                                                 "SharedMemoryObjects",
                                                 sizeof("SharedMemoryObjects"),
                                                 sizeof(OBJECT_HEADER),
                                                 NULL,
                                                 OBJECT_FLAG_USE_NAME_DIRECTLY,
                                                 FI_ALLOCATION_TAG);

    if (IoSharedMemoryObjectDirectory == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    //
    // Initialize the file system list head and create the lock protecting
    // access to it.
    //

    INITIALIZE_LIST_HEAD(&IoFileSystemList);
    IoFileSystemListLock = KeCreateQueuedLock();
    if (IoFileSystemListLock == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    //
    // Create the volume directory.
    //

    Flags = OBJECT_FLAG_USE_NAME_DIRECTLY;
    IoVolumeDirectory = ObCreateObject(ObjectDirectory,
                                       NULL,
                                       "Volume",
                                       sizeof("Volume"),
                                       sizeof(OBJECT_HEADER),
                                       NULL,
                                       Flags,
                                       FI_ALLOCATION_TAG);

    if (IoVolumeDirectory == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeEnd;
    }

    //
    // Initialize support for device information requests.
    //

    Status = IopInitializeDeviceInformationSupport();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Initialize support for file objects.
    //

    Status = IopInitializeFileObjectSupport();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Initialize support for path traversal.
    //

    Status = IopInitializePathSupport();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Initialize support for mount points.
    //

    Status = IopInitializeMountPointSupport();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Initialize support for the page cache.
    //

    Status = IopInitializePageCache();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Initialize support for terminals.
    //

    Status = IopInitializeTerminalSupport();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Initialize the device database.
    //

    Status = IopInitializeDeviceDatabase(Parameters);
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    Status = IopInitializeDeviceSupport();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Initialize support for resource allocation.
    //

    Status = IopInitializeResourceAllocation(Parameters);
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Load all boot drivers and call their entry routines.
    //

    Status = IopInitializeBootDrivers(Parameters);
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Create the base devices described in the device map.
    //

    Status = IopCreateBootDevices(Parameters);
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

    //
    // Fire up power management.
    //

    Status = PmInitializeLibrary();
    if (!KSUCCESS(Status)) {
        goto InitializeEnd;
    }

InitializeEnd:
    return Status;
}

//
// --------------------------------------------------------- Internal Functions
//

KSTATUS
IopInitializeDeviceSupport (
    VOID
    )

/*++

Routine Description:

    This routine initializes support for devices.

Arguments:

    None.

Return Value:

    Status code.

--*/

{

    KSTATUS Status;
    ULONG WorkQueueFlags;

    WorkQueueFlags = WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL;
    IoDeviceWorkQueue = KeCreateWorkQueue(WorkQueueFlags, "IoDeviceWorker");
    if (IoDeviceWorkQueue == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeDeviceSupportEnd;
    }

    //
    // Create and initialize the root device.
    //

    Status = IoCreateDevice(NULL,
                            NULL,
                            NULL,
                            "Device",
                            NULL,
                            NULL,
                            &IoRootDevice);

    if (!KSUCCESS(Status)) {
        goto InitializeDeviceSupportEnd;
    }

    ASSERT(IoRootDevice != NULL);

InitializeDeviceSupportEnd:
    return Status;
}

KSTATUS
IopInitializeResourceAllocation (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    )

/*++

Routine Description:

    This routine initializes support for device resource allocation.

Arguments:

    Parameters - Supplies a pointer to the kernel initialization block.

Return Value:

    Status code.

--*/

{

    IO_INIT_PHYSICAL_MAP_ITERATOR Context;
    KSTATUS Status;

    //
    // Create the physical address arbiter.
    //

    Status = IoCreateResourceArbiter(IoRootDevice,
                                     ResourceTypePhysicalAddressSpace);

    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Loop through the physical memory descriptor list looking for holes, and
    // add those holes as allocatable regions.
    //

    RtlZeroMemory(&Context, sizeof(IO_INIT_PHYSICAL_MAP_ITERATOR));
    Context.Status = STATUS_SUCCESS;
    MmMdIterate(Parameters->MemoryMap,
                IopInitializePhysicalAddressArbiterIterator,
                &Context);

    if (!KSUCCESS(Context.Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Create an I/O space arbiter.
    //

    if (ArGetIoPortCount() != 0) {
        Status = IoCreateResourceArbiter(IoRootDevice, ResourceTypeIoPort);
        if (!KSUCCESS(Status)) {
            goto InitializeResourceAllocationEnd;
        }

        Status = IoAddFreeSpaceToArbiter(IoRootDevice,
                                         ResourceTypeIoPort,
                                         0,
                                         ArGetIoPortCount(),
                                         0,
                                         NULL,
                                         0);

        if (!KSUCCESS(Status)) {
            goto InitializeResourceAllocationEnd;
        }
    }

    //
    // Create an interrupt line arbiter.
    //

    Status = IoCreateResourceArbiter(IoRootDevice, ResourceTypeInterruptLine);
    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    Status = IoAddFreeSpaceToArbiter(IoRootDevice,
                                     ResourceTypeInterruptLine,
                                     0,
                                     -1,
                                     0,
                                     NULL,
                                     0);

    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Create an interrupt vector arbiter.
    //

    Status = IoCreateResourceArbiter(IoRootDevice, ResourceTypeInterruptVector);
    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    Status = IoAddFreeSpaceToArbiter(IoRootDevice,
                                     ResourceTypeInterruptVector,
                                     ArGetMinimumDeviceVector(),
                                     ArGetMaximumDeviceVector() + 1,
                                     0,
                                     NULL,
                                     0);

    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Create a bus number arbiter.
    //

    Status = IoCreateResourceArbiter(IoRootDevice, ResourceTypeBusNumber);
    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    Status = IoAddFreeSpaceToArbiter(IoRootDevice,
                                     ResourceTypeBusNumber,
                                     0,
                                     -1,
                                     0,
                                     NULL,
                                     0);

    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Create a DMA line arbiter.
    //

    Status = IoCreateResourceArbiter(IoRootDevice, ResourceTypeDmaChannel);
    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    Status = IoAddFreeSpaceToArbiter(IoRootDevice,
                                     ResourceTypeDmaChannel,
                                     0,
                                     -1,
                                     0,
                                     NULL,
                                     0);

    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Create an empty vendor defined arbiter. Allocation requests that hit
    // this arbiter will always fail.
    //

    Status = IoCreateResourceArbiter(IoRootDevice,
                                     ResourceTypeVendorSpecific);

    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Also create an empty GPIO arbiter and an empty simple bus arbiter.
    //

    Status = IoCreateResourceArbiter(IoRootDevice, ResourceTypeGpio);
    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    Status = IoCreateResourceArbiter(IoRootDevice, ResourceTypeSimpleBus);
    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

    //
    // Perform any architecture specific initialization.
    //

    Status = IopArchInitializeKnownArbiterRegions();
    if (!KSUCCESS(Status)) {
        goto InitializeResourceAllocationEnd;
    }

InitializeResourceAllocationEnd:
    return Status;
}

KSTATUS
IopInitializeBootDrivers (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    )

/*++

Routine Description:

    This routine initializes all boot start drivers.

Arguments:

    Parameters - Supplies a pointer to the kernel's initialization information.

Return Value:

    Status code.

--*/

{

    PLIST_ENTRY CurrentEntry;
    PDRIVER Driver;
    PLOADED_IMAGE Image;
    PKPROCESS Process;
    KSTATUS Status;

    Status = STATUS_SUCCESS;

    //
    // Loop over every loaded image in the kernel process and create a driver
    // object for it. The driver image list is guarded by the device database
    // lock rather than the kernel process lock so that threads can be created.
    //

    Process = PsGetKernelProcess();
    KeAcquireQueuedLock(IoDeviceDatabaseLock);
    CurrentEntry = Process->ImageListHead.Next;
    while (CurrentEntry != &(Process->ImageListHead)) {
        Image = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
        CurrentEntry = CurrentEntry->Next;

        //
        // Skip the kernel module.
        //

        if (Image->LoadedLowestAddress ==
            Parameters->KernelModule->LowestAddress) {

            continue;
        }

        Image->SystemContext = Process;
        Status = IoCreateDriverStructure(Image);
        if (!KSUCCESS(Status)) {
            goto InitializeBootDriversEnd;
        }

        Status = IopInitializeDriver(Image);
        if (!KSUCCESS(Status)) {
            goto InitializeBootDriversEnd;
        }

        Driver = Image->SystemExtension;
        Driver->Flags |= DRIVER_FLAG_LOADED_AT_BOOT;
    }

InitializeBootDriversEnd:
    KeReleaseQueuedLock(IoDeviceDatabaseLock);
    return Status;
}

KSTATUS
IopInitializeDeviceDatabase (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    )

/*++

Routine Description:

    This routine initializes the device to driver database.

Arguments:

    Parameters - Supplies a pointer to the kernel's initialization information.

Return Value:

    Status code.

--*/

{

    PSTR Device;
    PSTR Driver;
    PSTR FileEnd;
    ULONG FileSize;
    PSTR LineEnd;
    PSTR Separator;
    KSTATUS Status;

    //
    // Initialize the device database lock and list heads.
    //

    IoDeviceDatabaseLock = KeCreateQueuedLock();
    if (IoDeviceDatabaseLock == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto InitializeDeviceDatabaseEnd;
    }

    INITIALIZE_LIST_HEAD(&IoDeviceDatabaseHead);
    INITIALIZE_LIST_HEAD(&IoDeviceClassDatabaseHead);

    //
    // Loop through every entry in the file.
    //

    Device = Parameters->DeviceToDriverFile.Buffer;
    FileSize = Parameters->DeviceToDriverFile.Size;
    FileEnd = Device + FileSize;
    while (TRUE) {
        Driver = NULL;

        //
        // Find the end of the line.
        //

        LineEnd = RtlStringFindCharacter(Device, '\n', FileSize);
        if (LineEnd != NULL) {

            //
            // If the line is less than 2 characters wide, ignore it.
            //

            if (LineEnd - Device < 2) {

                ASSERT(LineEnd != Device);

                if (LineEnd + 3 >= FileEnd) {
                    break;
                }

                FileSize -= (UINTN)(LineEnd + 1) - (UINTN)Device;
                Device = LineEnd + 1;
                continue;
            }

            //
            // Terminate the end. Watch for a CR.
            //

            if (*(LineEnd - 1) == '\r') {
                *(LineEnd - 1) = '\0';

            } else {
                *LineEnd = '\0';
            }
        }

        //
        // Find the last equals.
        //

        if (*Device != '#') {
            Separator = RtlStringFindCharacterRight(Device, '=', FileSize);
            if ((Separator == NULL) || (Separator == LineEnd - 1) ||
                (Separator == Device)) {

                Status = STATUS_FILE_CORRUPT;
                goto InitializeDeviceDatabaseEnd;
            }

            *Separator = '\0';
            Driver = Separator + 1;
        }

        //
        // Add a device or device class entry, depending on the first character
        // in the line.
        //

        if (*Device == 'D') {
            Status = IoAddDeviceDatabaseEntry(Device + 1, Driver);

        } else if (*Device == 'C') {
            Status = IoAddDeviceClassDatabaseEntry(Device + 1, Driver);

        } else if (*Device == '#') {
            Status = STATUS_SUCCESS;

        } else {
            Status = STATUS_FILE_CORRUPT;
        }

        if (!KSUCCESS(Status)) {
            goto InitializeDeviceDatabaseEnd;
        }

        //
        // Stop if this is end of the file.
        //

        if ((LineEnd == NULL) || (LineEnd == FileEnd) ||
            (LineEnd + 1 == FileEnd)) {

            break;
        }

        FileSize -= (UINTN)(LineEnd + 1) - (UINTN)Device;
        Device = LineEnd + 1;
    }

    Status = STATUS_SUCCESS;

InitializeDeviceDatabaseEnd:
    return Status;
}

KSTATUS
IopCreateBootDevices (
    PKERNEL_INITIALIZATION_BLOCK Parameters
    )

/*++

Routine Description:

    This routine creates all unenumerable devices described at boot time by the
    device map.

Arguments:

    Parameters - Supplies a pointer to the kernel's initialization information.

Return Value:

    Status code.

--*/

{

    PSTR Device;
    PSTR DeviceSeparator;
    PSTR FileEnd;
    ULONG FileSize;
    PSTR LineEnd;
    KSTATUS Status;

    Status = STATUS_SUCCESS;

    //
    // Loop through every entry in the file.
    //

    Device = Parameters->DeviceMapFile.Buffer;
    FileSize = Parameters->DeviceMapFile.Size;
    FileEnd = Device + FileSize;
    while (TRUE) {

        //
        // Find the end of the line.
        //

        LineEnd = RtlStringFindCharacter(Device, '\n', FileSize);
        if (LineEnd != NULL) {

            //
            // If the line is less than 2 characters wide, ignore it.
            //

            if (LineEnd - Device < 2) {

                ASSERT(LineEnd != Device);

                if (LineEnd + 3 >= FileEnd) {
                    break;
                }

                FileSize -= (UINTN)(LineEnd + 1) - (UINTN)Device;
                Device = LineEnd + 1;
                continue;
            }

            //
            // Terminate the end. Watch for a CR.
            //

            if (*(LineEnd - 1) == '\r') {
                *(LineEnd - 1) = '\0';

            } else {
                *LineEnd = '\0';
            }
        }

        //
        // Find the last colon.
        //

        if (*Device != '#') {
            DeviceSeparator = RtlStringFindCharacterRight(Device,
                                                          ':',
                                                          FileSize);

            if (DeviceSeparator == Device) {
                Status = STATUS_FILE_CORRUPT;
                goto CreateBootDevicesEnd;
            }

            if (DeviceSeparator != NULL) {
                *DeviceSeparator = '\0';
            }

            //
            // Create the device.
            //

            Status = IoCreateDevice(NULL, NULL, NULL, Device, NULL, NULL, NULL);
            if (!KSUCCESS(Status)) {
                goto CreateBootDevicesEnd;
            }
        }

        //
        // Stop if this is end of the file.
        //

        if ((LineEnd == NULL) || (LineEnd == FileEnd) ||
            (LineEnd + 1 == FileEnd)) {

            break;
        }

        FileSize -= (UINTN)(LineEnd + 1) - (UINTN)Device;
        Device = LineEnd + 1;
    }

    Status = STATUS_SUCCESS;

CreateBootDevicesEnd:
    return Status;
}

VOID
IopInitializePhysicalAddressArbiterIterator (
    PMEMORY_DESCRIPTOR_LIST DescriptorList,
    PMEMORY_DESCRIPTOR Descriptor,
    PVOID Context
    )

/*++

Routine Description:

    This routine is called once for each descriptor in the memory descriptor
    list.

Arguments:

    DescriptorList - Supplies a pointer to the descriptor list being iterated
        over.

    Descriptor - Supplies a pointer to the current descriptor.

    Context - Supplies an optional opaque pointer of context that was provided
        when the iteration was requested.

Return Value:

    None.

--*/

{

    PIO_INIT_PHYSICAL_MAP_ITERATOR PhysicalContext;
    KSTATUS Status;

    PhysicalContext = Context;

    ASSERT(PhysicalContext->PreviousEnd <= Descriptor->BaseAddress);

    //
    // If there was a gap between the last descriptor and this one, add it
    // as a hole.
    //

    if (PhysicalContext->PreviousEnd < Descriptor->BaseAddress) {
        Status = IoAddFreeSpaceToArbiter(
                        IoRootDevice,
                        ResourceTypePhysicalAddressSpace,
                        PhysicalContext->PreviousEnd,
                        Descriptor->BaseAddress - PhysicalContext->PreviousEnd,
                        0,
                        NULL,
                        0);

        if (!KSUCCESS(Status)) {
            PhysicalContext->Status = Status;
        }
    }

    PhysicalContext->PreviousEnd = Descriptor->BaseAddress + Descriptor->Size;
    return;
}

