ReactOS 0.4.16-dev-2332-g4cba65d
uefidisk.c
Go to the documentation of this file.
1/*
2 * PROJECT: FreeLoader UEFI Support
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
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>
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/* Maximum block size we support (8KB) - filters out flash devices */
21#define MAX_SUPPORTED_BLOCK_SIZE 8192
22
23/* GPT (GUID Partition Table) definitions */
24#define EFI_PARTITION_HEADER_SIGNATURE "EFI PART"
25#define EFI_HEADER_LOCATION 1ULL
26#define EFI_TABLE_REVISION 0x00010000
27#define EFI_PARTITION_ENTRIES_BLOCK 2ULL
28#define EFI_PARTITION_ENTRY_COUNT 128
29#define EFI_PARTITION_ENTRY_SIZE 128
30#define EFI_PARTITION_NAME_LENGTH 36
31
32/* GPT Partition Type GUIDs */
33#define EFI_PART_TYPE_UNUSED_GUID \
34 {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
35
36#define EFI_PART_TYPE_EFI_SYSTEM_PART_GUID \
37 {0xc12a7328, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b}}
38
39#include <pshpack1.h>
40
41/* GPT Table Header */
42typedef struct _GPT_TABLE_HEADER
43{
44 CHAR8 Signature[8]; /* "EFI PART" */
45 UINT32 Revision; /* 0x00010000 */
46 UINT32 HeaderSize; /* Size of header (usually 92) */
47 UINT32 HeaderCrc32; /* CRC32 of header */
48 UINT32 Reserved; /* Must be 0 */
49 UINT64 MyLba; /* LBA of this header */
50 UINT64 AlternateLba; /* LBA of alternate header */
51 UINT64 FirstUsableLba; /* First usable LBA for partitions */
52 UINT64 LastUsableLba; /* Last usable LBA for partitions */
53 EFI_GUID DiskGuid; /* Disk GUID */
54 UINT64 PartitionEntryLba; /* LBA of partition entries array */
55 UINT32 NumberOfPartitionEntries; /* Number of partition entries */
56 UINT32 SizeOfPartitionEntry; /* Size of each entry (usually 128) */
57 UINT32 PartitionEntryArrayCrc32; /* CRC32 of partition entries array */
59
60/* GPT Partition Entry */
62{
63 EFI_GUID PartitionTypeGuid; /* Partition type GUID */
64 EFI_GUID UniquePartitionGuid; /* Unique partition GUID */
65 UINT64 StartingLba; /* Starting LBA */
66 UINT64 EndingLba; /* Ending LBA */
67 UINT64 Attributes; /* Partition attributes */
68 CHAR16 PartitionName[EFI_PARTITION_NAME_LENGTH]; /* Partition name (UTF-16) */
70
71#include <poppack.h>
72
73typedef struct tagDISKCONTEXT
74{
81
82typedef struct _INTERNAL_UEFI_DISK
83{
90
91/* GLOBALS *******************************************************************/
92
95extern EFI_HANDLE PublicBootHandle; /* Freeldr itself */
96
97/* Made to match BIOS */
104
109
110static const CHAR Hex[] = "0123456789abcdef";
111static CHAR PcDiskIdentifier[32][20];
112
113/* UEFI-specific */
120
121static
124 IN PVOID Pointer,
126{
128
129 if (Alignment <= 1)
130 return TRUE;
131
132 Value = (ULONG_PTR)Pointer;
133 return ((Value & (Alignment - 1)) == 0);
134}
135
136static
140{
141 ULONG RequiredAlignment = (Alignment == 0) ? 1 : Alignment;
143
144 if (DiskReadBuffer != NULL && DiskReadBufferAlignment >= RequiredAlignment &&
145 UefiIsAlignedPointer(DiskReadBuffer, RequiredAlignment))
146 {
147 return TRUE;
148 }
149
150 DiskReadBufferAlignment = RequiredAlignment;
151
153 {
155 {
157 }
158 else
159 {
161 }
162
167 }
168
170 DiskReadBufferSize + RequiredAlignment,
171 (void**)&DiskReadBufferRaw);
173 {
174 /* This can sometimes happen on Mac firmware and probably happens on other EFI 1.x devices as well. */
175 WARN("Failed to allocate aligned disk read buffer using AllocatePool, trying MmAllocateMemoryWithType (buffer size = 0x%X, alignment %lu)\n",
176 DiskReadBufferSize, RequiredAlignment);
179 if (DiskReadBufferRaw == NULL)
180 {
181 /* That failed too */
182 ERR("Failed to allocate aligned disk read buffer (buffer size = 0x%X, alignment %lu)\n",
183 DiskReadBufferSize, RequiredAlignment);
184 return FALSE;
185 }
186
188 }
189
191
193 if (!UefiIsAlignedPointer(DiskReadBuffer, RequiredAlignment))
194 {
195 ERR("Aligned disk read buffer is not properly aligned (align %lu)\n", RequiredAlignment);
196 return FALSE;
197 }
198
199 return TRUE;
200}
201
202/* FUNCTIONS *****************************************************************/
203
204PCHAR
206{
207 TRACE("GetHarddiskIdentifier: DriveNumber: %d\n", DriveNumber);
208 if (DriveNumber < FIRST_BIOS_DISK)
209 return NULL;
210 return PcDiskIdentifier[DriveNumber - FIRST_BIOS_DISK];
211}
212
213static LONG lReportError = 0; // >= 0: display errors; < 0: hide errors.
214
215LONG
217{
218 /* Set the reference count */
219 if (bShowError) ++lReportError;
220 else --lReportError;
221 return lReportError;
222}
223
224
225/* GPT Support Functions ******************************************************/
226
227static
230 IN UCHAR DriveNumber,
231 OUT PGPT_TABLE_HEADER GptHeader)
232{
233 ULONG ArcDriveIndex;
234 EFI_BLOCK_IO* BlockIo;
236 ULONG BlockSize;
237 ULONG IoAlign;
238 ULONGLONG HeaderLba = EFI_HEADER_LOCATION;
239
240 if (DriveNumber < FIRST_BIOS_DISK)
241 return FALSE;
242
243 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
244 if (ArcDriveIndex >= PcBiosDiskCount || InternalUefiDisk == NULL)
245 return FALSE;
246
248 InternalUefiDisk[ArcDriveIndex].Handle,
250 (VOID**)&BlockIo);
251
252 if (EFI_ERROR(Status) || BlockIo == NULL)
253 return FALSE;
254
255 if (!BlockIo->Media->MediaPresent)
256 return FALSE;
257
258 BlockSize = BlockIo->Media->BlockSize;
259 IoAlign = BlockIo->Media->IoAlign;
260
262 {
263 ERR("Failed to align disk read buffer for drive %d\n", DriveNumber);
264 return FALSE;
265 }
266
267 /* Read GPT header from LBA 1 */
268 Status = BlockIo->ReadBlocks(
269 BlockIo,
270 BlockIo->Media->MediaId,
271 HeaderLba,
272 BlockSize,
274
275 if (EFI_ERROR(Status))
276 return FALSE;
277
278 RtlCopyMemory(GptHeader, DiskReadBuffer, sizeof(GPT_TABLE_HEADER));
279
280 /* Verify GPT signature */
281 if (memcmp(GptHeader->Signature, EFI_PARTITION_HEADER_SIGNATURE, 8) != 0)
282 return FALSE;
283
284 /* Verify revision */
285 if (GptHeader->Revision != EFI_TABLE_REVISION)
286 {
287 TRACE("GPT header has unsupported revision: 0x%x\n", GptHeader->Revision);
288 return FALSE;
289 }
290
291 return TRUE;
292}
293
296 IN UCHAR DriveNumber,
298 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
299{
300 GPT_TABLE_HEADER GptHeader;
301 GPT_PARTITION_ENTRY GptEntry;
302 ULONG ArcDriveIndex;
303 EFI_BLOCK_IO* BlockIo;
305 ULONG BlockSize;
306 ULONGLONG EntryLba;
307 ULONG EntryOffset;
308 ULONG EntriesPerBlock;
310
311 if (DriveNumber < FIRST_BIOS_DISK)
312 return FALSE;
313
314 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
315 if (ArcDriveIndex >= PcBiosDiskCount || InternalUefiDisk == NULL)
316 return FALSE;
317
318 /* Read GPT header */
319 if (!UefiReadGptHeader(DriveNumber, &GptHeader))
320 return FALSE;
321
322 /* Validate partition number */
324 return FALSE;
325
326 /* Convert to 0-based index */
327 ULONG EntryIndex = PartitionNumber - 1;
328
330 InternalUefiDisk[ArcDriveIndex].Handle,
332 (VOID**)&BlockIo);
333
334 if (EFI_ERROR(Status) || BlockIo == NULL)
335 return FALSE;
336
337 BlockSize = BlockIo->Media->BlockSize;
338 EntriesPerBlock = BlockSize / GptHeader.SizeOfPartitionEntry;
339 EntryLba = GptHeader.PartitionEntryLba + (EntryIndex / EntriesPerBlock);
340 EntryOffset = (EntryIndex % EntriesPerBlock) * GptHeader.SizeOfPartitionEntry;
341
342 /* Read the block containing the partition entry */
343 Status = BlockIo->ReadBlocks(
344 BlockIo,
345 BlockIo->Media->MediaId,
346 EntryLba,
347 BlockSize,
349
350 if (EFI_ERROR(Status))
351 return FALSE;
352
353 /* Extract partition entry */
354 RtlCopyMemory(&GptEntry, (PUCHAR)DiskReadBuffer + EntryOffset, sizeof(GPT_PARTITION_ENTRY));
355
356 /* Check if partition is unused */
357 if (memcmp(&GptEntry.PartitionTypeGuid, &UnusedGuid, sizeof(EFI_GUID)) == 0)
358 return FALSE;
359
360 /* Convert GPT entry to MBR-style PARTITION_TABLE_ENTRY */
361 RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
362
363 /* Calculate sector offset and count */
364 /* GPT uses LBA, convert to 512-byte sectors */
365 ULONGLONG StartLba = GptEntry.StartingLba;
366 ULONGLONG EndLba = GptEntry.EndingLba;
367 ULONGLONG SectorCount = (EndLba - StartLba + 1);
368
369 /* For GPT, we need to convert from device block size to 512-byte sectors */
370 ULONGLONG StartSector = (StartLba * BlockSize) / 512;
371 ULONGLONG SectorCount512 = (SectorCount * BlockSize) / 512;
372
373 PartitionTableEntry->SectorCountBeforePartition = (ULONG)StartSector;
374 PartitionTableEntry->PartitionSectorCount = (ULONG)SectorCount512;
375 PartitionTableEntry->SystemIndicator = PARTITION_GPT; /* Mark as GPT partition */
376
377 return TRUE;
378}
379
380static
383 IN UCHAR DriveNumber,
384 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
385 OUT PULONG BootPartition)
386{
387 ULONG PartitionNum;
388 ULONG ArcDriveIndex;
389 EFI_BLOCK_IO* BootBlockIo;
391 ULONGLONG BootPartitionSize;
392 PARTITION_TABLE_ENTRY TempPartitionEntry;
393
394 TRACE("UefiGetBootPartitionEntry: DriveNumber: %d\n", DriveNumber - FIRST_BIOS_DISK);
395
396 if (DriveNumber < FIRST_BIOS_DISK)
397 return FALSE;
398
399 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
400 if (ArcDriveIndex >= PcBiosDiskCount || handles == NULL || UefiBootRootIndex >= HandleCount)
401 return FALSE;
402
403 /* Get the boot handle's Block I/O protocol to determine partition offset/size */
407 (VOID**)&BootBlockIo);
408
409 if (EFI_ERROR(Status) || BootBlockIo == NULL)
410 {
411 ERR("Failed to get Block I/O protocol for boot handle\n");
412 return FALSE;
413 }
414
415 /* For logical partitions, UEFI Block I/O protocol starts at block 0 */
416 /* We need to find which partition it corresponds to by comparing sizes */
417 BootPartitionSize = BootBlockIo->Media->LastBlock + 1;
418
419 TRACE("Boot partition: Size=%llu blocks, BlockSize=%lu\n",
420 BootPartitionSize, BootBlockIo->Media->BlockSize);
421
422 /* If boot handle is the root device itself (not a logical partition) */
423 if (!BootBlockIo->Media->LogicalPartition)
424 {
425 TRACE("Boot handle is root device, using partition 0\n");
426 *BootPartition = 0;
427 if (PartitionTableEntry != NULL)
428 {
429 RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
430 }
431 return TRUE;
432 }
433
434 /* Boot handle is a logical partition - find matching partition entry */
435 /* Try to detect GPT first by reading GPT header */
436 GPT_TABLE_HEADER GptHeader;
437 BOOLEAN IsGpt = UefiReadGptHeader(DriveNumber, &GptHeader);
438
439 if (IsGpt)
440 {
441 /* For GPT, iterate through GPT partition entries */
442 GPT_TABLE_HEADER GptHeader;
443 GPT_PARTITION_ENTRY GptEntry;
444 ULONG ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
445 EFI_BLOCK_IO* RootBlockIo;
446 ULONG BlockSize;
447 ULONGLONG EntryLba;
448 ULONG EntryOffset;
449 ULONG EntriesPerBlock;
452
453 if (!UefiReadGptHeader(DriveNumber, &GptHeader))
454 {
455 ERR("Failed to read GPT header\n");
456 return FALSE;
457 }
458
460 InternalUefiDisk[ArcDriveIndex].Handle,
462 (VOID**)&RootBlockIo);
463
464 if (EFI_ERROR(Status) || RootBlockIo == NULL)
465 return FALSE;
466
467 BlockSize = RootBlockIo->Media->BlockSize;
468 EntriesPerBlock = BlockSize / GptHeader.SizeOfPartitionEntry;
469
470 /* Iterate through GPT partition entries */
471 for (ULONG i = 0; i < GptHeader.NumberOfPartitionEntries; i++)
472 {
473 EntryLba = GptHeader.PartitionEntryLba + (i / EntriesPerBlock);
474 EntryOffset = (i % EntriesPerBlock) * GptHeader.SizeOfPartitionEntry;
475
476 /* Read the block containing the partition entry */
477 Status = RootBlockIo->ReadBlocks(
478 RootBlockIo,
479 RootBlockIo->Media->MediaId,
480 EntryLba,
481 BlockSize,
483
484 if (EFI_ERROR(Status))
485 continue;
486
487 /* Extract partition entry */
488 RtlCopyMemory(&GptEntry, (PUCHAR)DiskReadBuffer + EntryOffset, sizeof(GPT_PARTITION_ENTRY));
489
490 /* Skip unused partitions */
491 if (memcmp(&GptEntry.PartitionTypeGuid, &UnusedGuid, sizeof(EFI_GUID)) == 0)
492 continue;
493
494 /* Calculate partition size in blocks */
495 ULONGLONG PartitionSizeBlocks = GptEntry.EndingLba - GptEntry.StartingLba + 1;
496
497 TRACE("GPT Partition %lu: StartLba=%llu, EndLba=%llu, SizeBlocks=%llu\n",
498 i + 1, GptEntry.StartingLba, GptEntry.EndingLba, PartitionSizeBlocks);
499
500 /* Match partition by size (within 1 block tolerance for rounding) */
501 if (PartitionSizeBlocks == BootPartitionSize ||
502 (PartitionSizeBlocks > 0 &&
503 (PartitionSizeBlocks - 1 <= BootPartitionSize &&
504 BootPartitionSize <= PartitionSizeBlocks + 1)))
505 {
506 TRACE("Found matching GPT partition %lu: Size matches (%llu blocks)\n",
507 i + 1, BootPartitionSize);
508
509 *BootPartition = i + 1; /* GPT partitions are 1-indexed */
510
511 /* Convert GPT entry to MBR-style entry for compatibility */
512 if (PartitionTableEntry != NULL)
513 {
514 RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
515 ULONGLONG StartSector = (GptEntry.StartingLba * BlockSize) / 512;
516 ULONGLONG SectorCount = (PartitionSizeBlocks * BlockSize) / 512;
517 PartitionTableEntry->SectorCountBeforePartition = (ULONG)StartSector;
518 PartitionTableEntry->PartitionSectorCount = (ULONG)SectorCount;
519 PartitionTableEntry->SystemIndicator = PARTITION_GPT;
520 }
521 return TRUE;
522 }
523 }
524 }
525 else
526 {
527 /* MBR partition matching */
528 PartitionNum = FIRST_PARTITION;
529 while (DiskGetPartitionEntry(DriveNumber, PartitionNum, &TempPartitionEntry))
530 {
531 ULONGLONG PartitionSizeSectors = TempPartitionEntry.PartitionSectorCount;
532 ULONGLONG PartitionSizeBlocks;
533
534 /* Convert partition size from MBR sectors (always 512 bytes) to UEFI blocks */
535 /* MBR partition table always uses 512-byte sectors per specification */
536 /* UEFI Block I/O protocol reports sizes in device's BlockSize bytes */
537 /* Compare in bytes to avoid rounding issues, then convert to boot partition's block size */
538 ULONGLONG PartitionSizeBytes = PartitionSizeSectors * 512ULL;
539 PartitionSizeBlocks = PartitionSizeBytes / BootBlockIo->Media->BlockSize;
540
541 TRACE("Partition %lu: SizeSectors=%llu, SizeBlocks=%llu\n",
542 PartitionNum, PartitionSizeSectors, PartitionSizeBlocks);
543
544 /* Match partition by size (within 1 block tolerance for rounding) */
545 if (PartitionSizeBlocks == BootPartitionSize ||
546 (PartitionSizeBlocks > 0 &&
547 (PartitionSizeBlocks - 1 <= BootPartitionSize &&
548 BootPartitionSize <= PartitionSizeBlocks + 1)))
549 {
550 TRACE("Found matching partition %lu: Size matches (%llu blocks)\n",
551 PartitionNum, BootPartitionSize);
552
553 *BootPartition = PartitionNum;
554 if (PartitionTableEntry != NULL)
555 {
556 RtlCopyMemory(PartitionTableEntry, &TempPartitionEntry, sizeof(*PartitionTableEntry));
557 }
558 return TRUE;
559 }
560
561 PartitionNum++;
562 }
563 }
564
565 /* If we couldn't find a match, check if it's a CD-ROM (special case) */
566 if (BootBlockIo->Media->RemovableMedia && BootBlockIo->Media->BlockSize == 2048)
567 {
568 TRACE("Boot device is CD-ROM, using partition 0xFF\n");
569 *BootPartition = 0xFF;
570 if (PartitionTableEntry != NULL)
571 {
572 RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
573 }
574 return TRUE;
575 }
576
577 /* Fallback: if we can't determine, use partition 1 */
578 ERR("Could not determine boot partition, using partition 1 as fallback\n");
579 PartitionNum = FIRST_PARTITION;
580 if (DiskGetPartitionEntry(DriveNumber, PartitionNum, &TempPartitionEntry))
581 {
582 *BootPartition = PartitionNum;
583 if (PartitionTableEntry != NULL)
584 {
585 RtlCopyMemory(PartitionTableEntry, &TempPartitionEntry, sizeof(*PartitionTableEntry));
586 }
587 return TRUE;
588 }
589
590 return FALSE;
591}
592
593static
596{
599 return ESUCCESS;
600}
601
602static
605{
608
609 /*
610 * The ARC specification mentions that for partitions, StartingAddress and
611 * EndingAddress are the start and end positions of the partition in terms
612 * of byte offsets from the start of the disk.
613 * CurrentAddress is the current offset into (i.e. relative to) the partition.
614 */
615 Information->StartingAddress.QuadPart = Context->SectorOffset * Context->SectorSize;
616 Information->EndingAddress.QuadPart = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
617 Information->CurrentAddress.QuadPart = Context->SectorNumber * Context->SectorSize;
618
619 Information->Type = DiskPeripheral; /* No floppy for you for now... */
620
621 return ESUCCESS;
622}
623
624static
626UefiDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
627{
629 UCHAR DriveNumber;
630 ULONG DrivePartition, SectorSize;
633 ULONG ArcDriveIndex;
634 PARTITION_TABLE_ENTRY PartitionTableEntry;
635 EFI_BLOCK_IO* BlockIo;
637
638 TRACE("UefiDiskOpen: File ID: %p, Path: %s\n", FileId, Path);
639
640 if (DiskReadBufferSize == 0)
641 {
642 ERR("DiskOpen(): DiskReadBufferSize is 0, something is wrong.\n");
643 ASSERT(FALSE);
644 return ENOMEM;
645 }
646
647 if (!DissectArcPath(Path, NULL, &DriveNumber, &DrivePartition))
648 return EINVAL;
649
650 TRACE("Opening disk: DriveNumber: %d, DrivePartition: %d\n", DriveNumber, DrivePartition);
651
652 if (DriveNumber < FIRST_BIOS_DISK)
653 return EINVAL;
654
655 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
656 if (ArcDriveIndex >= PcBiosDiskCount || InternalUefiDisk == NULL)
657 return EINVAL;
658
659 /* Get Block I/O protocol for this drive */
661 InternalUefiDisk[ArcDriveIndex].Handle,
663 (VOID**)&BlockIo);
664
665 if (EFI_ERROR(Status) || BlockIo == NULL)
666 {
667 ERR("Failed to get Block I/O protocol for drive %d\n", DriveNumber);
668 return EINVAL;
669 }
670
671 /* Check media is present */
672 if (!BlockIo->Media->MediaPresent)
673 {
674 ERR("Media not present for drive %d\n", DriveNumber);
675 return EINVAL;
676 }
677
678 SectorSize = BlockIo->Media->BlockSize;
679
680 if (DrivePartition != 0xff && DrivePartition != 0)
681 {
682 if (!DiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
683 return EINVAL;
684
685 SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
686 SectorCount = PartitionTableEntry.PartitionSectorCount;
687 }
688 else
689 {
690 GEOMETRY Geometry;
691 if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
692 return EINVAL;
693
694 if (SectorSize != Geometry.BytesPerSector)
695 {
696 ERR("SectorSize (%lu) != Geometry.BytesPerSector (%lu), expect problems!\n",
697 SectorSize, Geometry.BytesPerSector);
698 }
699
700 SectorOffset = 0;
701 SectorCount = Geometry.Sectors;
702 }
703
705 if (!Context)
706 return ENOMEM;
707
708 Context->DriveNumber = DriveNumber;
709 Context->SectorSize = SectorSize;
710 Context->SectorOffset = SectorOffset;
711 Context->SectorCount = SectorCount;
712 Context->SectorNumber = 0;
714 return ESUCCESS;
715}
716
717static
720{
722 UCHAR* Ptr = (UCHAR*)Buffer;
723 ULONG Length, TotalSectors, MaxSectors, ReadSectors;
725 BOOLEAN ret;
726 EFI_BLOCK_IO* BlockIo;
728 ULONG ArcDriveIndex;
729
731
732
733 TotalSectors = (N + Context->SectorSize - 1) / Context->SectorSize;
734 MaxSectors = DiskReadBufferSize / Context->SectorSize;
735 SectorOffset = Context->SectorOffset + Context->SectorNumber;
736
737 // If MaxSectors is 0, this will lead to infinite loop.
738 // In release builds assertions are disabled, however we also have sanity checks in DiskOpen()
739 ASSERT(MaxSectors > 0);
740
741 if (MaxSectors == 0)
742 {
743 ERR("MaxSectors is 0, cannot read\n");
744 *Count = 0;
745 return EIO;
746 }
747
748 ArcDriveIndex = Context->DriveNumber - FIRST_BIOS_DISK;
749 if (ArcDriveIndex >= PcBiosDiskCount || InternalUefiDisk == NULL)
750 {
751 ERR("Invalid drive number %d\n", Context->DriveNumber);
752 *Count = 0;
753 return EINVAL;
754 }
755
756 /* Get Block I/O protocol */
758 InternalUefiDisk[ArcDriveIndex].Handle,
760 (VOID**)&BlockIo);
761
762 if (EFI_ERROR(Status) || BlockIo == NULL)
763 {
764 ERR("Failed to get Block I/O protocol\n");
765 *Count = 0;
766 return EIO;
767 }
768
770 {
771 ERR("Failed to align disk read buffer\n");
772 *Count = 0;
773 return EIO;
774 }
775
776 ret = TRUE;
777
778 while (TotalSectors)
779 {
780 ReadSectors = min(TotalSectors, MaxSectors);
781
782 Status = BlockIo->ReadBlocks(
783 BlockIo,
784 BlockIo->Media->MediaId,
786 ReadSectors * Context->SectorSize,
788
789 if (EFI_ERROR(Status))
790 {
791 ERR("ReadBlocks failed: Status = 0x%lx\n", (ULONG)Status);
792 ret = FALSE;
793 break;
794 }
795
796 Length = ReadSectors * Context->SectorSize;
797 Length = min(Length, N);
798
800
801 Ptr += Length;
802 N -= Length;
803 SectorOffset += ReadSectors;
804 TotalSectors -= ReadSectors;
805 }
806
808 Context->SectorNumber = SectorOffset - Context->SectorOffset;
809
810 return (ret ? ESUCCESS : EIO);
811}
812
813static
816{
818 LARGE_INTEGER NewPosition = *Position;
819
820 switch (SeekMode)
821 {
822 case SeekAbsolute:
823 break;
824 case SeekRelative:
825 NewPosition.QuadPart += (Context->SectorNumber * Context->SectorSize);
826 break;
827 default:
828 ASSERT(FALSE);
829 return EINVAL;
830 }
831
832 if (NewPosition.QuadPart & (Context->SectorSize - 1))
833 return EINVAL;
834
835 /* Convert in number of sectors */
836 NewPosition.QuadPart /= Context->SectorSize;
837
838 /* HACK: CDROMs may have a SectorCount of 0 */
839 if (Context->SectorCount != 0 && NewPosition.QuadPart >= Context->SectorCount)
840 return EINVAL;
841
842 Context->SectorNumber = NewPosition.QuadPart;
843 return ESUCCESS;
844}
845
846static const DEVVTBL UefiDiskVtbl =
847{
853};
854
855static
856VOID
858{
861 ULONG i;
862 ULONG Checksum;
864 BOOLEAN ValidPartitionTable;
865 CHAR ArcName[MAX_PATH];
866 PARTITION_TABLE_ENTRY PartitionTableEntry;
867 ULONG ArcDriveIndex;
869
870 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
871 if (ArcDriveIndex >= 32)
872 return;
873
874 Identifier = PcDiskIdentifier[ArcDriveIndex];
875
876 /* Detect disk partition type */
877 DiskDetectPartitionType(DriveNumber);
878
879 /* Read the MBR */
880 if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, DiskReadBuffer))
881 {
882 ERR("Reading MBR failed\n");
883 /* We failed, use a default identifier */
884 sprintf(Identifier, "BIOSDISK%d", ArcDriveIndex);
885 return;
886 }
887
890
891 Signature = Mbr->Signature;
892 TRACE("Signature: %x\n", Signature);
893
894 /* Calculate the MBR checksum */
895 Checksum = 0;
896 for (i = 0; i < 512 / sizeof(ULONG); i++)
897 {
898 Checksum += Buffer[i];
899 }
900 Checksum = ~Checksum + 1;
901 TRACE("Checksum: %x\n", Checksum);
902
903 ValidPartitionTable = (Mbr->MasterBootRecordMagic == 0xAA55);
904
905 /* Fill out the ARC disk block */
906 sprintf(ArcName, "multi(0)disk(0)rdisk(%u)", ArcDriveIndex);
907 AddReactOSArcDiskInfo(ArcName, Signature, Checksum, ValidPartitionTable);
908
909 sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(0)", ArcDriveIndex);
911
912 /* Add partitions */
915 while (DiskGetPartitionEntry(DriveNumber, i, &PartitionTableEntry))
916 {
917 if (PartitionTableEntry.SystemIndicator != PARTITION_ENTRY_UNUSED)
918 {
919 sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(%lu)", ArcDriveIndex, i);
921 }
922 i++;
923 }
925
926 if (ArcDriveIndex < PcBiosDiskCount && InternalUefiDisk != NULL)
927 {
928 InternalUefiDisk[ArcDriveIndex].NumOfPartitions = i;
929 }
930
931 /* Convert checksum and signature to identifier string */
932 Identifier[0] = Hex[(Checksum >> 28) & 0x0F];
933 Identifier[1] = Hex[(Checksum >> 24) & 0x0F];
934 Identifier[2] = Hex[(Checksum >> 20) & 0x0F];
935 Identifier[3] = Hex[(Checksum >> 16) & 0x0F];
936 Identifier[4] = Hex[(Checksum >> 12) & 0x0F];
937 Identifier[5] = Hex[(Checksum >> 8) & 0x0F];
938 Identifier[6] = Hex[(Checksum >> 4) & 0x0F];
939 Identifier[7] = Hex[Checksum & 0x0F];
940 Identifier[8] = '-';
941 Identifier[9] = Hex[(Signature >> 28) & 0x0F];
942 Identifier[10] = Hex[(Signature >> 24) & 0x0F];
943 Identifier[11] = Hex[(Signature >> 20) & 0x0F];
944 Identifier[12] = Hex[(Signature >> 16) & 0x0F];
945 Identifier[13] = Hex[(Signature >> 12) & 0x0F];
946 Identifier[14] = Hex[(Signature >> 8) & 0x0F];
947 Identifier[15] = Hex[(Signature >> 4) & 0x0F];
948 Identifier[16] = Hex[Signature & 0x0F];
949 Identifier[17] = '-';
950 Identifier[18] = (ValidPartitionTable ? 'A' : 'X');
951 Identifier[19] = 0;
952 TRACE("Identifier: %s\n", Identifier);
953}
954
955static
956VOID
958{
959 ULONG BlockDeviceIndex;
960 ULONG SystemHandleCount;
962 ULONG i;
963 UINTN HandleSize = 0;
964 EFI_BLOCK_IO* BlockIo;
965
966 PcBiosDiskCount = 0;
968
969 /* Step 1: Get the size needed for handles buffer - no matter how it fails we're good */
973 NULL,
974 &HandleSize,
975 NULL);
976
977 if (HandleSize == 0)
978 {
979 ERR("Failed to get handle buffer size: Status = 0x%lx\n", (ULONG)Status);
980 return;
981 }
982
983 SystemHandleCount = HandleSize / sizeof(EFI_HANDLE);
984 if (SystemHandleCount == 0)
985 {
986 ERR("No block devices found\n");
987 return;
988 }
989
990 /* Step 2: Allocate buffer for handles */
992 if (handles == NULL)
993 {
994 ERR("Failed to allocate memory for handles\n");
995 return;
996 }
997
998 /* Step 3: Get actual handles */
1000 ByProtocol,
1001 &BlockIoGuid,
1002 NULL,
1003 &HandleSize,
1004 handles);
1005
1006 if (EFI_ERROR(Status))
1007 {
1008 ERR("Failed to locate block device handles: Status = 0x%lx\n", (ULONG)Status);
1009 return;
1010 }
1011
1012 HandleCount = SystemHandleCount;
1013
1014 /* Step 4: Allocate internal disk structure */
1016 sizeof(INTERNAL_UEFI_DISK) * SystemHandleCount,
1018
1019 if (InternalUefiDisk == NULL)
1020 {
1021 ERR("Failed to allocate memory for internal disk structure\n");
1022 return;
1023 }
1024
1025 RtlZeroMemory(InternalUefiDisk, sizeof(INTERNAL_UEFI_DISK) * SystemHandleCount);
1026
1027 /* Step 5: Find boot handle and determine if it's a root device or partition */
1029 for (i = 0; i < SystemHandleCount; i++)
1030 {
1031 if (handles[i] == PublicBootHandle)
1032 {
1034 TRACE("Found boot handle at index %lu\n", i);
1035
1036 /* Check if boot handle is a root device or partition */
1038 handles[i],
1039 &BlockIoGuid,
1040 (VOID**)&BlockIo);
1041
1042 if (!EFI_ERROR(Status) && BlockIo != NULL)
1043 {
1044 TRACE("Boot handle: LogicalPartition=%s, RemovableMedia=%s, BlockSize=%lu\n",
1045 BlockIo->Media->LogicalPartition ? "TRUE" : "FALSE",
1046 BlockIo->Media->RemovableMedia ? "TRUE" : "FALSE",
1047 BlockIo->Media->BlockSize);
1048 }
1049 break;
1050 }
1051 }
1052
1053 /* Step 6: Enumerate root block devices (skip logical partitions) */
1054 BlockDeviceIndex = 0;
1055 for (i = 0; i < SystemHandleCount; i++)
1056 {
1058 handles[i],
1059 &BlockIoGuid,
1060 (VOID**)&BlockIo);
1061
1062 if (EFI_ERROR(Status))
1063 {
1064 TRACE("HandleProtocol failed for handle %lu: Status = 0x%lx\n", i, (ULONG)Status);
1065 continue;
1066 }
1067
1068 if (BlockIo == NULL)
1069 {
1070 TRACE("BlockIo is NULL for handle %lu\n", i);
1071 continue;
1072 }
1073
1074 if (!BlockIo->Media->MediaPresent)
1075 {
1076 TRACE("Media not present for handle %lu\n", i);
1077 continue;
1078 }
1079
1080 if (BlockIo->Media->BlockSize == 0)
1081 {
1082 TRACE("Invalid block size (0) for handle %lu\n", i);
1083 continue;
1084 }
1085
1086 /* Filter out devices with unusually large block sizes (flash devices) */
1087 if (BlockIo->Media->BlockSize > MAX_SUPPORTED_BLOCK_SIZE)
1088 {
1089 TRACE("Block size too large (%lu) for handle %lu, skipping\n",
1090 BlockIo->Media->BlockSize, i);
1091 continue;
1092 }
1093
1094 /* Logical partitions are handled separately by partition scanning */
1095 if (BlockIo->Media->LogicalPartition)
1096 {
1097 /* If boot handle is a logical partition, we need to find its parent root device */
1098 /* For now, we'll handle this after enumeration by matching handles */
1099 TRACE("Skipping logical partition handle %lu\n", i);
1100 continue;
1101 }
1102
1103 /* This is a root block device */
1104 TRACE("Found root block device at index %lu: BlockSize=%lu, LastBlock=%llu\n",
1105 i, BlockIo->Media->BlockSize, BlockIo->Media->LastBlock);
1106
1107 InternalUefiDisk[BlockDeviceIndex].ArcDriveNumber = BlockDeviceIndex;
1108 InternalUefiDisk[BlockDeviceIndex].UefiHandleIndex = i;
1109 InternalUefiDisk[BlockDeviceIndex].Handle = handles[i];
1110 InternalUefiDisk[BlockDeviceIndex].IsThisTheBootDrive = FALSE;
1111
1112 /* Check if this root device contains the boot partition */
1113 /* If boot handle is a logical partition, we need to find which root device it belongs to */
1114 /* For now, if boot handle index matches, mark it as boot device */
1115 if (i == UefiBootRootIndex)
1116 {
1117 InternalUefiDisk[BlockDeviceIndex].IsThisTheBootDrive = TRUE;
1118 PublicBootArcDisk = BlockDeviceIndex;
1119 TRACE("Boot device is at ARC drive index %lu (root device)\n", BlockDeviceIndex);
1120 }
1121
1122 /* Increment PcBiosDiskCount BEFORE calling GetHarddiskInformation
1123 * so that UefiDiskReadLogicalSectors can validate the drive number */
1124 PcBiosDiskCount = BlockDeviceIndex + 1;
1125
1126 TRACE("Calling GetHarddiskInformation for drive %d (BlockDeviceIndex=%lu)\n",
1127 BlockDeviceIndex + FIRST_BIOS_DISK, BlockDeviceIndex);
1128 if (!UefiEnsureDiskReadBufferAligned(BlockIo->Media->IoAlign))
1129 {
1130 ERR("Failed to align disk read buffer for drive %d\n", BlockDeviceIndex + FIRST_BIOS_DISK);
1131 return;
1132 }
1133
1134 GetHarddiskInformation(BlockDeviceIndex + FIRST_BIOS_DISK);
1135 BlockDeviceIndex++;
1136 }
1137
1138 /* Step 7: If boot handle was a logical partition, find its parent root device */
1140 {
1143 &BlockIoGuid,
1144 (VOID**)&BlockIo);
1145
1146 if (!EFI_ERROR(Status) && BlockIo != NULL && BlockIo->Media->LogicalPartition)
1147 {
1148 TRACE("Boot handle is a logical partition, searching for parent root device\n");
1149 TRACE("Boot partition: BlockSize=%lu, RemovableMedia=%s\n",
1150 BlockIo->Media->BlockSize,
1151 BlockIo->Media->RemovableMedia ? "TRUE" : "FALSE");
1152
1153 /* Find the root device that matches the boot partition's characteristics */
1154 /* For CD-ROMs: match BlockSize=2048 and RemovableMedia=TRUE */
1155 /* For hard disks: match BlockSize and find the root device before this partition */
1156 BOOLEAN FoundBootDevice = FALSE;
1157 for (i = 0; i < BlockDeviceIndex; i++)
1158 {
1159 EFI_BLOCK_IO* RootBlockIo;
1162 &BlockIoGuid,
1163 (VOID**)&RootBlockIo);
1164
1165 if (EFI_ERROR(Status) || RootBlockIo == NULL)
1166 continue;
1167
1168 /* For CD-ROM: match BlockSize=2048 and RemovableMedia */
1169 if (BlockIo->Media->BlockSize == 2048 && BlockIo->Media->RemovableMedia)
1170 {
1171 if (RootBlockIo->Media->BlockSize == 2048 &&
1172 RootBlockIo->Media->RemovableMedia &&
1173 !RootBlockIo->Media->LogicalPartition)
1174 {
1177 FoundBootDevice = TRUE;
1178 TRACE("Found CD-ROM boot device at ARC drive index %lu\n", i);
1179 break;
1180 }
1181 }
1182 /* For hard disk partitions: the root device should be before the partition handle */
1183 else if (InternalUefiDisk[i].UefiHandleIndex < UefiBootRootIndex)
1184 {
1185 /* Check if this root device is likely the parent */
1186 if (RootBlockIo->Media->BlockSize == BlockIo->Media->BlockSize &&
1187 !RootBlockIo->Media->LogicalPartition)
1188 {
1189 /* This might be the parent, but we need to be more certain */
1190 /* For now, use the last root device before the boot handle */
1193 FoundBootDevice = TRUE;
1194 TRACE("Found potential hard disk boot device at ARC drive index %lu\n", i);
1195 }
1196 }
1197 }
1198
1199 if (!FoundBootDevice && PcBiosDiskCount > 0)
1200 {
1203 TRACE("Could not determine boot device, assuming first drive\n");
1204 }
1205 }
1206 }
1207
1208 TRACE("Found %lu root block devices\n", PcBiosDiskCount);
1209}
1210
1211static
1212BOOLEAN
1214{
1215 EFI_BLOCK_IO* BootBlockIo = NULL;
1216 EFI_BLOCK_IO* RootBlockIo = NULL;
1218 ULONG ArcDriveIndex;
1219
1220 TRACE("UefiSetBootpath: Setting up boot path\n");
1221
1223 {
1224 ERR("Invalid boot root index\n");
1225 return FALSE;
1226 }
1227
1228 ArcDriveIndex = PublicBootArcDisk;
1229 if (ArcDriveIndex >= PcBiosDiskCount || InternalUefiDisk == NULL)
1230 {
1231 ERR("Invalid boot arc disk index\n");
1232 return FALSE;
1233 }
1234
1237 &BlockIoGuid,
1238 (VOID**)&BootBlockIo);
1239
1240 if (EFI_ERROR(Status) || BootBlockIo == NULL)
1241 {
1242 ERR("Failed to get Block I/O protocol for boot handle\n");
1243 return FALSE;
1244 }
1245
1247 InternalUefiDisk[ArcDriveIndex].Handle,
1248 &BlockIoGuid,
1249 (VOID**)&RootBlockIo);
1250
1251 if (EFI_ERROR(Status) || RootBlockIo == NULL)
1252 {
1253 ERR("Failed to get Block I/O protocol for boot root device\n");
1254 return FALSE;
1255 }
1256
1257 FrldrBootDrive = (FIRST_BIOS_DISK + ArcDriveIndex);
1258
1259 /* Check if booting from CD-ROM by checking the boot handle properties */
1260 /* CD-ROMs have BlockSize=2048 and RemovableMedia=TRUE */
1261 if (BootBlockIo->Media->RemovableMedia == TRUE && BootBlockIo->Media->BlockSize == 2048)
1262 {
1263 /* Boot Partition 0xFF is the magic value that indicates booting from CD-ROM */
1264 FrldrBootPartition = 0xFF;
1266 "multi(0)disk(0)cdrom(%u)", ArcDriveIndex);
1267 TRACE("Boot path set to CD-ROM: %s\n", FrLdrBootPath);
1268 }
1269 else
1270 {
1271 ULONG BootPartition;
1272 PARTITION_TABLE_ENTRY PartitionEntry;
1273
1274 /* This is a hard disk */
1275 /* If boot handle is a logical partition, we need to determine which partition number */
1276 if (BootBlockIo->Media->LogicalPartition)
1277 {
1278 /* For logical partitions, we need to find the partition number */
1279 /* This is tricky - we'll use partition 1 as default for now */
1280 /* TODO: Properly determine partition number from boot handle */
1281 BootPartition = FIRST_PARTITION;
1282 TRACE("Boot handle is logical partition, using partition %lu\n", BootPartition);
1283 }
1284 else
1285 {
1286 /* Boot handle is the root device itself */
1287 if (!UefiGetBootPartitionEntry(FrldrBootDrive, &PartitionEntry, &BootPartition))
1288 {
1289 ERR("Failed to get boot partition entry\n");
1290 return FALSE;
1291 }
1292 }
1293
1295 "multi(0)disk(0)rdisk(%u)partition(%lu)",
1296 ArcDriveIndex, BootPartition);
1297 TRACE("Boot path set to hard disk: %s\n", FrLdrBootPath);
1298 }
1299
1300 return TRUE;
1301}
1302
1303BOOLEAN
1305{
1306 EFI_BLOCK_IO* BlockIo;
1308 ULONG ArcDriveIndex;
1310 PULONG Buffer;
1311 ULONG Checksum = 0;
1313 ULONG i;
1314
1321 {
1322 ERR("Failed to allocate disk read buffer\n");
1323 return FALSE;
1324 }
1325
1327
1328 if (PcBiosDiskCount == 0)
1329 {
1330 ERR("No block devices found\n");
1331 return FALSE;
1332 }
1333
1334 if (!UefiSetBootpath())
1335 {
1336 ERR("Failed to set boot path\n");
1337 return FALSE;
1338 }
1339
1340 /* Handle CD-ROM boot device registration */
1341 ArcDriveIndex = PublicBootArcDisk;
1342 if (ArcDriveIndex >= PcBiosDiskCount || InternalUefiDisk == NULL)
1343 {
1344 ERR("Invalid boot arc disk index\n");
1345 return FALSE;
1346 }
1347
1349 InternalUefiDisk[ArcDriveIndex].Handle,
1350 &BlockIoGuid,
1351 (VOID**)&BlockIo);
1352
1353 if (EFI_ERROR(Status) || BlockIo == NULL)
1354 {
1355 ERR("Failed to get Block I/O protocol\n");
1356 return FALSE;
1357 }
1358
1359 if (BlockIo->Media->RemovableMedia == TRUE && BlockIo->Media->BlockSize == 2048)
1360 {
1361 /* Read the MBR from CD-ROM (sector 16) */
1363 {
1364 ERR("Reading MBR from CD-ROM failed\n");
1365 return FALSE;
1366 }
1367
1370
1371 Signature = Mbr->Signature;
1372 TRACE("CD-ROM Signature: %x\n", Signature);
1373
1374 /* Calculate the MBR checksum */
1375 for (i = 0; i < 2048 / sizeof(ULONG); i++)
1376 {
1377 Checksum += Buffer[i];
1378 }
1379 Checksum = ~Checksum + 1;
1380 TRACE("CD-ROM Checksum: %x\n", Checksum);
1381
1382 /* Fill out the ARC disk block */
1384
1386 TRACE("Registered CD-ROM boot device: 0x%02X\n", (int)FrldrBootDrive);
1387 }
1388
1389 return TRUE;
1390}
1391
1392UCHAR
1394{
1395 /* No floppy support in UEFI */
1396 return 0;
1397}
1398
1399BOOLEAN
1401 IN UCHAR DriveNumber,
1402 IN ULONGLONG SectorNumber,
1405{
1406 ULONG ArcDriveIndex;
1407 EFI_BLOCK_IO* BlockIo;
1409 ULONG BlockSize;
1410 ULONG IoAlign;
1411
1412 if (DriveNumber < FIRST_BIOS_DISK)
1413 return FALSE;
1414
1415 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
1416
1417 if (InternalUefiDisk == NULL)
1418 {
1419 ERR("InternalUefiDisk not initialized\n");
1420 return FALSE;
1421 }
1422
1423 if (ArcDriveIndex >= 32)
1424 {
1425 ERR("Drive index out of bounds: %d (ArcDriveIndex=%lu)\n", DriveNumber, ArcDriveIndex);
1426 return FALSE;
1427 }
1428
1429 /* Allow access during initialization: check if handle is set up */
1430 /* During initialization, Handle is set before GetHarddiskInformation is called */
1431 if (InternalUefiDisk[ArcDriveIndex].Handle == NULL)
1432 {
1433 ERR("Invalid drive number: %d (ArcDriveIndex=%lu, PcBiosDiskCount=%lu, Handle=NULL)\n",
1434 DriveNumber, ArcDriveIndex, PcBiosDiskCount);
1435 return FALSE;
1436 }
1437
1439 InternalUefiDisk[ArcDriveIndex].Handle,
1440 &BlockIoGuid,
1441 (VOID**)&BlockIo);
1442
1443 if (EFI_ERROR(Status) || BlockIo == NULL)
1444 {
1445 ERR("Failed to get Block I/O protocol for drive %d\n", DriveNumber);
1446 return FALSE;
1447 }
1448
1449 if (!BlockIo->Media->MediaPresent)
1450 {
1451 ERR("Media not present for drive %d\n", DriveNumber);
1452 return FALSE;
1453 }
1454
1455 BlockSize = BlockIo->Media->BlockSize;
1456 IoAlign = BlockIo->Media->IoAlign;
1457
1458 if (!UefiEnsureDiskReadBufferAligned(IoAlign))
1459 {
1460 ERR("Failed to align disk read buffer for drive %d\n", DriveNumber);
1461 return FALSE;
1462 }
1463
1464 if (!UefiIsAlignedPointer(Buffer, (IoAlign == 0) ? 1 : IoAlign))
1465 {
1466 ULONG TotalSectors = SectorCount;
1467 ULONG MaxSectors = DiskReadBufferSize / BlockSize;
1468 ULONGLONG CurrentSector = SectorNumber;
1469 PUCHAR OutPtr = (PUCHAR)Buffer;
1470
1471 if (MaxSectors == 0)
1472 {
1473 ERR("DiskReadBufferSize too small for block size %lu\n", BlockSize);
1474 return FALSE;
1475 }
1476
1477 while (TotalSectors)
1478 {
1479 ULONG ReadSectors = min(TotalSectors, MaxSectors);
1480 UINTN ReadSize = ReadSectors * BlockSize;
1481
1482 Status = BlockIo->ReadBlocks(
1483 BlockIo,
1484 BlockIo->Media->MediaId,
1485 CurrentSector,
1486 ReadSize,
1488
1489 if (EFI_ERROR(Status))
1490 {
1491 ERR("ReadBlocks failed: DriveNumber=%d, SectorNumber=%llu, SectorCount=%lu, Status=0x%lx\n",
1492 DriveNumber, CurrentSector, ReadSectors, (ULONG)Status);
1493 ERR("ReadBlocks details: BlockSize=%lu, IoAlign=%lu, Buffer=%p, DiskReadBuffer=%p, MediaId=0x%lx\n",
1494 BlockSize, IoAlign, Buffer, DiskReadBuffer, (ULONG)BlockIo->Media->MediaId);
1495 ERR("ReadBlocks media: LastBlock=%llu, LogicalPartition=%s, RemovableMedia=%s\n",
1496 BlockIo->Media->LastBlock,
1497 BlockIo->Media->LogicalPartition ? "TRUE" : "FALSE",
1498 BlockIo->Media->RemovableMedia ? "TRUE" : "FALSE");
1499 return FALSE;
1500 }
1501
1502 RtlCopyMemory(OutPtr, DiskReadBuffer, ReadSize);
1503 OutPtr += ReadSize;
1504 CurrentSector += ReadSectors;
1505 TotalSectors -= ReadSectors;
1506 }
1507
1508 return TRUE;
1509 }
1510
1511 Status = BlockIo->ReadBlocks(
1512 BlockIo,
1513 BlockIo->Media->MediaId,
1514 SectorNumber,
1515 SectorCount * BlockSize,
1516 Buffer);
1517
1518 if (EFI_ERROR(Status))
1519 {
1520 ERR("ReadBlocks failed: DriveNumber=%d, SectorNumber=%llu, SectorCount=%lu, Status=0x%lx\n",
1521 DriveNumber, SectorNumber, SectorCount, (ULONG)Status);
1522 ERR("ReadBlocks details: BlockSize=%lu, IoAlign=%lu, Buffer=%p, DiskReadBuffer=%p, MediaId=0x%lx\n",
1523 BlockSize, IoAlign, Buffer, DiskReadBuffer, (ULONG)BlockIo->Media->MediaId);
1524 ERR("ReadBlocks media: LastBlock=%llu, LogicalPartition=%s, RemovableMedia=%s\n",
1525 BlockIo->Media->LastBlock,
1526 BlockIo->Media->LogicalPartition ? "TRUE" : "FALSE",
1527 BlockIo->Media->RemovableMedia ? "TRUE" : "FALSE");
1528 return FALSE;
1529 }
1530
1531 return TRUE;
1532}
1533
1534BOOLEAN
1536{
1537 ULONG ArcDriveIndex;
1538 EFI_BLOCK_IO* BlockIo;
1540
1541 if (DriveNumber < FIRST_BIOS_DISK)
1542 return FALSE;
1543
1544 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
1545
1546 if (InternalUefiDisk == NULL)
1547 {
1548 ERR("InternalUefiDisk not initialized\n");
1549 return FALSE;
1550 }
1551
1552 if (ArcDriveIndex >= 32 || InternalUefiDisk[ArcDriveIndex].Handle == NULL)
1553 {
1554 ERR("Invalid drive number: %d\n", DriveNumber);
1555 return FALSE;
1556 }
1557
1559 InternalUefiDisk[ArcDriveIndex].Handle,
1560 &BlockIoGuid,
1561 (VOID**)&BlockIo);
1562
1563 if (EFI_ERROR(Status) || BlockIo == NULL)
1564 {
1565 ERR("Failed to get Block I/O protocol for drive %d\n", DriveNumber);
1566 return FALSE;
1567 }
1568
1569 if (!BlockIo->Media->MediaPresent)
1570 {
1571 ERR("Media not present for drive %d\n", DriveNumber);
1572 return FALSE;
1573 }
1574
1575 Geometry->Cylinders = 1; /* Not relevant for UEFI Block I/O protocol */
1576 Geometry->Heads = 1; /* Not relevant for UEFI Block I/O protocol */
1577 Geometry->SectorsPerTrack = (ULONG)(BlockIo->Media->LastBlock + 1);
1578 Geometry->BytesPerSector = BlockIo->Media->BlockSize;
1579 Geometry->Sectors = BlockIo->Media->LastBlock + 1;
1580
1581 return TRUE;
1582}
1583
1584ULONG
1586{
1587 ULONG ArcDriveIndex;
1588 EFI_BLOCK_IO* BlockIo;
1590
1591 if (DriveNumber < FIRST_BIOS_DISK)
1592 return 0;
1593
1594 ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
1595
1596 if (InternalUefiDisk == NULL)
1597 {
1598 ERR("InternalUefiDisk not initialized\n");
1599 return 0;
1600 }
1601
1602 if (ArcDriveIndex >= 32 || InternalUefiDisk[ArcDriveIndex].Handle == NULL)
1603 {
1604 ERR("Invalid drive number: %d\n", DriveNumber);
1605 return 0;
1606 }
1607
1609 InternalUefiDisk[ArcDriveIndex].Handle,
1610 &BlockIoGuid,
1611 (VOID**)&BlockIo);
1612
1613 if (EFI_ERROR(Status) || BlockIo == NULL)
1614 {
1615 ERR("Failed to get Block I/O protocol for drive %d\n", DriveNumber);
1616 return 0;
1617 }
1618
1619 if (!BlockIo->Media->MediaPresent)
1620 {
1621 ERR("Media not present for drive %d\n", DriveNumber);
1622 return 0;
1623 }
1624
1625 return (ULONG)(BlockIo->Media->LastBlock + 1);
1626}
#define N
Definition: crc32.c:57
#define BLOCK_IO_PROTOCOL
Definition: BlockIo.h:31
#define WARNING
Definition: BusLogic958.h:56
unsigned short CHAR16
signed char CHAR8
UINT32 UINTN
PRTL_UNICODE_STRING_BUFFER Path
#define EFI_PAGE_SIZE
Definition: UefiBaseType.h:189
#define EFI_ERROR(A)
Definition: UefiBaseType.h:165
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:31
VOID * EFI_HANDLE
Definition: UefiBaseType.h:35
@ EfiLoaderData
@ ByProtocol
Definition: UefiSpec.h:1428
unsigned char BOOLEAN
Definition: actypes.h:127
COMPILER_DEPENDENT_UINT64 UINT64
Definition: actypes.h:131
VOID AddReactOSArcDiskInfo(IN PSTR ArcName, IN ULONG Signature, IN ULONG Checksum, IN BOOLEAN ValidPartitionTable)
Definition: archwsup.c:77
@ Identifier
Definition: asmpp.cpp:95
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
BOOLEAN DissectArcPath(IN PCSTR ArcPath, OUT PCSTR *Path OPTIONAL, OUT PUCHAR DriveNumber, OUT PULONG PartitionNumber)
Definition: arcname.c:25
BOOLEAN DiskGetPartitionEntry(IN UCHAR DriveNumber, IN ULONG PartitionNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:407
VOID DiskDetectPartitionType(IN UCHAR DriveNumber)
Definition: partition.c:314
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
#define PARTITION_ENTRY_UNUSED
Definition: disk.h:71
struct _MASTER_BOOT_RECORD * PMASTER_BOOT_RECORD
#define PARTITION_GPT
Definition: disk.h:90
PVOID FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:709
VOID FsSetDeviceSpecific(ULONG FileId, PVOID Specific)
Definition: fs.c:702
VOID FsRegisterDevice(_In_ PCSTR DeviceName, _In_ const DEVVTBL *FuncTable)
Definition: fs.c:673
#define MachDiskGetDriveGeometry(Drive, Geom)
Definition: machine.h:122
#define MachDiskReadLogicalSectors(Drive, Start, Count, Buf)
Definition: machine.h:120
VOID MmFreeMemory(PVOID MemoryPointer)
Definition: mm.c:215
VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: heap.c:553
PVOID MmAllocateMemoryWithType(SIZE_T MemorySize, TYPE_OF_MEMORY MemoryType)
Definition: mm.c:31
PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: heap.c:545
#define SectorOffset(L)
Definition: cdprocs.h:1622
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define MAX_PATH
Definition: compat.h:34
_ACRTIMP int __cdecl memcmp(const void *, const void *, size_t)
Definition: string.c:2802
#define EINVAL
Definition: errno.h:44
#define ENOMEM
Definition: errno.h:35
#define EIO
Definition: errno.h:28
static const WCHAR Signature[]
Definition: parser.c:141
return ret
Definition: mutex.c:146
#define ULONG_PTR
Definition: config.h:101
CCHAR FrLdrBootPath[MAX_PATH]
Definition: freeldr.c:29
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
ULONG Handle
Definition: gdb_input.c:15
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ASSERT(a)
Definition: mode.c:44
#define sprintf
Definition: sprintf.c:45
#define ULL(a, b)
Definition: format_msg.c:27
#define min(a, b)
Definition: monoChain.cc:55
int Count
Definition: noreturn.cpp:7
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTRSAFEVAPI RtlStringCbPrintfA(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest, _In_ size_t cbDest, _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,...)
Definition: ntstrsafe.h:1148
ULONG SectorCount
Definition: part_xbox.c:31
long LONG
Definition: pedump.c:60
@ ESUCCESS
Definition: arc.h:32
@ LoaderFirmwareTemporary
Definition: arc.h:298
ULONG ARC_STATUS
Definition: arc.h:4
@ DiskPeripheral
Definition: arc.h:138
@ SeekRelative
Definition: arc.h:60
@ SeekAbsolute
Definition: arc.h:59
enum _OPENMODE OPENMODE
enum _SEEKMODE SEEKMODE
#define TRACE(s)
Definition: solgame.cpp:4
_In_ PVOID Context
Definition: storport.h:2269
BOOLEAN RemovableMedia
Definition: BlockIo.h:143
BOOLEAN LogicalPartition
Definition: BlockIo.h:156
UINT32 BlockSize
Definition: BlockIo.h:173
EFI_LBA LastBlock
Definition: BlockIo.h:184
BOOLEAN MediaPresent
Definition: BlockIo.h:150
EFI_FREE_POOL FreePool
Definition: UefiSpec.h:1814
EFI_LOCATE_HANDLE LocateHandle
Definition: UefiSpec.h:1835
EFI_HANDLE_PROTOCOL HandleProtocol
Definition: UefiSpec.h:1832
EFI_ALLOCATE_POOL AllocatePool
Definition: UefiSpec.h:1813
EFI_BOOT_SERVICES * BootServices
Definition: UefiSpec.h:1959
Definition: parttest.c:75
ULONG PartitionSectorCount
Definition: parttest.c:85
ULONG SectorCountBeforePartition
Definition: parttest.c:84
UCHAR SystemIndicator
Definition: parttest.c:80
EFI_BLOCK_IO_MEDIA * Media
Definition: BlockIo.h:230
EFI_BLOCK_READ ReadBlocks
Definition: BlockIo.h:233
Definition: disk.h:26
ULONG BytesPerSector
Number of bytes per sector.
Definition: disk.h:30
ULONG Cylinders
Number of cylinders on the disk.
Definition: disk.h:27
ULONGLONG Sectors
Total number of disk sectors/LBA blocks.
Definition: disk.h:31
ULONG SectorsPerTrack
Number of sectors per track.
Definition: disk.h:29
ULONG Heads
Number of heads on the disk.
Definition: disk.h:28
Definition: uefidisk.c:62
UINT64 EndingLba
Definition: uefidisk.c:66
EFI_GUID PartitionTypeGuid
Definition: uefidisk.c:63
EFI_GUID UniquePartitionGuid
Definition: uefidisk.c:64
UINT64 Attributes
Definition: uefidisk.c:67
CHAR16 PartitionName[EFI_PARTITION_NAME_LENGTH]
Definition: uefidisk.c:68
UINT64 StartingLba
Definition: uefidisk.c:65
UINT64 FirstUsableLba
Definition: uefidisk.c:51
UINT64 LastUsableLba
Definition: uefidisk.c:52
UINT32 Revision
Definition: uefidisk.c:45
UINT32 NumberOfPartitionEntries
Definition: uefidisk.c:55
UINT32 SizeOfPartitionEntry
Definition: uefidisk.c:56
UINT32 HeaderSize
Definition: uefidisk.c:46
UINT32 PartitionEntryArrayCrc32
Definition: uefidisk.c:57
CHAR8 Signature[8]
Definition: uefidisk.c:44
UINT32 HeaderCrc32
Definition: uefidisk.c:47
UINT64 PartitionEntryLba
Definition: uefidisk.c:54
EFI_GUID DiskGuid
Definition: uefidisk.c:53
UINT32 Reserved
Definition: uefidisk.c:48
UINT64 AlternateLba
Definition: uefidisk.c:50
BOOLEAN IsThisTheBootDrive
Definition: uefidisk.c:87
ULONG UefiHandleIndex
Definition: uefidisk.c:86
UCHAR ArcDriveNumber
Definition: uefidisk.c:84
EFI_HANDLE Handle
Definition: uefidisk.c:88
UCHAR NumOfPartitions
Definition: uefidisk.c:85
USHORT MasterBootRecordMagic
Definition: disk.h:63
ULONG Signature
Definition: disk.h:60
Definition: disk.h:40
Definition: fs.h:25
ULONGLONG SectorOffset
Definition: hwdisk.c:39
UCHAR DriveNumber
Definition: hwdisk.c:36
ULONGLONG SectorCount
Definition: hwdisk.c:40
ULONGLONG SectorNumber
Definition: hwdisk.c:41
ULONG SectorSize
Definition: hwdisk.c:38
static COORD Position
Definition: mouse.c:34
uint32_t * PULONG
Definition: typedefs.h:59
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t UINT32
Definition: typedefs.h:59
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
char * PCHAR
Definition: typedefs.h:51
#define EFI_PARTITION_HEADER_SIGNATURE
Definition: uefidisk.c:24
#define EFI_PARTITION_NAME_LENGTH
Definition: uefidisk.c:30
static LONG lReportError
Definition: uefidisk.c:213
static ULONG PublicBootArcDisk
Definition: uefidisk.c:115
BOOLEAN UefiDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
Definition: uefidisk.c:1535
PVOID Buffer
Definition: uefidisk.c:108
static BOOLEAN UefiReadGptHeader(IN UCHAR DriveNumber, OUT PGPT_TABLE_HEADER GptHeader)
Definition: uefidisk.c:229
#define TAG_HW_DISK_CONTEXT
Definition: uefidisk.c:16
static BOOLEAN UefiGetBootPartitionEntry(IN UCHAR DriveNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry, OUT PULONG BootPartition)
Definition: uefidisk.c:382
PVOID DiskReadBuffer
Definition: uefidisk.c:98
BOOLEAN UefiDiskReadLogicalSectors(IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: uefidisk.c:1400
struct tagDISKCONTEXT DISKCONTEXT
static BOOLEAN DiskReadBufferFromPool
Definition: uefidisk.c:101
struct _GPT_PARTITION_ENTRY GPT_PARTITION_ENTRY
static CHAR PcDiskIdentifier[32][20]
Definition: uefidisk.c:111
static EFI_GUID BlockIoGuid
Definition: uefidisk.c:117
BOOLEAN UefiInitializeBootDevices(VOID)
Definition: uefidisk.c:1304
static ARC_STATUS UefiDiskGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: uefidisk.c:604
static BOOLEAN DiskReadBufferFallbackPool
Definition: uefidisk.c:102
#define EFI_TABLE_REVISION
Definition: uefidisk.c:26
#define EFI_PART_TYPE_UNUSED_GUID
Definition: uefidisk.c:33
EFI_HANDLE PublicBootHandle
Definition: uefimem.c:37
static ULONG DiskReadBufferAlignment
Definition: uefidisk.c:100
EFI_SYSTEM_TABLE * GlobalSystemTable
Definition: uefildr.c:16
LONG DiskReportError(BOOLEAN bShowError)
Definition: uefidisk.c:216
static const DEVVTBL UefiDiskVtbl
Definition: uefidisk.c:846
static BOOLEAN UefiEnsureDiskReadBufferAligned(IN ULONG Alignment)
Definition: uefidisk.c:138
static VOID UefiSetupBlockDevices(VOID)
Definition: uefidisk.c:957
struct _GPT_TABLE_HEADER GPT_TABLE_HEADER
#define EFI_HEADER_LOCATION
Definition: uefidisk.c:25
static const CHAR Hex[]
Definition: uefidisk.c:110
BOOLEAN UefiGetGptPartitionEntry(IN UCHAR DriveNumber, IN ULONG PartitionNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: uefidisk.c:295
struct _GPT_TABLE_HEADER * PGPT_TABLE_HEADER
static ULONG UefiBootRootIndex
Definition: uefidisk.c:114
static PVOID DiskReadBufferRaw
Definition: uefidisk.c:99
#define FIRST_BIOS_DISK
Definition: uefidisk.c:17
#define MAX_SUPPORTED_BLOCK_SIZE
Definition: uefidisk.c:21
static ARC_STATUS UefiDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: uefidisk.c:626
static ARC_STATUS UefiDiskSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: uefidisk.c:815
static INTERNAL_UEFI_DISK * InternalUefiDisk
Definition: uefidisk.c:116
static ARC_STATUS UefiDiskClose(ULONG FileId)
Definition: uefidisk.c:595
static VOID GetHarddiskInformation(UCHAR DriveNumber)
Definition: uefidisk.c:857
PCHAR GetHarddiskIdentifier(UCHAR DriveNumber)
Definition: uefidisk.c:205
static ARC_STATUS UefiDiskRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: uefidisk.c:719
static ULONG HandleCount
Definition: uefidisk.c:119
EFI_HANDLE GlobalImageHandle
Definition: uefildr.c:15
struct _INTERNAL_UEFI_DISK INTERNAL_UEFI_DISK
UCHAR PcBiosDiskCount
Definition: uefidisk.c:103
static EFI_HANDLE * handles
Definition: uefidisk.c:118
UCHAR UefiGetFloppyCount(VOID)
Definition: uefidisk.c:1393
SIZE_T DiskReadBufferSize
Definition: uefidisk.c:107
struct _GPT_PARTITION_ENTRY * PGPT_PARTITION_ENTRY
static BOOLEAN UefiIsAlignedPointer(IN PVOID Pointer, IN ULONG Alignment)
Definition: uefidisk.c:123
ULONG UefiDiskGetCacheableBlockCount(UCHAR DriveNumber)
Definition: uefidisk.c:1585
UCHAR FrldrBootDrive
Definition: uefidisk.c:105
static BOOLEAN UefiSetBootpath(VOID)
Definition: uefidisk.c:1213
ULONG FrldrBootPartition
Definition: uefidisk.c:106
struct _INTERNAL_UEFI_DISK * PINTERNAL_UEFI_DISK
#define FIRST_PARTITION
Definition: uefidisk.c:18
#define ALIGN_UP_POINTER_BY(ptr, align)
Definition: umtypes.h:85
LONGLONG QuadPart
Definition: typedefs.h:114
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1049
_In_ ULONG SectorSize
Definition: halfuncs.h:291
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2061
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175