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