1 /*
2  * PROJECT:     FreeLoader UEFI Support
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Disk Access Functions
5  * COPYRIGHT:   Copyright 2022 Justin Miller <justinmiller100@gmail.com>
6  */
7 
8 /* INCLUDES ******************************************************************/
9 
10 #include <uefildr.h>
11 
12 #include <debug.h>
13 DBG_DEFAULT_CHANNEL(WARNING);
14 
15 #define TAG_HW_RESOURCE_LIST    'lRwH'
16 #define TAG_HW_DISK_CONTEXT     'cDwH'
17 #define FIRST_BIOS_DISK 0x80
18 #define FIRST_PARTITION 1
19 
20 typedef struct tagDISKCONTEXT
21 {
22     UCHAR DriveNumber;
23     ULONG SectorSize;
24     ULONGLONG SectorOffset;
25     ULONGLONG SectorCount;
26     ULONGLONG SectorNumber;
27 } DISKCONTEXT;
28 
29 typedef struct _INTERNAL_UEFI_DISK
30 {
31     UCHAR ArcDriveNumber;
32     UCHAR NumOfPartitions;
33     UCHAR UefiRootNumber;
34     BOOLEAN IsThisTheBootDrive;
35 } INTERNAL_UEFI_DISK, *PINTERNAL_UEFI_DISK;
36 
37 /* GLOBALS *******************************************************************/
38 
39 extern EFI_SYSTEM_TABLE* GlobalSystemTable;
40 extern EFI_HANDLE GlobalImageHandle;
41 extern EFI_HANDLE PublicBootHandle; /* Freeldr itself */
42 
43 /* Made to match BIOS */
44 PVOID DiskReadBuffer;
45 UCHAR PcBiosDiskCount;
46 
47 UCHAR FrldrBootDrive;
48 ULONG FrldrBootPartition;
49 SIZE_T DiskReadBufferSize;
50 PVOID Buffer;
51 
52 static const CHAR Hex[] = "0123456789abcdef";
53 static CHAR PcDiskIdentifier[32][20];
54 
55 /* UEFI-specific */
56 static ULONG UefiBootRootIdentifier;
57 static ULONG OffsetToBoot;
58 static ULONG PublicBootArcDisk;
59 static INTERNAL_UEFI_DISK* InternalUefiDisk = NULL;
60 static EFI_GUID bioGuid = BLOCK_IO_PROTOCOL;
61 static EFI_BLOCK_IO* bio;
62 static EFI_HANDLE* handles = NULL;
63 
64 /* FUNCTIONS *****************************************************************/
65 
66 PCHAR
67 GetHarddiskIdentifier(UCHAR DriveNumber)
68 {
69     TRACE("GetHarddiskIdentifier: DriveNumber: %d\n", DriveNumber);
70     return PcDiskIdentifier[DriveNumber - FIRST_BIOS_DISK];
71 }
72 
73 static LONG lReportError = 0; // >= 0: display errors; < 0: hide errors.
74 
75 LONG
76 DiskReportError(BOOLEAN bShowError)
77 {
78     /* Set the reference count */
79     if (bShowError) ++lReportError;
80     else            --lReportError;
81     return lReportError;
82 }
83 
84 static
85 BOOLEAN
86 UefiGetBootPartitionEntry(
87     IN UCHAR DriveNumber,
88     OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
89     OUT PULONG BootPartition)
90 {
91     ULONG PartitionNum;
92 
93     TRACE("UefiGetBootPartitionEntry: DriveNumber: %d\n", DriveNumber - FIRST_BIOS_DISK);
94     /* UefiBootRoot is the offset into the array of handles where the raw disk of the boot drive is.
95      * Partitions start with 1 in ARC, but UEFI root drive identitfier is also first partition. */
96     PartitionNum = (OffsetToBoot - UefiBootRootIdentifier);
97     if (PartitionNum == 0)
98     {
99         TRACE("Boot PartitionNumber is 0\n");
100         /* The OffsetToBoot is equal to the RootIdentifier */
101         PartitionNum = FIRST_PARTITION;
102     }
103 
104     *BootPartition = PartitionNum;
105     TRACE("UefiGetBootPartitionEntry: Boot Partition is: %d\n", PartitionNum);
106     return TRUE;
107 }
108 
109 static
110 ARC_STATUS
111 UefiDiskClose(ULONG FileId)
112 {
113     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
114     FrLdrTempFree(Context, TAG_HW_DISK_CONTEXT);
115     return ESUCCESS;
116 }
117 
118 static
119 ARC_STATUS
120 UefiDiskGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
121 {
122     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
123     RtlZeroMemory(Information, sizeof(*Information));
124 
125     /*
126      * The ARC specification mentions that for partitions, StartingAddress and
127      * EndingAddress are the start and end positions of the partition in terms
128      * of byte offsets from the start of the disk.
129      * CurrentAddress is the current offset into (i.e. relative to) the partition.
130      */
131     Information->StartingAddress.QuadPart = Context->SectorOffset * Context->SectorSize;
132     Information->EndingAddress.QuadPart   = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
133     Information->CurrentAddress.QuadPart  = Context->SectorNumber * Context->SectorSize;
134 
135     return ESUCCESS;
136 }
137 
138 static
139 ARC_STATUS
140 UefiDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
141 {
142     DISKCONTEXT* Context;
143     UCHAR DriveNumber;
144     ULONG DrivePartition, SectorSize;
145     ULONGLONG SectorOffset = 0;
146     ULONGLONG SectorCount = 0;
147     ULONG UefiDriveNumber = 0;
148     PARTITION_TABLE_ENTRY PartitionTableEntry;
149 
150     TRACE("UefiDiskOpen: File ID: %d, Path: %s\n", FileId, Path);
151 
152     if (DiskReadBufferSize == 0)
153     {
154         ERR("DiskOpen(): DiskReadBufferSize is 0, something is wrong.\n");
155         ASSERT(FALSE);
156         return ENOMEM;
157     }
158 
159     if (!DissectArcPath(Path, NULL, &DriveNumber, &DrivePartition))
160         return EINVAL;
161 
162     TRACE("Opening disk: DriveNumber: %d, DrivePartition: %d\n", DriveNumber, DrivePartition);
163     UefiDriveNumber = DriveNumber - FIRST_BIOS_DISK;
164     GlobalSystemTable->BootServices->HandleProtocol(handles[UefiDriveNumber], &bioGuid, (void**)&bio);
165     SectorSize = bio->Media->BlockSize;
166 
167     if (DrivePartition != 0xff && DrivePartition != 0)
168     {
169         if (!DiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
170             return EINVAL;
171 
172         SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
173         SectorCount = PartitionTableEntry.PartitionSectorCount;
174     }
175     else
176     {
177         GEOMETRY Geometry;
178         if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
179             return EINVAL;
180 
181         if (SectorSize != Geometry.BytesPerSector)
182         {
183             ERR("SectorSize (%lu) != Geometry.BytesPerSector (%lu), expect problems!\n",
184                 SectorSize, Geometry.BytesPerSector);
185         }
186 
187         SectorOffset = 0;
188         SectorCount = (ULONGLONG)Geometry.Cylinders * Geometry.Heads * Geometry.Sectors;
189     }
190 
191     Context = FrLdrTempAlloc(sizeof(DISKCONTEXT), TAG_HW_DISK_CONTEXT);
192     if (!Context)
193         return ENOMEM;
194 
195     Context->DriveNumber = DriveNumber;
196     Context->SectorSize = SectorSize;
197     Context->SectorOffset = SectorOffset;
198     Context->SectorCount = SectorCount;
199     Context->SectorNumber = 0;
200     FsSetDeviceSpecific(*FileId, Context);
201     return ESUCCESS;
202 }
203 
204 static
205 ARC_STATUS
206 UefiDiskRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
207 {
208     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
209     UCHAR* Ptr = (UCHAR*)Buffer;
210     ULONG Length, TotalSectors, MaxSectors, ReadSectors;
211     ULONGLONG SectorOffset;
212     BOOLEAN ret;
213 
214     ASSERT(DiskReadBufferSize > 0);
215 
216     TotalSectors = (N + Context->SectorSize - 1) / Context->SectorSize;
217     MaxSectors   = DiskReadBufferSize / Context->SectorSize;
218     SectorOffset = Context->SectorOffset + Context->SectorNumber;
219 
220     // If MaxSectors is 0, this will lead to infinite loop.
221     // In release builds assertions are disabled, however we also have sanity checks in DiskOpen()
222     ASSERT(MaxSectors > 0);
223 
224     ret = TRUE;
225 
226     while (TotalSectors)
227     {
228         ReadSectors = min(TotalSectors, MaxSectors);
229 
230         ret = MachDiskReadLogicalSectors(Context->DriveNumber,
231                                          SectorOffset,
232                                          ReadSectors,
233                                          DiskReadBuffer);
234         if (!ret)
235             break;
236 
237         Length = ReadSectors * Context->SectorSize;
238         Length = min(Length, N);
239 
240         RtlCopyMemory(Ptr, DiskReadBuffer, Length);
241 
242         Ptr += Length;
243         N -= Length;
244         SectorOffset += ReadSectors;
245         TotalSectors -= ReadSectors;
246     }
247 
248     *Count = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)Buffer);
249     Context->SectorNumber = SectorOffset - Context->SectorOffset;
250 
251     return (ret ? ESUCCESS : EIO);
252 }
253 
254 static
255 ARC_STATUS
256 UefiDiskSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
257 {
258     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
259     LARGE_INTEGER NewPosition = *Position;
260 
261     switch (SeekMode)
262     {
263         case SeekAbsolute:
264             break;
265         case SeekRelative:
266             NewPosition.QuadPart += (Context->SectorNumber * Context->SectorSize);
267             break;
268         default:
269             ASSERT(FALSE);
270             return EINVAL;
271     }
272 
273     if (NewPosition.QuadPart & (Context->SectorSize - 1))
274         return EINVAL;
275 
276     /* Convert in number of sectors */
277     NewPosition.QuadPart /= Context->SectorSize;
278 
279     /* HACK: CDROMs may have a SectorCount of 0 */
280     if (Context->SectorCount != 0 && NewPosition.QuadPart >= Context->SectorCount)
281         return EINVAL;
282 
283     Context->SectorNumber = NewPosition.QuadPart;
284     return ESUCCESS;
285 }
286 
287 static const DEVVTBL UefiDiskVtbl =
288 {
289     UefiDiskClose,
290     UefiDiskGetFileInformation,
291     UefiDiskOpen,
292     UefiDiskRead,
293     UefiDiskSeek,
294 };
295 
296 static
297 VOID
298 GetHarddiskInformation(UCHAR DriveNumber)
299 {
300     PMASTER_BOOT_RECORD Mbr;
301     PULONG Buffer;
302     ULONG i;
303     ULONG Checksum;
304     ULONG Signature;
305     BOOLEAN ValidPartitionTable;
306     CHAR ArcName[MAX_PATH];
307     PARTITION_TABLE_ENTRY PartitionTableEntry;
308     PCHAR Identifier = PcDiskIdentifier[DriveNumber - FIRST_BIOS_DISK];
309 
310     /* Detect disk partition type */
311     DiskDetectPartitionType(DriveNumber);
312 
313     /* Read the MBR */
314     if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, DiskReadBuffer))
315     {
316         ERR("Reading MBR failed\n");
317         /* We failed, use a default identifier */
318         sprintf(Identifier, "BIOSDISK%d", DriveNumber - FIRST_BIOS_DISK);
319         return;
320     }
321 
322     Buffer = (ULONG*)DiskReadBuffer;
323     Mbr = (PMASTER_BOOT_RECORD)DiskReadBuffer;
324 
325     Signature = Mbr->Signature;
326     TRACE("Signature: %x\n", Signature);
327 
328     /* Calculate the MBR checksum */
329     Checksum = 0;
330     for (i = 0; i < 512 / sizeof(ULONG); i++)
331     {
332         Checksum += Buffer[i];
333     }
334     Checksum = ~Checksum + 1;
335     TRACE("Checksum: %x\n", Checksum);
336 
337     ValidPartitionTable = (Mbr->MasterBootRecordMagic == 0xAA55);
338 
339     /* Fill out the ARC disk block */
340     sprintf(ArcName, "multi(0)disk(0)rdisk(%u)", DriveNumber - FIRST_BIOS_DISK);
341     AddReactOSArcDiskInfo(ArcName, Signature, Checksum, ValidPartitionTable);
342 
343     sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(0)", DriveNumber - FIRST_BIOS_DISK);
344     FsRegisterDevice(ArcName, &UefiDiskVtbl);
345 
346     /* Add partitions */
347     i = FIRST_PARTITION;
348     DiskReportError(FALSE);
349     while (DiskGetPartitionEntry(DriveNumber, i, &PartitionTableEntry))
350     {
351         if (PartitionTableEntry.SystemIndicator != PARTITION_ENTRY_UNUSED)
352         {
353             sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(%lu)", DriveNumber - FIRST_BIOS_DISK, i);
354             FsRegisterDevice(ArcName, &UefiDiskVtbl);
355         }
356         i++;
357     }
358     DiskReportError(TRUE);
359 
360     InternalUefiDisk[DriveNumber].NumOfPartitions = i;
361     /* Convert checksum and signature to identifier string */
362     Identifier[0] = Hex[(Checksum >> 28) & 0x0F];
363     Identifier[1] = Hex[(Checksum >> 24) & 0x0F];
364     Identifier[2] = Hex[(Checksum >> 20) & 0x0F];
365     Identifier[3] = Hex[(Checksum >> 16) & 0x0F];
366     Identifier[4] = Hex[(Checksum >> 12) & 0x0F];
367     Identifier[5] = Hex[(Checksum >> 8) & 0x0F];
368     Identifier[6] = Hex[(Checksum >> 4) & 0x0F];
369     Identifier[7] = Hex[Checksum & 0x0F];
370     Identifier[8] = '-';
371     Identifier[9] = Hex[(Signature >> 28) & 0x0F];
372     Identifier[10] = Hex[(Signature >> 24) & 0x0F];
373     Identifier[11] = Hex[(Signature >> 20) & 0x0F];
374     Identifier[12] = Hex[(Signature >> 16) & 0x0F];
375     Identifier[13] = Hex[(Signature >> 12) & 0x0F];
376     Identifier[14] = Hex[(Signature >> 8) & 0x0F];
377     Identifier[15] = Hex[(Signature >> 4) & 0x0F];
378     Identifier[16] = Hex[Signature & 0x0F];
379     Identifier[17] = '-';
380     Identifier[18] = (ValidPartitionTable ? 'A' : 'X');
381     Identifier[19] = 0;
382     TRACE("Identifier: %s\n", Identifier);
383 }
384 
385 static
386 VOID
387 UefiSetupBlockDevices(VOID)
388 {
389     ULONG BlockDeviceIndex;
390     ULONG SystemHandleCount;
391     EFI_STATUS Status;
392     ULONG i;
393 
394     UINTN handle_size = 0;
395     PcBiosDiskCount = 0;
396     UefiBootRootIdentifier = 0;
397 
398     /* 1) Setup a list of boot handles by using the LocateHandle protocol */
399     Status = GlobalSystemTable->BootServices->LocateHandle(ByProtocol, &bioGuid, NULL, &handle_size, handles);
400     handles = MmAllocateMemoryWithType(handle_size, LoaderFirmwareTemporary);
401     Status = GlobalSystemTable->BootServices->LocateHandle(ByProtocol, &bioGuid, NULL, &handle_size, handles);
402     SystemHandleCount = handle_size / sizeof(EFI_HANDLE);
403     InternalUefiDisk = MmAllocateMemoryWithType(sizeof(INTERNAL_UEFI_DISK) * SystemHandleCount, LoaderFirmwareTemporary);
404 
405     BlockDeviceIndex = 0;
406     /* 2) Parse the handle list */
407     for (i = 0; i < SystemHandleCount; ++i)
408     {
409         Status = GlobalSystemTable->BootServices->HandleProtocol(handles[i], &bioGuid, (void**)&bio);
410         if (handles[i] == PublicBootHandle)
411         {
412             OffsetToBoot = i; /* Drive offset in the handles list */
413         }
414 
415         if (EFI_ERROR(Status) ||
416             bio == NULL ||
417             bio->Media->BlockSize == 0 ||
418             bio->Media->BlockSize > 2048)
419         {
420             TRACE("UefiSetupBlockDevices: UEFI has found a block device that failed, skipping\n");
421             continue;
422         }
423         if (bio->Media->LogicalPartition == FALSE)
424         {
425             TRACE("Found root of a HDD\n");
426             PcBiosDiskCount++;
427             InternalUefiDisk[BlockDeviceIndex].ArcDriveNumber = BlockDeviceIndex;
428             InternalUefiDisk[BlockDeviceIndex].UefiRootNumber = i;
429             GetHarddiskInformation(BlockDeviceIndex + FIRST_BIOS_DISK);
430             BlockDeviceIndex++;
431         }
432         else if (handles[i] == PublicBootHandle)
433         {
434             ULONG increment = 0;
435             ULONG i;
436 
437             /* 3) Grab the offset into the array of handles and decrement per volume (valid partition) */
438             for (increment = OffsetToBoot; increment > 0; increment--)
439             {
440                 GlobalSystemTable->BootServices->HandleProtocol(handles[increment], &bioGuid, (void**)&bio);
441                 if (bio->Media->LogicalPartition == FALSE)
442                 {
443                     TRACE("Found root at increment %u\n", increment);
444                     UefiBootRootIdentifier = increment;
445 
446                     for (i = 0; i <= PcBiosDiskCount; ++i)
447                     {
448                         /* Now only of the root drive number is equal to this drive we found above */
449                         if (InternalUefiDisk[i].UefiRootNumber == UefiBootRootIdentifier)
450                         {
451                             InternalUefiDisk[i].IsThisTheBootDrive = TRUE;
452                             PublicBootArcDisk = i;
453                             TRACE("Found Boot drive\n");
454                         }
455                     }
456 
457                     break;
458                 }
459             }
460         }
461     }
462 }
463 
464 static
465 BOOLEAN
466 UefiSetBootpath(VOID)
467 {
468    TRACE("UefiSetBootpath: Setting up boot path\n");
469    GlobalSystemTable->BootServices->HandleProtocol(handles[UefiBootRootIdentifier], &bioGuid, (void**)&bio);
470    FrldrBootDrive = (FIRST_BIOS_DISK + PublicBootArcDisk);
471    if (bio->Media->RemovableMedia == TRUE && bio->Media->BlockSize == 2048)
472    {
473         /* Boot Partition 0xFF is the magic value that indicates booting from CD-ROM (see isoboot.S) */
474         FrldrBootPartition = 0xFF;
475         RtlStringCbPrintfA(FrLdrBootPath, sizeof(FrLdrBootPath),
476                            "multi(0)disk(0)cdrom(%u)", PublicBootArcDisk);
477    }
478    else
479    {
480         ULONG BootPartition;
481         PARTITION_TABLE_ENTRY PartitionEntry;
482 
483         /* This is a hard disk */
484         if (!UefiGetBootPartitionEntry(FrldrBootDrive, &PartitionEntry, &BootPartition))
485         {
486             ERR("Failed to get boot partition entry\n");
487             return FALSE;
488         }
489 
490         RtlStringCbPrintfA(FrLdrBootPath, sizeof(FrLdrBootPath),
491                            "multi(0)disk(0)rdisk(%u)partition(%lu)",
492                            PublicBootArcDisk, BootPartition);
493     }
494 
495     return TRUE;
496 }
497 
498 BOOLEAN
499 UefiInitializeBootDevices(VOID)
500 {
501     ULONG i = 0;
502 
503     DiskReadBufferSize = EFI_PAGE_SIZE;
504     DiskReadBuffer = MmAllocateMemoryWithType(DiskReadBufferSize, LoaderFirmwareTemporary);
505     UefiSetupBlockDevices();
506     UefiSetBootpath();
507 
508     /* Add it, if it's a cdrom */
509     GlobalSystemTable->BootServices->HandleProtocol(handles[UefiBootRootIdentifier], &bioGuid, (void**)&bio);
510     if (bio->Media->RemovableMedia == TRUE && bio->Media->BlockSize == 2048)
511     {
512         PMASTER_BOOT_RECORD Mbr;
513         PULONG Buffer;
514         ULONG Checksum = 0;
515         ULONG Signature;
516 
517         /* Read the MBR */
518         if (!MachDiskReadLogicalSectors(FrldrBootDrive, 16ULL, 1, DiskReadBuffer))
519         {
520             ERR("Reading MBR failed\n");
521             return FALSE;
522         }
523 
524         Buffer = (ULONG*)DiskReadBuffer;
525         Mbr = (PMASTER_BOOT_RECORD)DiskReadBuffer;
526 
527         Signature = Mbr->Signature;
528         TRACE("Signature: %x\n", Signature);
529 
530         /* Calculate the MBR checksum */
531         for (i = 0; i < 2048 / sizeof(ULONG); i++)
532         {
533             Checksum += Buffer[i];
534         }
535         Checksum = ~Checksum + 1;
536         TRACE("Checksum: %x\n", Checksum);
537 
538         /* Fill out the ARC disk block */
539         AddReactOSArcDiskInfo(FrLdrBootPath, Signature, Checksum, TRUE);
540 
541         FsRegisterDevice(FrLdrBootPath, &UefiDiskVtbl);
542         PcBiosDiskCount++; // This is not accounted for in the number of pre-enumerated BIOS drives!
543         TRACE("Additional boot drive detected: 0x%02X\n", (int)FrldrBootDrive);
544     }
545     return TRUE;
546 }
547 
548 UCHAR
549 UefiGetFloppyCount(VOID)
550 {
551     /* No floppy for you for now... */
552     return 0;
553 }
554 
555 BOOLEAN
556 UefiDiskReadLogicalSectors(
557     IN UCHAR DriveNumber,
558     IN ULONGLONG SectorNumber,
559     IN ULONG SectorCount,
560     OUT PVOID Buffer)
561 {
562     ULONG UefiDriveNumber;
563 
564     UefiDriveNumber = InternalUefiDisk[DriveNumber - FIRST_BIOS_DISK].UefiRootNumber;
565     TRACE("UefiDiskReadLogicalSectors: DriveNumber: %d\n", UefiDriveNumber);
566     GlobalSystemTable->BootServices->HandleProtocol(handles[UefiDriveNumber], &bioGuid, (void**)&bio);
567 
568     /* Devices setup */
569     bio->ReadBlocks(bio, bio->Media->MediaId, SectorNumber, SectorCount * bio->Media->BlockSize, Buffer);
570     return TRUE;
571 }
572 
573 BOOLEAN
574 UefiDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
575 {
576     ULONG UefiDriveNumber;
577 
578     UefiDriveNumber = InternalUefiDisk[DriveNumber - FIRST_BIOS_DISK].UefiRootNumber;
579     GlobalSystemTable->BootServices->HandleProtocol(handles[UefiDriveNumber], &bioGuid, (void**)&bio);
580     Geometry->Cylinders = 1;      // Not relevant for the UEFI BIO protocol
581     Geometry->Heads = 1;          // Not relevant for the UEFI BIO protocol
582     Geometry->Sectors = bio->Media->LastBlock;        // Number of sectors per track
583     Geometry->BytesPerSector = bio->Media->BlockSize; // Number of bytes per sector
584 
585     return TRUE;
586 }
587 
588 ULONG
589 UefiDiskGetCacheableBlockCount(UCHAR DriveNumber)
590 {
591     ULONG UefiDriveNumber = InternalUefiDisk[DriveNumber - FIRST_BIOS_DISK].UefiRootNumber;
592     TRACE("UefiDiskGetCacheableBlockCount: DriveNumber: %d\n", UefiDriveNumber);
593 
594     GlobalSystemTable->BootServices->HandleProtocol(handles[UefiDriveNumber], &bioGuid, (void**)&bio);
595     return bio->Media->LastBlock;
596 }
597