75c6013c5d7e3954fca98d9db68cf36bed4ee138
[reactos.git] / reactos / ntoskrnl / io / xhaldrv.c
1 /* $Id: xhaldrv.c,v 1.41 2003/12/14 17:56:22 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/xhaldrv.c
6 * PURPOSE: Hal drive routines
7 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
8 * Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * UPDATE HISTORY:
10 * Created 19/06/2000
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <internal/xhal.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* LOCAL MACROS and TYPES ***************************************************/
22
23 #define AUTO_DRIVE ((ULONG)-1)
24
25 #define PARTITION_MAGIC 0xaa55
26
27 #define PARTITION_TBL_SIZE 4
28
29
30 typedef struct _PARTITION
31 {
32 unsigned char BootFlags; /* bootable? 0=no, 128=yes */
33 unsigned char StartingHead; /* beginning head number */
34 unsigned char StartingSector; /* beginning sector number */
35 unsigned char StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */
36 unsigned char PartitionType; /* Operating System type indicator code */
37 unsigned char EndingHead; /* ending head number */
38 unsigned char EndingSector; /* ending sector number */
39 unsigned char EndingCylinder; /* also a 10 bit nmbr, with same high 2 bit trick */
40 unsigned int StartingBlock; /* first sector relative to start of disk */
41 unsigned int SectorCount; /* number of sectors in partition */
42 } PACKED PARTITION, *PPARTITION;
43
44
45 typedef struct _PARTITION_SECTOR
46 {
47 UCHAR BootCode[440]; /* 0x000 */
48 ULONG Signature; /* 0x1B8 */
49 UCHAR Reserved[2]; /* 0x1BC */
50 PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */
51 USHORT Magic; /* 0x1FE */
52 } PACKED PARTITION_SECTOR, *PPARTITION_SECTOR;
53
54
55 typedef enum _DISK_MANAGER
56 {
57 NoDiskManager,
58 OntrackDiskManager,
59 EZ_Drive
60 } DISK_MANAGER;
61
62
63 /* FUNCTIONS *****************************************************************/
64
65 NTSTATUS
66 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName,
67 OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
68 {
69 IO_STATUS_BLOCK StatusBlock;
70 DISK_GEOMETRY DiskGeometry;
71 PDEVICE_OBJECT DeviceObject = NULL;
72 PFILE_OBJECT FileObject;
73 KEVENT Event;
74 PIRP Irp;
75 NTSTATUS Status;
76
77 DPRINT("xHalpQueryDriveLayout %wZ %p\n",
78 DeviceName,
79 LayoutInfo);
80
81 /* Get the drives sector size */
82 Status = IoGetDeviceObjectPointer(DeviceName,
83 FILE_READ_DATA,
84 &FileObject,
85 &DeviceObject);
86 if (!NT_SUCCESS(Status))
87 {
88 DPRINT("Status %x\n",Status);
89 return(Status);
90 }
91
92 KeInitializeEvent(&Event,
93 NotificationEvent,
94 FALSE);
95
96 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
97 DeviceObject,
98 NULL,
99 0,
100 &DiskGeometry,
101 sizeof(DISK_GEOMETRY),
102 FALSE,
103 &Event,
104 &StatusBlock);
105 if (Irp == NULL)
106 {
107 ObDereferenceObject(FileObject);
108 return(STATUS_INSUFFICIENT_RESOURCES);
109 }
110
111 Status = IoCallDriver(DeviceObject,
112 Irp);
113 if (Status == STATUS_PENDING)
114 {
115 KeWaitForSingleObject(&Event,
116 Executive,
117 KernelMode,
118 FALSE,
119 NULL);
120 Status = StatusBlock.Status;
121 }
122 if (!NT_SUCCESS(Status))
123 {
124 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
125 {
126 DiskGeometry.BytesPerSector = 512;
127 }
128 else
129 {
130 ObDereferenceObject(FileObject);
131 return(Status);
132 }
133 }
134
135 DPRINT("DiskGeometry.BytesPerSector: %d\n",
136 DiskGeometry.BytesPerSector);
137
138 /* Read the partition table */
139 Status = IoReadPartitionTable(DeviceObject,
140 DiskGeometry.BytesPerSector,
141 FALSE,
142 LayoutInfo);
143
144 if ((!NT_SUCCESS(Status) || (*LayoutInfo)->PartitionCount == 0) &&
145 DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
146 {
147 PDRIVE_LAYOUT_INFORMATION Buffer;
148
149 if (NT_SUCCESS(Status))
150 {
151 ExFreePool(*LayoutInfo);
152 }
153
154 /* Allocate a partition list for a single entry. */
155 Buffer = ExAllocatePool(NonPagedPool,
156 sizeof(DRIVE_LAYOUT_INFORMATION));
157 if (Buffer != NULL)
158 {
159 RtlZeroMemory(Buffer,
160 sizeof(DRIVE_LAYOUT_INFORMATION));
161 Buffer->PartitionCount = 1;
162 *LayoutInfo = Buffer;
163
164 Status = STATUS_SUCCESS;
165 }
166 }
167
168 ObDereferenceObject(FileObject);
169
170 return(Status);
171 }
172
173
174 static NTSTATUS
175 xHalpReadSector (IN PDEVICE_OBJECT DeviceObject,
176 IN ULONG SectorSize,
177 IN PLARGE_INTEGER SectorOffset,
178 IN PVOID Sector)
179 {
180 IO_STATUS_BLOCK StatusBlock;
181 KEVENT Event;
182 PIRP Irp;
183 NTSTATUS Status;
184
185 DPRINT("xHalpReadSector() called\n");
186
187 assert(DeviceObject);
188 assert(Sector);
189
190 KeInitializeEvent(&Event,
191 NotificationEvent,
192 FALSE);
193
194 /* Read the sector */
195 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
196 DeviceObject,
197 Sector,
198 SectorSize,
199 SectorOffset,
200 &Event,
201 &StatusBlock);
202
203 Status = IoCallDriver(DeviceObject,
204 Irp);
205 if (Status == STATUS_PENDING)
206 {
207 KeWaitForSingleObject(&Event,
208 Executive,
209 KernelMode,
210 FALSE,
211 NULL);
212 Status = StatusBlock.Status;
213 }
214
215 if (!NT_SUCCESS(Status))
216 {
217 DPRINT("Reading sector failed (Status 0x%08lx)\n",
218 Status);
219 return Status;
220 }
221
222 return Status;
223 }
224
225
226 static NTSTATUS
227 xHalpWriteSector (IN PDEVICE_OBJECT DeviceObject,
228 IN ULONG SectorSize,
229 IN PLARGE_INTEGER SectorOffset,
230 IN PVOID Sector)
231 {
232 IO_STATUS_BLOCK StatusBlock;
233 KEVENT Event;
234 PIRP Irp;
235 NTSTATUS Status;
236
237 DPRINT("xHalpWriteSector() called\n");
238
239 KeInitializeEvent(&Event,
240 NotificationEvent,
241 FALSE);
242
243 /* Write the sector */
244 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
245 DeviceObject,
246 Sector,
247 SectorSize,
248 SectorOffset,
249 &Event,
250 &StatusBlock);
251
252 Status = IoCallDriver(DeviceObject,
253 Irp);
254 if (Status == STATUS_PENDING)
255 {
256 KeWaitForSingleObject(&Event,
257 Executive,
258 KernelMode,
259 FALSE,
260 NULL);
261 Status = StatusBlock.Status;
262 }
263
264 if (!NT_SUCCESS(Status))
265 {
266 DPRINT("Writing sector failed (Status 0x%08lx)\n",
267 Status);
268 }
269
270 return Status;
271 }
272
273
274 VOID FASTCALL
275 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
276 IN ULONG SectorSize,
277 IN ULONG MBRTypeIdentifier,
278 OUT PVOID *Buffer)
279 {
280 LARGE_INTEGER SectorOffset;
281 PPARTITION_SECTOR Sector;
282 NTSTATUS Status;
283
284 DPRINT("xHalExamineMBR()\n");
285
286 *Buffer = NULL;
287
288 if (SectorSize < 512)
289 SectorSize = 512;
290 if (SectorSize > 4096)
291 SectorSize = 4096;
292
293 Sector = (PPARTITION_SECTOR) ExAllocatePool (PagedPool,
294 SectorSize);
295 if (Sector == NULL)
296 {
297 DPRINT ("Partition sector allocation failed\n");
298 return;
299 }
300
301 SectorOffset.QuadPart = 0LL;
302 Status = xHalpReadSector (DeviceObject,
303 SectorSize,
304 &SectorOffset,
305 (PVOID)Sector);
306 if (!NT_SUCCESS(Status))
307 {
308 DPRINT("xHalpReadSector() failed (Status %lx)\n", Status);
309 ExFreePool(Sector);
310 return;
311 }
312
313 if (Sector->Magic != PARTITION_MAGIC)
314 {
315 DPRINT("Invalid MBR magic value\n");
316 ExFreePool(Sector);
317 return;
318 }
319
320 if (Sector->Partition[0].PartitionType != MBRTypeIdentifier)
321 {
322 DPRINT("Invalid MBRTypeIdentifier\n");
323 ExFreePool(Sector);
324 return;
325 }
326
327 if (Sector->Partition[0].PartitionType == 0x54)
328 {
329 /* Found 'Ontrack Disk Manager'. Shift all sectors by 63 */
330 DPRINT("Found 'Ontrack Disk Manager'!\n");
331 *((PULONG)Sector) = 63;
332 }
333
334 *Buffer = (PVOID)Sector;
335 }
336
337
338 static VOID
339 HalpAssignDrive(IN PUNICODE_STRING PartitionName,
340 IN ULONG DriveNumber,
341 IN UCHAR DriveType)
342 {
343 WCHAR DriveNameBuffer[8];
344 UNICODE_STRING DriveName;
345 ULONG i;
346
347 DPRINT("HalpAssignDrive()\n");
348
349 if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 24))
350 {
351 /* Force assignment */
352 if ((SharedUserData->DosDeviceMap & (1 << DriveNumber)) != 0)
353 {
354 DbgPrint("Drive letter already used!\n");
355 return;
356 }
357 }
358 else
359 {
360 /* Automatic assignment */
361 DriveNumber = AUTO_DRIVE;
362
363 for (i = 2; i < 24; i++)
364 {
365 if ((SharedUserData->DosDeviceMap & (1 << i)) == 0)
366 {
367 DriveNumber = i;
368 break;
369 }
370 }
371
372 if (DriveNumber == AUTO_DRIVE)
373 {
374 DbgPrint("No drive letter available!\n");
375 return;
376 }
377 }
378
379 DPRINT("DriveNumber %d\n", DriveNumber);
380
381 /* Update the shared user page */
382 SharedUserData->DosDeviceMap |= (1 << DriveNumber);
383 SharedUserData->DosDeviceDriveType[DriveNumber] = DriveType;
384
385 /* Build drive name */
386 swprintf(DriveNameBuffer,
387 L"\\??\\%C:",
388 'A' + DriveNumber);
389 RtlInitUnicodeString(&DriveName,
390 DriveNameBuffer);
391
392 DPRINT(" %wZ ==> %wZ\n",
393 &DriveName,
394 PartitionName);
395
396 /* Create symbolic link */
397 IoCreateSymbolicLink(&DriveName,
398 PartitionName);
399 }
400
401
402 VOID FASTCALL
403 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
404 IN PSTRING NtDeviceName,
405 OUT PUCHAR NtSystemPath,
406 OUT PSTRING NtSystemPathString)
407 {
408 PDRIVE_LAYOUT_INFORMATION *LayoutArray;
409 PCONFIGURATION_INFORMATION ConfigInfo;
410 OBJECT_ATTRIBUTES ObjectAttributes;
411 IO_STATUS_BLOCK StatusBlock;
412 UNICODE_STRING UnicodeString1;
413 UNICODE_STRING UnicodeString2;
414 HANDLE FileHandle;
415 PWSTR Buffer1;
416 PWSTR Buffer2;
417 ULONG i;
418 NTSTATUS Status;
419 ULONG j;
420
421 DPRINT("xHalIoAssignDriveLetters()\n");
422
423 ConfigInfo = IoGetConfigurationInformation();
424
425 Buffer1 = (PWSTR)ExAllocatePool(PagedPool,
426 64 * sizeof(WCHAR));
427 Buffer2 = (PWSTR)ExAllocatePool(PagedPool,
428 32 * sizeof(WCHAR));
429
430 /* Create PhysicalDrive links */
431 DPRINT("Physical disk drives: %d\n", ConfigInfo->DiskCount);
432 for (i = 0; i < ConfigInfo->DiskCount; i++)
433 {
434 swprintf(Buffer1,
435 L"\\Device\\Harddisk%d\\Partition0",
436 i);
437 RtlInitUnicodeString(&UnicodeString1,
438 Buffer1);
439
440 InitializeObjectAttributes(&ObjectAttributes,
441 &UnicodeString1,
442 0,
443 NULL,
444 NULL);
445
446 Status = NtOpenFile(&FileHandle,
447 0x10001,
448 &ObjectAttributes,
449 &StatusBlock,
450 1,
451 FILE_SYNCHRONOUS_IO_NONALERT);
452 if (NT_SUCCESS(Status))
453 {
454 NtClose(FileHandle);
455
456 swprintf(Buffer2,
457 L"\\??\\PhysicalDrive%d",
458 i);
459 RtlInitUnicodeString(&UnicodeString2,
460 Buffer2);
461
462 DPRINT("Creating link: %S ==> %S\n",
463 Buffer2,
464 Buffer1);
465
466 IoCreateSymbolicLink(&UnicodeString2,
467 &UnicodeString1);
468 }
469 }
470
471 /* Initialize layout array */
472 LayoutArray = ExAllocatePool(NonPagedPool,
473 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
474 RtlZeroMemory(LayoutArray,
475 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
476 for (i = 0; i < ConfigInfo->DiskCount; i++)
477 {
478 swprintf(Buffer1,
479 L"\\Device\\Harddisk%d\\Partition0",
480 i);
481 RtlInitUnicodeString(&UnicodeString1,
482 Buffer1);
483
484 Status = xHalQueryDriveLayout(&UnicodeString1,
485 &LayoutArray[i]);
486 if (!NT_SUCCESS(Status))
487 {
488 DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
489 Status);
490 LayoutArray[i] = NULL;
491 continue;
492 }
493 }
494
495 #ifndef NDEBUG
496 /* Dump layout array */
497 for (i = 0; i < ConfigInfo->DiskCount; i++)
498 {
499 DPRINT("Harddisk %d:\n",
500 i);
501
502 if (LayoutArray[i] == NULL)
503 continue;
504
505 DPRINT("Logical partitions: %d\n",
506 LayoutArray[i]->PartitionCount);
507
508 for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
509 {
510 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
511 j,
512 LayoutArray[i]->PartitionEntry[j].PartitionNumber,
513 LayoutArray[i]->PartitionEntry[j].BootIndicator,
514 LayoutArray[i]->PartitionEntry[j].PartitionType,
515 LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart,
516 LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart);
517 }
518 }
519 #endif
520
521 /* Assign pre-assigned (registry) partitions */
522
523
524 /* Assign bootable partition on first harddisk */
525 DPRINT("Assigning bootable primary partition on first harddisk:\n");
526 if (ConfigInfo->DiskCount > 0)
527 {
528 /* Search for bootable partition */
529 for (j = 0; j < LayoutArray[0]->PartitionCount; j++)
530 {
531 if ((LayoutArray[0]->PartitionEntry[j].BootIndicator == TRUE) &&
532 IsRecognizedPartition(LayoutArray[0]->PartitionEntry[j].PartitionType))
533 {
534 swprintf(Buffer2,
535 L"\\Device\\Harddisk0\\Partition%d",
536 LayoutArray[0]->PartitionEntry[j].PartitionNumber);
537 RtlInitUnicodeString(&UnicodeString2,
538 Buffer2);
539
540 /* Assign drive */
541 DPRINT(" %wZ\n", &UnicodeString2);
542 HalpAssignDrive(&UnicodeString2,
543 AUTO_DRIVE,
544 DOSDEVICE_DRIVE_FIXED);
545 }
546 }
547 }
548
549 /* Assign remaining primary partitions */
550 DPRINT("Assigning remaining primary partitions:\n");
551 for (i = 0; i < ConfigInfo->DiskCount; i++)
552 {
553 /* Search for primary partitions */
554 for (j = 0; (j < PARTITION_TBL_SIZE) && (j < LayoutArray[i]->PartitionCount); j++)
555 {
556 if ((i == 0) && (LayoutArray[i]->PartitionEntry[j].BootIndicator == TRUE))
557 continue;
558
559 if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType))
560 {
561 swprintf(Buffer2,
562 L"\\Device\\Harddisk%d\\Partition%d",
563 i,
564 LayoutArray[i]->PartitionEntry[j].PartitionNumber);
565 RtlInitUnicodeString(&UnicodeString2,
566 Buffer2);
567
568 /* Assign drive */
569 DPRINT(" %wZ\n",
570 &UnicodeString2);
571 HalpAssignDrive(&UnicodeString2,
572 AUTO_DRIVE,
573 DOSDEVICE_DRIVE_FIXED);
574 }
575 }
576 }
577
578 /* Assign extended (logical) partitions */
579 DPRINT("Assigning extended (logical) partitions:\n");
580 for (i = 0; i < ConfigInfo->DiskCount; i++)
581 {
582 if (LayoutArray[i])
583 {
584 /* Search for extended partitions */
585 for (j = PARTITION_TBL_SIZE; j < LayoutArray[i]->PartitionCount; j++)
586 {
587 if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) &&
588 (LayoutArray[i]->PartitionEntry[j].PartitionNumber != 0))
589 {
590 swprintf(Buffer2,
591 L"\\Device\\Harddisk%d\\Partition%d",
592 i,
593 LayoutArray[i]->PartitionEntry[j].PartitionNumber);
594 RtlInitUnicodeString(&UnicodeString2,
595 Buffer2);
596
597 /* Assign drive */
598 DPRINT(" %wZ\n",
599 &UnicodeString2);
600 HalpAssignDrive(&UnicodeString2,
601 AUTO_DRIVE,
602 DOSDEVICE_DRIVE_FIXED);
603 }
604 }
605 }
606 }
607
608 /* Assign removable disk drives */
609 DPRINT("Assigning removable disk drives:\n");
610 for (i = 0; i < ConfigInfo->DiskCount; i++)
611 {
612 /* Search for virtual partitions */
613 if (LayoutArray[i]->PartitionCount == 1 &&
614 LayoutArray[i]->PartitionEntry[0].PartitionType == 0)
615 {
616 swprintf(Buffer2,
617 L"\\Device\\Harddisk%d\\Partition1",
618 i);
619 RtlInitUnicodeString(&UnicodeString2,
620 Buffer2);
621
622 /* Assign drive */
623 DPRINT(" %wZ\n",
624 &UnicodeString2);
625 HalpAssignDrive(&UnicodeString2,
626 AUTO_DRIVE,
627 DOSDEVICE_DRIVE_REMOVABLE);
628 }
629 }
630
631 /* Free layout array */
632 for (i = 0; i < ConfigInfo->DiskCount; i++)
633 {
634 if (LayoutArray[i] != NULL)
635 ExFreePool(LayoutArray[i]);
636 }
637 ExFreePool(LayoutArray);
638
639 /* Assign floppy drives */
640 DPRINT("Floppy drives: %d\n", ConfigInfo->FloppyCount);
641 for (i = 0; i < ConfigInfo->FloppyCount; i++)
642 {
643 swprintf(Buffer1,
644 L"\\Device\\Floppy%d",
645 i);
646 RtlInitUnicodeString(&UnicodeString1,
647 Buffer1);
648
649 /* Assign drive letters A: or B: or first free drive letter */
650 DPRINT(" %wZ\n",
651 &UnicodeString1);
652 HalpAssignDrive(&UnicodeString1,
653 (i < 2) ? i : AUTO_DRIVE,
654 DOSDEVICE_DRIVE_REMOVABLE);
655 }
656
657 /* Assign cdrom drives */
658 DPRINT("CD-Rom drives: %d\n", ConfigInfo->CdRomCount);
659 for (i = 0; i < ConfigInfo->CdRomCount; i++)
660 {
661 swprintf(Buffer1,
662 L"\\Device\\CdRom%d",
663 i);
664 RtlInitUnicodeString(&UnicodeString1,
665 Buffer1);
666
667 /* Assign first free drive letter */
668 DPRINT(" %wZ\n", &UnicodeString1);
669 HalpAssignDrive(&UnicodeString1,
670 AUTO_DRIVE,
671 DOSDEVICE_DRIVE_CDROM);
672 }
673
674 /* Anything else to do? */
675
676 ExFreePool(Buffer2);
677 ExFreePool(Buffer1);
678 }
679
680
681 NTSTATUS FASTCALL
682 xHalIoReadPartitionTable(PDEVICE_OBJECT DeviceObject,
683 ULONG SectorSize,
684 BOOLEAN ReturnRecognizedPartitions,
685 PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
686 {
687 LARGE_INTEGER RealPartitionOffset;
688 ULONGLONG PartitionOffset;
689 ULONGLONG nextPartitionOffset = 0LL;
690 ULONGLONG containerOffset;
691 NTSTATUS Status;
692 PPARTITION_SECTOR PartitionSector;
693 PDRIVE_LAYOUT_INFORMATION LayoutBuffer;
694 ULONG i;
695 ULONG Count = 0;
696 ULONG Number = 1;
697 BOOLEAN ExtendedFound = FALSE;
698 PVOID MbrBuffer;
699 DISK_MANAGER DiskManager = NoDiskManager;
700
701 DPRINT("xHalIoReadPartitionTable(%p %lu %x %p)\n",
702 DeviceObject,
703 SectorSize,
704 ReturnRecognizedPartitions,
705 PartitionBuffer);
706
707 *PartitionBuffer = NULL;
708
709 /* Check sector size */
710 if (SectorSize < 512)
711 SectorSize = 512;
712 if (SectorSize > 4096)
713 SectorSize = 4096;
714
715 /* Check for 'Ontrack Disk Manager' */
716 xHalExamineMBR(DeviceObject,
717 SectorSize,
718 0x54,
719 &MbrBuffer);
720 if (MbrBuffer != NULL)
721 {
722 DPRINT("Found 'Ontrack Disk Manager'\n");
723 DiskManager = OntrackDiskManager;
724 ExFreePool(MbrBuffer);
725 }
726
727 /* Check for 'EZ-Drive' */
728 xHalExamineMBR(DeviceObject,
729 SectorSize,
730 0x55,
731 &MbrBuffer);
732 if (MbrBuffer != NULL)
733 {
734 DPRINT("Found 'EZ-Drive'\n");
735 DiskManager = EZ_Drive;
736 ExFreePool(MbrBuffer);
737 }
738
739 PartitionSector = (PPARTITION_SECTOR)ExAllocatePool(PagedPool,
740 SectorSize);
741 if (PartitionSector == NULL)
742 {
743 return(STATUS_INSUFFICIENT_RESOURCES);
744 }
745
746 LayoutBuffer = (PDRIVE_LAYOUT_INFORMATION)ExAllocatePool(NonPagedPool,
747 0x1000);
748 if (LayoutBuffer == NULL)
749 {
750 ExFreePool(PartitionSector);
751 return(STATUS_INSUFFICIENT_RESOURCES);
752 }
753
754 RtlZeroMemory(LayoutBuffer,
755 0x1000);
756
757 PartitionOffset = 0ULL;
758 containerOffset = 0ULL;
759
760 do
761 {
762 DPRINT("PartitionOffset: %I64u\n", PartitionOffset / SectorSize);
763
764 /* Handle disk managers */
765 if (DiskManager == OntrackDiskManager)
766 {
767 /* Shift offset by 63 sectors */
768 RealPartitionOffset.QuadPart = PartitionOffset + (ULONGLONG)(63 * SectorSize);
769 }
770 else if (DiskManager == EZ_Drive && PartitionOffset == 0ULL)
771 {
772 /* Use sector 1 instead of sector 0 */
773 RealPartitionOffset.QuadPart = (ULONGLONG)SectorSize;
774 }
775 else
776 {
777 RealPartitionOffset.QuadPart = PartitionOffset;
778 }
779
780 DPRINT ("RealPartitionOffset: %I64u\n",
781 RealPartitionOffset.QuadPart / SectorSize);
782
783 Status = xHalpReadSector (DeviceObject,
784 SectorSize,
785 &RealPartitionOffset,
786 PartitionSector);
787 if (!NT_SUCCESS(Status))
788 {
789 DPRINT ("Failed to read partition table sector (Status = 0x%08lx)\n",
790 Status);
791 ExFreePool (PartitionSector);
792 ExFreePool (LayoutBuffer);
793 return Status;
794 }
795
796 /* Check the boot sector id */
797 DPRINT("Magic %x\n", PartitionSector->Magic);
798 if (PartitionSector->Magic != PARTITION_MAGIC)
799 {
800 DPRINT ("Invalid partition sector magic\n");
801 ExFreePool (PartitionSector);
802 *PartitionBuffer = LayoutBuffer;
803 return STATUS_SUCCESS;
804 }
805
806 #ifndef NDEBUG
807 for (i = 0; i < PARTITION_TBL_SIZE; i++)
808 {
809 DPRINT1(" %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
810 i,
811 PartitionSector->Partition[i].BootFlags,
812 PartitionSector->Partition[i].PartitionType,
813 PartitionSector->Partition[i].StartingHead,
814 PartitionSector->Partition[i].StartingSector & 0x3f,
815 (((PartitionSector->Partition[i].StartingSector) & 0xc0) << 2) +
816 PartitionSector->Partition[i].StartingCylinder,
817 PartitionSector->Partition[i].EndingHead,
818 PartitionSector->Partition[i].EndingSector & 0x3f,
819 (((PartitionSector->Partition[i].EndingSector) & 0xc0) << 2) +
820 PartitionSector->Partition[i].EndingCylinder,
821 PartitionSector->Partition[i].StartingBlock,
822 PartitionSector->Partition[i].SectorCount);
823 }
824 #endif
825
826 if (PartitionOffset == 0ULL)
827 {
828 LayoutBuffer->Signature = PartitionSector->Signature;
829 DPRINT("Disk signature: %lx\n", LayoutBuffer->Signature);
830 }
831
832 ExtendedFound = FALSE;
833
834 for (i = 0; i < PARTITION_TBL_SIZE; i++)
835 {
836 if (IsContainerPartition(PartitionSector->Partition[i].PartitionType))
837 {
838 ExtendedFound = TRUE;
839 if ((ULONGLONG) containerOffset == (ULONGLONG) 0)
840 {
841 containerOffset = PartitionOffset;
842 }
843 nextPartitionOffset = (ULONGLONG) containerOffset +
844 (ULONGLONG) PartitionSector->Partition[i].StartingBlock *
845 (ULONGLONG) SectorSize;
846 }
847
848 if ((ReturnRecognizedPartitions == FALSE) ||
849 ((ReturnRecognizedPartitions == TRUE) &&
850 IsRecognizedPartition(PartitionSector->Partition[i].PartitionType)))
851 {
852 /* handle normal partition */
853 DPRINT("Partition %u: Normal Partition\n", i);
854 Count = LayoutBuffer->PartitionCount;
855 DPRINT("Logical Partition %u\n", Count);
856
857 if (PartitionSector->Partition[i].StartingBlock == 0)
858 {
859 LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart = 0;
860 }
861 else if (IsContainerPartition(PartitionSector->Partition[i].PartitionType))
862 {
863 LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart =
864 (ULONGLONG) containerOffset +
865 (ULONGLONG) PartitionSector->Partition[i].StartingBlock *
866 (ULONGLONG) SectorSize;
867 }
868 else
869 {
870 LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart =
871 (ULONGLONG)PartitionOffset +
872 ((ULONGLONG)PartitionSector->Partition[i].StartingBlock * (ULONGLONG)SectorSize);
873 }
874 LayoutBuffer->PartitionEntry[Count].PartitionLength.QuadPart =
875 (ULONGLONG)PartitionSector->Partition[i].SectorCount * (ULONGLONG)SectorSize;
876 LayoutBuffer->PartitionEntry[Count].HiddenSectors =
877 PartitionSector->Partition[i].StartingBlock;
878
879 if (IsRecognizedPartition(PartitionSector->Partition[i].PartitionType))
880 {
881 LayoutBuffer->PartitionEntry[Count].PartitionNumber = Number;
882 Number++;
883 }
884 else
885 {
886 LayoutBuffer->PartitionEntry[Count].PartitionNumber = 0;
887 }
888
889 LayoutBuffer->PartitionEntry[Count].PartitionType =
890 PartitionSector->Partition[i].PartitionType;
891 LayoutBuffer->PartitionEntry[Count].BootIndicator =
892 (PartitionSector->Partition[i].BootFlags & 0x80)?TRUE:FALSE;
893 LayoutBuffer->PartitionEntry[Count].RecognizedPartition =
894 IsRecognizedPartition (PartitionSector->Partition[i].PartitionType);
895 LayoutBuffer->PartitionEntry[Count].RewritePartition = FALSE;
896
897 DPRINT(" %ld: nr: %d boot: %1x type: %x start: 0x%I64x count: 0x%I64x\n",
898 Count,
899 LayoutBuffer->PartitionEntry[Count].PartitionNumber,
900 LayoutBuffer->PartitionEntry[Count].BootIndicator,
901 LayoutBuffer->PartitionEntry[Count].PartitionType,
902 LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart,
903 LayoutBuffer->PartitionEntry[Count].PartitionLength.QuadPart);
904
905 LayoutBuffer->PartitionCount++;
906 }
907 }
908
909 PartitionOffset = nextPartitionOffset;
910 }
911 while (ExtendedFound == TRUE);
912
913 *PartitionBuffer = LayoutBuffer;
914 ExFreePool(PartitionSector);
915
916 return(STATUS_SUCCESS);
917 }
918
919
920 NTSTATUS FASTCALL
921 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
922 IN ULONG SectorSize,
923 IN ULONG PartitionNumber,
924 IN ULONG PartitionType)
925 {
926 PPARTITION_SECTOR PartitionSector;
927 LARGE_INTEGER RealPartitionOffset;
928 ULONGLONG PartitionOffset;
929 ULONGLONG nextPartitionOffset = 0LL;
930 ULONGLONG containerOffset;
931 NTSTATUS Status;
932 ULONG i;
933 ULONG Number = 1;
934 BOOLEAN ExtendedFound = FALSE;
935 DISK_MANAGER DiskManager = NoDiskManager;
936
937 DPRINT ("xHalIoSetPartitionInformation(%p %lu %lu %lu)\n",
938 DeviceObject,
939 SectorSize,
940 PartitionNumber,
941 PartitionType);
942
943 /* Check sector size */
944 if (SectorSize < 512)
945 SectorSize = 512;
946 if (SectorSize > 4096)
947 SectorSize = 4096;
948
949 /* Check for 'Ontrack Disk Manager' */
950 xHalExamineMBR (DeviceObject,
951 SectorSize,
952 0x54,
953 (PVOID*) &PartitionSector);
954 if (PartitionSector != NULL)
955 {
956 DPRINT ("Found 'Ontrack Disk Manager'\n");
957 DiskManager = OntrackDiskManager;
958 ExFreePool (PartitionSector);
959 }
960
961 /* Check for 'EZ-Drive' */
962 xHalExamineMBR (DeviceObject,
963 SectorSize,
964 0x55,
965 (PVOID*) &PartitionSector);
966 if (PartitionSector != NULL)
967 {
968 DPRINT ("Found 'EZ-Drive'\n");
969 DiskManager = EZ_Drive;
970 ExFreePool (PartitionSector);
971 }
972
973 /* Allocate partition sector */
974 PartitionSector = (PPARTITION_SECTOR) ExAllocatePool (PagedPool,
975 SectorSize);
976 if (PartitionSector == NULL)
977 {
978 return STATUS_INSUFFICIENT_RESOURCES;
979 }
980
981 PartitionOffset = 0ULL;
982 containerOffset = 0ULL;
983
984 do
985 {
986 DPRINT ("PartitionOffset: %I64u\n", PartitionOffset / SectorSize);
987
988 /* Handle disk managers */
989 if (DiskManager == OntrackDiskManager)
990 {
991 /* Shift offset by 63 sectors */
992 RealPartitionOffset.QuadPart = PartitionOffset + (ULONGLONG)(63 * SectorSize);
993 }
994 else if (DiskManager == EZ_Drive && PartitionOffset == 0ULL)
995 {
996 /* Use sector 1 instead of sector 0 */
997 RealPartitionOffset.QuadPart = (ULONGLONG)SectorSize;
998 }
999 else
1000 {
1001 RealPartitionOffset.QuadPart = PartitionOffset;
1002 }
1003
1004 DPRINT ("RealPartitionOffset: %I64u\n",
1005 RealPartitionOffset.QuadPart / SectorSize);
1006
1007 Status = xHalpReadSector (DeviceObject,
1008 SectorSize,
1009 &RealPartitionOffset,
1010 PartitionSector);
1011 if (!NT_SUCCESS (Status))
1012 {
1013 DPRINT ("Failed to read partition table sector (Status = 0x%08lx)\n",
1014 Status);
1015 ExFreePool (PartitionSector);
1016 return Status;
1017 }
1018
1019 /* Check the boot sector id */
1020 DPRINT("Magic %x\n", PartitionSector->Magic);
1021 if (PartitionSector->Magic != PARTITION_MAGIC)
1022 {
1023 DPRINT ("Invalid partition sector magic\n");
1024 ExFreePool (PartitionSector);
1025 return STATUS_UNSUCCESSFUL;
1026 }
1027
1028 #ifndef NDEBUG
1029 for (i = 0; i < PARTITION_TBL_SIZE; i++)
1030 {
1031 DPRINT1(" %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
1032 i,
1033 PartitionSector->Partition[i].BootFlags,
1034 PartitionSector->Partition[i].PartitionType,
1035 PartitionSector->Partition[i].StartingHead,
1036 PartitionSector->Partition[i].StartingSector & 0x3f,
1037 (((PartitionSector->Partition[i].StartingSector) & 0xc0) << 2) +
1038 PartitionSector->Partition[i].StartingCylinder,
1039 PartitionSector->Partition[i].EndingHead,
1040 PartitionSector->Partition[i].EndingSector & 0x3f,
1041 (((PartitionSector->Partition[i].EndingSector) & 0xc0) << 2) +
1042 PartitionSector->Partition[i].EndingCylinder,
1043 PartitionSector->Partition[i].StartingBlock,
1044 PartitionSector->Partition[i].SectorCount);
1045 }
1046 #endif
1047
1048 ExtendedFound = FALSE;
1049 for (i = 0; i < PARTITION_TBL_SIZE; i++)
1050 {
1051 if (IsContainerPartition (PartitionSector->Partition[i].PartitionType))
1052 {
1053 ExtendedFound = TRUE;
1054 if (containerOffset == 0ULL)
1055 {
1056 containerOffset = PartitionOffset;
1057 }
1058 nextPartitionOffset = containerOffset +
1059 (ULONGLONG) PartitionSector->Partition[i].StartingBlock *
1060 (ULONGLONG) SectorSize;
1061 }
1062
1063 /* Handle recognized partition */
1064 if (IsRecognizedPartition (PartitionSector->Partition[i].PartitionType))
1065 {
1066 if (Number == PartitionNumber)
1067 {
1068 /* Set partition type */
1069 PartitionSector->Partition[i].PartitionType = PartitionType;
1070
1071 /* Write partition sector */
1072 Status = xHalpWriteSector (DeviceObject,
1073 SectorSize,
1074 &RealPartitionOffset,
1075 PartitionSector);
1076 if (!NT_SUCCESS(Status))
1077 {
1078 DPRINT1("xHalpWriteSector() failed (Status %lx)\n", Status);
1079 }
1080
1081 ExFreePool (PartitionSector);
1082 return Status;
1083 }
1084 Number++;
1085 }
1086 }
1087
1088 PartitionOffset = nextPartitionOffset;
1089 }
1090 while (ExtendedFound == TRUE);
1091
1092 ExFreePool(PartitionSector);
1093
1094 return STATUS_UNSUCCESSFUL;
1095 }
1096
1097
1098 NTSTATUS FASTCALL
1099 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
1100 IN ULONG SectorSize,
1101 IN ULONG SectorsPerTrack,
1102 IN ULONG NumberOfHeads,
1103 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
1104 {
1105 PPARTITION_SECTOR PartitionSector;
1106 LARGE_INTEGER RealPartitionOffset;
1107 ULONGLONG PartitionOffset;
1108 ULONGLONG NextPartitionOffset = 0LL;
1109 ULONGLONG ContainerOffset;
1110 BOOLEAN ContainerEntry;
1111 DISK_MANAGER DiskManager;
1112 ULONG i;
1113 ULONG j;
1114 ULONG StartBlock;
1115 ULONG SectorCount;
1116 ULONG StartCylinder;
1117 ULONG StartSector;
1118 ULONG StartHead;
1119 ULONG EndCylinder;
1120 ULONG EndSector;
1121 ULONG EndHead;
1122 ULONG lba;
1123 ULONG x;
1124 NTSTATUS Status;
1125
1126 DPRINT ("xHalIoWritePartitionTable(%p %lu %lu %lu %p)\n",
1127 DeviceObject,
1128 SectorSize,
1129 SectorsPerTrack,
1130 NumberOfHeads,
1131 PartitionBuffer);
1132
1133 assert(DeviceObject);
1134 assert(PartitionBuffer);
1135
1136 DiskManager = NoDiskManager;
1137
1138 /* Check sector size */
1139 if (SectorSize < 512)
1140 SectorSize = 512;
1141 if (SectorSize > 4096)
1142 SectorSize = 4096;
1143
1144 /* Check for 'Ontrack Disk Manager' */
1145 xHalExamineMBR (DeviceObject,
1146 SectorSize,
1147 0x54,
1148 (PVOID *) &PartitionSector);
1149 if (PartitionSector != NULL)
1150 {
1151 DPRINT ("Found 'Ontrack Disk Manager'\n");
1152 DiskManager = OntrackDiskManager;
1153 ExFreePool (PartitionSector);
1154 }
1155
1156 /* Check for 'EZ-Drive' */
1157 xHalExamineMBR (DeviceObject,
1158 SectorSize,
1159 0x55,
1160 (PVOID *) &PartitionSector);
1161 if (PartitionSector != NULL)
1162 {
1163 DPRINT ("Found 'EZ-Drive'\n");
1164 DiskManager = EZ_Drive;
1165 ExFreePool (PartitionSector);
1166 }
1167
1168 /* Allocate partition sector */
1169 PartitionSector = (PPARTITION_SECTOR)ExAllocatePool(PagedPool,
1170 SectorSize);
1171 if (PartitionSector == NULL)
1172 {
1173 return STATUS_INSUFFICIENT_RESOURCES;
1174 }
1175
1176 Status = STATUS_SUCCESS;
1177 PartitionOffset = 0ULL;
1178 ContainerOffset = 0ULL;
1179 for (i = 0; i < PartitionBuffer->PartitionCount; i += 4)
1180 {
1181 DPRINT ("PartitionOffset: %I64u\n", PartitionOffset);
1182 DPRINT ("ContainerOffset: %I64u\n", ContainerOffset);
1183
1184 /* Handle disk managers */
1185 if (DiskManager == OntrackDiskManager)
1186 {
1187 /* Shift offset by 63 sectors */
1188 RealPartitionOffset.QuadPart = PartitionOffset + (ULONGLONG)(63 * SectorSize);
1189 }
1190 else if (DiskManager == EZ_Drive && PartitionOffset == 0ULL)
1191 {
1192 /* Use sector 1 instead of sector 0 */
1193 RealPartitionOffset.QuadPart = (ULONGLONG)SectorSize;
1194 }
1195 else
1196 {
1197 RealPartitionOffset.QuadPart = PartitionOffset;
1198 }
1199
1200 /* Write modified partition tables */
1201 if (PartitionBuffer->PartitionEntry[i].RewritePartition == TRUE ||
1202 PartitionBuffer->PartitionEntry[i + 1].RewritePartition == TRUE ||
1203 PartitionBuffer->PartitionEntry[i + 2].RewritePartition == TRUE ||
1204 PartitionBuffer->PartitionEntry[i + 3].RewritePartition == TRUE)
1205 {
1206 /* Read partition sector */
1207 Status = xHalpReadSector (DeviceObject,
1208 SectorSize,
1209 &RealPartitionOffset,
1210 PartitionSector);
1211 if (!NT_SUCCESS(Status))
1212 {
1213 DPRINT1 ("xHalpReadSector() failed (Status %lx)\n", Status);
1214 break;
1215 }
1216
1217 /* Initialize a new partition sector */
1218 if (PartitionSector->Magic != PARTITION_MAGIC)
1219 {
1220 /* Create empty partition sector */
1221 RtlZeroMemory (PartitionSector,
1222 SectorSize);
1223 PartitionSector->Magic = PARTITION_MAGIC;
1224 }
1225
1226 /* Update partition sector entries */
1227 for (j = 0; j < 4; j++)
1228 {
1229 if (PartitionBuffer->PartitionEntry[i + j].RewritePartition == TRUE)
1230 {
1231 /* Set partition boot flag */
1232 if (PartitionBuffer->PartitionEntry[i + j].BootIndicator)
1233 {
1234 PartitionSector->Partition[j].BootFlags |= 0x80;
1235 }
1236 else
1237 {
1238 PartitionSector->Partition[j].BootFlags &= ~0x80;
1239 }
1240
1241 /* Set partition type */
1242 PartitionSector->Partition[j].PartitionType =
1243 PartitionBuffer->PartitionEntry[i + j].PartitionType;
1244
1245 /* Set partition data */
1246 if (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart == 0ULL &&
1247 PartitionBuffer->PartitionEntry[i + j].PartitionLength.QuadPart == 0ULL)
1248 {
1249 PartitionSector->Partition[j].StartingBlock = 0;
1250 PartitionSector->Partition[j].SectorCount = 0;
1251 PartitionSector->Partition[j].StartingCylinder = 0;
1252 PartitionSector->Partition[j].StartingHead = 0;
1253 PartitionSector->Partition[j].StartingSector = 0;
1254 PartitionSector->Partition[j].EndingCylinder = 0;
1255 PartitionSector->Partition[j].EndingHead = 0;
1256 PartitionSector->Partition[j].EndingSector = 0;
1257 }
1258 else
1259 {
1260 /*
1261 * CHS formulas:
1262 * x = LBA DIV SectorsPerTrack
1263 * cylinder = (x DIV NumberOfHeads) % 1024
1264 * head = x MOD NumberOfHeads
1265 * sector = (LBA MOD SectorsPerTrack) + 1
1266 */
1267
1268 /* Compute starting CHS values */
1269 lba = (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart) / SectorSize;
1270 x = lba / SectorsPerTrack;
1271 StartCylinder = (x / NumberOfHeads) %1024;
1272 StartHead = x % NumberOfHeads;
1273 StartSector = (lba % SectorsPerTrack) + 1;
1274 DPRINT ("StartingOffset (LBA:%d C:%d H:%d S:%d)\n",
1275 lba, StartCylinder, StartHead, StartSector);
1276
1277 /* Compute ending CHS values */
1278 lba = (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart +
1279 (PartitionBuffer->PartitionEntry[i + j].PartitionLength.QuadPart - 1)) / SectorSize;
1280 x = lba / SectorsPerTrack;
1281 EndCylinder = (x / NumberOfHeads) % 1024;
1282 EndHead = x % NumberOfHeads;
1283 EndSector = (lba % SectorsPerTrack) + 1;
1284 DPRINT ("EndingOffset (LBA:%d C:%d H:%d S:%d)\n",
1285 lba, EndCylinder, EndHead, EndSector);
1286
1287 /* Set starting CHS values */
1288 PartitionSector->Partition[j].StartingCylinder = StartCylinder & 0xff;
1289 PartitionSector->Partition[j].StartingHead = StartHead;
1290 PartitionSector->Partition[j].StartingSector =
1291 ((StartCylinder & 0x0300) >> 2) + (StartSector & 0x3f);
1292
1293 /* Set ending CHS values */
1294 PartitionSector->Partition[j].EndingCylinder = EndCylinder & 0xff;
1295 PartitionSector->Partition[j].EndingHead = EndHead;
1296 PartitionSector->Partition[j].EndingSector =
1297 ((EndCylinder & 0x0300) >> 2) + (EndSector & 0x3f);
1298
1299 /* Calculate start sector and sector count */
1300 StartBlock =
1301 (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart - ContainerOffset) / SectorSize;
1302 SectorCount =
1303 PartitionBuffer->PartitionEntry[i + j].PartitionLength.QuadPart / SectorSize;
1304 DPRINT ("LBA (StartBlock:%lu SectorCount:%lu)\n",
1305 StartBlock, SectorCount);
1306
1307 /* Set start sector and sector count */
1308 PartitionSector->Partition[j].StartingBlock = StartBlock;
1309 PartitionSector->Partition[j].SectorCount = SectorCount;
1310 }
1311 }
1312 }
1313
1314 /* Write partition sector */
1315 Status = xHalpWriteSector (DeviceObject,
1316 SectorSize,
1317 &RealPartitionOffset,
1318 PartitionSector);
1319 if (!NT_SUCCESS(Status))
1320 {
1321 DPRINT1("xHalpWriteSector() failed (Status %lx)\n", Status);
1322 break;
1323 }
1324 }
1325
1326 ContainerEntry = FALSE;
1327 for (j = 0; j < 4; j++)
1328 {
1329 if (IsContainerPartition (PartitionBuffer->PartitionEntry[i + j].PartitionType))
1330 {
1331 ContainerEntry = TRUE;
1332 NextPartitionOffset =
1333 PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart;
1334
1335 if (ContainerOffset == 0ULL)
1336 {
1337 ContainerOffset = NextPartitionOffset;
1338 }
1339 }
1340 }
1341
1342 if (ContainerEntry == FALSE)
1343 {
1344 DPRINT ("No container entry in partition sector!\n");
1345 break;
1346 }
1347
1348 PartitionOffset = NextPartitionOffset;
1349 }
1350
1351 ExFreePool (PartitionSector);
1352
1353 return Status;
1354 }
1355
1356 /* EOF */