Synchronize with trunk's revision r57652.
[reactos.git] / ntoskrnl / fstub / fstubex.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fstub/fstubex.c
5 * PURPOSE: Extended FSTUB Routines (not linked to HAL)
6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE FUNCTIONS *********************************************************/
16
17 typedef struct _DISK_INFORMATION
18 {
19 PDEVICE_OBJECT DeviceObject;
20 ULONG SectorSize;
21 DISK_GEOMETRY_EX DiskGeometry;
22 PUSHORT Buffer;
23 ULONGLONG SectorCount;
24 } DISK_INFORMATION, *PDISK_INFORMATION;
25
26 #include <pshpack1.h>
27 typedef struct _EFI_PARTITION_HEADER
28 {
29 ULONGLONG Signature; // 0
30 ULONG Revision; // 8
31 ULONG HeaderSize; // 12
32 ULONG HeaderCRC32; // 16
33 ULONG Reserved; // 20
34 ULONGLONG MyLBA; // 24
35 ULONGLONG AlternateLBA; // 32
36 ULONGLONG FirstUsableLBA; // 40
37 ULONGLONG LastUsableLBA; // 48
38 GUID DiskGUID; // 56
39 ULONGLONG PartitionEntryLBA; // 72
40 ULONG NumberOfEntries; // 80
41 ULONG SizeOfPartitionEntry; // 84
42 ULONG PartitionEntryCRC32; // 88
43 } EFI_PARTITION_HEADER, *PEFI_PARTITION_HEADER;
44 #include <poppack.h>
45
46 typedef struct _EFI_PARTITION_ENTRY
47 {
48 GUID PartitionType; // 0
49 GUID UniquePartition; // 16
50 ULONGLONG StartingLBA; // 32
51 ULONGLONG EndingLBA; // 40
52 ULONGLONG Attributes; // 48
53 WCHAR Name[0x24]; // 56
54 } EFI_PARTITION_ENTRY, *PEFI_PARTITION_ENTRY;
55
56 typedef struct _PARTITION_TABLE_ENTRY
57 {
58 UCHAR BootIndicator;
59 UCHAR StartHead;
60 UCHAR StartSector;
61 UCHAR StartCylinder;
62 UCHAR SystemIndicator;
63 UCHAR EndHead;
64 UCHAR EndSector;
65 UCHAR EndCylinder;
66 ULONG SectorCountBeforePartition;
67 ULONG PartitionSectorCount;
68 } PARTITION_TABLE_ENTRY, *PPARTITION_TABLE_ENTRY;
69
70 typedef struct _MASTER_BOOT_RECORD
71 {
72 UCHAR MasterBootRecordCodeAndData[0x1B8]; // 0
73 ULONG Signature; // 440
74 USHORT Reserved; // 444
75 PARTITION_TABLE_ENTRY PartitionTable[4]; // 446
76 USHORT MasterBootRecordMagic; // 510
77 } MASTER_BOOT_RECORD, *PMASTER_BOOT_RECORD;
78
79 /* Tag for Fstub allocations */
80 #define TAG_FSTUB 'BtsF'
81 /* Partition entry size (bytes) - FIXME: It's hardcoded as Microsoft does, but according to specs, it shouldn't be */
82 #define PARTITION_ENTRY_SIZE 128
83 /* Defines "EFI PART" */
84 #define EFI_HEADER_SIGNATURE 0x5452415020494645ULL
85 /* Defines version 1.0 */
86 #define EFI_HEADER_REVISION_1 0x00010000
87 /* Defines system type for MBR showing that a GPT is following */
88 #define EFI_PMBR_OSTYPE_EFI 0xEE
89
90 #define IS_VALID_DISK_INFO(Disk) \
91 (Disk) && \
92 (Disk->DeviceObject) && \
93 (Disk->SectorSize) && \
94 (Disk->Buffer) && \
95 (Disk->SectorCount)
96
97 VOID
98 NTAPI
99 FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry,
100 IN ULONG PartitionNumber
101 );
102
103 NTSTATUS
104 NTAPI
105 FstubDetectPartitionStyle(IN PDISK_INFORMATION Disk,
106 IN PARTITION_STYLE * PartitionStyle
107 );
108
109 VOID
110 NTAPI
111 FstubFreeDiskInformation(IN PDISK_INFORMATION DiskBuffer
112 );
113
114 NTSTATUS
115 NTAPI
116 FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject,
117 OUT PDISK_GEOMETRY_EX Geometry
118 );
119
120 NTSTATUS
121 NTAPI
122 FstubReadSector(IN PDEVICE_OBJECT DeviceObject,
123 IN ULONG SectorSize,
124 IN ULONGLONG StartingSector OPTIONAL,
125 OUT PUSHORT Buffer
126 );
127
128 NTSTATUS
129 NTAPI
130 FstubWriteBootSectorEFI(IN PDISK_INFORMATION Disk
131 );
132
133 NTSTATUS
134 NTAPI
135 FstubWritePartitionTableEFI(IN PDISK_INFORMATION Disk,
136 IN GUID DiskGUID,
137 IN ULONG MaxPartitionCount,
138 IN ULONGLONG FirstUsableLBA,
139 IN ULONGLONG LastUsableLBA,
140 IN BOOLEAN WriteBackupTable,
141 IN ULONG PartitionCount,
142 IN PPARTITION_INFORMATION_EX PartitionEntries OPTIONAL
143 );
144
145 NTSTATUS
146 NTAPI
147 FstubWriteSector(IN PDEVICE_OBJECT DeviceObject,
148 IN ULONG SectorSize,
149 IN ULONGLONG StartingSector OPTIONAL,
150 IN PUSHORT Buffer
151 );
152
153 VOID
154 NTAPI
155 FstubAdjustPartitionCount(IN ULONG SectorSize,
156 IN OUT PULONG PartitionCount)
157 {
158 ULONG Count;
159 PAGED_CODE();
160
161 ASSERT(SectorSize);
162 ASSERT(PartitionCount);
163
164 /* Get partition count */
165 Count = *PartitionCount;
166 /* We need at least 128 entries */
167 if (Count < 128)
168 {
169 Count = 128;
170 }
171
172 /* Then, ensure that we will have a round value,
173 * ie, all sectors will be full of entries
174 * There won't be lonely entries
175 */
176 Count = (Count * PARTITION_ENTRY_SIZE) / SectorSize;
177 Count = (Count * SectorSize) / PARTITION_ENTRY_SIZE;
178 ASSERT(*PartitionCount <= Count);
179 /* Return result */
180 *PartitionCount = Count;
181
182 /* One more sanity check */
183 if (SectorSize == 512)
184 {
185 ASSERT(Count % 4 == 0);
186 }
187 }
188
189 NTSTATUS
190 NTAPI
191 FstubAllocateDiskInformation(IN PDEVICE_OBJECT DeviceObject,
192 OUT PDISK_INFORMATION * DiskBuffer,
193 PDISK_GEOMETRY_EX DiskGeometry OPTIONAL)
194 {
195 NTSTATUS Status;
196 PDISK_INFORMATION DiskInformation;
197 PAGED_CODE();
198
199 ASSERT(DeviceObject);
200 ASSERT(DiskBuffer);
201
202 /* Allocate internal structure */
203 DiskInformation = ExAllocatePoolWithTag(NonPagedPool, sizeof(DISK_INFORMATION), TAG_FSTUB);
204 if (!DiskInformation)
205 {
206 return STATUS_INSUFFICIENT_RESOURCES;
207 }
208
209 /* If caller don't pass needed information, let's get them */
210 if (!DiskGeometry)
211 {
212 Status = FstubGetDiskGeometry(DeviceObject, &(DiskInformation->DiskGeometry));
213 if (!NT_SUCCESS(Status))
214 {
215 ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
216 return Status;
217 }
218 }
219 else
220 {
221 DiskInformation->DiskGeometry = *DiskGeometry;
222 }
223
224 /* Ensure read/received information are correct */
225 if (DiskInformation->DiskGeometry.Geometry.BytesPerSector == 0 ||
226 DiskInformation->DiskGeometry.DiskSize.QuadPart == 0)
227 {
228 ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
229 return STATUS_DEVICE_NOT_READY;
230 }
231
232 /* Store vital information as well */
233 DiskInformation->DeviceObject = DeviceObject;
234 DiskInformation->SectorSize = DiskInformation->DiskGeometry.Geometry.BytesPerSector;
235 DiskInformation->SectorCount = DiskInformation->DiskGeometry.DiskSize.QuadPart / DiskInformation->SectorSize;
236
237 /* Finally, allocate the buffer that will be used for different read */
238 DiskInformation->Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskInformation->SectorSize, TAG_FSTUB);
239 if (!DiskInformation->Buffer)
240 {
241 ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
242 return STATUS_INSUFFICIENT_RESOURCES;
243 }
244
245 /* Return allocated internal structure */
246 *DiskBuffer = DiskInformation;
247
248 return STATUS_SUCCESS;
249 }
250
251 PDRIVE_LAYOUT_INFORMATION
252 NTAPI
253 FstubConvertExtendedToLayout(IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx)
254 {
255 ULONG i;
256 PDRIVE_LAYOUT_INFORMATION DriveLayout;
257 PAGED_CODE();
258
259 ASSERT(LayoutEx);
260
261 /* Check whether we're dealing with MBR partition table */
262 if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR)
263 {
264 ASSERT(FALSE);
265 return NULL;
266 }
267
268 /* Allocate needed buffer */
269 DriveLayout = ExAllocatePoolWithTag(NonPagedPool,
270 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) +
271 LayoutEx->PartitionCount * sizeof(PARTITION_INFORMATION),
272 TAG_FSTUB);
273 if (!DriveLayout)
274 {
275 return NULL;
276 }
277
278 /* Convert information about partition table */
279 DriveLayout->PartitionCount = LayoutEx->PartitionCount;
280 DriveLayout->Signature = LayoutEx->Mbr.Signature;
281
282 /* Convert each partition */
283 for (i = 0; i < LayoutEx->PartitionCount; i++)
284 {
285 DriveLayout->PartitionEntry[i].StartingOffset = LayoutEx->PartitionEntry[i].StartingOffset;
286 DriveLayout->PartitionEntry[i].PartitionLength = LayoutEx->PartitionEntry[i].PartitionLength;
287 DriveLayout->PartitionEntry[i].HiddenSectors = LayoutEx->PartitionEntry[i].Mbr.HiddenSectors;
288 DriveLayout->PartitionEntry[i].PartitionNumber = LayoutEx->PartitionEntry[i].PartitionNumber;
289 DriveLayout->PartitionEntry[i].PartitionType = LayoutEx->PartitionEntry[i].Mbr.PartitionType;
290 DriveLayout->PartitionEntry[i].BootIndicator = LayoutEx->PartitionEntry[i].Mbr.BootIndicator;
291 DriveLayout->PartitionEntry[i].RecognizedPartition = LayoutEx->PartitionEntry[i].Mbr.RecognizedPartition;
292 DriveLayout->PartitionEntry[i].RewritePartition = LayoutEx->PartitionEntry[i].RewritePartition;
293 }
294
295 return DriveLayout;
296 }
297
298 VOID
299 NTAPI
300 FstubCopyEntryEFI(OUT PEFI_PARTITION_ENTRY Entry,
301 IN PPARTITION_INFORMATION_EX Partition,
302 ULONG SectorSize)
303 {
304 PAGED_CODE();
305
306 ASSERT(Entry);
307 ASSERT(Partition);
308 ASSERT(SectorSize);
309
310 /* Just convert data to EFI partition entry type */
311 Entry->PartitionType = Partition->Gpt.PartitionType;
312 Entry->UniquePartition = Partition->Gpt.PartitionId;
313 Entry->StartingLBA = Partition->StartingOffset.QuadPart / SectorSize;
314 Entry->EndingLBA = (Partition->StartingOffset.QuadPart + Partition->PartitionLength.QuadPart - 1) / SectorSize;
315 Entry->Attributes = Partition->Gpt.Attributes;
316 RtlCopyMemory(Entry->Name, Partition->Gpt.Name, sizeof(Entry->Name));
317 }
318
319 NTSTATUS
320 NTAPI
321 FstubCreateDiskMBR(IN PDEVICE_OBJECT DeviceObject,
322 IN PCREATE_DISK_MBR DiskInfo)
323 {
324 NTSTATUS Status;
325 PDISK_INFORMATION Disk = NULL;
326 PMASTER_BOOT_RECORD MasterBootRecord;
327 PAGED_CODE();
328
329 ASSERT(DeviceObject);
330
331 /* Allocate internal structure */
332 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0);
333 if (!NT_SUCCESS(Status))
334 {
335 return Status;
336 }
337
338 /* Read previous MBR, if any */
339 Status = FstubReadSector(Disk->DeviceObject,
340 Disk->SectorSize,
341 0ULL,
342 Disk->Buffer);
343 if (!NT_SUCCESS(Status))
344 {
345 FstubFreeDiskInformation(Disk);
346 return Status;
347 }
348 /* Fill the buffer with needed information, we won't overwrite boot code */
349 MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer;
350 MasterBootRecord->Signature = DiskInfo->Signature;
351 RtlZeroMemory(MasterBootRecord->PartitionTable, sizeof(PARTITION_TABLE_ENTRY) * 4);
352 MasterBootRecord->MasterBootRecordMagic = BOOT_RECORD_SIGNATURE;
353
354 /* Finally, write MBR */
355 Status = FstubWriteSector(Disk->DeviceObject,
356 Disk->SectorSize,
357 0ULL,
358 Disk->Buffer);
359
360 /* Release internal structure and return */
361 FstubFreeDiskInformation(Disk);
362 return Status;
363 }
364
365 NTSTATUS
366 NTAPI
367 FstubCreateDiskEFI(IN PDEVICE_OBJECT DeviceObject,
368 IN PCREATE_DISK_GPT DiskInfo)
369 {
370 NTSTATUS Status;
371 PDISK_INFORMATION Disk = NULL;
372 ULONGLONG FirstUsableLBA, LastUsableLBA;
373 ULONG MaxPartitionCount, SectorsForPartitions;
374 PAGED_CODE();
375
376 ASSERT(DeviceObject);
377 ASSERT(DiskInfo);
378
379 /* Allocate internal structure */
380 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0);
381 if (!NT_SUCCESS(Status))
382 {
383 return Status;
384 }
385 ASSERT(Disk);
386
387 /* Write legacy MBR */
388 Status = FstubWriteBootSectorEFI(Disk);
389 if (!NT_SUCCESS(Status))
390 {
391 FstubFreeDiskInformation(Disk);
392 return Status;
393 }
394
395 /* Get max entries and adjust its number */
396 MaxPartitionCount = DiskInfo->MaxPartitionCount;
397 FstubAdjustPartitionCount(Disk->SectorSize, &MaxPartitionCount);
398
399 /* Count number of sectors needed to store partitions */
400 SectorsForPartitions = (MaxPartitionCount * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
401 /* Set first usable LBA: Legacy MBR + GPT header + Partitions entries */
402 FirstUsableLBA = SectorsForPartitions + 2;
403 /* Set last usable LBA: Last sector - GPT header - Partitions entries */
404 LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1;
405
406 /* First, write primary table */
407 Status = FstubWritePartitionTableEFI(Disk,
408 DiskInfo->DiskId,
409 MaxPartitionCount,
410 FirstUsableLBA,
411 LastUsableLBA,
412 FALSE,
413 0,
414 NULL);
415 /* Then, write backup table */
416 if (NT_SUCCESS(Status))
417 {
418 Status = FstubWritePartitionTableEFI(Disk,
419 DiskInfo->DiskId,
420 MaxPartitionCount,
421 FirstUsableLBA,
422 LastUsableLBA,
423 TRUE,
424 0,
425 NULL);
426 }
427
428 /* Release internal structure and return */
429 FstubFreeDiskInformation(Disk);
430 return Status;
431 }
432
433 NTSTATUS
434 NTAPI
435 FstubCreateDiskRaw(IN PDEVICE_OBJECT DeviceObject)
436 {
437 NTSTATUS Status;
438 PDISK_INFORMATION Disk = NULL;
439 PARTITION_STYLE PartitionStyle;
440 PMASTER_BOOT_RECORD MasterBootRecord;
441 PAGED_CODE();
442
443 ASSERT(DeviceObject);
444
445 /* Allocate internal structure */
446 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0);
447 if (!NT_SUCCESS(Status))
448 {
449 return Status;
450 }
451
452 /* Detect current disk partition style */
453 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
454 if (!NT_SUCCESS(Status))
455 {
456 FstubFreeDiskInformation(Disk);
457 return Status;
458 }
459
460 /* Read MBR, if any */
461 Status = FstubReadSector(Disk->DeviceObject,
462 Disk->SectorSize,
463 0ULL,
464 Disk->Buffer);
465 if (!NT_SUCCESS(Status))
466 {
467 FstubFreeDiskInformation(Disk);
468 return Status;
469 }
470
471 /* Only zero useful stuff */
472 MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer;
473 MasterBootRecord->Signature = 0;
474 RtlZeroMemory(MasterBootRecord->PartitionTable, sizeof(PARTITION_TABLE_ENTRY));
475 MasterBootRecord->MasterBootRecordMagic = 0;
476
477 /* Write back that destroyed MBR */
478 Status = FstubWriteSector(Disk->DeviceObject,
479 Disk->SectorSize,
480 0ULL,
481 Disk->Buffer);
482 /* If previous style wasn't GPT, we're done here */
483 if (PartitionStyle != PARTITION_STYLE_GPT)
484 {
485 FstubFreeDiskInformation(Disk);
486 return Status;
487 }
488
489 /* Otherwise, we've to zero the two GPT headers */
490 RtlZeroMemory(Disk->Buffer, Disk->SectorSize);
491 /* Erase primary header */
492 Status = FstubWriteSector(Disk->DeviceObject,
493 Disk->SectorSize,
494 1ULL,
495 Disk->Buffer);
496 /* In case of success, erase backup header */
497 if (NT_SUCCESS(Status))
498 {
499 Status = FstubWriteSector(Disk->DeviceObject,
500 Disk->SectorSize,
501 Disk->SectorCount - 1ULL,
502 Disk->Buffer);
503 }
504
505 /* Release internal structure and return */
506 FstubFreeDiskInformation(Disk);
507 return Status;
508 }
509
510 PCHAR
511 NTAPI
512 FstubDbgGuidToString(IN PGUID Guid,
513 OUT PCHAR String)
514 {
515 sprintf(String,
516 "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
517 Guid->Data1,
518 Guid->Data2,
519 Guid->Data3,
520 Guid->Data4[0],
521 Guid->Data4[1],
522 Guid->Data4[2],
523 Guid->Data4[3],
524 Guid->Data4[4],
525 Guid->Data4[5],
526 Guid->Data4[6],
527 Guid->Data4[7]);
528
529 return String;
530 }
531
532 VOID
533 NTAPI
534 FstubDbgPrintDriveLayoutEx(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout)
535 {
536 ULONG i;
537 CHAR Guid[38];
538 PAGED_CODE();
539
540 DPRINT("FSTUB: DRIVE_LAYOUT_INFORMATION_EX: %p\n", DriveLayout);
541 switch (DriveLayout->PartitionStyle)
542 {
543 case PARTITION_STYLE_MBR:
544 if (DriveLayout->PartitionCount % 4 != 0)
545 {
546 DPRINT("Warning: Partition count isn't a 4-factor: %ld!\n", DriveLayout->PartitionCount);
547 }
548
549 DPRINT("Signature: %8.8x\n", DriveLayout->Mbr.Signature);
550 for (i = 0; i < DriveLayout->PartitionCount; i++)
551 {
552 FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i);
553 }
554
555 break;
556 case PARTITION_STYLE_GPT:
557 FstubDbgGuidToString(&(DriveLayout->Gpt.DiskId), Guid);
558 DPRINT("DiskId: %s\n", Guid);
559 DPRINT("StartingUsableOffset: %I64x\n", DriveLayout->Gpt.StartingUsableOffset.QuadPart);
560 DPRINT("UsableLength: %I64x\n", DriveLayout->Gpt.UsableLength.QuadPart);
561 DPRINT("MaxPartitionCount: %ld\n", DriveLayout->Gpt.MaxPartitionCount);
562 for (i = 0; i < DriveLayout->PartitionCount; i++)
563 {
564 FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i);
565 }
566
567 break;
568 default:
569 DPRINT("Unsupported partition style: %ld\n", DriveLayout->PartitionStyle);
570 }
571 }
572
573 VOID
574 NTAPI
575 FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry,
576 IN ULONG PartitionNumber)
577 {
578 CHAR Guid[38];
579 PAGED_CODE();
580
581 DPRINT("Printing partition %ld\n", PartitionNumber);
582
583 switch (PartitionEntry[PartitionNumber].PartitionStyle)
584 {
585 case PARTITION_STYLE_MBR:
586 DPRINT(" StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart);
587 DPRINT(" PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart);
588 DPRINT(" RewritePartition: %d\n", PartitionEntry[PartitionNumber].RewritePartition);
589 DPRINT(" PartitionType: %02x\n", PartitionEntry[PartitionNumber].Mbr.PartitionType);
590 DPRINT(" BootIndicator: %d\n", PartitionEntry[PartitionNumber].Mbr.BootIndicator);
591 DPRINT(" RecognizedPartition: %d\n", PartitionEntry[PartitionNumber].Mbr.RecognizedPartition);
592 DPRINT(" HiddenSectors: %ld\n", PartitionEntry[PartitionNumber].Mbr.HiddenSectors);
593
594 break;
595 case PARTITION_STYLE_GPT:
596 DPRINT(" StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart);
597 DPRINT(" PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart);
598 DPRINT(" RewritePartition: %d\n", PartitionEntry[PartitionNumber].RewritePartition);
599 FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionType), Guid);
600 DPRINT(" PartitionType: %s\n", Guid);
601 FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionId), Guid);
602 DPRINT(" PartitionId: %s\n", Guid);
603 DPRINT(" Attributes: %16x\n", PartitionEntry[PartitionNumber].Gpt.Attributes);
604 DPRINT(" Name: %ws\n", PartitionEntry[PartitionNumber].Gpt.Name);
605
606 break;
607 default:
608 DPRINT(" Unsupported partition style: %ld\n", PartitionEntry[PartitionNumber].PartitionStyle);
609 }
610 }
611
612 VOID
613 NTAPI
614 FstubDbgPrintSetPartitionEx(IN PSET_PARTITION_INFORMATION_EX PartitionEntry,
615 IN ULONG PartitionNumber)
616 {
617 CHAR Guid[38];
618 PAGED_CODE();
619
620 DPRINT("FSTUB: SET_PARTITION_INFORMATION_EX: %p\n", PartitionEntry);
621 DPRINT("Modifying partition %ld\n", PartitionNumber);
622 switch (PartitionEntry->PartitionStyle)
623 {
624 case PARTITION_STYLE_MBR:
625 DPRINT(" PartitionType: %02x\n", PartitionEntry->Mbr.PartitionType);
626
627 break;
628 case PARTITION_STYLE_GPT:
629 FstubDbgGuidToString(&(PartitionEntry->Gpt.PartitionType), Guid);
630 DPRINT(" PartitionType: %s\n", Guid);
631 FstubDbgGuidToString(&(PartitionEntry->Gpt.PartitionId), Guid);
632 DPRINT(" PartitionId: %s\n", Guid);
633 DPRINT(" Attributes: %16x\n", PartitionEntry->Gpt.Attributes);
634 DPRINT(" Name: %ws\n", PartitionEntry->Gpt.Name);
635
636 break;
637 default:
638 DPRINT(" Unsupported partition style: %ld\n", PartitionEntry[PartitionNumber].PartitionStyle);
639 }
640 }
641
642 NTSTATUS
643 NTAPI
644 FstubDetectPartitionStyle(IN PDISK_INFORMATION Disk,
645 IN PARTITION_STYLE * PartitionStyle)
646 {
647 NTSTATUS Status;
648 PPARTITION_DESCRIPTOR PartitionDescriptor;
649 PAGED_CODE();
650
651 ASSERT(IS_VALID_DISK_INFO(Disk));
652 ASSERT(PartitionStyle);
653
654 /* Read disk first sector */
655 Status = FstubReadSector(Disk->DeviceObject,
656 Disk->SectorSize,
657 0,
658 Disk->Buffer);
659 if (!NT_SUCCESS(Status))
660 {
661 return Status;
662 }
663
664 /* Get the partition descriptor array */
665 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
666 &(Disk->Buffer[PARTITION_TABLE_OFFSET]);
667 /* If we have not the 0xAA55 then it's raw partition */
668 if (Disk->Buffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
669 {
670 *PartitionStyle = PARTITION_STYLE_RAW;
671 }
672 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
673 else if (PartitionDescriptor[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
674 PartitionDescriptor[1].PartitionType == 0 &&
675 PartitionDescriptor[2].PartitionType == 0 &&
676 PartitionDescriptor[3].PartitionType == 0)
677 {
678 *PartitionStyle = PARTITION_STYLE_GPT;
679 }
680 /* Otherwise, partition table is in MBR */
681 else
682 {
683 *PartitionStyle = PARTITION_STYLE_MBR;
684 }
685
686 return STATUS_SUCCESS;
687 }
688
689 VOID
690 NTAPI
691 FstubFreeDiskInformation(IN PDISK_INFORMATION DiskBuffer)
692 {
693 if (DiskBuffer)
694 {
695 if (DiskBuffer->Buffer)
696 {
697 ExFreePoolWithTag(DiskBuffer->Buffer, TAG_FSTUB);
698 }
699 ExFreePoolWithTag(DiskBuffer, TAG_FSTUB);
700 }
701 }
702
703 NTSTATUS
704 NTAPI
705 FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject,
706 OUT PDISK_GEOMETRY_EX Geometry)
707 {
708 PIRP Irp;
709 NTSTATUS Status;
710 PKEVENT Event = NULL;
711 PDISK_GEOMETRY_EX DiskGeometry = NULL;
712 PIO_STATUS_BLOCK IoStatusBlock = NULL;
713 PAGED_CODE();
714
715 ASSERT(DeviceObject);
716 ASSERT(Geometry);
717
718 /* Allocate needed components */
719 DiskGeometry = ExAllocatePoolWithTag(NonPagedPool, sizeof(DISK_GEOMETRY_EX), TAG_FSTUB);
720 if (!DiskGeometry)
721 {
722 Status = STATUS_INSUFFICIENT_RESOURCES;
723 goto Cleanup;
724 }
725
726 IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool, sizeof(IO_STATUS_BLOCK), TAG_FSTUB);
727 if (!IoStatusBlock)
728 {
729 Status = STATUS_INSUFFICIENT_RESOURCES;
730 goto Cleanup;
731 }
732
733 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_FSTUB);
734 if (!Event)
735 {
736 Status = STATUS_INSUFFICIENT_RESOURCES;
737 goto Cleanup;
738 }
739 /* Initialize the waiting event */
740 KeInitializeEvent(Event, NotificationEvent, FALSE);
741
742 /* Build the request to get disk geometry */
743 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
744 DeviceObject,
745 0,
746 0,
747 DiskGeometry,
748 sizeof(DISK_GEOMETRY_EX),
749 FALSE,
750 Event,
751 IoStatusBlock);
752 if (!Irp)
753 {
754 Status = STATUS_INSUFFICIENT_RESOURCES;
755 goto Cleanup;
756 }
757
758 /* Call the driver and wait for completion if needed */
759 Status = IoCallDriver(DeviceObject, Irp);
760 if (Status == STATUS_PENDING)
761 {
762 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
763 Status = IoStatusBlock->Status;
764 }
765
766 /* In case of a success, return read data */
767 if (NT_SUCCESS(Status))
768 {
769 *Geometry = *DiskGeometry;
770 }
771
772 Cleanup:
773 if (DiskGeometry)
774 {
775 ExFreePoolWithTag(DiskGeometry, TAG_FSTUB);
776
777 if (NT_SUCCESS(Status))
778 {
779 ASSERT(Geometry->Geometry.BytesPerSector % PARTITION_ENTRY_SIZE == 0);
780 }
781 }
782
783 if (IoStatusBlock)
784 {
785 ExFreePoolWithTag(IoStatusBlock, TAG_FSTUB);
786 }
787
788 if (Event)
789 {
790 ExFreePoolWithTag(Event, TAG_FSTUB);
791 }
792
793 return Status;
794 }
795
796 NTSTATUS
797 NTAPI
798 FstubReadHeaderEFI(IN PDISK_INFORMATION Disk,
799 IN BOOLEAN ReadBackupTable,
800 PEFI_PARTITION_HEADER HeaderBuffer)
801 {
802 NTSTATUS Status;
803 PUCHAR Sector = NULL;
804 ULONGLONG StartingSector;
805 PEFI_PARTITION_HEADER EFIHeader;
806 ULONG i, HeaderCRC32, PreviousCRC32, SectoredPartitionEntriesSize, LonelyPartitions;
807 PAGED_CODE();
808
809 ASSERT(Disk);
810 ASSERT(IS_VALID_DISK_INFO(Disk));
811 ASSERT(HeaderBuffer);
812
813 /* In case we want to read backup table, we read last disk sector */
814 if (ReadBackupTable)
815 {
816 StartingSector = Disk->SectorCount - 1ULL;
817 }
818 else
819 {
820 /* Otherwise we start at first sector (as sector 0 is the MBR) */
821 StartingSector = 1ULL;
822 }
823
824 Status = FstubReadSector(Disk->DeviceObject,
825 Disk->SectorSize,
826 StartingSector,
827 Disk->Buffer);
828 if (!NT_SUCCESS(Status))
829 {
830 DPRINT("EFI::Failed reading header!\n");
831 return Status;
832 }
833 /* Let's use read buffer as EFI_PARTITION_HEADER */
834 EFIHeader = (PEFI_PARTITION_HEADER)Disk->Buffer;
835
836
837 /* First check signature
838 * Then, check version (we only support v1)
839 * Finally check header size
840 */
841 if (EFIHeader->Signature != EFI_HEADER_SIGNATURE ||
842 EFIHeader->Revision != EFI_HEADER_REVISION_1 ||
843 EFIHeader->HeaderSize != sizeof(EFI_PARTITION_HEADER))
844 {
845 DPRINT("EFI::Wrong signature/version/header size!\n");
846 DPRINT("%I64x (expected: %I64x)\n", EFIHeader->Signature, EFI_HEADER_SIGNATURE);
847 DPRINT("%03x (expected: %03x)\n", EFIHeader->Revision, EFI_HEADER_REVISION_1);
848 DPRINT("%02x (expected: %02x)\n", EFIHeader->HeaderSize, sizeof(EFI_PARTITION_HEADER));
849 return STATUS_DISK_CORRUPT_ERROR;
850 }
851
852 /* Save current checksum */
853 HeaderCRC32 = EFIHeader->HeaderCRC32;
854 /* Then zero the one in EFI header. This is needed to compute header checksum */
855 EFIHeader->HeaderCRC32 = 0;
856 /* Compute header checksum and compare with the one present in partition table */
857 if (RtlComputeCrc32(0, (PUCHAR)Disk->Buffer, sizeof(EFI_PARTITION_HEADER)) != HeaderCRC32)
858 {
859 DPRINT("EFI::Not matching header checksum!\n");
860 return STATUS_DISK_CORRUPT_ERROR;
861 }
862 /* Put back removed checksum in header */
863 EFIHeader->HeaderCRC32 = HeaderCRC32;
864
865 /* Check if current LBA is matching with ours */
866 if (EFIHeader->MyLBA != StartingSector)
867 {
868 DPRINT("EFI::Not matching starting sector!\n");
869 return STATUS_DISK_CORRUPT_ERROR;
870 }
871
872 /* Allocate a buffer to read a sector on the disk */
873 Sector = ExAllocatePoolWithTag(NonPagedPool,
874 Disk->SectorSize,
875 TAG_FSTUB);
876 if (!Sector)
877 {
878 DPRINT("EFI::Lacking resources!\n");
879 return STATUS_INSUFFICIENT_RESOURCES;
880 }
881
882 /* Count how much sectors we'll have to read to read the whole partition table */
883 SectoredPartitionEntriesSize = (EFIHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
884 /* Compute partition table checksum */
885 for (i = 0, PreviousCRC32 = 0; i < SectoredPartitionEntriesSize; i++)
886 {
887 Status = FstubReadSector(Disk->DeviceObject,
888 Disk->SectorSize,
889 EFIHeader->PartitionEntryLBA + i,
890 (PUSHORT)Sector);
891 if (!NT_SUCCESS(Status))
892 {
893 ExFreePoolWithTag(Sector, TAG_FSTUB);
894 DPRINT("EFI::Failed reading sector for partition entry!\n");
895 return Status;
896 }
897
898 PreviousCRC32 = RtlComputeCrc32(PreviousCRC32, Sector, Disk->SectorSize);
899 }
900
901 /* Check whether we have a last sector not full of partitions */
902 LonelyPartitions = (EFIHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) % Disk->SectorSize;
903 /* In such case, we have to complete checksum computation */
904 if (LonelyPartitions != 0)
905 {
906 /* Read the sector that contains those partitions */
907 Status = FstubReadSector(Disk->DeviceObject,
908 Disk->SectorSize,
909 EFIHeader->PartitionEntryLBA + i,
910 (PUSHORT)Sector);
911 if (!NT_SUCCESS(Status))
912 {
913 ExFreePoolWithTag(Sector, TAG_FSTUB);
914 DPRINT("EFI::Failed reading sector for partition entry!\n");
915 return Status;
916 }
917
918 /* Then complete checksum by computing on each partition */
919 for (i = 0; i < LonelyPartitions; i++)
920 {
921 PreviousCRC32 = RtlComputeCrc32(PreviousCRC32, Sector + i * PARTITION_ENTRY_SIZE, PARTITION_ENTRY_SIZE);
922 }
923 }
924
925 /* Finally, release memory */
926 ExFreePoolWithTag(Sector, TAG_FSTUB);
927
928 /* Compare checksums */
929 if (PreviousCRC32 == EFIHeader->PartitionEntryCRC32)
930 {
931 /* In case of a success, return read header */
932 *HeaderBuffer = *EFIHeader;
933 return STATUS_SUCCESS;
934 }
935 else
936 {
937 DPRINT("EFI::Not matching partition table checksum!\n");
938 DPRINT("EFI::Expected: %x, received: %x\n", EFIHeader->PartitionEntryCRC32, PreviousCRC32);
939 return STATUS_DISK_CORRUPT_ERROR;
940 }
941 }
942
943 NTSTATUS
944 NTAPI
945 FstubReadPartitionTableEFI(IN PDISK_INFORMATION Disk,
946 IN BOOLEAN ReadBackupTable,
947 OUT struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout)
948 {
949 NTSTATUS Status;
950 EFI_PARTITION_HEADER EfiHeader;
951 ULONGLONG SectorsForPartitions;
952 EFI_PARTITION_ENTRY PartitionEntry;
953 BOOLEAN UpdatedPartitionTable = FALSE;
954 PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = NULL;
955 ULONG i, PartitionCount, PartitionIndex, PartitionsPerSector;
956 PAGED_CODE();
957
958 ASSERT(Disk);
959
960 /* Zero output */
961 *DriveLayout = NULL;
962
963 /* Read EFI header */
964 Status = FstubReadHeaderEFI(Disk,
965 ReadBackupTable,
966 &EfiHeader);
967 if (!NT_SUCCESS(Status))
968 {
969 return Status;
970 }
971
972 /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */
973 DriveLayoutEx = ExAllocatePoolWithTag(NonPagedPool,
974 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
975 EfiHeader.NumberOfEntries * sizeof(PARTITION_INFORMATION_EX),
976 TAG_FSTUB);
977 if (!DriveLayoutEx)
978 {
979 return STATUS_INSUFFICIENT_RESOURCES;
980 }
981
982 if (ReadBackupTable)
983 {
984 /* If we read backup but if it doesn't match with current geometry */
985 if ((Disk->SectorCount - 1ULL) != EfiHeader.AlternateLBA)
986 {
987 /* We'll update it. First, count number of sectors needed to store partitions */
988 SectorsForPartitions = ((ULONGLONG)EfiHeader.NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
989 /* Then set first usable LBA: Legacy MBR + GPT header + Partitions entries */
990 EfiHeader.FirstUsableLBA = SectorsForPartitions + 2;
991 /* Then set last usable LBA: Last sector - GPT header - Partitions entries */
992 EfiHeader.LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1;
993 /* Inform that we'll rewrite partition table */
994 UpdatedPartitionTable = TRUE;
995 }
996 }
997
998 DriveLayoutEx->PartitionStyle = PARTITION_STYLE_GPT;
999 /* Translate LBA -> Offset */
1000 DriveLayoutEx->Gpt.StartingUsableOffset.QuadPart = EfiHeader.FirstUsableLBA * Disk->SectorSize;
1001 DriveLayoutEx->Gpt.UsableLength.QuadPart = EfiHeader.LastUsableLBA - EfiHeader.FirstUsableLBA * Disk->SectorSize;
1002 DriveLayoutEx->Gpt.MaxPartitionCount = EfiHeader.NumberOfEntries;
1003 DriveLayoutEx->Gpt.DiskId = EfiHeader.DiskGUID;
1004
1005 /* Count number of partitions per sector */
1006 PartitionsPerSector = (Disk->SectorSize / PARTITION_ENTRY_SIZE);
1007 /* Read all partitions and fill in structure */
1008 for (i = 0, PartitionCount = 0, PartitionIndex = PartitionsPerSector;
1009 i < EfiHeader.NumberOfEntries;
1010 i++)
1011 {
1012 /* Only read following sector if we finished with previous sector */
1013 if (PartitionIndex == PartitionsPerSector)
1014 {
1015 Status = FstubReadSector(Disk->DeviceObject,
1016 Disk->SectorSize,
1017 EfiHeader.PartitionEntryLBA + (i / PartitionsPerSector),
1018 Disk->Buffer);
1019 if (!NT_SUCCESS(Status))
1020 {
1021 ExFreePoolWithTag(DriveLayoutEx, TAG_FSTUB);
1022 return Status;
1023 }
1024
1025 PartitionIndex = 0;
1026 }
1027 /* Read following partition */
1028 PartitionEntry = ((PEFI_PARTITION_ENTRY)Disk->Buffer)[PartitionIndex];
1029 PartitionIndex++;
1030
1031 /* If partition GUID is 00000000-0000-0000-0000-000000000000, then it's unused, skip it */
1032 if (PartitionEntry.PartitionType.Data1 == 0 &&
1033 PartitionEntry.PartitionType.Data2 == 0 &&
1034 PartitionEntry.PartitionType.Data3 == 0 &&
1035 ((PULONGLONG)PartitionEntry.PartitionType.Data4)[0] == 0)
1036 {
1037 continue;
1038 }
1039
1040 /* Write data to structure. Don't forget GPT is using sectors, Windows offsets */
1041 DriveLayoutEx->PartitionEntry[PartitionCount].StartingOffset.QuadPart = PartitionEntry.StartingLBA * Disk->SectorSize;
1042 DriveLayoutEx->PartitionEntry[PartitionCount].PartitionLength.QuadPart = (PartitionEntry.EndingLBA -
1043 PartitionEntry.StartingLBA + 1) *
1044 Disk->SectorSize;
1045 /* This number starts from 1 */
1046 DriveLayoutEx->PartitionEntry[PartitionCount].PartitionNumber = PartitionCount + 1;
1047 DriveLayoutEx->PartitionEntry[PartitionCount].RewritePartition = FALSE;
1048 DriveLayoutEx->PartitionEntry[PartitionCount].PartitionStyle = PARTITION_STYLE_GPT;
1049 DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.PartitionType = PartitionEntry.PartitionType;
1050 DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.PartitionId = PartitionEntry.UniquePartition;
1051 DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.Attributes = PartitionEntry.Attributes;
1052 RtlCopyMemory(DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.Name,
1053 PartitionEntry.Name, sizeof(PartitionEntry.Name));
1054
1055 /* Update partition count */
1056 PartitionCount++;
1057 }
1058 DriveLayoutEx->PartitionCount = PartitionCount;
1059
1060 /* If we updated partition table using backup table, rewrite partition table */
1061 if (UpdatedPartitionTable)
1062 {
1063 IoWritePartitionTableEx(Disk->DeviceObject,
1064 DriveLayoutEx);
1065 }
1066
1067 /* Finally, return read data */
1068 *DriveLayout = DriveLayoutEx;
1069
1070 return Status;
1071 }
1072
1073 NTSTATUS
1074 NTAPI
1075 FstubReadPartitionTableMBR(IN PDISK_INFORMATION Disk,
1076 IN BOOLEAN ReturnRecognizedPartitions,
1077 OUT struct _DRIVE_LAYOUT_INFORMATION_EX** ReturnedDriveLayout)
1078 {
1079 ULONG i;
1080 NTSTATUS Status;
1081 PDRIVE_LAYOUT_INFORMATION DriveLayout = NULL;
1082 PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = NULL;
1083 PAGED_CODE();
1084
1085 ASSERT(IS_VALID_DISK_INFO(Disk));
1086 ASSERT(ReturnedDriveLayout);
1087
1088 /* Zero output */
1089 *ReturnedDriveLayout = NULL;
1090
1091 /* Read partition table the old way */
1092 Status = IoReadPartitionTable(Disk->DeviceObject,
1093 Disk->SectorSize,
1094 ReturnRecognizedPartitions,
1095 &DriveLayout);
1096 if (!NT_SUCCESS(Status))
1097 {
1098 return Status;
1099 }
1100
1101 /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */
1102 DriveLayoutEx = ExAllocatePoolWithTag(NonPagedPool,
1103 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
1104 DriveLayout->PartitionCount * sizeof(PARTITION_INFORMATION_EX),
1105 TAG_FSTUB);
1106 if (!DriveLayoutEx)
1107 {
1108 /* Let's not leak memory as in Windows 2003 */
1109 ExFreePool(DriveLayout);
1110 return STATUS_INSUFFICIENT_RESOURCES;
1111 }
1112
1113 /* Start converting the DRIVE_LAYOUT_INFORMATION structure */
1114 DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
1115 DriveLayoutEx->PartitionCount = DriveLayout->PartitionCount;
1116 DriveLayoutEx->Mbr.Signature = DriveLayout->Signature;
1117
1118 /* Convert each found partition */
1119 for (i = 0; i < DriveLayout->PartitionCount; i++)
1120 {
1121 DriveLayoutEx->PartitionEntry[i].PartitionStyle = PARTITION_STYLE_MBR;
1122 DriveLayoutEx->PartitionEntry[i].StartingOffset = DriveLayout->PartitionEntry[i].StartingOffset;
1123 DriveLayoutEx->PartitionEntry[i].PartitionLength = DriveLayout->PartitionEntry[i].PartitionLength;
1124 DriveLayoutEx->PartitionEntry[i].PartitionNumber = DriveLayout->PartitionEntry[i].PartitionNumber;
1125 DriveLayoutEx->PartitionEntry[i].RewritePartition = DriveLayout->PartitionEntry[i].RewritePartition;
1126 DriveLayoutEx->PartitionEntry[i].Mbr.PartitionType = DriveLayout->PartitionEntry[i].PartitionType;
1127 DriveLayoutEx->PartitionEntry[i].Mbr.BootIndicator = DriveLayout->PartitionEntry[i].BootIndicator;
1128 DriveLayoutEx->PartitionEntry[i].Mbr.RecognizedPartition = DriveLayout->PartitionEntry[i].RecognizedPartition;
1129 DriveLayoutEx->PartitionEntry[i].Mbr.HiddenSectors = DriveLayout->PartitionEntry[i].HiddenSectors;
1130 }
1131
1132 /* Finally, return data and free old structure */
1133 *ReturnedDriveLayout = DriveLayoutEx;
1134 ExFreePool(DriveLayout);
1135
1136 return STATUS_SUCCESS;
1137 }
1138
1139 NTSTATUS
1140 NTAPI
1141 FstubReadSector(IN PDEVICE_OBJECT DeviceObject,
1142 IN ULONG SectorSize,
1143 IN ULONGLONG StartingSector OPTIONAL,
1144 OUT PUSHORT Buffer)
1145 {
1146 PIRP Irp;
1147 KEVENT Event;
1148 NTSTATUS Status;
1149 LARGE_INTEGER StartingOffset;
1150 IO_STATUS_BLOCK IoStatusBlock;
1151 PIO_STACK_LOCATION IoStackLocation;
1152 PAGED_CODE();
1153
1154 ASSERT(DeviceObject);
1155 ASSERT(Buffer);
1156 ASSERT(SectorSize);
1157
1158 /* Compute starting offset */
1159 StartingOffset.QuadPart = StartingSector * SectorSize;
1160
1161 /* Initialize waiting event */
1162 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1163
1164 /* Prepare IRP */
1165 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1166 DeviceObject,
1167 Buffer,
1168 SectorSize,
1169 &StartingOffset,
1170 &Event,
1171 &IoStatusBlock);
1172 if (!Irp)
1173 {
1174 return STATUS_INSUFFICIENT_RESOURCES;
1175 }
1176
1177 /* Override volume verify */
1178 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1179 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1180
1181 /* Then call driver, and wait for completion if needed */
1182 Status = IoCallDriver(DeviceObject, Irp);
1183 if (Status == STATUS_PENDING)
1184 {
1185 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1186 Status = IoStatusBlock.Status;
1187 }
1188
1189 return Status;
1190 }
1191
1192 NTSTATUS
1193 NTAPI
1194 FstubSetPartitionInformationEFI(IN PDISK_INFORMATION Disk,
1195 IN ULONG PartitionNumber,
1196 IN SET_PARTITION_INFORMATION_GPT * PartitionInfo)
1197 {
1198 NTSTATUS Status;
1199 PDRIVE_LAYOUT_INFORMATION_EX Layout = NULL;
1200 PAGED_CODE();
1201
1202 ASSERT(Disk);
1203 ASSERT(PartitionInfo);
1204
1205 /* Partition 0 isn't correct (should start at 1) */
1206 if (PartitionNumber == 0)
1207 {
1208 return STATUS_INVALID_PARAMETER;
1209 }
1210
1211 /* Read partition table */
1212 Status = IoReadPartitionTableEx(Disk->DeviceObject, &Layout);
1213 if (!NT_SUCCESS(Status))
1214 {
1215 return Status;
1216 }
1217 ASSERT(Layout);
1218
1219 /* If our partition (started at 0 now) is higher than partition count, then, there's an issue */
1220 if (Layout->PartitionCount <= --PartitionNumber)
1221 {
1222 ExFreePool(Layout);
1223 return STATUS_INVALID_PARAMETER;
1224 }
1225
1226 /* Erase actual partition entry data with provided ones */
1227 Layout->PartitionEntry[PartitionNumber].Gpt.PartitionType = PartitionInfo->PartitionType;
1228 Layout->PartitionEntry[PartitionNumber].Gpt.PartitionId = PartitionInfo->PartitionId;
1229 Layout->PartitionEntry[PartitionNumber].Gpt.Attributes = PartitionInfo->Attributes;
1230 RtlCopyMemory(Layout->PartitionEntry[PartitionNumber].Gpt.Name, PartitionInfo->Name, sizeof(PartitionInfo->Name));
1231
1232 /* Rewrite the whole partition table to update the modified entry */
1233 Status = IoWritePartitionTableEx(Disk->DeviceObject, Layout);
1234
1235 /* Free partition table and return */
1236 ExFreePool(Layout);
1237 return Status;
1238 }
1239
1240 NTSTATUS
1241 NTAPI
1242 FstubVerifyPartitionTableEFI(IN PDISK_INFORMATION Disk,
1243 IN BOOLEAN FixErrors)
1244 {
1245 NTSTATUS Status;
1246 PEFI_PARTITION_HEADER EFIHeader;
1247 EFI_PARTITION_HEADER ReadEFIHeader;
1248 BOOLEAN PrimaryValid = FALSE, BackupValid = FALSE;
1249 PAGED_CODE();
1250
1251 EFIHeader = ExAllocatePoolWithTag(NonPagedPool, sizeof(EFI_PARTITION_HEADER), TAG_FSTUB);
1252 if (!EFIHeader)
1253 {
1254 return STATUS_INSUFFICIENT_RESOURCES;
1255 }
1256
1257 Status = FstubReadHeaderEFI(Disk, FALSE, &ReadEFIHeader);
1258 if (NT_SUCCESS(Status))
1259 {
1260 PrimaryValid = TRUE;
1261 }
1262
1263 Status = FstubReadHeaderEFI(Disk, TRUE, &ReadEFIHeader);
1264 if (NT_SUCCESS(Status))
1265 {
1266 BackupValid = TRUE;
1267 }
1268
1269 if (!PrimaryValid)
1270 {
1271 if (!BackupValid || !FixErrors)
1272 {
1273 ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1274 return STATUS_DISK_CORRUPT_ERROR;
1275 }
1276
1277 DPRINT1("EFI::Partition table fixing not yet supported!\n");
1278 ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1279 return STATUS_NOT_IMPLEMENTED;
1280 }
1281 else if (!BackupValid)
1282 {
1283 if (!PrimaryValid || !FixErrors)
1284 {
1285 ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1286 return STATUS_DISK_CORRUPT_ERROR;
1287 }
1288
1289 DPRINT1("EFI::Partition table fixing not yet supported!\n");
1290 ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1291 return STATUS_NOT_IMPLEMENTED;
1292 }
1293 else
1294 {
1295 ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1296 return STATUS_SUCCESS;
1297 }
1298 }
1299
1300 NTSTATUS
1301 NTAPI
1302 FstubWriteBootSectorEFI(IN PDISK_INFORMATION Disk)
1303 {
1304 NTSTATUS Status;
1305 ULONG Signature = 0;
1306 PMASTER_BOOT_RECORD MasterBootRecord;
1307 PAGED_CODE();
1308
1309 ASSERT(Disk);
1310 ASSERT(IS_VALID_DISK_INFO(Disk));
1311
1312 /* Read if a MBR is already present */
1313 Status = FstubReadSector(Disk->DeviceObject,
1314 Disk->SectorSize,
1315 0ULL,
1316 Disk->Buffer);
1317 MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer;
1318 /* If one has been found */
1319 if (NT_SUCCESS(Status) && MasterBootRecord->MasterBootRecordMagic == BOOT_RECORD_SIGNATURE)
1320 {
1321 /* Save its signature */
1322 Signature = MasterBootRecord->Signature;
1323 }
1324
1325 /* Reset the MBR */
1326 RtlZeroMemory(MasterBootRecord, Disk->SectorSize);
1327 /* Then create a fake MBR matching those purposes:
1328 * It must have only partition. Type of this partition
1329 * has to be 0xEE to signal a GPT is following.
1330 * This partition has to cover the whole disk. To prevent
1331 * any disk modification by a program that wouldn't
1332 * understand anything to GPT.
1333 */
1334 MasterBootRecord->Signature = Signature;
1335 MasterBootRecord->PartitionTable[0].StartSector = 2;
1336 MasterBootRecord->PartitionTable[0].SystemIndicator = EFI_PMBR_OSTYPE_EFI;
1337 MasterBootRecord->PartitionTable[0].EndHead = 0xFF;
1338 MasterBootRecord->PartitionTable[0].EndSector = 0xFF;
1339 MasterBootRecord->PartitionTable[0].EndCylinder = 0xFF;
1340 MasterBootRecord->PartitionTable[0].SectorCountBeforePartition = 1;
1341 MasterBootRecord->PartitionTable[0].PartitionSectorCount = 0xFFFFFFFF;
1342 MasterBootRecord->MasterBootRecordMagic = BOOT_RECORD_SIGNATURE;
1343
1344 /* Finally, write that MBR */
1345 return FstubWriteSector(Disk->DeviceObject,
1346 Disk->SectorSize,
1347 0,
1348 Disk->Buffer);
1349 }
1350
1351 NTSTATUS
1352 NTAPI
1353 FstubWriteEntryEFI(IN PDISK_INFORMATION Disk,
1354 IN ULONG PartitionsSizeSector,
1355 IN ULONG PartitionEntryNumber,
1356 IN PEFI_PARTITION_ENTRY PartitionEntry,
1357 IN BOOLEAN WriteBackupTable,
1358 IN BOOLEAN ForceWrite,
1359 OUT PULONG PartitionEntryCRC32 OPTIONAL)
1360 {
1361 ULONG Offset;
1362 ULONGLONG FirstEntryLBA;
1363 NTSTATUS Status = STATUS_SUCCESS;
1364 PAGED_CODE();
1365
1366 ASSERT(Disk);
1367 ASSERT(IS_VALID_DISK_INFO(Disk));
1368
1369 /* Get the first LBA where the partition table is:
1370 * On primary table, it's sector 2 (skip MBR & Header)
1371 * On backup table, it's ante last sector (Header) minus partition table size
1372 */
1373 if (!WriteBackupTable)
1374 {
1375 FirstEntryLBA = 2ULL;
1376 }
1377 else
1378 {
1379 FirstEntryLBA = Disk->SectorCount - PartitionsSizeSector - 1;
1380 }
1381
1382 /* Copy the entry at the proper place into the buffer
1383 * That way, we don't erase previous entries
1384 */
1385 RtlCopyMemory(Disk->Buffer + (((PartitionEntryNumber * PARTITION_ENTRY_SIZE) % Disk->SectorSize) / sizeof(PUSHORT)),
1386 PartitionEntry,
1387 sizeof(EFI_PARTITION_ENTRY));
1388 /* Compute size of buffer */
1389 Offset = (PartitionEntryNumber * PARTITION_ENTRY_SIZE) % Disk->SectorSize + PARTITION_ENTRY_SIZE;
1390 ASSERT(Offset <= Disk->SectorSize);
1391
1392 /* If it's full of partition entries, or if call ask for it, write down the data */
1393 if (Offset == Disk->SectorSize || ForceWrite)
1394 {
1395 /* We will write at first entry LBA + a shift made by already present/written entries */
1396 Status = FstubWriteSector(Disk->DeviceObject,
1397 Disk->SectorSize,
1398 FirstEntryLBA + ((PartitionEntryNumber * PARTITION_ENTRY_SIZE) / Disk->SectorSize),
1399 Disk->Buffer);
1400 if (!NT_SUCCESS(Status))
1401 {
1402 return Status;
1403 }
1404 /* We clean buffer */
1405 RtlZeroMemory(Disk->Buffer, Disk->SectorSize);
1406 }
1407
1408 /* If we have a buffer for CRC32, then compute it */
1409 if (PartitionEntryCRC32)
1410 {
1411 *PartitionEntryCRC32 = RtlComputeCrc32(*PartitionEntryCRC32, (PUCHAR)PartitionEntry, PARTITION_ENTRY_SIZE);
1412 }
1413
1414 return Status;
1415 }
1416
1417 NTSTATUS
1418 NTAPI
1419 FstubWriteHeaderEFI(IN PDISK_INFORMATION Disk,
1420 IN ULONG PartitionsSizeSector,
1421 IN GUID DiskGUID,
1422 IN ULONG NumberOfEntries,
1423 IN ULONGLONG FirstUsableLBA,
1424 IN ULONGLONG LastUsableLBA,
1425 IN ULONG PartitionEntryCRC32,
1426 IN BOOLEAN WriteBackupTable)
1427 {
1428 PEFI_PARTITION_HEADER EFIHeader;
1429 PAGED_CODE();
1430
1431 ASSERT(Disk);
1432 ASSERT(IS_VALID_DISK_INFO(Disk));
1433
1434 /* Let's use read buffer as EFI_PARTITION_HEADER */
1435 EFIHeader = (PEFI_PARTITION_HEADER)Disk->Buffer;
1436
1437 /* Complete standard header information */
1438 EFIHeader->Signature = EFI_HEADER_SIGNATURE;
1439 EFIHeader->Revision = EFI_HEADER_REVISION_1;
1440 EFIHeader->HeaderSize = sizeof(EFI_PARTITION_HEADER);
1441 /* Set no CRC32 checksum at the moment */
1442 EFIHeader->HeaderCRC32 = 0;
1443 EFIHeader->Reserved = 0;
1444 /* Check whether we're writing primary or backup
1445 * That way, we can ajust LBA setting:
1446 * Primary is on first sector
1447 * Backup is on last sector
1448 */
1449 if (!WriteBackupTable)
1450 {
1451 EFIHeader->MyLBA = 1ULL;
1452 EFIHeader->AlternateLBA = Disk->SectorCount - 1ULL;
1453 }
1454 else
1455 {
1456 EFIHeader->MyLBA = Disk->SectorCount - 1ULL;
1457 EFIHeader->AlternateLBA = 1ULL;
1458 }
1459 /* Fill in with received data */
1460 EFIHeader->FirstUsableLBA = FirstUsableLBA;
1461 EFIHeader->LastUsableLBA = LastUsableLBA;
1462 EFIHeader->DiskGUID = DiskGUID;
1463 /* Check whether we're writing primary or backup
1464 * That way, we can ajust LBA setting:
1465 * On primary, partition entries are just after header, so sector 2
1466 * On backup, partition entries are just before header, so, last sector minus partition table size
1467 */
1468 if (!WriteBackupTable)
1469 {
1470 EFIHeader->PartitionEntryLBA = EFIHeader->MyLBA + 1ULL;
1471 }
1472 else
1473 {
1474 EFIHeader->PartitionEntryLBA = EFIHeader->MyLBA - PartitionsSizeSector;
1475 }
1476 /* Complete filling in */
1477 EFIHeader->NumberOfEntries = NumberOfEntries;
1478 EFIHeader->SizeOfPartitionEntry = PARTITION_ENTRY_SIZE;
1479 EFIHeader->PartitionEntryCRC32 = PartitionEntryCRC32;
1480 /* Finally, compute header checksum */
1481 EFIHeader->HeaderCRC32 = RtlComputeCrc32(0, (PUCHAR)EFIHeader, sizeof(EFI_PARTITION_HEADER));
1482
1483 /* Debug the way we'll break disk, to let user pray */
1484 DPRINT("FSTUB: About to write the following header for %s table\n", (WriteBackupTable ? "backup" : "primary"));
1485 DPRINT(" Signature: %I64x\n Revision: %x\n HeaderSize: %x\n HeaderCRC32: %x\n",
1486 EFIHeader->Signature, EFIHeader->Revision, EFIHeader->HeaderSize, EFIHeader->HeaderCRC32);
1487 DPRINT(" MyLBA: %I64x\n AlternateLBA: %I64x\n FirstUsableLBA: %I64x\n LastUsableLBA: %I64x\n",
1488 EFIHeader->MyLBA, EFIHeader->AlternateLBA, EFIHeader->FirstUsableLBA, EFIHeader->LastUsableLBA);
1489 DPRINT(" PartitionEntryLBA: %I64x\n NumberOfEntries: %x\n SizeOfPartitionEntry: %x\n PartitionEntryCRC32: %x\n",
1490 EFIHeader->PartitionEntryLBA, EFIHeader->NumberOfEntries,
1491 EFIHeader->SizeOfPartitionEntry, EFIHeader->PartitionEntryCRC32);
1492
1493 /* Write header to disk */
1494 return FstubWriteSector(Disk->DeviceObject,
1495 Disk->SectorSize,
1496 EFIHeader->MyLBA,
1497 Disk->Buffer);
1498 }
1499
1500 NTSTATUS
1501 NTAPI
1502 FstubWritePartitionTableEFI(IN PDISK_INFORMATION Disk,
1503 IN GUID DiskGUID,
1504 IN ULONG MaxPartitionCount,
1505 IN ULONGLONG FirstUsableLBA,
1506 IN ULONGLONG LastUsableLBA,
1507 IN BOOLEAN WriteBackupTable,
1508 IN ULONG PartitionCount,
1509 IN PPARTITION_INFORMATION_EX PartitionEntries OPTIONAL)
1510 {
1511 NTSTATUS Status;
1512 EFI_PARTITION_ENTRY Entry;
1513 ULONG i, WrittenPartitions, SectoredPartitionEntriesSize, PartitionEntryCRC32;
1514 PAGED_CODE();
1515
1516 ASSERT(Disk);
1517 ASSERT(MaxPartitionCount >= 128);
1518 ASSERT(PartitionCount <= MaxPartitionCount);
1519
1520 PartitionEntryCRC32 = 0;
1521 /* Count how much sectors we'll have to read to read the whole partition table */
1522 SectoredPartitionEntriesSize = (MaxPartitionCount * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
1523
1524 for (i = 0, WrittenPartitions = 0; i < PartitionCount; i++)
1525 {
1526 /* If partition GUID is 00000000-0000-0000-0000-000000000000, then it's unused, skip it */
1527 if (PartitionEntries[i].Gpt.PartitionType.Data1 == 0 &&
1528 PartitionEntries[i].Gpt.PartitionType.Data2 == 0 &&
1529 PartitionEntries[i].Gpt.PartitionType.Data3 == 0 &&
1530 ((PULONGLONG)PartitionEntries[i].Gpt.PartitionType.Data4)[0] == 0)
1531 {
1532 continue;
1533 }
1534
1535 /* Copy the entry in the partition entry format */
1536 FstubCopyEntryEFI(&Entry, &PartitionEntries[i], Disk->SectorSize);
1537 /* Then write the entry to the disk */
1538 Status = FstubWriteEntryEFI(Disk,
1539 SectoredPartitionEntriesSize,
1540 WrittenPartitions,
1541 &Entry,
1542 WriteBackupTable,
1543 FALSE,
1544 &PartitionEntryCRC32);
1545 if (!NT_SUCCESS(Status))
1546 {
1547 return Status;
1548 }
1549 WrittenPartitions++;
1550 }
1551
1552 /* Zero the buffer to write zeros to the disk */
1553 RtlZeroMemory(&Entry, sizeof(EFI_PARTITION_ENTRY));
1554 /* Write the disks with zeros for every unused remaining partition entry */
1555 for (i = WrittenPartitions; i < MaxPartitionCount; i++)
1556 {
1557 Status = FstubWriteEntryEFI(Disk,
1558 SectoredPartitionEntriesSize,
1559 i,
1560 &Entry,
1561 WriteBackupTable,
1562 FALSE,
1563 &PartitionEntryCRC32);
1564 if (!NT_SUCCESS(Status))
1565 {
1566 return Status;
1567 }
1568 }
1569
1570 /* Once we're done, write the GPT header */
1571 return FstubWriteHeaderEFI(Disk,
1572 SectoredPartitionEntriesSize,
1573 DiskGUID,
1574 MaxPartitionCount,
1575 FirstUsableLBA,
1576 LastUsableLBA,
1577 PartitionEntryCRC32,
1578 WriteBackupTable);
1579 }
1580
1581 NTSTATUS
1582 NTAPI
1583 FstubWritePartitionTableMBR(IN PDISK_INFORMATION Disk,
1584 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx)
1585 {
1586 NTSTATUS Status;
1587 PDRIVE_LAYOUT_INFORMATION DriveLayout;
1588 PAGED_CODE();
1589
1590 ASSERT(IS_VALID_DISK_INFO(Disk));
1591 ASSERT(LayoutEx);
1592
1593 /* Convert data to the correct format */
1594 DriveLayout = FstubConvertExtendedToLayout(LayoutEx);
1595 if (!DriveLayout)
1596 {
1597 return STATUS_INSUFFICIENT_RESOURCES;
1598 }
1599
1600 /* Really write information */
1601 Status = IoWritePartitionTable(Disk->DeviceObject,
1602 Disk->SectorSize,
1603 Disk->DiskGeometry.Geometry.SectorsPerTrack,
1604 Disk->DiskGeometry.Geometry.TracksPerCylinder,
1605 DriveLayout);
1606
1607 /* Free allocated structure and return */
1608 ExFreePoolWithTag(DriveLayout, TAG_FSTUB);
1609 return Status;
1610 }
1611
1612 NTSTATUS
1613 NTAPI
1614 FstubWriteSector(IN PDEVICE_OBJECT DeviceObject,
1615 IN ULONG SectorSize,
1616 IN ULONGLONG StartingSector OPTIONAL,
1617 IN PUSHORT Buffer)
1618 {
1619 PIRP Irp;
1620 KEVENT Event;
1621 NTSTATUS Status;
1622 LARGE_INTEGER StartingOffset;
1623 IO_STATUS_BLOCK IoStatusBlock;
1624 PIO_STACK_LOCATION IoStackLocation;
1625 PAGED_CODE();
1626
1627 ASSERT(DeviceObject);
1628 ASSERT(Buffer);
1629 ASSERT(SectorSize);
1630
1631 /* Compute starting offset */
1632 StartingOffset.QuadPart = StartingSector * SectorSize;
1633
1634 /* Initialize waiting event */
1635 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1636
1637 /* Prepare IRP */
1638 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
1639 DeviceObject,
1640 Buffer,
1641 SectorSize,
1642 &StartingOffset,
1643 &Event,
1644 &IoStatusBlock);
1645 if (!Irp)
1646 {
1647 return STATUS_INSUFFICIENT_RESOURCES;
1648 }
1649
1650 /* Override volume verify */
1651 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1652 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1653
1654 /* Then call driver, and wait for completion if needed */
1655 Status = IoCallDriver(DeviceObject, Irp);
1656 if (Status == STATUS_PENDING)
1657 {
1658 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1659 Status = IoStatusBlock.Status;
1660 }
1661
1662 return Status;
1663 }
1664
1665 /* FUNCTIONS *****************************************************************/
1666
1667 /*
1668 * @implemented
1669 */
1670 NTSTATUS
1671 NTAPI
1672 IoCreateDisk(IN PDEVICE_OBJECT DeviceObject,
1673 IN struct _CREATE_DISK* Disk)
1674 {
1675 PARTITION_STYLE PartitionStyle;
1676 PAGED_CODE();
1677
1678 ASSERT(DeviceObject);
1679
1680 /* Get partition style. If caller didn't provided data, assume it's raw */
1681 PartitionStyle = ((Disk) ? Disk->PartitionStyle : PARTITION_STYLE_RAW);
1682 /* Then, call appropriate internal function */
1683 switch (PartitionStyle)
1684 {
1685 case PARTITION_STYLE_MBR:
1686 return FstubCreateDiskMBR(DeviceObject, &(Disk->Mbr));
1687 case PARTITION_STYLE_GPT:
1688 return FstubCreateDiskEFI(DeviceObject, &(Disk->Gpt));
1689 case PARTITION_STYLE_RAW:
1690 return FstubCreateDiskRaw(DeviceObject);
1691 default:
1692 return STATUS_NOT_SUPPORTED;
1693 }
1694 }
1695
1696 /*
1697 * @implemented
1698 */
1699 NTSTATUS
1700 NTAPI
1701 IoGetBootDiskInformation(IN OUT PBOOTDISK_INFORMATION BootDiskInformation,
1702 IN ULONG Size)
1703 {
1704 PIRP Irp;
1705 KEVENT Event;
1706 PLIST_ENTRY NextEntry;
1707 PFILE_OBJECT FileObject;
1708 DISK_GEOMETRY DiskGeometry;
1709 PDEVICE_OBJECT DeviceObject;
1710 UNICODE_STRING DeviceStringW;
1711 IO_STATUS_BLOCK IoStatusBlock;
1712 CHAR Buffer[128], ArcBuffer[128];
1713 NTSTATUS Status = STATUS_SUCCESS;
1714 BOOLEAN SingleDisk, IsBootDiskInfoEx;
1715 PARC_DISK_SIGNATURE ArcDiskSignature;
1716 PARC_DISK_INFORMATION ArcDiskInformation;
1717 PARTITION_INFORMATION_EX PartitionInformation;
1718 PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL;
1719 ULONG DiskCount, DiskNumber, Signature, PartitionNumber;
1720 ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA;
1721 extern PLOADER_PARAMETER_BLOCK IopLoaderBlock;
1722 PAGED_CODE();
1723
1724 /* Get loader block. If it's null, we come to late */
1725 if (!IopLoaderBlock)
1726 {
1727 return STATUS_TOO_LATE;
1728 }
1729
1730 /* Check buffer size */
1731 if (Size < sizeof(BOOTDISK_INFORMATION))
1732 {
1733 return STATUS_INVALID_PARAMETER;
1734 }
1735
1736 /* Init some useful stuff:
1737 * Get arc disks information
1738 * Check whether we have a single disk
1739 * Check received structure size (extended or not?)
1740 * Init boot strings (system/boot)
1741 * Finaly, get disk count
1742 */
1743 ArcDiskInformation = IopLoaderBlock->ArcDiskInformation;
1744 SingleDisk = IsListEmpty(&(ArcDiskInformation->DiskSignatureListHead));
1745 IsBootDiskInfoEx = (Size >= sizeof(BOOTDISK_INFORMATION_EX));
1746 RtlInitAnsiString(&ArcBootString, IopLoaderBlock->ArcBootDeviceName);
1747 RtlInitAnsiString(&ArcSystemString, IopLoaderBlock->ArcHalDeviceName);
1748 DiskCount = IoGetConfigurationInformation()->DiskCount;
1749
1750 /* If no disk, return success */
1751 if (DiskCount == 0)
1752 {
1753 return STATUS_SUCCESS;
1754 }
1755
1756 /* Now, browse all disks */
1757 for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++)
1758 {
1759 /* Create the device name */
1760 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
1761 RtlInitAnsiString(&DeviceStringA, Buffer);
1762 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
1763 if (!NT_SUCCESS(Status))
1764 {
1765 continue;
1766 }
1767
1768 /* Get its device object */
1769 Status = IoGetDeviceObjectPointer(&DeviceStringW,
1770 FILE_READ_ATTRIBUTES,
1771 &FileObject,
1772 &DeviceObject);
1773 RtlFreeUnicodeString(&DeviceStringW);
1774 if (!NT_SUCCESS(Status))
1775 {
1776 continue;
1777 }
1778
1779 /* Prepare for getting disk geometry */
1780 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
1781 DeviceObject,
1782 NULL,
1783 0,
1784 &DiskGeometry,
1785 sizeof(DISK_GEOMETRY),
1786 FALSE,
1787 &Event,
1788 &IoStatusBlock);
1789 if (!Irp)
1790 {
1791 ObDereferenceObject(FileObject);
1792 continue;
1793 }
1794
1795 /* Then, call the drive, and wait for it if needed */
1796 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1797 Status = IoCallDriver(DeviceObject, Irp);
1798 if (Status == STATUS_PENDING)
1799 {
1800 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1801 Status = IoStatusBlock.Status;
1802 }
1803 if (!NT_SUCCESS(Status))
1804 {
1805 ObDereferenceObject(FileObject);
1806 continue;
1807 }
1808
1809 /* Read partition table */
1810 Status = IoReadPartitionTableEx(DeviceObject,
1811 &DriveLayout);
1812
1813 /* FileObject, you can go! */
1814 ObDereferenceObject(FileObject);
1815
1816 if (!NT_SUCCESS(Status))
1817 {
1818 continue;
1819 }
1820
1821 /* Ensure we have at least 512 bytes per sector */
1822 if (DiskGeometry.BytesPerSector < 512)
1823 {
1824 DiskGeometry.BytesPerSector = 512;
1825 }
1826
1827 /* Now, for each arc disk, try to find the matching */
1828 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
1829 NextEntry != &ArcDiskInformation->DiskSignatureListHead;
1830 NextEntry = NextEntry->Flink)
1831 {
1832 ArcDiskSignature = CONTAINING_RECORD(NextEntry,
1833 ARC_DISK_SIGNATURE,
1834 ListEntry);
1835 /* If they matches, ie
1836 * - There's only one disk for both BIOS and detected
1837 * - Signatures are matching
1838 * - This is MBR
1839 * (We don't check checksums here)
1840 */
1841 if (((SingleDisk && DiskCount == 1) ||
1842 (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature))) &&
1843 (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR))
1844 {
1845 /* Create arc name */
1846 sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName);
1847 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
1848
1849 /* Browse all partitions */
1850 for (PartitionNumber = 1; PartitionNumber <= DriveLayout->PartitionCount; PartitionNumber++)
1851 {
1852 /* Create its device name */
1853 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", DiskNumber, PartitionNumber);
1854 RtlInitAnsiString(&DeviceStringA, Buffer);
1855 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
1856 if (!NT_SUCCESS(Status))
1857 {
1858 continue;
1859 }
1860
1861 /* If IopVerifyDiskSignature returned no signature, take the one from DriveLayout */
1862 if (!Signature)
1863 {
1864 Signature = DriveLayout->Mbr.Signature;
1865 }
1866
1867 /* Create partial arc name */
1868 sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, PartitionNumber);
1869 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
1870
1871 /* If it's matching boot string */
1872 if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE))
1873 {
1874 /* Then, fill in information about boot device */
1875 BootDiskInformation->BootDeviceSignature = Signature;
1876
1877 /* Get its device object */
1878 Status = IoGetDeviceObjectPointer(&DeviceStringW,
1879 FILE_READ_ATTRIBUTES,
1880 &FileObject,
1881 &DeviceObject);
1882 if (!NT_SUCCESS(Status))
1883 {
1884 RtlFreeUnicodeString(&DeviceStringW);
1885 continue;
1886 }
1887
1888 /* And call the drive to get information about partition */
1889 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
1890 DeviceObject,
1891 NULL,
1892 0,
1893 &PartitionInformation,
1894 sizeof(PARTITION_INFORMATION_EX),
1895 FALSE,
1896 &Event,
1897 &IoStatusBlock);
1898 if (!Irp)
1899 {
1900 ObDereferenceObject(FileObject);
1901 RtlFreeUnicodeString(&DeviceStringW);
1902 continue;
1903 }
1904
1905 /* Call & wait if needed */
1906 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1907 Status = IoCallDriver(DeviceObject, Irp);
1908 if (Status == STATUS_PENDING)
1909 {
1910 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1911 Status = IoStatusBlock.Status;
1912 }
1913 if (!NT_SUCCESS(Status))
1914 {
1915 ObDereferenceObject(FileObject);
1916 RtlFreeUnicodeString(&DeviceStringW);
1917 continue;
1918 }
1919
1920 /* We get partition offset as demanded and return it */
1921 BootDiskInformation->BootPartitionOffset = PartitionInformation.StartingOffset.QuadPart;
1922
1923 /* If called passed a BOOTDISK_INFORMATION_EX structure, give more intel */
1924 if (IsBootDiskInfoEx)
1925 {
1926 /* Is PT MBR or GPT? */
1927 if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
1928 {
1929 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceGuid = DriveLayout->Gpt.DiskId;
1930 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceIsGpt = TRUE;
1931 }
1932 else
1933 {
1934 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceIsGpt = FALSE;
1935 }
1936 }
1937
1938 /* Dereference FileObject */
1939 ObDereferenceObject(FileObject);
1940 }
1941
1942 /* If it's matching system string */
1943 if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE))
1944 {
1945 /* Then, fill in information about the system device */
1946 BootDiskInformation->SystemDeviceSignature = Signature;
1947
1948 /* Get its device object */
1949 Status = IoGetDeviceObjectPointer(&DeviceStringW,
1950 FILE_READ_ATTRIBUTES,
1951 &FileObject,
1952 &DeviceObject);
1953 if (!NT_SUCCESS(Status))
1954 {
1955 RtlFreeUnicodeString(&DeviceStringW);
1956 continue;
1957 }
1958
1959 /* And call the drive to get information about partition */
1960 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
1961 DeviceObject,
1962 NULL,
1963 0,
1964 &PartitionInformation,
1965 sizeof(PARTITION_INFORMATION_EX),
1966 FALSE,
1967 &Event,
1968 &IoStatusBlock);
1969 if (!Irp)
1970 {
1971 ObDereferenceObject(FileObject);
1972 RtlFreeUnicodeString(&DeviceStringW);
1973 continue;
1974 }
1975
1976 /* Call & wait if needed */
1977 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1978 Status = IoCallDriver(DeviceObject, Irp);
1979 if (Status == STATUS_PENDING)
1980 {
1981 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1982 Status = IoStatusBlock.Status;
1983 }
1984 if (!NT_SUCCESS(Status))
1985 {
1986 ObDereferenceObject(FileObject);
1987 RtlFreeUnicodeString(&DeviceStringW);
1988 continue;
1989 }
1990
1991 /* We get partition offset as demanded and return it */
1992 BootDiskInformation->SystemPartitionOffset = PartitionInformation.StartingOffset.QuadPart;
1993
1994 /* If called passed a BOOTDISK_INFORMATION_EX structure, give more intel */
1995 if (IsBootDiskInfoEx)
1996 {
1997 /* Is PT MBR or GPT? */
1998 if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
1999 {
2000 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceGuid = DriveLayout->Gpt.DiskId;
2001 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceIsGpt = TRUE;
2002 }
2003 else
2004 {
2005 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceIsGpt = FALSE;
2006 }
2007 }
2008
2009 /* Dereference FileObject */
2010 ObDereferenceObject(FileObject);
2011 }
2012
2013 /* Release device string */
2014 RtlFreeUnicodeString(&DeviceStringW);
2015 }
2016 }
2017 }
2018
2019 /* Finally, release drive layout structure */
2020 ExFreePool(DriveLayout);
2021 }
2022
2023 /* And return */
2024 return Status;
2025 }
2026
2027 /*
2028 * @implemented
2029 */
2030 NTSTATUS
2031 NTAPI
2032 IoReadDiskSignature(IN PDEVICE_OBJECT DeviceObject,
2033 IN ULONG BytesPerSector,
2034 OUT PDISK_SIGNATURE Signature)
2035 {
2036 PULONG Buffer;
2037 NTSTATUS Status;
2038 ULONG HeaderCRC32, i, CheckSum;
2039 PEFI_PARTITION_HEADER EFIHeader;
2040 PPARTITION_DESCRIPTOR PartitionDescriptor;
2041 PAGED_CODE();
2042
2043 /* Ensure we'll read at least 512 bytes */
2044 if (BytesPerSector < 512)
2045 {
2046 BytesPerSector = 512;
2047 }
2048
2049 /* Allocate a buffer for reading operations */
2050 Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, BytesPerSector, TAG_FSTUB);
2051 if (!Buffer)
2052 {
2053 return STATUS_NO_MEMORY;
2054 }
2055
2056 /* Read first sector (sector 0) for MBR */
2057 Status = FstubReadSector(DeviceObject,
2058 BytesPerSector,
2059 0ULL,
2060 (PUSHORT)Buffer);
2061 if (!NT_SUCCESS(Status))
2062 {
2063 goto Cleanup;
2064 }
2065
2066 /* Get the partition descriptor array */
2067 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
2068 &(Buffer[PARTITION_TABLE_OFFSET]);
2069 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
2070 if (PartitionDescriptor[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
2071 PartitionDescriptor[1].PartitionType == 0 &&
2072 PartitionDescriptor[2].PartitionType == 0 &&
2073 PartitionDescriptor[3].PartitionType == 0)
2074 {
2075 /* If we have GPT, read second sector (sector 1) for GPT header */
2076 Status = FstubReadSector(DeviceObject,
2077 BytesPerSector,
2078 1ULL,
2079 (PUSHORT)Buffer);
2080 if (!NT_SUCCESS(Status))
2081 {
2082 goto Cleanup;
2083 }
2084 EFIHeader = (PEFI_PARTITION_HEADER)Buffer;
2085
2086 /* First check signature
2087 * Then, check version (we only support v1
2088 * Finally check header size
2089 */
2090 if (EFIHeader->Signature != EFI_HEADER_SIGNATURE ||
2091 EFIHeader->Revision != EFI_HEADER_REVISION_1 ||
2092 EFIHeader->HeaderSize != sizeof(EFI_PARTITION_HEADER))
2093 {
2094 Status = STATUS_DISK_CORRUPT_ERROR;
2095 goto Cleanup;
2096 }
2097
2098 /* Save current checksum */
2099 HeaderCRC32 = EFIHeader->HeaderCRC32;
2100 /* Then zero the one in EFI header. This is needed to compute header checksum */
2101 EFIHeader->HeaderCRC32 = 0;
2102 /* Compute header checksum and compare with the one present in partition table */
2103 if (RtlComputeCrc32(0, (PUCHAR)Buffer, sizeof(EFI_PARTITION_HEADER)) != HeaderCRC32)
2104 {
2105 Status = STATUS_DISK_CORRUPT_ERROR;
2106 goto Cleanup;
2107 }
2108
2109 /* Set partition table style to GPT and return disk GUID */
2110 Signature->PartitionStyle = PARTITION_STYLE_GPT;
2111 Signature->Gpt.DiskId = EFIHeader->DiskGUID;
2112 }
2113 else
2114 {
2115 /* Compute MBR checksum */
2116 for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG) ; i++)
2117 {
2118 CheckSum += Buffer[i];
2119 }
2120
2121 /* Set partition table style to MBR and return signature (offset 440) and checksum */
2122 Signature->PartitionStyle = PARTITION_STYLE_MBR;
2123 Signature->Mbr.Signature = Buffer[PARTITION_TABLE_OFFSET / 2 - 1];
2124 Signature->Mbr.CheckSum = CheckSum;
2125 }
2126
2127 Cleanup:
2128 /* Free buffer and return */
2129 ExFreePoolWithTag(Buffer, TAG_FSTUB);
2130 return Status;
2131 }
2132
2133 /*
2134 * @implemented
2135 */
2136 NTSTATUS
2137 NTAPI
2138 IoReadPartitionTableEx(IN PDEVICE_OBJECT DeviceObject,
2139 IN struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout)
2140 {
2141 NTSTATUS Status;
2142 PDISK_INFORMATION Disk;
2143 PARTITION_STYLE PartitionStyle;
2144 PAGED_CODE();
2145
2146 ASSERT(DeviceObject);
2147 ASSERT(DriveLayout);
2148
2149 /* First of all, allocate internal structure */
2150 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0);
2151 if (!NT_SUCCESS(Status))
2152 {
2153 return Status;
2154 }
2155 ASSERT(Disk);
2156
2157 /* Then, detect partition style (MBR? GTP/EFI? RAW?) */
2158 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
2159 if (!NT_SUCCESS(Status))
2160 {
2161 FstubFreeDiskInformation(Disk);
2162 return Status;
2163 }
2164
2165 /* Here partition table is really read, depending on its style */
2166 switch (PartitionStyle)
2167 {
2168 case PARTITION_STYLE_MBR:
2169 case PARTITION_STYLE_RAW:
2170 Status = FstubReadPartitionTableMBR(Disk, FALSE, DriveLayout);
2171 break;
2172
2173 case PARTITION_STYLE_GPT:
2174 /* Read primary table */
2175 Status = FstubReadPartitionTableEFI(Disk, FALSE, DriveLayout);
2176 /* If it failed, try reading backup table */
2177 if (!NT_SUCCESS(Status))
2178 {
2179 Status = FstubReadPartitionTableEFI(Disk, TRUE, DriveLayout);
2180 }
2181 break;
2182
2183 default:
2184 DPRINT("Unknown partition type\n");
2185 Status = STATUS_UNSUCCESSFUL;
2186 }
2187
2188 /* It's over, internal structure not needed anymore */
2189 FstubFreeDiskInformation(Disk);
2190
2191 /* In case of success, print data */
2192 if (NT_SUCCESS(Status))
2193 {
2194 FstubDbgPrintDriveLayoutEx(*DriveLayout);
2195 }
2196
2197 return Status;
2198 }
2199
2200 /*
2201 * @implemented
2202 */
2203 NTSTATUS
2204 NTAPI
2205 IoSetPartitionInformationEx(IN PDEVICE_OBJECT DeviceObject,
2206 IN ULONG PartitionNumber,
2207 IN struct _SET_PARTITION_INFORMATION_EX* PartitionInfo)
2208 {
2209 NTSTATUS Status;
2210 PDISK_INFORMATION Disk;
2211 PARTITION_STYLE PartitionStyle;
2212 PAGED_CODE();
2213
2214 ASSERT(DeviceObject);
2215 ASSERT(PartitionInfo);
2216
2217 /* Debug given modifications */
2218 FstubDbgPrintSetPartitionEx(PartitionInfo, PartitionNumber);
2219
2220 /* Allocate internal structure */
2221 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, NULL);
2222 if (!NT_SUCCESS(Status))
2223 {
2224 return Status;
2225 }
2226
2227 /* Get partition table style on disk */
2228 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
2229 if (!NT_SUCCESS(Status))
2230 {
2231 FstubFreeDiskInformation(Disk);
2232 return Status;
2233 }
2234
2235 /* If it's not matching partition style given in modifications, give up */
2236 if (PartitionInfo->PartitionStyle != PartitionStyle)
2237 {
2238 FstubFreeDiskInformation(Disk);
2239 return STATUS_INVALID_PARAMETER;
2240 }
2241
2242 /* Finally, handle modifications using proper function */
2243 switch (PartitionStyle)
2244 {
2245 case PARTITION_STYLE_MBR:
2246 Status = IoSetPartitionInformation(DeviceObject,
2247 Disk->SectorSize,
2248 PartitionNumber,
2249 PartitionInfo->Mbr.PartitionType);
2250 break;
2251 case PARTITION_STYLE_GPT:
2252 Status = FstubSetPartitionInformationEFI(Disk,
2253 PartitionNumber,
2254 &(PartitionInfo->Gpt));
2255 break;
2256 default:
2257 Status = STATUS_NOT_SUPPORTED;
2258 }
2259
2260 /* Release internal structure and return */
2261 FstubFreeDiskInformation(Disk);
2262 return Status;
2263 }
2264
2265 /*
2266 * @implemented
2267 */
2268 NTSTATUS
2269 NTAPI
2270 IoVerifyPartitionTable(IN PDEVICE_OBJECT DeviceObject,
2271 IN BOOLEAN FixErrors)
2272 {
2273 NTSTATUS Status;
2274 PDISK_INFORMATION Disk;
2275 PARTITION_STYLE PartitionStyle;
2276 PAGED_CODE();
2277
2278 ASSERT(DeviceObject);
2279
2280 /* Allocate internal structure */
2281 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, NULL);
2282 if (!NT_SUCCESS(Status))
2283 {
2284 return Status;
2285 }
2286 ASSERT(Disk);
2287
2288 /* Get partition table style on disk */
2289 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
2290 if (!NT_SUCCESS(Status))
2291 {
2292 FstubFreeDiskInformation(Disk);
2293 return Status;
2294 }
2295
2296 /* Action will depend on partition style */
2297 switch (PartitionStyle)
2298 {
2299 /* For MBR, assume it's always OK */
2300 case PARTITION_STYLE_MBR:
2301 Status = STATUS_SUCCESS;
2302 break;
2303 /* For GPT, call internal function */
2304 case PARTITION_STYLE_GPT:
2305 Status = FstubVerifyPartitionTableEFI(Disk, FixErrors);
2306 break;
2307 /* Otherwise, signal we can't work */
2308 default:
2309 Status = STATUS_NOT_SUPPORTED;
2310 }
2311
2312 /* Release internal structure and return */
2313 FstubFreeDiskInformation(Disk);
2314 return Status;
2315 }
2316
2317 /*
2318 * @implemented
2319 */
2320 NTSTATUS
2321 NTAPI
2322 IoWritePartitionTableEx(IN PDEVICE_OBJECT DeviceObject,
2323 IN struct _DRIVE_LAYOUT_INFORMATION_EX* DriveLayout)
2324 {
2325 NTSTATUS Status;
2326 PDISK_INFORMATION Disk;
2327 ULONGLONG SectorsForPartitions;
2328 EFI_PARTITION_HEADER EfiHeader;
2329 PAGED_CODE();
2330
2331 ASSERT(DeviceObject);
2332 ASSERT(DriveLayout);
2333
2334 /* Debug partition table that must be written */
2335 FstubDbgPrintDriveLayoutEx(DriveLayout);
2336
2337 /* Allocate internal structure */
2338 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0);
2339 if (!NT_SUCCESS(Status))
2340 {
2341 return Status;
2342 }
2343 ASSERT(Disk);
2344
2345 switch (DriveLayout->PartitionStyle)
2346 {
2347 case PARTITION_STYLE_MBR:
2348 Status = FstubWritePartitionTableMBR(Disk, DriveLayout);
2349 break;
2350
2351 case PARTITION_STYLE_GPT:
2352 /* Read primary table header */
2353 Status = FstubReadHeaderEFI(Disk,
2354 FALSE,
2355 &EfiHeader);
2356 /* If it failed, try reading back table header */
2357 if (!NT_SUCCESS(Status))
2358 {
2359 Status = FstubReadHeaderEFI(Disk,
2360 TRUE,
2361 &EfiHeader);
2362 }
2363
2364 /* We have a header! */
2365 if (NT_SUCCESS(Status))
2366 {
2367 /* Check if there are enough places for the partitions to be written */
2368 if (DriveLayout->PartitionCount <= EfiHeader.NumberOfEntries)
2369 {
2370 /* Count number of sectors needed to store partitions */
2371 SectorsForPartitions = (EfiHeader.NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
2372 /* Set first usable LBA: Legacy MBR + GPT header + Partitions entries */
2373 EfiHeader.FirstUsableLBA = SectorsForPartitions + 2;
2374 /* Set last usable LBA: Last sector - GPT header - Partitions entries */
2375 EfiHeader.LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1;
2376 /* Write primary table */
2377 Status = FstubWritePartitionTableEFI(Disk,
2378 EfiHeader.DiskGUID,
2379 EfiHeader.NumberOfEntries,
2380 EfiHeader.FirstUsableLBA,
2381 EfiHeader.LastUsableLBA,
2382 FALSE,
2383 DriveLayout->PartitionCount,
2384 DriveLayout->PartitionEntry);
2385 /* If it succeed, also update backup table */
2386 if (NT_SUCCESS(Status))
2387 {
2388 Status = FstubWritePartitionTableEFI(Disk,
2389 EfiHeader.DiskGUID,
2390 EfiHeader.NumberOfEntries,
2391 EfiHeader.FirstUsableLBA,
2392 EfiHeader.LastUsableLBA,
2393 TRUE,
2394 DriveLayout->PartitionCount,
2395 DriveLayout->PartitionEntry);
2396 }
2397 }
2398 }
2399 break;
2400
2401 default:
2402 DPRINT("Unsupported partition style: %ld\n", DriveLayout->PartitionStyle);
2403 Status = STATUS_NOT_SUPPORTED;
2404 }
2405
2406 /* It's over, internal structure not needed anymore */
2407 FstubFreeDiskInformation(Disk);
2408
2409 return Status;
2410 }
2411
2412 /* EOF */