[BOOTMGFW]
authorAlex Ionescu <aionescu@gmail.com>
Thu, 10 Sep 2015 23:13:31 +0000 (23:13 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Thu, 10 Sep 2015 23:13:31 +0000 (23:13 +0000)
- Implement Block I/O read operations & related functions. Code needs cleanup, TBD.
- Unfortunately, I wish I could say it works, but it seems like all we get back are zeroes (from EFI itself). I suspect we are reading from the wrong device -- will have to investigate for a bit.

svn path=/trunk/; revision=69178

reactos/boot/environ/include/bl.h
reactos/boot/environ/lib/io/device.c
reactos/boot/environ/lib/io/fat.c

index 0817140..0a444cf 100644 (file)
@@ -898,7 +898,7 @@ typedef struct _BL_BLOCK_DEVICE_INFORMATION
     BL_PARTITION_TYPE PartitionType;
     ULONG BlockSize;
     ULONG Alignment;
-    ULONGLONG MaxBlock;
+    ULONGLONG LastBlock;
     ULONGLONG Offset;
     ULONG Block;
     struct
@@ -929,7 +929,7 @@ typedef struct _BL_DEVICE_INFORMATION
 typedef struct _BL_BLOCK_DEVICE
 {
     BL_BLOCK_DEVICE_INFORMATION;
-    ULONGLONG LastBlock;
+    ULONGLONG StartOffset;
     EFI_BLOCK_IO* Protocol;
     EFI_HANDLE Handle;
 } BL_BLOCK_DEVICE, *PBL_BLOCK_DEVICE;
index e4c9424..4b2be5e 100644 (file)
@@ -73,17 +73,487 @@ BlockIoSetInformation (
     _Out_ PBL_DEVICE_INFORMATION DeviceInformation
     );
 
+NTSTATUS
+BlockIoRead (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry,
+    _In_ PVOID Buffer,
+    _In_ ULONG Size,
+    _Out_ PULONG BytesRead
+    );
+
 BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable =
 {
     NULL,
     BlockIoOpen,
     NULL,
-    NULL,
+    BlockIoRead,
     NULL,
     BlockIoGetInformation,
     BlockIoSetInformation
 };
 
+NTSTATUS
+BlockIoFirmwareWrite (
+    _In_ PBL_BLOCK_DEVICE BlockDevice,
+    _In_ PVOID Buffer,
+    _In_ ULONGLONG Block,
+    _In_ ULONGLONG BlockCount
+    )
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlockIoFirmwareRead (
+    _In_ PBL_BLOCK_DEVICE BlockDevice,
+    _In_ PVOID Buffer,
+    _In_ ULONGLONG Block,
+    _In_ ULONGLONG BlockCount
+    )
+{
+    NTSTATUS Status;
+    EFI_BLOCK_IO *BlockProtocol;
+    BL_ARCH_MODE OldMode;
+    EFI_STATUS EfiStatus;
+    ULONG FailureCount;
+
+    for (FailureCount = 0, Status = STATUS_SUCCESS;
+         FailureCount < 2 && NT_SUCCESS(Status);
+         FailureCount++)
+    {
+        BlockProtocol = BlockDevice->Protocol;
+
+        OldMode = CurrentExecutionContext->Mode;
+        if (CurrentExecutionContext->Mode != 1)
+        {
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+        }
+
+        EfiPrintf(L"EFI Reading BLOCK %d off media %lx (%d blocks)\r\n",
+                 Block, BlockProtocol->Media->MediaId, BlockCount);
+        EfiStatus = BlockProtocol->ReadBlocks(BlockProtocol,
+                                              BlockProtocol->Media->MediaId,
+                                              Block,
+                                              BlockProtocol->Media->BlockSize * BlockCount,
+                                              Buffer);
+        if (EfiStatus == EFI_SUCCESS)
+        {
+            EfiPrintf(L"EFI Read complete into buffer\r\n");
+            EfiPrintf(L"Buffer data: %lx %lx %lx %lx\r\n", *(PULONG)Buffer, *((PULONG)Buffer + 1), *((PULONG)Buffer + 2), *((PULONG)Buffer + 3));
+        }
+
+        if (OldMode != 1)
+        {
+            BlpArchSwitchContext(OldMode);
+        }
+
+        Status = EfiGetNtStatusCode(EfiStatus);
+        if (Status != STATUS_MEDIA_CHANGED)
+        {
+            break;
+        }
+
+        EfiCloseProtocol(BlockDevice->Handle, &EfiBlockIoProtocol);
+
+        Status = EfiOpenProtocol(BlockDevice->Handle,
+                                 &EfiBlockIoProtocol,
+                                 (PVOID*)BlockDevice->Protocol);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+BlockIopFirmwareOperation (
+    PBL_DEVICE_ENTRY DeviceEntry,
+    _In_ PVOID Buffer,
+    _In_ ULONGLONG Block,
+    _In_ ULONGLONG BlockCount,
+    _In_ ULONG OperationType
+    )
+{
+    ULONG FailureCount;
+    PBL_BLOCK_DEVICE BlockDevice;
+    NTSTATUS Status;
+
+    BlockDevice = DeviceEntry->DeviceSpecificData;
+
+    if (OperationType == 1)
+    {
+        for (FailureCount = 0; FailureCount < 3; FailureCount++)
+        {
+            Status = BlockIoFirmwareWrite(BlockDevice, Buffer, Block, BlockCount);
+            if (Status >= 0)
+            {
+                break;
+            }
+        }
+    }
+    else
+    {
+        for (FailureCount = 0; FailureCount < 3; FailureCount++)
+        {
+            Status = BlockIoFirmwareRead(BlockDevice, Buffer, Block, BlockCount);
+            if (Status >= 0)
+            {
+                break;
+            }
+        }
+    }
+    return Status;
+}
+
+NTSTATUS
+BlockIopFreeAlignedBuffer (
+    _Inout_ PVOID* Buffer,
+    _Inout_ PULONG BufferSize
+    )
+{
+    NTSTATUS Status;
+
+    if (*BufferSize)
+    {
+        EfiPrintf(L"Aligned free not yet implemented\r\n");
+        Status = STATUS_NOT_IMPLEMENTED;
+        //Status = MmPapFreePages(*Buffer, 1);
+
+        *Buffer = NULL;
+        *BufferSize = 0;
+    }
+    else
+    {
+        Status = STATUS_SUCCESS;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+BlockIopAllocateAlignedBuffer (
+    _Inout_ PVOID* Buffer,
+    _Inout_ PULONG BufferSize,
+    _In_ ULONG Size,
+    _In_ ULONG Alignment
+    )
+{
+    NTSTATUS Status;
+
+    if (!Alignment)
+    {
+        ++Alignment;
+    }
+
+    Status = STATUS_SUCCESS;
+    if ((Size > *BufferSize) || ((Alignment - 1) & (ULONG_PTR)*Buffer))
+    {
+        BlockIopFreeAlignedBuffer(Buffer, BufferSize);
+
+        *BufferSize = ROUND_TO_PAGES(Size);
+
+        Status = MmPapAllocatePagesInRange(Buffer,
+                                           BlLoaderDeviceMemory,
+                                           *BufferSize >> PAGE_SHIFT,
+                                           0,
+                                           Alignment >> PAGE_SHIFT,
+                                           NULL,
+                                           0);
+        if (!NT_SUCCESS(Status))
+        {
+            *BufferSize = 0;
+        }
+    }
+
+    return Status;
+}
+
+NTSTATUS
+BlockIopReadUsingPrefetch (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry,
+    _In_ PVOID Buffer,
+    _In_ ULONG BlockCount
+    )
+{
+    EfiPrintf(L"No prefetch support\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlockIopOperation (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry,
+    _In_ PVOID Buffer,
+    _In_ ULONG BlockCount,
+    _In_ ULONG OperationType
+    )
+{
+    PBL_BLOCK_DEVICE BlockDevice;
+    ULONG BufferSize, Alignment;
+    ULONGLONG Offset;
+    NTSTATUS Status;
+
+    BlockDevice = DeviceEntry->DeviceSpecificData;
+    BufferSize = BlockDevice->BlockSize * BlockCount;
+    Offset = BlockDevice->Block + BlockDevice->StartOffset;
+    if ((BlockDevice->LastBlock + 1) < (BlockDevice->Block + BlockCount))
+    {
+        EfiPrintf(L"Read past end of device\r\n");
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Alignment = BlockDevice->Alignment;
+    if (!Alignment || !((Alignment - 1) & (ULONG_PTR)Buffer))
+    {
+        Status = BlockIopFirmwareOperation(DeviceEntry,
+                                           Buffer,
+                                           Offset,
+                                           BlockCount,
+                                           OperationType);
+        if (!NT_SUCCESS(Status))
+        {
+            EfiPrintf(L"EFI op failed: %lx\r\n", Status);
+            return Status;
+        }
+
+        return STATUS_SUCCESS;
+    }
+
+    EfiPrintf(L"Firmware alignment fixup required\r\n");
+    Status = BlockIopAllocateAlignedBuffer(&BlockIopAlignedBuffer,
+                                           &BlockIopAlignedBufferSize,
+                                           BufferSize,
+                                           BlockDevice->Alignment);
+    if (!NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"No memory for align\r\n");
+        return STATUS_NO_MEMORY;
+    }
+
+    if (OperationType == 1)
+    {
+        RtlCopyMemory(BlockIopAlignedBuffer, Buffer, BufferSize);
+    }
+
+    Status = BlockIopFirmwareOperation(DeviceEntry,
+                                       BlockIopAlignedBuffer,
+                                       Offset,
+                                       BlockCount,
+                                       OperationType);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    if (!OperationType)
+    {
+        RtlCopyMemory(Buffer, BlockIopAlignedBuffer, BufferSize);
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlockIopReadWriteVirtualDevice (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry,
+    _In_ PVOID Buffer,
+    _In_ ULONG Size,
+    _In_ ULONG Operation,
+    _Out_ PULONG BytesRead
+    )
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlockIopReadPhysicalDevice (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry,
+    _In_ PVOID Buffer,
+    _In_ ULONG Size,
+    _Out_ PULONG BytesRead
+    )
+{
+    PBL_BLOCK_DEVICE BlockDevice;
+    PVOID ReadBuffer; // edi@1
+    ULONGLONG OffsetEnd, AlignedOffsetEnd, Offset;
+    NTSTATUS Status;
+
+    BlockDevice = DeviceEntry->DeviceSpecificData;
+    ReadBuffer = Buffer;
+    OffsetEnd = Size + BlockDevice->Offset;
+    if (OffsetEnd < Size)
+    {
+        OffsetEnd = -1;
+        return STATUS_INTEGER_OVERFLOW;
+    }
+
+    AlignedOffsetEnd = ~(BlockDevice->BlockSize - 1) & (OffsetEnd + BlockDevice->BlockSize - 1);
+    if (AlignedOffsetEnd < OffsetEnd)
+    {
+        return STATUS_INTEGER_OVERFLOW;
+    }
+
+    if ((BlockDevice->Offset) || (Size != AlignedOffsetEnd))
+    {
+        Status = BlockIopAllocateAlignedBuffer(&BlockIopReadBlockBuffer,
+                                               &BlockIopReadBlockBufferSize,
+                                               AlignedOffsetEnd,
+                                               BlockDevice->Alignment);
+        if (!NT_SUCCESS(Status))
+        {
+            EfiPrintf(L"Failed to allocate buffer: %lx\r\n", Status);
+            return Status;
+        }
+
+        ReadBuffer = BlockIopReadBlockBuffer;
+    }
+
+    Offset = AlignedOffsetEnd / BlockDevice->BlockSize;
+
+    if (BlockDevice->Unknown & 2)
+    {
+        Status = BlockIopReadUsingPrefetch(DeviceEntry,
+                                           ReadBuffer,
+                                           AlignedOffsetEnd / BlockDevice->BlockSize);
+        if (NT_SUCCESS(Status))
+        {
+            goto ReadComplete;
+        }
+    }
+
+    Status = BlockIopOperation(DeviceEntry, ReadBuffer, Offset, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"Block I/O failed:%lx\r\n", Status);
+        return Status;
+    }
+
+    BlockDevice->Block += Offset;
+
+ReadComplete:
+    if (ReadBuffer != Buffer)
+    {
+        RtlCopyMemory(Buffer,
+                      (PVOID)((ULONG_PTR)ReadBuffer +
+                              (ULONG_PTR)BlockDevice->Offset),
+                      Size);
+    }
+
+    if (BytesRead)
+    {
+        *BytesRead = Size;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlockIopBlockInformationCheck (
+    _In_ PBL_BLOCK_DEVICE BlockDevice,
+    _In_opt_ PULONG DesiredSize,
+    _Out_opt_ PULONG Size,
+    _Out_opt_ PULONG OutputAdjustedSize
+    )
+{
+    ULONG RealSize;
+    ULONGLONG Offset, LastOffset, RemainingOffset, MaxOffset;
+    NTSTATUS Status;
+
+    RealSize = 0;
+
+    Offset = (BlockDevice->Offset * BlockDevice->BlockSize) + BlockDevice->Block;
+
+    if (Offset > ((BlockDevice->LastBlock + 1) * BlockDevice->BlockSize))
+    {
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    LastOffset = (BlockDevice->LastBlock * BlockDevice->BlockSize) + BlockDevice->BlockSize - 1;
+
+    MaxOffset = BlockDevice->LastBlock;
+    if (MaxOffset < BlockDevice->BlockSize)
+    {
+        MaxOffset = BlockDevice->BlockSize;
+    }
+
+    if (LastOffset < MaxOffset)
+    {
+
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    if (Offset > LastOffset)
+    {
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    RemainingOffset = LastOffset - Offset + 1;
+
+    if (DesiredSize != FALSE)
+    {
+        RealSize = *DesiredSize;
+    }
+    else
+    {
+        RealSize = ULONG_MAX;
+    }
+
+    if (RemainingOffset < RealSize)
+    {
+        if (Size == FALSE)
+        {
+            RealSize = 0;
+            Status = STATUS_INVALID_PARAMETER;
+            goto Quickie;
+        }
+
+        RealSize = RemainingOffset;
+    }
+
+    Status = STATUS_SUCCESS;
+
+Quickie:
+    if (Size)
+    {
+        *Size = RealSize;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+BlockIoRead (
+    _In_ PBL_DEVICE_ENTRY DeviceEntry,
+    _In_ PVOID Buffer,
+    _In_ ULONG Size,
+    _Out_ PULONG BytesRead
+    )
+{
+    PBL_BLOCK_DEVICE BlockDevice;
+    NTSTATUS Status;
+
+    BlockDevice = DeviceEntry->DeviceSpecificData;
+
+    Status = BlockIopBlockInformationCheck(BlockDevice, &Size, BytesRead, &Size);
+    if (NT_SUCCESS(Status))
+    {
+        if (BlockDevice->DeviceFlags & 4)
+        {
+            Status = BlockIopReadWriteVirtualDevice(DeviceEntry, Buffer, Size, 0, BytesRead);
+        }
+        else
+        {
+            Status = BlockIopReadPhysicalDevice(DeviceEntry, Buffer, Size, BytesRead);
+        }
+    }
+    else if (BytesRead)
+    {
+        *BytesRead = 0;
+    }
+    return Status;
+}
+
 NTSTATUS
 BlockIoSetInformation (
     _In_ PBL_DEVICE_ENTRY DeviceEntry,
@@ -96,8 +566,9 @@ BlockIoSetInformation (
     BlockDevice = DeviceEntry->DeviceSpecificData;
 
     Offset = DeviceInformation->BlockDeviceInfo.Block * BlockDevice->BlockSize + DeviceInformation->BlockDeviceInfo.Offset;
-    if (Offset > ((BlockDevice->MaxBlock + 1) * BlockDevice->BlockSize - 1))
+    if (Offset > ((BlockDevice->LastBlock + 1) * BlockDevice->BlockSize - 1))
     {
+        EfiPrintf(L"Invalid offset\r\n");
         return STATUS_INVALID_PARAMETER;
     }
 
@@ -159,7 +630,7 @@ BlDeviceSetInformation (
 
 NTSTATUS
 BlDeviceGetInformation (
-    _In_ ULONG DeviceId, 
+    _In_ ULONG DeviceId,
     _Out_ PBL_DEVICE_INFORMATION DeviceInformation
     )
 {
@@ -198,33 +669,37 @@ BlDeviceRead (
     _Out_ PULONG BytesRead
     )
 {
-    PBL_DEVICE_ENTRY DeviceEntry; // ecx@3
+    PBL_DEVICE_ENTRY DeviceEntry;
     NTSTATUS Status;
     ULONG BytesTransferred;
 
-    if (Buffer
-        && DmTableEntries > DeviceId
-        && (DeviceEntry = DmDeviceTable[DeviceId]) != 0
-        && DeviceEntry->Flags & 1
-        && DeviceEntry->Flags & 2)
+    if (!(Buffer) || (DmTableEntries <= DeviceId))
     {
-        EfiPrintf(L"Calling read...\r\n");
-        Status = DeviceEntry->Callbacks.Read(DeviceEntry, Buffer, Size, &BytesTransferred);
+        return STATUS_INVALID_PARAMETER;
+    }
 
-        if (!DeviceEntry->Unknown)
-        {
-            DmDeviceIoInformation.ReadCount += BytesTransferred;
-        }
+    DeviceEntry = DmDeviceTable[DeviceId];
+    if (!DeviceEntry)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
 
-        if (BytesRead)
-        {
-            *BytesRead = BytesTransferred;
-        }
+    if (!(DeviceEntry->Flags & 1) || !(DeviceEntry->Flags & 2))
+    {
+        return STATUS_INVALID_PARAMETER;
     }
-    else
+
+    Status = DeviceEntry->Callbacks.Read(DeviceEntry, Buffer, Size, &BytesTransferred);
+    if (!DeviceEntry->Unknown)
     {
-        Status = STATUS_INVALID_PARAMETER;
+        DmDeviceIoInformation.ReadCount += BytesTransferred;
     }
+
+    if (BytesRead)
+    {
+        *BytesRead = BytesTransferred;
+    }
+
     return Status;
 }
 
@@ -241,22 +716,22 @@ BlDeviceReadAtOffset (
     BL_DEVICE_INFORMATION DeviceInformation;
 
     Status = BlDeviceGetInformation(DeviceId, &DeviceInformation);
-    if (Status >= 0)
+    if (!NT_SUCCESS(Status))
     {
-        DeviceInformation.BlockDeviceInfo.Block = Offset / DeviceInformation.BlockDeviceInfo.BlockSize;
-        DeviceInformation.BlockDeviceInfo.Offset = Offset % DeviceInformation.BlockDeviceInfo.BlockSize;
-        Status = BlDeviceSetInformation(DeviceId, &DeviceInformation);
+        return Status;
+    }
 
-        if (NT_SUCCESS(Status))
-        {
-            EfiPrintf(L"Block: %d Offset: %d\r\n", DeviceInformation.BlockDeviceInfo.Block, DeviceInformation.BlockDeviceInfo.Offset);
-            Status = BlDeviceRead(DeviceId, Buffer, Size, BytesRead);
-        }
+    DeviceInformation.BlockDeviceInfo.Block = Offset / DeviceInformation.BlockDeviceInfo.BlockSize;
+    DeviceInformation.BlockDeviceInfo.Offset = Offset % DeviceInformation.BlockDeviceInfo.BlockSize;
+    Status = BlDeviceSetInformation(DeviceId, &DeviceInformation);
+    if (NT_SUCCESS(Status))
+    {
+        Status = BlDeviceRead(DeviceId, Buffer, Size, BytesRead);
     }
+
     return Status;
 }
 
-
 BOOLEAN
 BlpDeviceCompare (
     _In_ PBL_DEVICE_DESCRIPTOR Device1,
@@ -1633,7 +2108,7 @@ BlpDeviceInitialize (
     {
         /* Clear it */
         RtlZeroMemory(DmDeviceTable, DmTableEntries * sizeof(PVOID));
-#if 0
+#if BL_BITLOCKER_SUPPORT
         /* Initialize BitLocker support */
         Status = FvebInitialize();
 #else
index 49f1f24..717ac4f 100644 (file)
@@ -30,6 +30,7 @@ FatMount (
     ULONG UnknownFlag;
     NTSTATUS Status;
     PACKED_BOOT_SECTOR FatBootSector;
+    BIOS_PARAMETER_BLOCK BiosBlock;
 
     EfiPrintf(L"FAT Mount on Device %d\r\n", DeviceId);
 
@@ -58,7 +59,21 @@ FatMount (
         return Status;
     }
 
+    FatUnpackBios(&BiosBlock, &FatBootSector.PackedBpb);
+
     EfiPrintf(L"Drive read\r\n");
+
+    EfiPrintf(L"Jump: %lx Bytes Per Sector: %d Sectors Per Cluster: %d Reserved: %d Fats: %d Sectors: %d Large Sectors: %d Media: %lx RootEntries: %d\r\n",
+        FatBootSector.Jump[0],
+        BiosBlock.BytesPerSector,
+        BiosBlock.SectorsPerCluster,
+        BiosBlock.ReservedSectors,
+        BiosBlock.Fats,
+        BiosBlock.Sectors,
+        BiosBlock.LargeSectors,
+        BiosBlock.Media,
+        BiosBlock.RootEntries);
+
     EfiStall(3000000);
     return STATUS_NOT_IMPLEMENTED;
 }