[BOOTMGFW]
authorAlex Ionescu <aionescu@gmail.com>
Wed, 9 Sep 2015 05:48:50 +0000 (05:48 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Wed, 9 Sep 2015 05:48:50 +0000 (05:48 +0000)
- 1.5KLOC code dump of current device block I/O handling. Totally untested and broken, just a checkpoint for now.
- Implement most of Hash Table Utility Functions.
- Implement parts of Block Allocator.
- Finish Implementation of Generic Table Utility Functions.
- Fix some EFI device emulation code.
- Temporarily disable freeing from heap while I figure out what's corrupting it.

svn path=/trunk/; revision=69142

14 files changed:
reactos/boot/environ/app/bootmgr/bootmgr.c
reactos/boot/environ/app/bootmgr/efiemu.c
reactos/boot/environ/include/bl.h
reactos/boot/environ/include/efi/BlockIo.h [new file with mode: 0644]
reactos/boot/environ/lib/bootlib.c
reactos/boot/environ/lib/firmware/efi/firmware.c
reactos/boot/environ/lib/io/device.c
reactos/boot/environ/lib/io/display/display.c
reactos/boot/environ/lib/io/display/emscons.c
reactos/boot/environ/lib/io/io.c
reactos/boot/environ/lib/misc/util.c
reactos/boot/environ/lib/mm/blkalloc.c
reactos/boot/environ/lib/mm/heapalloc.c
reactos/boot/environ/lib/mm/pagealloc.c

index 69f0902..dc938d6 100644 (file)
@@ -22,43 +22,42 @@ DEFINE_GUID(GUID_WINDOWS_BOOTMGR,
 ULONGLONG ApplicationStartTime;
 ULONGLONG PostTime;
 GUID BmApplicationIdentifier;
+PWCHAR BootDirectory;
 
 /* FUNCTIONS *****************************************************************/
 
-PGUID
-BlGetApplicationIdentifier (
+NTSTATUS
+BmFwInitializeBootDirectoryPath (
     VOID
     )
 {
-    return NULL;
-}
-
-PWCHAR BootDirectory;
-
-NTSTATUS
-BmFwInitializeBootDirectoryPath()
-{
-#if 0
     PWCHAR FinalPath;
     NTSTATUS Status;
     PWCHAR BcdDirectory;
-    UNICODE_STRING BcdPath;
-    ULONG FinalSize, FileHandle, DeviceHandle;
-
-    BcdPath.MaximumLength = 0;
-    BcdPath.Buffer = NULL;
-
+   // UNICODE_STRING BcdPath;
+    //ULONG FinalSize;
+    ULONG FileHandle, DeviceHandle;
+
+    /* Initialize everything for failure */
+   // BcdPath.MaximumLength = 0;
+   // BcdPath.Buffer = NULL;
+    BcdDirectory = NULL;
     FinalPath = NULL;
-
     FileHandle = -1;
     DeviceHandle = -1;
 
+    /* Try to open the boot device */
     Status = BlpDeviceOpen(BlpBootDevice, 1u, 0, &DeviceHandle);
     if (!NT_SUCCESS(Status))
     {
         goto Quickie;
     }
 
+    /* For now, do nothing */
+    EfiPrintf(L"Successfully opened boot device: %lx\r\n", DeviceHandle);
+    EfiStall(2000000);
+
+#if 0
     Status = BmpFwGetApplicationDirectoryPath(&BcdPath);
     BcdDirectory = BcdPath.Buffer;
     if (!NT_SUCCESS(Status))
@@ -91,8 +90,10 @@ BmFwInitializeBootDirectoryPath()
     }
 
     BootDirectory = L"\\EFI\\Microsoft\\Boot";
+#endif
 
 Quickie:
+    /* Free all the allocations we made */
     if (BcdDirectory)
     {
         Status = BlMmFreeHeap(BcdDirectory);
@@ -101,18 +102,21 @@ Quickie:
     {
         Status = BlMmFreeHeap(FinalPath);
     }
+
+    /* Close the BCD file */
     if (FileHandle != -1)
     {
-        Status = BlFileClose(FileHandle);
+        //Status = BlFileClose(FileHandle);
     }
+
+    /* Close the boot device */
     if (DeviceHandle != -1)
     {
         Status = BlDeviceClose(DeviceHandle);
     }
+
+    /* Return back to the caller */
     return Status;
-#else
-    return STATUS_NOT_IMPLEMENTED;
-#endif
 }
 
 
@@ -172,6 +176,9 @@ BmMain (
         goto Quickie;
     }
 
+    EfiPrintf(L"We are A-OK!\n");
+    EfiStall(10000000);
+
     /* Get the application identifier */
     AppIdentifier = BlGetApplicationIdentifier();
     if (!AppIdentifier)
index a249c66..40b9487 100644 (file)
@@ -253,7 +253,10 @@ EfiInitpConvertEfiFilePath (
                                               FilePath->PathName,
                                               StringLength,
                                               &BytesAppended);
-            if (!NT_SUCCESS(Status)) return Status;
+            if (!NT_SUCCESS(Status))
+            {
+                return Status;
+            }
 
             /* Increase the size of the data, consume buffer space */
             DataSize += BytesAppended;
@@ -345,7 +348,7 @@ EfiInitpGetDeviceNode (
  *
  *--*/
 NTSTATUS
-EfiInitTranslateDevicePath(
+EfiInitTranslateDevicePath (
     _In_ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
     _In_ PBL_DEVICE_DESCRIPTOR DeviceEntry
     )
@@ -418,7 +421,7 @@ EfiInitTranslateDevicePath(
             }
 
             /* Other types should come in as MEDIA_DEVICE_PATH -- Windows assumes this is a floppy */
-            DeviceEntry->DeviceType = LocalDevice;
+            DeviceEntry->DeviceType = DiskDevice;
             DeviceEntry->Local.Type = FloppyDevice;
             DeviceEntry->Local.FloppyDisk.DriveNumber = 0;
             return STATUS_SUCCESS;
@@ -434,7 +437,7 @@ EfiInitTranslateDevicePath(
                 if (DiskPath->SignatureType == SIGNATURE_TYPE_MBR)
                 {
                     /* Set that this is a local partition */
-                    DeviceEntry->DeviceType = PartitionDevice;
+                    DeviceEntry->DeviceType = LegacyPartitionDevice;
                     DeviceEntry->Partition.Disk.Type = LocalDevice;
 
                     DeviceEntry->Partition.Disk.HardDisk.PartitionType = MbrPartition;
@@ -448,7 +451,7 @@ EfiInitTranslateDevicePath(
                 if (DiskPath->SignatureType == SIGNATURE_TYPE_GUID)
                 {
                     /* Set that this is a local disk */
-                    DeviceEntry->DeviceType = HardDiskDevice;
+                    DeviceEntry->DeviceType = PartitionDevice;
                     DeviceEntry->Partition.Disk.Type = LocalDevice;
 
                     /* Set GPT partition ID */
@@ -463,15 +466,16 @@ EfiInitTranslateDevicePath(
                     return STATUS_SUCCESS;
                 }
 
-                /* Othertwise, raw boot is not supported */
-                DeviceEntry->DeviceType = HardDiskDevice;
+                /* Otherwise, raw boot is not supported */
+                DeviceEntry->DeviceType = PartitionDevice;
+                DeviceEntry->Partition.Disk.Type = LocalDevice;
                 DeviceEntry->Partition.Disk.HardDisk.PartitionType = RawPartition;
                 DeviceEntry->Partition.Disk.HardDisk.Raw.DiskNumber = 0;
             }
             else if (DeviceNode->SubType == MEDIA_CDROM_DP)
             {
                 /* Set the right type for a CDROM */
-                DeviceEntry->DeviceType = LocalDevice;
+                DeviceEntry->DeviceType = DiskDevice;
                 DeviceEntry->Local.Type = CdRomDevice;
 
                 /* Set the drive number to zero */
index 41f94a0..33fda87 100644 (file)
@@ -28,6 +28,7 @@
 #include <LoadedImage.h>
 #include <GraphicsOutput.h>
 #include <UgaDraw.h>
+#include <BlockIo.h>
 
 /* DEFINES *******************************************************************/
 
@@ -76,6 +77,8 @@
 #define BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG      0x01
 #define BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG   0x02
 
+#define BL_HT_VALUE_IS_INLINE                           0x01
+
 #define BL_FS_REGISTER_AT_HEAD_FLAG                     1
 
 #define BL_MEMORY_CLASS_SHIFT                           28
@@ -127,10 +130,13 @@ typedef enum _BL_ARCH_MODE
 //
 typedef enum _BL_DEVICE_TYPE
 {
-    LocalDevice = 0,
-    PartitionDevice = 2,
+    DiskDevice = 0,
+    LegacyPartitionDevice = 2,
+    SerialDevice = 3,
     UdpDevice = 4,
-    HardDiskDevice = 6
+    BootDevice = 5,
+    PartitionDevice = 6,
+    LocateDevice = 8,
 } BL_DEVICE_TYPE;
 
 //
@@ -138,9 +144,12 @@ typedef enum _BL_DEVICE_TYPE
 //
 typedef enum _BL_LOCAL_DEVICE_TYPE
 {
+    LocalDevice = 0,
     FloppyDevice = 1,
     CdRomDevice = 2,
     RamDiskDevice = 3,
+    FileDevice = 5,
+    VirtualDiskDevice = 6
 } BL_LOCAL_DEVICE_TYPE;
 
 //
@@ -180,11 +189,13 @@ typedef enum _BL_MEMORY_TYPE
     // Loader Memory
     //
     BlLoaderMemory = 0xD0000002,
+    BlLoaderDeviceMemory = 0xD0000004,
     BlLoaderHeap = 0xD0000005,
     BlLoaderPageDirectory = 0xD0000006,
     BlLoaderReferencePage = 0xD0000007,
     BlLoaderRamDisk = 0xD0000008,
     BlLoaderData = 0xD000000A,
+    BlLoaderBlockMemory = 0xD000000C,
     BlLoaderSelfMap = 0xD000000F,
 
     //
@@ -341,6 +352,50 @@ NTSTATUS
     _In_ ULONG Attribute
     );
 
+typedef
+BOOLEAN
+(*PBL_TBL_LOOKUP_ROUTINE) (
+    _In_ PVOID Entry,
+    _In_ PVOID Argument1,
+    _In_ PVOID Argument2,
+    _In_ PVOID Argument3,
+    _In_ PVOID Argument4
+    );
+
+typedef
+NTSTATUS
+(*PBL_TBL_MAP_ROUTINE) (
+    _In_ PVOID Entry,
+    _In_ ULONG EntryIndex
+    );
+
+typedef
+NTSTATUS
+(*PBL_TBL_SET_ROUTINE) (
+    _In_ PVOID Entry
+    );
+
+typedef
+NTSTATUS
+(*PBL_IO_DESTROY_ROUTINE) (
+    VOID
+    );
+
+struct _BL_HASH_ENTRY;
+typedef
+BOOLEAN
+(*PBL_HASH_TABLE_COMPARE_FUNCTION) (
+    _In_ struct _BL_HASH_ENTRY* Entry1,
+    _In_ struct _BL_HASH_ENTRY* Entry2
+    );
+
+typedef
+ULONG
+(*PBL_HASH_TABLE_HASH_FUNCTION) (
+    _In_ struct _BL_HASH_ENTRY* Entry,
+    _In_ ULONG TableSize
+    );
+
 /* DATA STRUCTURES ***********************************************************/
 
 typedef struct _BL_LIBRARY_PARAMETERS
@@ -568,11 +623,6 @@ typedef struct _BL_FILE_ENTRY
     PBL_FILE_DESTROY_CALLBACK DestroyCallback;
 } BL_FILE_ENTRY, *PBL_FILE_ENTRY;
 
-typedef struct _BL_DEVICE_ENTRY
-{
-    ULONG ReferenceCount;
-} BL_DEVICE_ENTRY, *PBL_DEVICE_ENTRY;
-
 typedef struct _BL_FILE_SYSTEM_ENTRY
 {
     LIST_ENTRY ListEntry;
@@ -665,6 +715,67 @@ typedef struct _BL_REMOTE_CONSOLE
     BL_TEXT_CONSOLE TextConsole;
 } BL_REMOTE_CONSOLE, *PBL_REMOTE_CONSOLE;
 
+typedef struct _BL_HASH_TABLE
+{
+    PLIST_ENTRY HashLinks;
+    ULONG Size;
+    PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction;
+    PBL_HASH_TABLE_HASH_FUNCTION HashFunction;
+} BL_HASH_TABLE, *PBL_HASH_TABLE;
+
+typedef struct _BL_HASH_ENTRY
+{
+    ULONG Size;
+    ULONG Flags;
+    PVOID Value;
+} BL_HASH_ENTRY, *PBL_HASH_ENTRY;
+
+typedef struct _BL_HASH_VALUE
+{
+    ULONG DataSize;
+    PVOID Data;
+} BL_HASH_VALUE, *PBL_HASH_VALUE;
+
+typedef struct _BL_HASH_NODE
+{
+    LIST_ENTRY ListEntry;
+    BL_HASH_ENTRY Entry;
+    BL_HASH_VALUE Value;
+} BL_HASH_NODE, *PBL_HASH_NODE;
+
+typedef struct _BL_BLOCK_DEVICE
+{
+    BL_LOCAL_DEVICE_TYPE Type;
+    ULONG DeviceFlags;
+    ULONG Unknown;
+    BL_PARTITION_TYPE PartitionType;
+    ULONG BlockSize;
+    ULONG Alignment;
+    struct
+    {
+        union
+        {
+            struct
+            {
+                ULONG Signature;
+            } Mbr;
+            struct
+            {
+                GUID Signature;
+            } Gpt;
+        };
+    } Disk;
+    ULONGLONG LastBlock;
+    EFI_BLOCK_IO* Protocol;
+    EFI_HANDLE Handle;
+} BL_BLOCK_DEVICE, *PBL_BLOCK_DEVICE;
+
+typedef struct _BL_PROTOCOL_HANDLE
+{
+    EFI_HANDLE Handle;
+    PVOID Interface;
+} BL_PROTOCOL_HANDLE, *PBL_PROTOCOL_HANDLE;
+
 /* INLINE ROUTINES ***********************************************************/
 
 FORCEINLINE
@@ -893,6 +1004,17 @@ EfiResetSystem (
     _In_ EFI_RESET_TYPE ResetType
     );
 
+EFI_DEVICE_PATH*
+EfiGetLeafNode (
+    _In_ EFI_DEVICE_PATH *DevicePath
+    );
+
+EFI_DEVICE_PATH *
+EfiIsDevicePathParent (
+    _In_ EFI_DEVICE_PATH *DevicePath1,
+    _In_ EFI_DEVICE_PATH *DevicePath2
+    );
+
 /* PLATFORM TIMER ROUTINES ***************************************************/
 
 NTSTATUS
@@ -922,6 +1044,71 @@ BlFwReboot (
     VOID
     );
 
+PGUID
+BlGetApplicationIdentifier (
+    VOID
+    );
+
+/* TABLE ROUTINES ************************************************************/
+
+NTSTATUS
+BlTblMap (
+    _In_ PVOID *Table,
+    _In_ ULONG Count,
+    _In_ PBL_TBL_MAP_ROUTINE MapCallback
+    );
+
+PVOID
+BlTblFindEntry (
+    _In_ PVOID *Table,
+    _In_ ULONG Count,
+    _Out_ PULONG EntryIndex,
+    _In_ PBL_TBL_LOOKUP_ROUTINE Callback,
+    _In_ PVOID Argument1,
+    _In_ PVOID Argument2,
+    _In_ PVOID Argument3,
+    _In_ PVOID Argument4
+    );
+
+NTSTATUS
+BlTblSetEntry (
+    _Inout_ PVOID** Table,
+    _Inout_ PULONG Count,
+    _In_ PVOID Entry,
+    _Out_ PULONG EntryIndex,
+    _In_ PBL_TBL_SET_ROUTINE Callback
+    );
+
+NTSTATUS
+TblDoNotPurgeEntry (
+    _In_ PVOID Entry
+    );
+
+/* HASH TABLE ROUTINES *******************************************************/
+
+NTSTATUS
+BlHtStore (
+    _In_ ULONG TableId,
+    _In_ PBL_HASH_ENTRY Entry,
+    _In_ PVOID Data,
+    _In_ ULONG DataSize
+    );
+
+NTSTATUS
+BlHtLookup (
+    _In_ ULONG TableId,
+    _In_ PBL_HASH_ENTRY Entry,
+    _Out_ PBL_HASH_VALUE *Value
+    );
+
+NTSTATUS
+BlHtCreate (
+    _In_ ULONG Size,
+    _In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction,
+    _In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction,
+    _Out_ PULONG Id
+    );
+
 /* BCD ROUTINES **************************************************************/
 
 ULONG
@@ -1001,7 +1188,7 @@ MmMdFreeDescriptor (
 
 NTSTATUS
 MmPapAllocatePagesInRange (
-    _Inout_ PULONG PhysicalAddress,
+    _Inout_ PVOID* PhysicalAddress,
     _In_ BL_MEMORY_TYPE MemoryType,
     _In_ ULONGLONG Pages,
     _In_ ULONG Attributes,
@@ -1026,6 +1213,13 @@ BlMmMapPhysicalAddressEx (
     _In_ PHYSICAL_ADDRESS PhysicalAddress
     );
 
+/* BLOCK ALLOCATOR ROUTINES **************************************************/
+
+NTSTATUS
+BlpMmCreateBlockAllocator (
+    VOID
+    );
+
 /* HEAP ALLOCATOR ROUTINES ***************************************************/
 
 PVOID
@@ -1046,7 +1240,27 @@ BlDisplayGetTextCellResolution (
     _Out_ PULONG TextHeight
     );
 
-/* TExT CONSOLE ROUTINES *****************************************************/
+/* I/O ROUTINES **************************************************************/
+
+NTSTATUS
+BlpIoRegisterDestroyRoutine (
+    _In_ PBL_IO_DESTROY_ROUTINE DestroyRoutine
+    );
+
+NTSTATUS
+BlDeviceClose (
+    _In_ ULONG DeviceId
+    );
+
+NTSTATUS
+BlpDeviceOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ ULONG Flags,
+    _In_ ULONG Unknown,
+    _Out_ PULONG DeviceId
+    );
+
+/* TEXT CONSOLE ROUTINES *****************************************************/
 
 NTSTATUS
 ConsoleTextLocalDestruct (
@@ -1197,6 +1411,7 @@ extern EFI_GUID EfiGraphicsOutputProtocol;
 extern EFI_GUID EfiUgaDrawProtocol;
 extern EFI_GUID EfiLoadedImageProtocol;
 extern EFI_GUID EfiDevicePathProtocol;
+extern EFI_GUID EfiBlockIoProtocol;
 extern EFI_GUID EfiSimpleTextInputExProtocol;
 extern ULONG ConsoleGraphicalResolutionListFlags;
 extern BL_DISPLAY_MODE ConsoleGraphicalResolutionList[];
diff --git a/reactos/boot/environ/include/efi/BlockIo.h b/reactos/boot/environ/include/efi/BlockIo.h
new file mode 100644 (file)
index 0000000..4bc2109
--- /dev/null
@@ -0,0 +1,241 @@
+/** @file
+  Block IO protocol as defined in the UEFI 2.0 specification.
+
+  The Block IO protocol is used to abstract block devices like hard drives,
+  DVD-ROMs and floppy drives.
+
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials                          
+  are licensed and made available under the terms and conditions of the BSD License         
+  which accompanies this distribution.  The full text of the license may be found at        
+  http://opensource.org/licenses/bsd-license.php                                            
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+
+**/
+
+#ifndef __BLOCK_IO_H__
+#define __BLOCK_IO_H__
+
+#define EFI_BLOCK_IO_PROTOCOL_GUID \
+  { \
+    0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+typedef struct _EFI_BLOCK_IO_PROTOCOL  EFI_BLOCK_IO_PROTOCOL;
+
+///
+/// Protocol GUID name defined in EFI1.1.
+/// 
+#define BLOCK_IO_PROTOCOL       EFI_BLOCK_IO_PROTOCOL_GUID
+
+///
+/// Protocol defined in EFI1.1.
+/// 
+typedef EFI_BLOCK_IO_PROTOCOL   EFI_BLOCK_IO;
+
+/**
+  Reset the Block Device.
+
+  @param  This                 Indicates a pointer to the calling context.
+  @param  ExtendedVerification Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS          The device was reset.
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
+                               not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BLOCK_RESET)(
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
+  IN BOOLEAN                        ExtendedVerification
+  );
+
+/**
+  Read BufferSize bytes from Lba into Buffer.
+
+  @param  This       Indicates a pointer to the calling context.
+  @param  MediaId    Id of the media, changes every time the media is replaced.
+  @param  Lba        The starting Logical Block Address to read from
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is
+                     responsible for either having implicit or explicit ownership of the buffer.
+
+  @retval EFI_SUCCESS           The data was read correctly from the device.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, 
+                                or the buffer is not on proper alignment.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BLOCK_READ)(
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
+  IN UINT32                         MediaId,
+  IN EFI_LBA                        Lba,
+  IN UINTN                          BufferSize,
+  OUT VOID                          *Buffer
+  );
+
+/**
+  Write BufferSize bytes from Lba into Buffer.
+
+  @param  This       Indicates a pointer to the calling context.
+  @param  MediaId    The media ID that the write request is for.
+  @param  Lba        The starting logical block address to be written. The caller is
+                     responsible for writing to only legitimate locations.
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.
+  @param  Buffer     A pointer to the source buffer for the data.
+
+  @retval EFI_SUCCESS           The data was written correctly to the device.
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, 
+                                or the buffer is not on proper alignment.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BLOCK_WRITE)(
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
+  IN UINT32                         MediaId,
+  IN EFI_LBA                        Lba,
+  IN UINTN                          BufferSize,
+  IN VOID                           *Buffer
+  );
+
+/**
+  Flush the Block Device.
+
+  @param  This              Indicates a pointer to the calling context.
+
+  @retval EFI_SUCCESS       All outstanding data was written to the device
+  @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data
+  @retval EFI_NO_MEDIA      There is no media in the device.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BLOCK_FLUSH)(
+  IN EFI_BLOCK_IO_PROTOCOL  *This
+  );
+
+/**
+  Block IO read only mode data and updated only via members of BlockIO
+**/
+typedef struct {
+  ///
+  /// The curent media Id. If the media changes, this value is changed.
+  ///
+  UINT32  MediaId;         
+   
+  ///
+  /// TRUE if the media is removable; otherwise, FALSE.
+  ///    
+  BOOLEAN RemovableMedia;
+  
+  ///
+  /// TRUE if there is a media currently present in the device;
+  /// othersise, FALSE. THis field shows the media present status
+  /// as of the most recent ReadBlocks() or WriteBlocks() call.  
+  ///
+  BOOLEAN MediaPresent;
+
+  ///
+  /// TRUE if LBA 0 is the first block of a partition; otherwise
+  /// FALSE. For media with only one partition this would be TRUE.
+  ///
+  BOOLEAN LogicalPartition;
+  
+  ///
+  /// TRUE if the media is marked read-only otherwise, FALSE.
+  /// This field shows the read-only status as of the most recent WriteBlocks () call.
+  ///
+  BOOLEAN ReadOnly;
+  
+  ///
+  /// TRUE if the WriteBlock () function caches write data.
+  ///
+  BOOLEAN WriteCaching; 
+  
+  ///
+  /// The intrinsic block size of the device. If the media changes, then
+  /// this field is updated.  
+  ///
+  UINT32  BlockSize; 
+  
+  ///
+  /// Supplies the alignment requirement for any buffer to read or write block(s).
+  ///
+  UINT32  IoAlign; 
+  
+  ///
+  /// The last logical block address on the device.
+  /// If the media changes, then this field is updated. 
+  ///
+  EFI_LBA LastBlock; 
+
+  ///
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the first LBA is aligned to 
+  /// a physical block boundary. 
+  ///
+  EFI_LBA LowestAlignedLba;
+
+  ///
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the number of logical blocks 
+  /// per physical block.
+  ///
+  UINT32 LogicalBlocksPerPhysicalBlock;
+
+  ///
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION3. Returns the optimal transfer length
+  /// granularity as a number of logical blocks.
+  ///
+  UINT32 OptimalTransferLengthGranularity;
+} EFI_BLOCK_IO_MEDIA;
+
+#define EFI_BLOCK_IO_PROTOCOL_REVISION  0x00010000
+#define EFI_BLOCK_IO_PROTOCOL_REVISION2 0x00020001
+#define EFI_BLOCK_IO_PROTOCOL_REVISION3 0x00020031
+
+///
+/// Revision defined in EFI1.1.
+/// 
+#define EFI_BLOCK_IO_INTERFACE_REVISION   EFI_BLOCK_IO_PROTOCOL_REVISION
+
+///
+///  This protocol provides control over block devices.
+///
+struct _EFI_BLOCK_IO_PROTOCOL {
+  ///
+  /// The revision to which the block IO interface adheres. All future
+  /// revisions must be backwards compatible. If a future version is not
+  /// back wards compatible, it is not the same GUID.
+  ///
+  UINT64              Revision;
+  ///
+  /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
+  ///
+  EFI_BLOCK_IO_MEDIA  *Media;
+
+  EFI_BLOCK_RESET     Reset;
+  EFI_BLOCK_READ      ReadBlocks;
+  EFI_BLOCK_WRITE     WriteBlocks;
+  EFI_BLOCK_FLUSH     FlushBlocks;
+
+};
+
+extern EFI_GUID gEfiBlockIoProtocolGuid;
+
+#endif
index 512385d..fbbb946 100644 (file)
@@ -393,3 +393,13 @@ BlDestroyLibrary (
     EfiPrintf(L"Destroy not yet implemented\r\n");
     return;
 }
+
+PGUID
+BlGetApplicationIdentifier (
+    VOID
+    )
+{
+    /* Return the GUID, if one was present */
+    return (BlpApplicationEntry.Flags & BL_APPLICATION_ENTRY_FLAG_NO_GUID) ?
+            NULL : &BlpApplicationEntry.Guid;
+}
index a1ce379..6bf3359 100644 (file)
@@ -29,11 +29,84 @@ EFI_GUID EfiUgaDrawProtocol = EFI_UGA_DRAW_PROTOCOL_GUID;
 EFI_GUID EfiLoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
 EFI_GUID EfiDevicePathProtocol = EFI_DEVICE_PATH_PROTOCOL_GUID;
 EFI_GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+EFI_GUID EfiBlockIoProtocol = EFI_BLOCK_IO_PROTOCOL_GUID;
 
 WCHAR BlScratchBuffer[8192];
 
 /* FUNCTIONS *****************************************************************/
 
+EFI_DEVICE_PATH *
+EfiIsDevicePathParent (
+    _In_ EFI_DEVICE_PATH *DevicePath1,
+    _In_ EFI_DEVICE_PATH *DevicePath2
+    )
+{
+    USHORT Length1, Length2;
+
+    /* Loop each element of the device path */
+    while (!IsDevicePathEndType(DevicePath1) && !IsDevicePathEndType(DevicePath2))
+    {
+        /* Check if the element has a different length */
+        Length1 = DevicePathNodeLength(DevicePath1);
+        Length2 = DevicePathNodeLength(DevicePath2);
+        if (Length1 != Length2)
+        {
+            /* Then they're not related */
+            return NULL;
+        }
+
+        /* Check if the rest of the element data matches */
+        if (RtlCompareMemory(DevicePath1, DevicePath2, Length1) != Length1)
+        {
+            /* Nope, not related */
+            return NULL;
+        }
+
+        /* Move to the next element */
+        DevicePath1 = NextDevicePathNode(DevicePath1);
+        DevicePath2 = NextDevicePathNode(DevicePath2);
+    }
+
+    /* If the last element in path 1 is empty, then path 2 is the child (deeper) */
+    if (!IsDevicePathEndType(DevicePath1))
+    {
+        return DevicePath2;
+    }
+
+    /* If the last element in path 2 is empty, then path 1 is the child (deeper) */
+    if (!IsDevicePathEndType(DevicePath2))
+    {
+        return DevicePath1;
+    }
+
+    /* They're both the end, so they're identical, so there's no parent */
+    return NULL;
+}
+
+EFI_DEVICE_PATH*
+EfiGetLeafNode (
+    _In_ EFI_DEVICE_PATH *DevicePath
+    )
+{
+    EFI_DEVICE_PATH *NextDevicePath;
+
+    /* Make sure we're not already at the end */
+    if (!IsDevicePathEndType(DevicePath))
+    {
+        /* Grab the next node element, and keep going until the end */
+        for (NextDevicePath = NextDevicePathNode(DevicePath);
+             !IsDevicePathEndType(NextDevicePath);
+             NextDevicePath = NextDevicePathNode(NextDevicePath))
+        {
+            /* Save the current node we're at  */
+            DevicePath = NextDevicePath;
+        }
+    }
+
+    /* This now contains the deepeest (leaf) node */
+    return DevicePath;
+}
+
 VOID
 EfiPrintf (
     _In_ PWCHAR Format,
index 31b8428..1687c5a 100644 (file)
@@ -29,6 +29,1520 @@ BL_DEVICE_INFORMATION DmDeviceIoInformation;
 
 /* FUNCTIONS *****************************************************************/
 
+struct _BL_DEVICE_ENTRY;
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_ENUMERATE_DEVICE_CLASS) (
+    VOID
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_OPEN) (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ struct _BL_DEVICE_ENTRY* DeviceEntry
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_CLOSE) (
+    _In_ struct _BL_DEVICE_ENTRY* DeviceEntry
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_READ) (
+    VOID
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_WRITE) (
+    VOID
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_GET_INFORMATION) (
+    VOID
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_SET_INFORMATION) (
+    VOID
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_RESET) (
+    VOID
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_FLUSH) (
+    VOID
+    );
+
+typedef
+NTSTATUS
+(*PBL_DEVICE_CREATE) (
+    VOID
+    );
+
+typedef struct _BL_DEVICE_CALLBACKS
+{
+    PBL_DEVICE_ENUMERATE_DEVICE_CLASS EnumerateDeviceClass;
+    PBL_DEVICE_OPEN Open;
+    PBL_DEVICE_CLOSE Close;
+    PBL_DEVICE_READ Read;
+    PBL_DEVICE_WRITE Write;
+    PBL_DEVICE_GET_INFORMATION GetInformation;
+    PBL_DEVICE_SET_INFORMATION SetInformation;
+    PBL_DEVICE_RESET Reset;
+    PBL_DEVICE_FLUSH Flush;
+    PBL_DEVICE_CREATE Create;
+} BL_DEVICE_CALLBACKS, *PBL_DEVICE_CALLBACKS;
+
+typedef struct _BL_DEVICE_ENTRY
+{
+    ULONG DeviceId;
+    ULONG Flags;
+    ULONG Unknown;
+    ULONG ReferenceCount;
+    BL_DEVICE_CALLBACKS Callbacks;
+    PVOID DeviceSpecificData;
+    PBL_DEVICE_DESCRIPTOR DeviceDescriptor;
+} BL_DEVICE_ENTRY, *PBL_DEVICE_ENTRY;
+
+typedef struct _BL_REGISTERED_DEVICE
+{
+    LIST_ENTRY ListEntry;
+    BL_DEVICE_CALLBACKS Callbacks;
+} BL_REGISTERED_DEVICE, *PBL_REGISTERED_DEVICE;
+
+PVOID* BlockIoDeviceTable;
+ULONG BlockIoDeviceTableEntries;
+
+ULONG BlockIoFirmwareRemovableDiskCount;
+ULONG BlockIoFirmwareRawDiskCount;
+ULONG BlockIoFirmwareCdromCount;
+
+PVOID BlockIopAlignedBuffer;
+ULONG BlockIopAlignedBufferSize;
+
+PVOID BlockIopPartialBlockBuffer;
+ULONG BlockIopPartialBlockBufferSize;
+
+PVOID BlockIopPrefetchBuffer;
+
+PVOID BlockIopReadBlockBuffer;
+ULONG BlockIopReadBlockBufferSize;
+
+ULONG HashTableId;
+
+BOOLEAN BlockIoInitialized;
+
+NTSTATUS
+BlockIoOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    );
+
+NTSTATUS
+PartitionOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+VhdFileDeviceOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+DiskOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+RdDeviceOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+FileDeviceOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+SpOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+UdpOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+BL_DEVICE_CALLBACKS FileDeviceFunctionTable =
+{
+    NULL,
+    FileDeviceOpen,
+    NULL,
+};
+
+BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable =
+{
+    NULL,
+    PartitionOpen,
+    NULL,
+};
+
+BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable =
+{
+    NULL,
+    RdDeviceOpen,
+    NULL,
+};
+
+BL_DEVICE_CALLBACKS DiskDeviceFunctionTable =
+{
+    NULL,
+    DiskOpen,
+    NULL,
+};
+
+BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable =
+{
+    NULL,
+    VhdFileDeviceOpen,
+    NULL,
+};
+
+BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable =
+{
+    NULL,
+    BlockIoOpen,
+    NULL,
+};
+
+BL_DEVICE_CALLBACKS UdpFunctionTable =
+{
+    NULL,
+    UdpOpen,
+    NULL,
+};
+
+BL_DEVICE_CALLBACKS SerialPortFunctionTable =
+{
+    NULL,
+    SpOpen,
+    NULL,
+};
+
+
+ULONG BcpBlockAllocatorHandle;
+ULONG BcpHashTableId;
+
+NTSTATUS
+BcpDestroy (
+    VOID
+    )
+{
+    //BcpPurgeCacheEntries();
+    //return BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle);
+    EfiPrintf(L"Destructor for block cache not yet implemented\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+BOOLEAN
+BcpCompareKey (
+    _In_ PBL_HASH_ENTRY Entry1,
+    _In_ PBL_HASH_ENTRY Entry2
+    )
+{
+    PULONG Value1, Value2;
+
+    Value1 = Entry1->Value;
+    Value2 = Entry2->Value;
+    return Entry1->Size == Entry2->Size && Entry1->Flags == Entry2->Flags && *Value1 == *Value2 && Value1[1] == Value2[1] && Value1[2] == Value2[2];
+}
+
+ULONG
+BcpHashFunction (
+    _In_ PBL_HASH_ENTRY Entry,
+    _In_ ULONG TableSize
+    )
+{
+    ULONG i, j, ValueHash;
+    PUCHAR ValueBuffer;
+
+    j = 0;
+    ValueHash = 0;
+    i = 0;
+
+    ValueBuffer = Entry->Value;
+
+    do
+    {
+        ValueHash += ValueBuffer[i++];
+    }
+    while (i < 8);
+
+    do
+    {
+        ValueHash += ValueBuffer[j++ + 8];
+    }
+    while (j < 4);
+
+    return ValueHash % TableSize;
+}
+
+NTSTATUS
+BcInitialize (
+    VOID
+    )
+{
+    NTSTATUS Status;
+
+    Status = BlHtCreate(50, BcpHashFunction, BcpCompareKey, &BcpHashTableId);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    BcpBlockAllocatorHandle = BlpMmCreateBlockAllocator();
+    if (BcpBlockAllocatorHandle == -1)
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        goto Quickie;
+    }
+
+    Status = BlpIoRegisterDestroyRoutine(BcpDestroy);
+    if (Status >= 0)
+    {
+        return Status;
+    }
+
+Quickie:
+    EfiPrintf(L"Failure path not yet implemented\n");
+#if 0
+    if (BcpHashTableId != -1)
+    {
+        BlHtDestroy(BcpHashTableId);
+    }
+    if (BcpBlockAllocatorHandle != -1)
+    {
+        BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle);
+    }
+#endif
+  return Status;
+}
+
+BOOLEAN
+BlpDeviceCompare (
+    _In_ PBL_DEVICE_DESCRIPTOR Device1,
+    _In_ PBL_DEVICE_DESCRIPTOR Device2
+    )
+{
+    BOOLEAN DeviceMatch;
+    ULONG DeviceSize;
+
+    /* Assume failure */
+    DeviceMatch = FALSE;
+
+    /* Check if the two devices exist and are identical in typ */
+    if ((Device1) && (Device2) && (Device1->DeviceType == Device2->DeviceType))
+    {
+        /* Take the bigger of the two sizes */
+        DeviceSize = max(Device1->Size, Device2->Size);
+        if (DeviceSize >= (ULONG)FIELD_OFFSET(BL_DEVICE_DESCRIPTOR, Local))
+        {
+            /* Compare the two devices up to their size */
+            if (RtlEqualMemory(&Device1->Local,
+                               &Device2->Local,
+                               DeviceSize - FIELD_OFFSET(BL_DEVICE_DESCRIPTOR, Local)))
+            {
+                /* They match! */
+                DeviceMatch = TRUE;
+            }
+        }
+    }
+
+    /* Return matching state */
+    return DeviceMatch;
+}
+
+BOOLEAN
+DeviceTableCompare (
+    _In_ PVOID Entry,
+    _In_ PVOID Argument1,
+    _In_ PVOID Argument2,
+    _Inout_ PVOID Argument3,
+    _Inout_ PVOID Argument4
+    )
+{
+    BOOLEAN Found;
+    PBL_DEVICE_DESCRIPTOR Device = (PBL_DEVICE_DESCRIPTOR)Entry;
+    PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Argument1;
+    ULONG Flags = *(PULONG)Argument2;
+    ULONG Unknown = *(PULONG)Argument3;
+
+    /* Assume failure */
+    Found = FALSE;
+
+    /* Compare the device descriptor */
+    if (BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device))
+    {
+        /* Compare something */
+        if (DeviceEntry->Unknown == Unknown)
+        {
+            /* Compare flags */
+            if ((!(Flags & 1) || (DeviceEntry->Flags & 2)) &&
+                (!(Flags & 2) || (DeviceEntry->Flags & 4)))
+            {
+                /* And more flags */
+                if (((Flags & 8) || !(DeviceEntry->Flags & 8)) &&
+                    (!(Flags & 8) || (DeviceEntry->Flags & 8)))
+                {
+                    /* Found a match! */
+                    Found = TRUE;
+                }
+            }
+        }
+    }
+
+    /* Return matching state */
+    return Found;
+}
+
+NTSTATUS
+DeviceTableDestroyEntry (
+    _In_ PVOID Entry,
+    _In_ ULONG DeviceId
+    )
+{
+    PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
+    NTSTATUS Status;
+
+    /* Call the close routine for this entry */
+    Status = DeviceEntry->Callbacks.Close(DmDeviceTable[DeviceId]);
+
+    /* Free the descriptor, and the device itself */
+    BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
+    BlMmFreeHeap(DeviceEntry);
+
+    /* Clear out the netry, and return */
+    DmDeviceTable[DeviceId] = NULL;
+    return Status;
+}
+
+NTSTATUS
+DeviceTablePurge (
+    _In_ PVOID Entry
+    )
+{
+    PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
+    NTSTATUS Status;
+
+    /* Check if the device is opened */
+    if (DeviceEntry->Flags & 1)
+    {
+        /* It is, so can't purge it */
+        Status = STATUS_UNSUCCESSFUL;
+    }
+    else
+    {
+        /* It isn't, so destroy the entry */
+        Status = DeviceTableDestroyEntry(DeviceEntry, DeviceEntry->DeviceId);
+    }
+
+    /* Return back to caller */
+    return Status;
+}
+
+NTSTATUS
+BlockIoDeviceTableDestroyEntry (
+    _In_ PVOID Entry,
+    _In_ ULONG DeviceId
+    )
+{
+    PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
+    NTSTATUS Status;
+
+    /* Call the close routine for this entry */
+    Status = DeviceEntry->Callbacks.Close(DeviceEntry);
+
+    /* Free the descriptor, and the device itself */
+    BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
+    BlMmFreeHeap(DeviceEntry);
+
+    /* Clear out the netry, and return */
+    BlockIoDeviceTable[DeviceId] = NULL;
+    return Status;
+}
+
+NTSTATUS
+BlockIoDeviceTableDestroy (
+    VOID
+    )
+{
+    NTSTATUS Status;
+
+    /* Call the entry destructor on each entry in the table */
+    Status = BlTblMap(BlockIoDeviceTable,
+                      BlockIoDeviceTableEntries,
+                      BlockIoDeviceTableDestroyEntry);
+
+    /* Free the table and return */
+    BlMmFreeHeap(BlockIoDeviceTable);
+    return Status;
+}
+
+NTSTATUS
+BlockIopDestroy (
+    VOID
+    )
+{
+    /* Free the prefetch buffer */
+    BlMmFreeHeap(BlockIopPrefetchBuffer);
+
+    /* Set state to non initialized */
+    BlockIoInitialized = FALSE;
+
+    /* Return back */
+    return STATUS_SUCCESS;
+}
+
+ULONG
+BlockIoEfiHashFunction (
+    _In_ PBL_HASH_ENTRY Entry,
+    _In_ ULONG TableSize
+    )
+{
+    /* Get rid of the alignment bits to have a more unique number */
+    return ((ULONG)Entry->Value >> 3) % TableSize;
+}
+
+NTSTATUS
+BlockIopInitialize (
+    VOID
+    )
+{
+    NTSTATUS Status;
+
+    /* Allocate the block device table and zero it out */
+    BlockIoDeviceTableEntries = 8;
+    BlockIoDeviceTable = BlMmAllocateHeap(sizeof(PVOID) *
+                                          BlockIoDeviceTableEntries);
+    if (!BlockIoDeviceTableEntries)
+    {
+        return STATUS_NO_MEMORY;
+    }
+    RtlZeroMemory(BlockIoDeviceTable, sizeof(PVOID) * BlockIoDeviceTableEntries);
+
+    /* Register our destructor */
+    Status = BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Initialize all counters */
+    BlockIoFirmwareRemovableDiskCount = 0;
+    BlockIoFirmwareRawDiskCount = 0;
+    BlockIoFirmwareCdromCount = 0;
+
+    /* Initialize the buffers and their sizes */
+    BlockIopAlignedBuffer = NULL;
+    BlockIopAlignedBufferSize = 0;
+    BlockIopPartialBlockBuffer = NULL;
+    BlockIopPartialBlockBufferSize = 0;
+    BlockIopPrefetchBuffer = NULL;
+    BlockIopReadBlockBuffer = NULL;
+    BlockIopReadBlockBufferSize = 0;
+
+    /* Allocate the prefetch buffer */
+    Status = MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer,
+                                       BlLoaderDeviceMemory,
+                                       0x100,
+                                       0,
+                                       0,
+                                       NULL,
+                                       0);
+    if (NT_SUCCESS(Status))
+    {
+        /* Initialize the block cache */
+        Status = BcInitialize();
+        if (NT_SUCCESS(Status))
+        {
+            /* Initialize the block device hash table */
+            Status = BlHtCreate(29, BlockIoEfiHashFunction, NULL, &HashTableId);
+            if (NT_SUCCESS(Status))
+            {
+                /* Register our destructor */
+                Status = BlpIoRegisterDestroyRoutine(BlockIopDestroy);
+                if (NT_SUCCESS(Status))
+                {
+                    /* We're good */
+                    BlockIoInitialized = TRUE;
+                }
+            }
+        }
+    }
+
+    /* Check if this is the failure path */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Free the prefetch buffer is one was allocated */
+        if (BlockIopPrefetchBuffer)
+        {
+            EfiPrintf(L"Failure path not implemented %lx\r\n", Status);
+            //MmPapFreePages(BlockIopPrefetchBuffer, 1);
+        }
+    }
+
+    /* Return back to the caller */
+    return Status;
+}
+
+NTSTATUS
+BlockIopFreeAllocations (
+    _In_ PBL_BLOCK_DEVICE BlockDevice
+    )
+{
+    /* If a block device was passed in, free it */
+    if (BlockDevice)
+    {
+        BlMmFreeHeap(BlockDevice);
+    }
+
+    /* Nothing else to do */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlockIoEfiGetBlockIoInformation (
+    _In_ PBL_BLOCK_DEVICE BlockDevice
+    )
+{
+    NTSTATUS Status;
+    EFI_BLOCK_IO_MEDIA *Media;
+
+    /* Open the Block I/O protocol on this device */
+    Status = EfiOpenProtocol(BlockDevice->Handle,
+                             &EfiBlockIoProtocol,
+                             (PVOID*)&BlockDevice->Protocol);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Get information on the block media */
+    Media = BlockDevice->Protocol->Media;
+
+    /* Set the appropriate device flags */
+    BlockDevice->DeviceFlags = 0;
+    if (Media->RemovableMedia)
+    {
+        BlockDevice->DeviceFlags = 1;
+    }
+    if (Media->MediaPresent)
+    {
+        BlockDevice->DeviceFlags |= 2;
+    }
+
+    /* No clue */
+    BlockDevice->Unknown = 0;
+
+    /* Set the block size */
+    BlockDevice->BlockSize = Media->BlockSize;
+
+    /* Make sure there's a last block value */
+    if (!Media->LastBlock)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Don't let it be too high */
+    if (Media->LastBlock > 0xFFFFFFFFFFE)
+    {
+        BlockDevice->LastBlock = 0xFFFFFFFFFFE;
+    }
+    else
+    {
+        BlockDevice->LastBlock = Media->LastBlock;
+    }
+
+    /* Make the alignment the smaller of the I/O alignment or the block size */
+    if (Media->IoAlign >= Media->BlockSize)
+    {
+        BlockDevice->Alignment = Media->IoAlign;
+    }
+    else
+    {
+        BlockDevice->Alignment = Media->BlockSize;
+    }
+
+    /* All good */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlockIoEfiGetChildHandle (
+    _In_ PBL_PROTOCOL_HANDLE ProtocolInterface,
+    _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface)
+{
+    NTSTATUS Status;
+    ULONG i, DeviceCount;
+    EFI_DEVICE_PATH *DevicePath, *ParentDevicePath;
+    EFI_HANDLE *DeviceHandles;
+    EFI_HANDLE Handle;
+
+    /* Find all the Block I/O device handles on the system */
+    DeviceCount = 0;
+    DeviceHandles = 0;
+    Status = EfiLocateHandleBuffer(ByProtocol,
+                                   &EfiBlockIoProtocol,
+                                   &DeviceCount,
+                                   &DeviceHandles);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed to enumerate, bail out */
+        return Status;
+    }
+
+    /* Loop all the handles */
+    for (i = 0; i < DeviceCount; i++)
+    {
+        /* Check if this is the device itself */
+        Handle = DeviceHandles[i];
+        if (Handle == ProtocolInterface->Handle)
+        {
+            /* Skip it */
+            continue;
+        }
+
+        /* Get the device path of this device */
+        Status = EfiOpenProtocol(Handle,
+                                 &EfiDevicePathProtocol,
+                                 (PVOID*)&DevicePath);
+        if (!NT_SUCCESS(Status))
+        {
+            /* We failed, skip it */
+            continue;
+        }
+
+        /* See if we are its parent  */
+        ParentDevicePath = EfiIsDevicePathParent(ProtocolInterface->Interface,
+                                                 DevicePath);
+        if (ParentDevicePath == ProtocolInterface->Interface)
+        {
+            /* Yup, return back to caller */
+            ChildProtocolInterface->Handle = Handle;
+            ChildProtocolInterface->Interface = DevicePath;
+            break;
+        }
+
+        /* Close the device path */
+        EfiCloseProtocol(Handle, &EfiDevicePathProtocol);
+    }
+
+    /* If we got here, nothing was found */
+    Status = STATUS_NO_SUCH_DEVICE;
+
+    /* Free the handle array buffer */
+    BlMmFreeHeap(DeviceHandles);
+    return Status;
+}
+
+NTSTATUS
+BlockIoGetGPTDiskSignature (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry,
+    _Out_ PGUID DiskSignature
+    )
+{
+    EfiPrintf(L"GPT not supported\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlockIoEfiGetDeviceInformation (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    NTSTATUS Status;
+    PBL_DEVICE_DESCRIPTOR Device;
+    PBL_BLOCK_DEVICE BlockDevice;
+    EFI_DEVICE_PATH *LeafNode;
+    EFI_HANDLE Handle;
+    BL_PROTOCOL_HANDLE Protocol[2];
+    ACPI_HID_DEVICE_PATH *AcpiPath;
+    HARDDRIVE_DEVICE_PATH *DiskPath;
+    BOOLEAN Found;
+    ULONG i;
+
+    Device = DeviceEntry->DeviceDescriptor;
+    BlockDevice = (PBL_BLOCK_DEVICE)DeviceEntry->DeviceSpecificData;
+
+    Found = FALSE;
+
+    Handle = BlockDevice->Handle;
+
+    Protocol[0].Handle = Handle;
+    Protocol[1].Handle = 0;
+
+    Status = EfiOpenProtocol(Handle,
+                             &EfiDevicePathProtocol,
+                             &Protocol[0].Interface);
+    if (Status < 0)
+    {
+        return Status;
+    }
+
+    for (i = 0, Found = FALSE; Found == FALSE && Protocol[i].Handle; i++)
+    {
+        LeafNode = EfiGetLeafNode(Protocol[i].Interface);
+        if (LeafNode->Type == ACPI_DEVICE_PATH)
+        {
+            /* We only support floppy drives */
+            AcpiPath = (ACPI_HID_DEVICE_PATH*)LeafNode;
+            if ((AcpiPath->HID == EISA_PNP_ID(0x604)) &&
+                (AcpiPath->HID == EISA_PNP_ID(0x700)))
+            {
+                /* Set the boot library specific device types */
+                Device->DeviceType = LocalDevice;
+                Device->Local.Type = FloppyDevice;
+
+                /* The ACPI UID is the drive number */
+                Device->Local.FloppyDisk.DriveNumber = AcpiPath->UID;
+
+                /* We found a match */
+                Found = TRUE;
+            }
+        }
+        else if ((LeafNode->Type == MEDIA_DEVICE_PATH) && (i == 1))
+        {
+            /* Extract the disk path and check if it's a physical disk */
+            DiskPath = (HARDDRIVE_DEVICE_PATH*)LeafNode;
+            if (LeafNode->SubType == MEDIA_HARDDRIVE_DP)
+            {
+                Device->Local.Type = LocalDevice;
+
+                /* Check if this is an MBR partition */
+                if (DiskPath->SignatureType == SIGNATURE_TYPE_MBR)
+                {
+                    /* Set that this is a local partition */
+                    Device->DeviceType = LegacyPartitionDevice;
+                    Device->Partition.Disk.Type = LocalDevice;
+
+                    BlockDevice->PartitionType = MbrPartition;
+                    BlockDevice->Disk.Mbr.Signature = *(PULONG)&DiskPath->Signature[0];
+                    Found = TRUE;
+                }
+                else if (DiskPath->SignatureType == SIGNATURE_TYPE_GUID)
+                {
+                    BlockDevice->PartitionType = 0;
+                    Device->Local.HardDisk.PartitionType = GptPartition;
+
+                    Status = BlockIoGetGPTDiskSignature(DeviceEntry,
+                                                        &Device->Local.HardDisk.Gpt.PartitionSignature);
+                    if (NT_SUCCESS(Status))
+                    {
+                        RtlCopyMemory(&BlockDevice->Disk.Gpt.Signature,
+                                      &Device->Local.HardDisk.Gpt.PartitionSignature,
+                                      sizeof(&BlockDevice->Disk.Gpt.Signature));
+                        Found = TRUE;
+                    }
+                }
+
+                /* Otherwise, raw boot is not supported */
+                BlockDevice->PartitionType = RawPartition;
+                Device->Local.HardDisk.PartitionType = RawPartition;
+                Device->Local.HardDisk.Raw.DiskNumber = BlockIoFirmwareRawDiskCount++;;
+            }
+            else if (LeafNode->SubType == MEDIA_CDROM_DP)
+            {
+                /* Set block device information */
+                BlockDevice->PartitionType = RawPartition;
+                BlockDevice->Type = CdRomDevice;
+
+                /* Set CDROM data */
+                Device->Local.Type = CdRomDevice;
+                Device->Local.FloppyDisk.DriveNumber = 0;
+                Found = TRUE;
+            }
+        }
+        else if ((LeafNode->Type != MEDIA_DEVICE_PATH) &&
+                 (LeafNode->Type == ACPI_DEVICE_PATH) &&
+                 (i == 0))
+        {
+            Status = BlockIoEfiGetChildHandle(Protocol, &Protocol[i]);
+            if (!NT_SUCCESS(Status))
+            {
+                Device->DeviceType = LocalDevice;
+                Found = 1;
+                if (BlockDevice->DeviceFlags & 1)
+                {
+                    BlockDevice->Type = FloppyDevice;
+                    Device->Local.HardDisk.PartitionType = BlockIoFirmwareRemovableDiskCount++;
+                    Device->Local.Type = FloppyDevice;
+                }
+                else
+                {
+                    BlockDevice->Type = DiskDevice;
+                    Device->Local.Type = DiskDevice;
+                    Device->Local.HardDisk.PartitionType = RawPartition;
+                    BlockDevice->PartitionType = RawPartition;
+                    Device->Local.HardDisk.Mbr.PartitionSignature = BlockIoFirmwareRawDiskCount++;
+                }
+            }
+        }
+    }
+
+    while (i)
+    {
+        EfiCloseProtocol(Protocol[--i].Handle, &EfiDevicePathProtocol);
+    }
+
+    if (Found)
+    {
+        Status = 0;
+    }
+    else
+    {
+        Status = STATUS_NOT_SUPPORTED;
+    }
+    return Status;
+}
+
+NTSTATUS
+BlockIoEfiReset (
+    VOID
+    )
+{
+    EfiPrintf(L"not implemented\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlockIoEfiFlush (
+    VOID
+    )
+{
+    EfiPrintf(L"not implemented\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlockIoEfiCreateDeviceEntry (
+    _In_ PBL_DEVICE_ENTRY *DeviceEntry,
+    _Out_ PVOID Handle
+    )
+{
+    PBL_DEVICE_ENTRY IoDeviceEntry;
+    PBL_BLOCK_DEVICE BlockDevice;
+    NTSTATUS Status;
+    PBL_DEVICE_DESCRIPTOR Device;
+
+    /* Allocate the entry for this device and zero it out */
+    IoDeviceEntry = BlMmAllocateHeap(sizeof(*IoDeviceEntry));
+    if (!IoDeviceEntry)
+    {
+        return STATUS_NO_MEMORY;
+    }
+    RtlZeroMemory(IoDeviceEntry, sizeof(*IoDeviceEntry));
+
+    /* Allocate the device descriptor for this device and zero it out */
+    Device = BlMmAllocateHeap(sizeof(*Device));
+    if (!Device)
+    {
+        return STATUS_NO_MEMORY;
+    }
+    RtlZeroMemory(Device, sizeof(*Device));
+
+    /* Allocate the block device specific data, and zero it out */
+    BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice));
+    if (!BlockDevice)
+    {
+        return STATUS_NO_MEMORY;
+    }
+    RtlZeroMemory(BlockDevice, sizeof(*BlockDevice));
+
+    /* Save the descriptor and block device specific data */
+    IoDeviceEntry->DeviceSpecificData = BlockDevice;
+    IoDeviceEntry->DeviceDescriptor = Device;
+
+    /* Set the size of the descriptor */
+    Device->Size = sizeof(*Device);
+
+    /* Copy the standard I/O callbacks */
+    RtlCopyMemory(&IoDeviceEntry->Callbacks,
+                  &BlockIoDeviceFunctionTable,
+                  sizeof(IoDeviceEntry->Callbacks));
+
+    /* Add the two that are firmware specific */
+    IoDeviceEntry->Callbacks.Reset = BlockIoEfiReset;
+    IoDeviceEntry->Callbacks.Flush = BlockIoEfiFlush;
+
+    /* Save the EFI handle */
+    BlockDevice->Handle = Handle;
+
+    /* Get information on this device from EFI, caching it in the device */
+    Status = BlockIoEfiGetBlockIoInformation(BlockDevice);
+    if (NT_SUCCESS(Status))
+    {
+        /* Build the descriptor structure for this device */
+        Status = BlockIoEfiGetDeviceInformation(IoDeviceEntry);
+        if (NT_SUCCESS(Status))
+        {
+            /* We have a fully constructed device, reuturn it */
+            *DeviceEntry = IoDeviceEntry;
+            return STATUS_SUCCESS;
+        }
+    }
+
+    /* Failure path, free the descriptor if we allocated one */
+    if (IoDeviceEntry->DeviceDescriptor)
+    {
+        BlMmFreeHeap(IoDeviceEntry->DeviceDescriptor);
+    }
+
+    /* Free any other specific allocations */
+    BlockIopFreeAllocations(IoDeviceEntry->DeviceSpecificData);
+
+    /* Free the device entry itself and return the failure code */
+    BlMmFreeHeap(IoDeviceEntry);
+    return Status;
+}
+
+NTSTATUS
+BlockIoFirmwareOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_BLOCK_DEVICE BlockIoDevice
+    )
+{
+    NTSTATUS Status;
+    BOOLEAN DeviceMatch;
+    BL_HASH_ENTRY HashEntry;
+    ULONG i, Id, DeviceCount;
+    PBL_DEVICE_ENTRY DeviceEntry;
+    EFI_HANDLE* DeviceHandles;
+
+    /* Initialize everything */
+    DeviceEntry = NULL;
+    DeviceCount = 0;
+    DeviceHandles = 0;
+    DeviceEntry = NULL;
+
+    /* Ask EFI for handles to all block devices */
+    Status = EfiLocateHandleBuffer(ByProtocol,
+                                   &EfiBlockIoProtocol,
+                                   &DeviceCount,
+                                   &DeviceHandles);
+    if (!NT_SUCCESS(Status))
+    {
+        return STATUS_NO_SUCH_DEVICE;
+    }
+
+    /* Build a hash entry, with the value inline */
+    HashEntry.Flags = 1;
+    HashEntry.Size = sizeof(EFI_HANDLE);
+
+    /* Loop each device we got */
+    DeviceMatch = FALSE;
+    Status = STATUS_NO_SUCH_DEVICE;
+    for (i = 0; i < DeviceCount; i++)
+    {
+        /* Check if we have a match in the device hash table */
+        HashEntry.Value = DeviceHandles[i];
+        Status = BlHtLookup(HashTableId, &HashEntry, 0);
+        if (NT_SUCCESS(Status))
+        {
+            /* We already know about this device */
+            continue;
+        }
+
+        /* New device, store it in the hash table */
+        Status = BlHtStore(HashTableId,
+                           &HashEntry,
+                           DeviceHandles[i],
+                           sizeof(DeviceHandles[i]));
+        if (!NT_SUCCESS(Status))
+        {
+            /* Free the array and fail */
+            BlMmFreeHeap(DeviceHandles);
+            break;
+        }
+
+        /* Create an entry for this device*/
+        Status = BlockIoEfiCreateDeviceEntry(&DeviceEntry, DeviceHandles[i]);
+        if (!NT_SUCCESS(Status))
+        {
+            break;
+        }
+
+        /* Add the device entry to the device table */
+        Status = BlTblSetEntry(&BlockIoDeviceTable,
+                               &BlockIoDeviceTableEntries,
+                               DeviceEntry,
+                               &Id,
+                               TblDoNotPurgeEntry);
+        if (!NT_SUCCESS(Status))
+        {
+            EfiPrintf(L"Failure path not implemented: %lx\r\n", Status);
+#if 0
+            BlHtDelete(HashTableId, &HashKey);
+#endif
+            /* Free the block I/O device data */
+            BlockIopFreeAllocations(DeviceEntry->DeviceSpecificData);
+
+            /* Free the descriptor */
+            BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
+
+            /* Free the entry */
+            BlMmFreeHeap(DeviceEntry);
+            break;
+        }
+
+        /* Does this device match what we're looking for? */
+        DeviceMatch = BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device);
+        if (DeviceMatch)
+        {
+            /* Yep, return the data back */
+            RtlCopyMemory(BlockIoDevice,
+                          DeviceEntry->DeviceSpecificData,
+                          sizeof(*BlockIoDevice));
+            Status = STATUS_SUCCESS;
+            break;
+        }
+    }
+
+    /* Free the device handle buffer array */
+    BlMmFreeHeap(DeviceHandles);
+    /* Return status */
+    return Status;
+}
+
+BOOLEAN
+BlockIoDeviceTableCompare (
+    _In_ PVOID Entry,
+    _In_ PVOID Argument1,
+    _In_ PVOID Argument2,
+    _In_ PVOID Argument3,
+    _In_ PVOID Argument4
+    )
+{
+    PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
+    PBL_DEVICE_DESCRIPTOR Device = (PBL_DEVICE_DESCRIPTOR)Argument1;
+
+    /* Compare the two devices */
+    return BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device);
+}
+
+NTSTATUS
+BlockIoOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ PBL_DEVICE_ENTRY DeviceEntry
+    )
+{
+    NTSTATUS Status;
+    PBL_BLOCK_DEVICE BlockDevice;
+    PBL_DEVICE_ENTRY FoundDeviceEntry;
+    ULONG Dummy;
+
+    /* Check if the block I/O manager is initialized */
+    if (!BlockIoInitialized)
+    {
+        /* First call, initialize it now */
+        Status = BlockIopInitialize();
+        if (!NT_SUCCESS(Status))
+        {
+            /* Failed to initialize block I/O */
+            return Status;
+        }
+    }
+
+    /* Copy a function table for block I/O devices */
+    RtlCopyMemory(&DeviceEntry->Callbacks,
+                  &BlockIoDeviceFunctionTable,
+                  sizeof(DeviceEntry->Callbacks));
+
+    /* Allocate a block I/O device */
+    BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice));
+    if (!BlockDevice)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Set this as the device-specific data for this device entry */
+    Status = STATUS_SUCCESS;
+    DeviceEntry->DeviceSpecificData = BlockDevice;
+
+    /* Check if we already have this device in our device table */
+    FoundDeviceEntry = BlTblFindEntry(BlockIoDeviceTable,
+                                      BlockIoDeviceTableEntries,
+                                      &Dummy,
+                                      BlockIoDeviceTableCompare,
+                                      Device,
+                                      NULL,
+                                      NULL,
+                                      NULL);
+    if (FoundDeviceEntry)
+    {
+        /* We already found a device, so copy its device data and callbacks */
+        RtlCopyMemory(BlockDevice, FoundDeviceEntry->DeviceSpecificData, sizeof(*BlockDevice));
+        RtlCopyMemory(&DeviceEntry->Callbacks,
+                      &FoundDeviceEntry->Callbacks,
+                      sizeof(DeviceEntry->Callbacks));
+        return Status;
+    }
+
+    /* Zero out the device for now */
+    RtlZeroMemory(BlockDevice, sizeof(*BlockDevice));
+
+    /* Is this a disk? */
+    if (Device->DeviceType == DiskDevice)
+    {
+        /* What type of disk is it? */
+        switch (Device->Local.Type)
+        {
+            /* Is it a raw physical disk? */
+            case LocalDevice:
+            case FloppyDevice:
+            case CdRomDevice:
+                /* Open a disk device */
+                Status = DiskDeviceFunctionTable.Open(Device, DeviceEntry);
+                break;
+
+            /* Is it a RAM disk? */
+            case RamDiskDevice:
+                /* Open a RAM disk */
+                Status = RamDiskDeviceFunctionTable.Open(Device, DeviceEntry);
+                break;
+
+            /* Is it a file? */
+            case FileDevice:
+                /* Open a file */
+                Status = FileDeviceFunctionTable.Open(Device, DeviceEntry);
+                break;
+
+            /* Is it a VHD? */
+            case VirtualDiskDevice:
+                /* Open a virtual disk */
+                Status = VirtualDiskDeviceFunctionTable.Open(Device, DeviceEntry);
+                break;
+
+            /* Is it something else? */
+            default:
+                /* Not supported */
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+        }
+    }
+    else if ((Device->DeviceType == LegacyPartitionDevice) ||
+             (Device->DeviceType == PartitionDevice))
+    {
+        /* This is a partition on a disk, open it as such */
+        Status = PartitionDeviceFunctionTable.Open(Device, DeviceEntry);
+    }
+    else
+    {
+        /* Other devices are not supported */
+        Status = STATUS_INVALID_PARAMETER;
+    }
+
+    /* Check for failure */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Free any allocations for this device */
+        BlockIopFreeAllocations(BlockDevice);
+    }
+
+    /* Return back to the caller */
+    return Status;
+}
+
+NTSTATUS
+BlpDeviceResolveLocate (
+    _In_ PBL_DEVICE_DESCRIPTOR InputDevice,
+    _Out_ PBL_DEVICE_DESCRIPTOR* LocateDevice
+    )
+{
+    EfiPrintf(L"Not implemented!\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlDeviceClose (
+    _In_ ULONG DeviceId
+    )
+{
+    PBL_DEVICE_ENTRY DeviceEntry;
+
+    /* Validate the device ID */
+    if (DmTableEntries <= DeviceId)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Make sure there's a device there */
+    DeviceEntry = DmDeviceTable[DeviceId];
+    if (DeviceEntry == NULL)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Make sure the device is active */
+    if (!(DeviceEntry->Flags & 1))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Drop a reference and check if it's the last one */
+    DeviceEntry->ReferenceCount--;
+    if (!DeviceEntry->ReferenceCount)
+    {
+        /* Mark the device as inactive */
+        DeviceEntry->Flags = ~1;
+    }
+
+    /* We're good */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlpDeviceOpen (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ ULONG Flags,
+    _In_ ULONG Unknown,
+    _Out_ PULONG DeviceId
+    )
+{
+    NTSTATUS Status;
+    PBL_DEVICE_ENTRY DeviceEntry;
+    PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor;
+    PBL_REGISTERED_DEVICE RegisteredDevice;
+    PLIST_ENTRY NextEntry, ListHead;
+
+    DeviceEntry = NULL;
+
+    /* Check for missing parameters */
+    if (!(Device) || !(DeviceId) || !(Device->Size))
+    {
+        /* Bail out */
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    /* Check for unsupported flags */
+    if (!(Flags & 3))
+    {
+        /* Bail out */
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    /* Check if the boot device is being opened */
+    if (Device->DeviceType == BootDevice)
+    {
+        /* Select it */
+        Device = BlpBootDevice;
+    }
+
+    /* Check if the 'locate' device is being opened */
+    if (Device->DeviceType == LocateDevice)
+    {
+        /* Go find it */
+        Status = BlpDeviceResolveLocate(Device, &LocateDeviceDescriptor);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Not found, bail out */
+            goto Quickie;
+        }
+
+        /* Select it */
+        Device = LocateDeviceDescriptor;
+    }
+
+    /* Check if the device isn't ready yet */
+    if (Device->Flags & 1)
+    {
+        /* Return a failure */
+        Status = STATUS_DEVICE_NOT_READY;
+        goto Quickie;
+    }
+
+    /* Check if we already have an entry for the device */
+    DeviceEntry = BlTblFindEntry(DmDeviceTable,
+                                 DmTableEntries,
+                                 DeviceId,
+                                 DeviceTableCompare,
+                                 Device,
+                                 &Flags,
+                                 &Unknown,
+                                 NULL);
+    if (DeviceEntry)
+    {
+        /* Return it, taking a reference on it */
+        *DeviceId = DeviceEntry->DeviceId;
+        ++DeviceEntry->ReferenceCount;
+        DeviceEntry->Flags |= 1;
+        return STATUS_SUCCESS;
+    }
+
+    /* We don't, allocate one */
+    DeviceEntry = BlMmAllocateHeap(sizeof(*DeviceEntry));
+    if (!DeviceEntry)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Fill it out */
+    RtlZeroMemory(DeviceEntry, sizeof(*DeviceEntry));
+    DeviceEntry->ReferenceCount = 1;
+    DeviceEntry->Flags |= 7;
+    DeviceEntry->Unknown = Unknown;
+
+    /* Save flag 8 if needed */
+    if (Flags & 8)
+    {
+        DeviceEntry->Flags |= 8;
+    }
+
+    /* Allocate a device descriptor for the device */
+    DeviceEntry->DeviceDescriptor = BlMmAllocateHeap(Device->Size);
+    if (!DeviceEntry->DeviceDescriptor)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Copy the descriptor that was passed in */
+    RtlCopyMemory(DeviceEntry->DeviceDescriptor, Device, Device->Size);
+
+    /* Now loop the list of dynamically registered devices */
+    ListHead = &DmRegisteredDevices;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the device */
+        RegisteredDevice = CONTAINING_RECORD(NextEntry,
+                                             BL_REGISTERED_DEVICE,
+                                             ListEntry);
+
+        /* Open the device */
+        Status = RegisteredDevice->Callbacks.Open(Device, DeviceEntry);
+        if (NT_SUCCESS(Status))
+        {
+            /* The device was opened, so we have the right one */
+            goto DeviceOpened;
+        }
+
+        /* Nope, keep trying */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Well, it wasn't a dynamic device. Is it a block device? */
+    if ((Device->DeviceType == PartitionDevice) ||
+        (Device->DeviceType == DiskDevice) ||
+        (Device->DeviceType == LegacyPartitionDevice))
+    {
+        /* Call the Block I/O handler */
+        Status = BlockIoDeviceFunctionTable.Open(Device, DeviceEntry);
+    }
+    else if (Device->DeviceType == SerialDevice)
+    {
+        /* It's a serial device, call the serial device handler */
+        Status = SerialPortFunctionTable.Open(Device, DeviceEntry);
+    }
+    else if (Device->DeviceType == UdpDevice)
+    {
+        /* It's a network device, call the UDP device handler */
+        Status = UdpFunctionTable.Open(Device, DeviceEntry);
+    }
+    else 
+    {
+        /* Unsupported type of device */
+        Status = STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* Check if the device was opened successfuly */
+    if (NT_SUCCESS(Status))
+    {
+DeviceOpened:
+        /* Save the entry in the device table */
+        Status = BlTblSetEntry(&DmDeviceTable,
+                               &DmTableEntries,
+                               DeviceEntry,
+                               DeviceId,
+                               DeviceTablePurge);
+        if (NT_SUCCESS(Status))
+        {
+            /* It worked -- return the ID in the table to the caller */
+            DeviceEntry->DeviceId = *DeviceId;
+            return STATUS_SUCCESS;
+        }
+    }
+
+Quickie:
+    /* Failure path -- did we allocate a device entry? */
+    if (DeviceEntry)
+    {
+        /* Yep -- did it have a descriptor? */
+        if (DeviceEntry->DeviceDescriptor)
+        {
+            /* Free it */
+            BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
+        }
+
+        /* Free the entry */
+        BlMmFreeHeap(DeviceEntry);
+    }
+
+    /* Return the failure */
+    return Status;
+}
+
 NTSTATUS
 BlpDeviceInitialize (
     VOID
@@ -52,7 +1566,6 @@ BlpDeviceInitialize (
     {
         /* Clear it */
         RtlZeroMemory(DmDeviceTable, DmTableEntries * sizeof(PVOID));
-
 #if 0
         /* Initialize BitLocker support */
         Status = FvebInitialize();
index 82f77bf..21e80fc 100644 (file)
@@ -66,7 +66,7 @@ DsppInitialize (
     InitializeListHead(&BfiFontFileListHead);
 
     /* Allocate the font rectangle */
-    BfiGraphicsRectangle = BlMmAllocateHeap(0x5A);
+    BfiGraphicsRectangle = BlMmAllocateHeap(90);
     if (!BfiGraphicsRectangle)
     {
         return STATUS_NO_MEMORY;
index 6610324..96607dd 100644 (file)
@@ -44,7 +44,7 @@ ConsoleCreateRemoteConsole (
 
     /* Construct it */
     Status = ConsoleRemoteConstruct(RemoteConsole);
-    if (Status < 0)
+    if (!NT_SUCCESS(Status));
     {
         /* Failed to construct it, delete it */
         BlMmFreeHeap(RemoteConsole);
index 83c90f7..4138b49 100644 (file)
@@ -17,6 +17,20 @@ PVOID* IoMgrDestroyRoutineTable;
 
 /* FUNCTIONS *****************************************************************/
 
+NTSTATUS
+BlpIoRegisterDestroyRoutine (
+    _In_ PBL_IO_DESTROY_ROUTINE DestroyRoutine
+    )
+{
+    ULONG Id;
+
+    return BlTblSetEntry(&IoMgrDestroyRoutineTable,
+                         &IoMgrRoutineEntries,
+                         DestroyRoutine,
+                         &Id,
+                         TblDoNotPurgeEntry);
+}
+
 NTSTATUS
 BlpIoInitialize (
     VOID
index 3b67fb3..2bd951a 100644 (file)
@@ -188,6 +188,455 @@ BlUtlInitialize (
     return STATUS_SUCCESS;
 }
 
+PVOID
+BlTblFindEntry (
+    _In_ PVOID *Table,
+    _In_ ULONG Count,
+    _Out_ PULONG EntryIndex,
+    _In_ PBL_TBL_LOOKUP_ROUTINE Callback,
+    _In_ PVOID Argument1,
+    _In_ PVOID Argument2,
+    _In_ PVOID Argument3,
+    _In_ PVOID Argument4
+    )
+{
+    PVOID Entry = NULL;
+    ULONG Index = 0;
+    BOOLEAN Result;
+
+    /* Check for invalid parameters */
+    if (!(Table) || !(EntryIndex) || !(Count))
+    {
+        return Entry;
+    }
+
+    /* Loop each entry in the table */
+    while (Index < Count)
+    {
+        /* Check if this entry is filled out */
+        if (Table[Index])
+        {
+            /* Call the comparison function */
+            Result = Callback(Table[Index],
+                              Argument1,
+                              Argument2,
+                              Argument3,
+                              Argument4);
+            if (Result)
+            {
+                /* Entry fouund return it */
+                *EntryIndex = Index;
+                Entry = Table[Index];
+                break;
+            }
+        }
+    }
+
+    /* Return the entry that was (or wasn't) found */
+    return Entry;
+}
+
+NTSTATUS
+BlTblSetEntry (
+    _Inout_ PVOID** Table,
+    _Inout_ PULONG Count,
+    _In_ PVOID Entry,
+    _Out_ PULONG EntryIndex,
+    _In_ PBL_TBL_SET_ROUTINE Callback
+    )
+{
+    ULONG NewCount;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Index = 0;
+    PVOID* NewTable;
+
+    /* Make sure all the parameters were specified */
+    if (!(Table) || !(*Table) || !(Count) || !(Callback))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Read the current table */
+    NewTable = *Table;
+    NewCount = *Count;
+
+    /* Iterate over it */
+    while (Index < NewCount)
+    {
+        /* Look for a free index */
+        if (!NewTable[Index])
+        {
+            goto SetIndex;
+        }
+
+        /* No free index yet, keep going */
+        ++Index;
+    }
+
+    /* No free index was found, try to purge some entries */
+    Index = 0;
+    while (Index < NewCount)
+    {
+        /* Call each purge callback, trying to make space */
+        Status = Callback(NewTable[Index]);
+        if (NT_SUCCESS(Status))
+        {
+            /* We should have this slot available now */
+            goto SetIndex;
+        }
+
+        /* Keep trying to purge more */
+        ++Index;
+    }
+
+    /* Double the table */
+    NewTable = BlMmAllocateHeap(2 * sizeof(PVOID) * NewCount);
+    if (!NewTable)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Clear the new table, and copy the old entries */
+    RtlZeroMemory(&NewTable[NewCount], sizeof(PVOID) * NewCount);
+    RtlCopyMemory(NewTable, *Table, sizeof(PVOID) * NewCount);
+
+    /* Free the old table */
+    BlMmFreeHeap(*Table);
+
+    /* Return the new table and count */
+    *Count = 2 * NewCount;
+    *Table = NewTable;
+
+SetIndex:
+    /* Set the index and return */
+    NewTable[Index] = Entry;
+    *EntryIndex = Index;
+    return Status;
+}
+
+NTSTATUS
+BlTblMap (
+    _In_ PVOID *Table,
+    _In_ ULONG Count,
+    _In_ PBL_TBL_MAP_ROUTINE MapCallback
+    )
+{
+    NTSTATUS Status, LocalStatus;
+    PVOID Entry;
+    ULONG Index;
+
+    /* Bail out if there's no table */
+    if (!Table)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Assume success and loop each index */
+    Status = STATUS_SUCCESS;
+    for (Index = 0; Index < Count; Index++)
+    {
+        /* See if an entry exists at this index */
+        Entry = Table[Index];
+        if (Entry)
+        {
+            /* Call the map routine for this entry */
+            LocalStatus = MapCallback(Entry, Index);
+            if (!NT_SUCCESS(LocalStatus))
+            {
+                /* Propagate failure only */
+                Status = LocalStatus;
+            }
+        }
+    }
+
+    /* Return status to caller */
+    return Status;
+}
+
+ULONG HtTableSize;
+PBL_HASH_TABLE* HtTableArray;
+ULONG HtTableEntries;
+
+ULONG
+DefaultHashFunction (
+    _In_ PBL_HASH_ENTRY Entry,
+    _In_ ULONG TableSize
+    )
+{
+    PUCHAR Value;
+    ULONG KeyHash, i;
+
+    /* Check if the value is a pointer, or embedded inline */
+    Value = (Entry->Flags & BL_HT_VALUE_IS_INLINE) ? Entry->Value : (PUCHAR)&Entry->Value;
+
+    /* Iterate over each byte, and sum it */
+    for (i = 0, KeyHash = 0; i < Entry->Size; i++)
+    {
+        KeyHash += Value[i++];
+    }
+
+    /* Modulo the number of buckets */
+    return KeyHash % TableSize;
+}
+
+BOOLEAN
+HtpCompareKeys (
+    _In_ PBL_HASH_ENTRY Entry1,
+    _In_ PBL_HASH_ENTRY Entry2
+    )
+{
+    ULONG Flags;
+    BOOLEAN ValueMatch;
+
+    /* Check if the flags or sizes are not matching */
+    Flags = Entry1->Flags;
+    if ((Entry1->Size != Entry2->Size) || (Flags != Entry2->Flags))
+    {
+        ValueMatch = FALSE;
+    }
+    else if (Flags & BL_HT_VALUE_IS_INLINE)
+    {
+        /* Check if this is an in-line value, compare it */
+        ValueMatch = Entry1->Value == Entry2->Value;
+    }
+    else
+    {
+        /* This is a pointer value, compare it */
+        ValueMatch = (RtlCompareMemory(Entry1->Value, Entry2->Value, Entry1->Size) ==
+                      Entry1->Size);
+    }
+
+    /* Return if it matched */
+    return ValueMatch;
+}
+
+NTSTATUS
+TblDoNotPurgeEntry (
+    _In_ PVOID Entry
+    )
+{
+    /* Never purge this entry */
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+BlHtCreate (
+    _In_ ULONG Size,
+    _In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction,
+    _In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction,
+    _Out_ PULONG Id
+    )
+{
+    NTSTATUS Status;
+    PBL_HASH_TABLE HashTable;
+    ULONG i;
+
+    /* Assume failure */
+    HashTable = NULL;
+
+    /* Can't create a table with no ID */
+    if (!Id)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Check if we don't already have a hash table table */
+    if (!HtTableSize)
+    {
+        /* Allocate it and zero it out */
+        HtTableSize = 4;
+        HtTableArray = BlMmAllocateHeap(HtTableSize * sizeof(PVOID));
+        if (!HtTableArray)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Quickie;
+        }
+        RtlZeroMemory(HtTableArray, HtTableSize * sizeof(PVOID));
+        HtTableEntries = 0;
+    }
+
+    /* Allocate the hash table */
+    HashTable = BlMmAllocateHeap(sizeof(*HashTable));
+    if (!HashTable)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Fill it out */
+    HashTable->HashFunction = HashFunction ? HashFunction : DefaultHashFunction;
+    HashTable->CompareFunction = CompareFunction ? CompareFunction : HtpCompareKeys;
+    HashTable->Size = Size ? Size : 13;
+
+    /* Allocate the hash links, one for each bucket */
+    HashTable->HashLinks = BlMmAllocateHeap(sizeof(LIST_ENTRY) * HashTable->Size);
+    if (!HashTable->HashLinks)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Initialize the hash links */
+    for (i = 0; i < HashTable->Size; i++)
+    {
+        InitializeListHead(&HashTable->HashLinks[i]);
+    }
+
+    /* Save us in the table of hash tables */
+    Status = BlTblSetEntry((PVOID**)&HtTableArray,
+                           &Size,
+                           HashTable,
+                           Id,
+                           TblDoNotPurgeEntry);
+    if (NT_SUCCESS(Status))
+    {
+        /* One more -- we're done */
+        ++HtTableEntries;
+        return Status;
+    }
+
+Quickie:
+    /* Check if we just allocated the table array now */
+    if (!(HtTableEntries) && (HtTableArray))
+    {
+        /* Free it */
+        BlMmFreeHeap(HtTableArray);
+        HtTableArray = NULL;
+        HtTableSize = 0;
+    }
+
+    /* Check if we allocated a hash table*/
+    if (HashTable)
+    {
+        /* With links? */
+        if (HashTable->HashLinks)
+        {
+            /* Free them */
+            BlMmFreeHeap(HashTable->HashLinks);
+        }
+
+        /* Free the table*/
+        BlMmFreeHeap(HashTable);
+    }
+
+    /* We're done */
+    return Status;
+}
+
+NTSTATUS
+BlHtLookup (
+    _In_ ULONG TableId,
+    _In_ PBL_HASH_ENTRY Entry,
+    _Out_opt_ PBL_HASH_VALUE *Value
+    )
+{
+    PBL_HASH_TABLE HashTable;
+    ULONG HashValue;
+    NTSTATUS Status;
+    PLIST_ENTRY HashLinkHead, HashLink;
+    PBL_HASH_NODE HashNode;
+
+    /* Check if the table ID is invalid, or we have no entry, or it's malformed */
+    if ((HtTableSize <= TableId) ||
+        !(Entry) ||
+        ((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
+    {
+        /* Fail */
+        Status = STATUS_INVALID_PARAMETER;
+    }
+    else
+    {
+        /* Otherwise, get the hash table for this index */
+        HashTable = HtTableArray[TableId];
+
+        /* Get the hash bucket */
+        HashValue = HashTable->HashFunction(Entry, HashTable->Size);
+
+        /* Start iterating each entry in the bucket, assuming failure */
+        Status = STATUS_NOT_FOUND;
+        HashLinkHead = &HashTable->HashLinks[HashValue];
+        HashLink = HashLinkHead->Flink;
+        while (HashLink != HashLinkHead)
+        {
+            /* Get a node in this bucket, and compare the value */
+            HashNode = CONTAINING_RECORD(HashLink, BL_HASH_NODE, ListEntry);
+            if (HashTable->CompareFunction(&HashNode->Entry, Entry))
+            {
+                /* Does the caller want the value? */
+                if (Value)
+                {
+                    /* Return it */
+                    *Value = &HashNode->Value;
+                }
+
+                /* Return success and stop scanning */
+                Status = STATUS_SUCCESS;
+                break;
+            }
+
+            /* Try the next node */
+            HashLink = HashLink->Flink;
+        }
+    }
+
+    /* Return back to the caller */
+    return Status;
+}
+
+NTSTATUS
+BlHtStore (
+    _In_ ULONG TableId,
+    _In_ PBL_HASH_ENTRY Entry,
+    _In_ PVOID Data,
+    _In_ ULONG DataSize
+    )
+{
+    PBL_HASH_NODE HashNode;
+    NTSTATUS Status;
+    PLIST_ENTRY HashLinkHead;
+    PBL_HASH_TABLE HashTable;
+
+    /* Check for invalid tablle ID, missing arguments, or malformed entry */
+    if ((HtTableSize <= TableId) ||
+        !(Entry) ||
+        !(Data) ||
+        !(Entry->Size) ||
+        !(Entry->Value) ||
+        !(DataSize) ||
+        ((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
+    {
+        /* Fail the call */
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    /* Get the hash table for this ID */
+    HashTable = HtTableArray[TableId];
+
+    /* Allocate a hash node */
+    HashNode = BlMmAllocateHeap(sizeof(*HashNode));
+    if (!HashNode)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Capture all the data*/
+    HashNode->Entry.Size = Entry->Size;
+    HashNode->Entry.Flags = Entry->Flags;
+    HashNode->Entry.Value = Entry->Value;
+    HashNode->Value.DataSize = DataSize;
+    HashNode->Value.Data = Data;
+
+    /* Insert it into the bucket list and return success */
+    HashLinkHead = &HashTable->HashLinks[HashTable->HashFunction(Entry, HashTable->Size)];
+    InsertTailList(HashLinkHead, &HashNode->ListEntry);
+    Status = STATUS_SUCCESS;
+
+Quickie:
+    return Status;
+}
+
 VOID
 BlFwReboot (
     VOID
index 1549638..bbf996d 100644 (file)
 
 /* DATA VARIABLES ************************************************************/
 
-PVOID MmBlockAllocatorTable;
+PVOID* MmBlockAllocatorTable;
 ULONG MmBlockAllocatorTableEntries;
 BOOLEAN MmBlockAllocatorInitialized;
 
 typedef struct _BL_BLOCK_DESCRIPTOR
 {
-    LIST_ENTRY NextEntry;
-    UCHAR Unknown[0x50 - sizeof(LIST_ENTRY)];
+    LIST_ENTRY ListHead;
+    ULONG Unknown;
+    BL_MEMORY_TYPE Type;
+    ULONG Attributes;
+    ULONG Unknown2;
+    ULONG Count;
+    ULONG Count2;
+    ULONG Size;
+    ULONG BlockId;
+    ULONG ReferenceCount;
 } BL_BLOCK_DESCRIPTOR, *PBL_BLOCK_DESCRIPTOR;
 
+typedef struct _BL_BLOCK_ENTRY
+{
+    LIST_ENTRY ListEntry;
+    ULONG Todo;
+} BL_BLOCK_ENTRY, *PBL_BLOCK_ENTRY;
+
 /* FUNCTIONS *****************************************************************/
 
+BOOLEAN
+MmBapCompareBlockAllocatorTableEntry (
+    _In_ PVOID Entry,
+    _In_ PVOID Argument1,
+    _In_ PVOID Argument2,
+    _In_ PVOID Argument3,
+    _In_ PVOID Argument4
+    )
+{
+    PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
+    ULONG BlockId = (ULONG)Argument1;
+
+    /* Check if the block ID matches */
+    return BlockInfo->BlockId == BlockId;
+}
+
+PBL_BLOCK_DESCRIPTOR
+MmBapFindBlockInformation (
+    ULONG BlockId
+    )
+{
+    ULONG EntryId;
+
+    /* Find the block that matches */
+    EntryId = BlockId;
+    return BlTblFindEntry(MmBlockAllocatorTable,
+                          MmBlockAllocatorTableEntries,
+                          &EntryId,
+                          MmBapCompareBlockAllocatorTableEntry,
+                          (PVOID)EntryId,
+                          NULL,
+                          NULL,
+                          NULL);
+}
+
+NTSTATUS
+MmBapFreeBlockAllocatorDescriptor (
+    _In_ PBL_BLOCK_DESCRIPTOR BlockInfo,
+    _In_ PBL_BLOCK_ENTRY BlockEntry
+    )
+{
+    /* @TODO FIXME: Later */
+    EfiPrintf(L"Block free not yet implemented\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlpMmDeleteBlockAllocator (
+    _In_ ULONG BlockId
+    )
+{
+    NTSTATUS Status, LocalStatus;
+    PBL_BLOCK_DESCRIPTOR BlockInfo;
+    PLIST_ENTRY ListHead, NextEntry;
+    PBL_BLOCK_ENTRY BlockEntry;
+
+    /* Nothing to delete if we're not initialized */
+    if (!MmBlockAllocatorInitialized)
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* Find the block descriptor */
+    BlockInfo = MmBapFindBlockInformation(BlockId);
+    if (BlockInfo)
+    {
+        /* Assume success for now */
+        Status = STATUS_SUCCESS;
+
+        /* Do we have at least one reference? */
+        if (BlockInfo->ReferenceCount)
+        {
+            /* Iterate over the allocated blocks */
+            ListHead = &BlockInfo->ListHead;
+            NextEntry = ListHead->Flink;
+            while (NextEntry != ListHead)
+            {
+                /* Free each one */
+                BlockEntry = CONTAINING_RECORD(NextEntry,
+                                               BL_BLOCK_ENTRY,
+                                               ListEntry);
+                LocalStatus = MmBapFreeBlockAllocatorDescriptor(BlockInfo,
+                                                                BlockEntry);
+                if (!NT_SUCCESS(LocalStatus))
+                {
+                    /* Remember status on failure only */
+                    Status = LocalStatus;
+                }
+            }
+
+            /* Drop a reference */
+            BlockInfo->ReferenceCount--;
+        }
+        else
+        {
+            /* There aren't any references, so why are we being called? */
+            Status = STATUS_INVALID_PARAMETER;
+        }
+    }
+    else
+    {
+        /* No block exists with this ID */
+        Status = STATUS_UNSUCCESSFUL;
+    }
+
+    /* Return back */
+    return Status;
+}
+
+NTSTATUS
+MmBapFreeBlockAllocatorTableEntry (
+    _In_ PVOID Entry,
+    _In_ ULONG Index
+    )
+{
+    PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
+    NTSTATUS Status, LocalStatus;
+
+    /* Assume success */
+    Status = STATUS_SUCCESS;
+
+    /* Check if there was at least one reference */
+    if (BlockInfo->ReferenceCount > 1)
+    {
+        /* Try to delete the allocator */
+        LocalStatus = BlpMmDeleteBlockAllocator(BlockInfo->BlockId);
+        if (!NT_SUCCESS(LocalStatus))
+        {
+            /* Remember status on failure only */
+            Status = LocalStatus;
+        }
+    }
+
+    /* Now destroy the allocator's descriptor */
+    LocalStatus = BlMmFreeHeap(BlockInfo);
+    if (!NT_SUCCESS(LocalStatus))
+    {
+        /* Remember status on failure only */
+        Status = LocalStatus;
+    }
+
+    /* Free the entry, and return failure, if any */
+    MmBlockAllocatorTable[Index] = NULL;
+    return Status;
+}
+
+NTSTATUS
+MmBapPurgeBlockAlloctorTableEntry (
+    _In_ PVOID Entry
+    )
+{
+    PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
+    NTSTATUS Status;
+
+    /* Check if there's a reference on the block descriptor */
+    if (BlockInfo->ReferenceCount)
+    {
+        /* Don't allow purging */
+        Status = STATUS_UNSUCCESSFUL;
+    }
+    else
+    {
+        /* Free the entry */
+        Status = MmBapFreeBlockAllocatorTableEntry(BlockInfo,
+                                                   BlockInfo->BlockId);
+    }
+
+    /* Return purge status */
+    return Status;
+}
+
+NTSTATUS
+BlpMmCreateBlockAllocator (
+    VOID
+    )
+{
+    PBL_BLOCK_DESCRIPTOR BlockInfo;
+    ULONG BlockId;
+    NTSTATUS Status;
+
+    /* If the block allocator isn't initialized, bail out */
+    BlockId = -1;
+    if (!MmBlockAllocatorInitialized)
+    {
+        goto Quickie;
+    }
+
+    /* Allocate a block descriptor and zero it out */
+    BlockInfo = BlMmAllocateHeap(sizeof(*BlockInfo));
+    if (!BlockInfo)
+    {
+        goto Quickie;
+    }
+    RtlZeroMemory(BlockInfo, sizeof(*BlockInfo));
+
+    /* Setup the block descriptor */
+    BlockInfo->Attributes = 0;
+    BlockInfo->Type = BlLoaderBlockMemory;
+    BlockInfo->Unknown = 1;
+    BlockInfo->Unknown2 = 1;
+    BlockInfo->Size = PAGE_SIZE;
+    BlockInfo->Count = 128;
+    BlockInfo->Count2 = 128;
+    InitializeListHead(&BlockInfo->ListHead);
+
+    /* Add it to the list of block descriptors */
+    Status = BlTblSetEntry(&MmBlockAllocatorTable,
+                           &MmBlockAllocatorTableEntries,
+                           BlockInfo,
+                           &BlockId,
+                           MmBapPurgeBlockAlloctorTableEntry);
+    if (NT_SUCCESS(Status))
+    {
+        /* Add the initial reference and store the block ID */
+        BlockInfo->ReferenceCount = 1;
+        BlockInfo->BlockId = BlockId;
+    }
+
+Quickie:
+    /* On failure, free the block descriptor */
+    if (BlockId == -1)
+    {
+        BlMmFreeHeap(BlockInfo);
+    }
+
+    /* Return the block descriptor ID, or -1 on failure */
+    return BlockId;
+}
+
 NTSTATUS
 MmBaInitialize (
     VOID
index 28889d4..9bdc92c 100644 (file)
@@ -146,7 +146,7 @@ MmHapHeapAllocatorExtend (
     }
 
     /* We do not -- allocate one */
-    Status = MmPapAllocatePagesInRange((PULONG)&HeapBase,
+    Status = MmPapAllocatePagesInRange((PVOID*)&HeapBase,
                                        BlLoaderHeap,
                                        AlignedSize >> PAGE_SHIFT,
                                        HapAllocationAttributes,
@@ -673,6 +673,13 @@ BlMmFreeHeap (
     }
 
     /* Get the heap header */
+    EfiPrintf(L"Freeing entry at: %p\r\n", Buffer);
+    if (Buffer)
+    {
+        /* Don't free heap until we discover the corruption */
+        return STATUS_SUCCESS;
+    }
+
     BusyEntry = CONTAINING_RECORD(Buffer, BL_BUSY_HEAP_ENTRY, Buffer);
 
     /* Loop all the heaps */
index 00697b7..120f501 100644 (file)
@@ -391,7 +391,7 @@ Quickie:
 
 NTSTATUS
 MmPapAllocatePagesInRange (
-    _Inout_ PULONG PhysicalAddress,
+    _Inout_ PVOID* PhysicalAddress,
     _In_ BL_MEMORY_TYPE MemoryType,
     _In_ ULONGLONG Pages,
     _In_ ULONG Attributes,
@@ -425,7 +425,7 @@ MmPapAllocatePagesInRange (
     else
     {
         /* Check if this is a fixed allocation */
-        BaseAddress.QuadPart = (Attributes & BlMemoryFixed) ? *PhysicalAddress : 0;
+        BaseAddress.QuadPart = (Attributes & BlMemoryFixed) ? (ULONG_PTR)*PhysicalAddress : 0;
 
         /* Allocate the pages */
         Status = MmPapAllocatePhysicalPagesInRange(&BaseAddress,
@@ -441,7 +441,7 @@ MmPapAllocatePagesInRange (
                                                    Type);
 
         /* Return the allocated address */
-        *PhysicalAddress = BaseAddress.LowPart;
+        *PhysicalAddress = (PVOID)BaseAddress.LowPart;
     }
 
 Exit: