1 /* $Id: xhaldrv.c,v 1.5 2000/08/22 21:10:28 ekohl Exp $
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)
14 * - Read disk signature in xHalIoReadPartitionTable().
15 * - Build correct system path from nt device name or arc name.
16 * For example: \Device\Harddisk0\Partition1\reactos ==> C:\reactos
17 * Or: multi(0)disk(0)rdisk(0)partition(1)\reactos ==> C:\reactos
20 /* INCLUDES *****************************************************************/
22 #include <ddk/ntddk.h>
23 #include <internal/xhal.h>
26 #include <internal/debug.h>
28 /* LOCAL MACROS and TYPES ***************************************************/
30 #define AUTO_DRIVE ((ULONG)-1)
32 #define PARTITION_MAGIC 0xaa55
33 #define PART_MAGIC_OFFSET 0x01fe
34 #define PARTITION_OFFSET 0x01be
35 #define PARTITION_TBL_SIZE 4
38 #define PTCHSToLBA(c, h, s, scnt, hcnt) ((s) & 0x3f) + \
39 (scnt) * ( (h) + (hcnt) * ((c) | (((s) & 0xc0) << 2)))
40 #define PTLBAToCHS(lba, c, h, s, scnt, hcnt) ( \
41 (s) = (lba) % (scnt) + 1, \
43 (h) = (lba) % (hcnt), \
46 (s) |= ((lba) >> 2) & 0xc0)
49 #define IsUsablePartition(P) \
51 (P) != PTDosExtended && \
52 (P) != PTWin95ExtendedLBA)
55 typedef struct _PARTITION
57 unsigned char BootFlags
;
58 unsigned char StartingHead
;
59 unsigned char StartingSector
;
60 unsigned char StartingCylinder
;
61 unsigned char PartitionType
;
62 unsigned char EndingHead
;
63 unsigned char EndingSector
;
64 unsigned char EndingCylinder
;
65 unsigned int StartingBlock
;
66 unsigned int SectorCount
;
67 } PARTITION
, *PPARTITION
;
69 typedef struct _PARTITION_TABLE
71 PARTITION Partition
[PARTITION_TBL_SIZE
];
73 } PARTITION_TABLE
, *PPARTITION_TABLE
;
75 /* FUNCTIONS *****************************************************************/
78 xHalpQueryDriveLayout (
79 IN PUNICODE_STRING DeviceName
,
80 OUT PDRIVE_LAYOUT_INFORMATION
*LayoutInfo
83 IO_STATUS_BLOCK StatusBlock
;
84 DISK_GEOMETRY DiskGeometry
;
85 PDEVICE_OBJECT DeviceObject
= NULL
;
86 PFILE_OBJECT FileObject
;
91 DPRINT ("xHalpQueryDriveLayout %wZ %p\n",
96 * Get the drives sector size
98 Status
= IoGetDeviceObjectPointer (DeviceName
,
102 if (!NT_SUCCESS(Status
))
104 DPRINT ("Status %x\n",Status
);
108 KeInitializeEvent (&Event
,
112 Irp
= IoBuildDeviceIoControlRequest (IOCTL_DISK_GET_DRIVE_GEOMETRY
,
117 sizeof(DISK_GEOMETRY
),
123 ObDereferenceObject (FileObject
);
124 return STATUS_INSUFFICIENT_RESOURCES
;
127 Status
= IoCallDriver(DeviceObject
, Irp
);
128 if (Status
== STATUS_PENDING
)
130 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
131 Status
= StatusBlock
.Status
;
133 if (!NT_SUCCESS(Status
))
135 ObDereferenceObject (FileObject
);
139 DPRINT("DiskGeometry.BytesPerSector: %d\n",
140 DiskGeometry
.BytesPerSector
);
142 /* read the partition table */
143 Status
= IoReadPartitionTable (DeviceObject
,
144 DiskGeometry
.BytesPerSector
,
148 ObDereferenceObject (FileObject
);
157 IN PDEVICE_OBJECT DeviceObject
,
159 IN ULONG MBRTypeIdentifier
,
164 IO_STATUS_BLOCK StatusBlock
;
165 LARGE_INTEGER Offset
;
170 DPRINT ("xHalExamineMBR()\n");
173 if (SectorSize
< 512)
175 if (SectorSize
> 4096)
178 LocalBuffer
= (PUCHAR
)ExAllocatePool (PagedPool
,
180 if (LocalBuffer
== NULL
)
183 KeInitializeEvent (&Event
,
189 Irp
= IoBuildSynchronousFsdRequest (IRP_MJ_READ
,
197 Status
= IoCallDriver (DeviceObject
,
199 if (Status
== STATUS_PENDING
)
201 KeWaitForSingleObject (&Event
,
206 Status
= StatusBlock
.Status
;
209 if (!NT_SUCCESS(Status
))
211 DPRINT ("xHalExamineMBR failed (Status = 0x%08lx)\n",
213 ExFreePool (LocalBuffer
);
217 if (LocalBuffer
[0x1FE] != 0x55 || LocalBuffer
[0x1FF] != 0xAA)
219 DPRINT ("xHalExamineMBR: invalid MBR signature\n");
220 ExFreePool (LocalBuffer
);
224 if (LocalBuffer
[0x1C2] != MBRTypeIdentifier
)
226 DPRINT ("xHalExamineMBR: invalid MBRTypeIdentifier\n");
227 ExFreePool (LocalBuffer
);
231 *Buffer
= (PVOID
)LocalBuffer
;
236 IN PUNICODE_STRING PartitionName
,
237 IN OUT PULONG DriveMap
,
241 WCHAR DriveNameBuffer
[8];
242 UNICODE_STRING DriveName
;
245 DPRINT("HalpAssignDrive()\n");
247 if ((DriveNumber
!= AUTO_DRIVE
) && (DriveNumber
< 24))
249 /* force assignment */
250 if ((*DriveMap
& (1 << DriveNumber
)) != 0)
252 DbgPrint("Drive letter already used!\n");
258 /* automatic assignment */
259 DriveNumber
= AUTO_DRIVE
;
261 for (i
= 2; i
< 24; i
++)
263 if ((*DriveMap
& (1 << i
)) == 0)
270 if (DriveNumber
== AUTO_DRIVE
)
272 DbgPrint("No drive letter available!\n");
277 DPRINT("DriveNumber %d\n", DriveNumber
);
279 /* set bit in drive map */
280 *DriveMap
= *DriveMap
| (1 << DriveNumber
);
282 /* build drive name */
283 swprintf (DriveNameBuffer
,
286 RtlInitUnicodeString (&DriveName
,
289 DPRINT1(" %wZ ==> %wZ\n",
293 /* create symbolic link */
294 IoCreateSymbolicLink (&DriveName
,
301 xHalIoAssignDriveLetters (
302 IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
303 IN PSTRING NtDeviceName
,
304 OUT PUCHAR NtSystemPath
,
305 OUT PSTRING NtSystemPathString
308 PDRIVE_LAYOUT_INFORMATION LayoutInfo
;
309 PCONFIGURATION_INFORMATION ConfigInfo
;
310 OBJECT_ATTRIBUTES ObjectAttributes
;
311 IO_STATUS_BLOCK StatusBlock
;
312 UNICODE_STRING UnicodeString1
;
313 UNICODE_STRING UnicodeString2
;
322 DPRINT("xHalIoAssignDriveLetters()\n");
324 ConfigInfo
= IoGetConfigurationInformation ();
326 Buffer1
= (PWSTR
)ExAllocatePool (PagedPool
,
328 Buffer2
= (PWSTR
)ExAllocatePool (PagedPool
,
331 /* Create PhysicalDrive links */
332 DPRINT("Physical disk drives: %d\n", ConfigInfo
->DiskCount
);
333 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
336 L
"\\Device\\Harddisk%d\\Partition0",
338 RtlInitUnicodeString (&UnicodeString1
,
341 InitializeObjectAttributes (&ObjectAttributes
,
347 Status
= NtOpenFile (&FileHandle
,
352 FILE_SYNCHRONOUS_IO_NONALERT
);
353 if (NT_SUCCESS(Status
))
355 NtClose (FileHandle
);
358 L
"\\??\\PhysicalDrive%d",
360 RtlInitUnicodeString (&UnicodeString2
,
363 DPRINT1("Creating link: %S ==> %S\n",
367 IoCreateSymbolicLink (&UnicodeString2
,
372 /* Assign pre-assigned (registry) partitions */
374 /* Assign bootable partitions */
375 DPRINT("Assigning bootable partitions:\n");
376 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
379 L
"\\Device\\Harddisk%d\\Partition0",
381 RtlInitUnicodeString (&UnicodeString1
,
384 Status
= xHalpQueryDriveLayout (&UnicodeString1
,
386 if (!NT_SUCCESS(Status
))
388 DPRINT1("xHalpQueryDriveLayout() failed (Status = 0x%lx)\n",
393 DPRINT("Logical partitions: %d\n",
394 LayoutInfo
->PartitionCount
);
396 /* search for bootable partitions */
397 for (j
= 0; j
< LayoutInfo
->PartitionCount
; j
++)
399 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%lu count:%lu\n",
401 LayoutInfo
->PartitionEntry
[j
].PartitionNumber
,
402 LayoutInfo
->PartitionEntry
[j
].BootIndicator
,
403 LayoutInfo
->PartitionEntry
[j
].PartitionType
,
404 LayoutInfo
->PartitionEntry
[j
].StartingOffset
.u
.LowPart
,
405 LayoutInfo
->PartitionEntry
[j
].PartitionLength
.u
.LowPart
);
407 if (LayoutInfo
->PartitionEntry
[j
].BootIndicator
)
410 L
"\\Device\\Harddisk%d\\Partition%d",
412 LayoutInfo
->PartitionEntry
[j
].PartitionNumber
);
413 RtlInitUnicodeString (&UnicodeString2
,
416 DPRINT(" %wZ\n", &UnicodeString2
);
419 HalpAssignDrive (&UnicodeString2
,
425 ExFreePool (LayoutInfo
);
428 /* Assign remaining primary partitions */
429 DPRINT("Assigning primary partitions:\n");
430 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
433 L
"\\Device\\Harddisk%d\\Partition0",
435 RtlInitUnicodeString (&UnicodeString1
,
438 Status
= xHalpQueryDriveLayout (&UnicodeString1
,
440 if (!NT_SUCCESS(Status
))
442 DPRINT1("xHalpQueryDriveLayout() failed (Status = 0x%lx)\n",
447 DPRINT("Logical partitions: %d\n",
448 LayoutInfo
->PartitionCount
);
450 /* search for primary (non-bootable) partitions */
451 for (j
= 0; j
< PARTITION_TBL_SIZE
; j
++)
453 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%lu count:%lu\n",
455 LayoutInfo
->PartitionEntry
[j
].PartitionNumber
,
456 LayoutInfo
->PartitionEntry
[j
].BootIndicator
,
457 LayoutInfo
->PartitionEntry
[j
].PartitionType
,
458 LayoutInfo
->PartitionEntry
[j
].StartingOffset
.u
.LowPart
,
459 LayoutInfo
->PartitionEntry
[j
].PartitionLength
.u
.LowPart
);
461 if ((LayoutInfo
->PartitionEntry
[j
].BootIndicator
== FALSE
) &&
462 IsUsablePartition(LayoutInfo
->PartitionEntry
[j
].PartitionType
))
465 L
"\\Device\\Harddisk%d\\Partition%d",
467 LayoutInfo
->PartitionEntry
[j
].PartitionNumber
);
468 RtlInitUnicodeString (&UnicodeString2
,
472 DPRINT(" %wZ\n", &UnicodeString2
);
473 HalpAssignDrive (&UnicodeString2
, &DriveMap
, AUTO_DRIVE
);
477 ExFreePool (LayoutInfo
);
480 /* Assign extended (logical) partitions */
481 DPRINT("Assigning extended (logical) partitions:\n");
482 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
485 L
"\\Device\\Harddisk%d\\Partition0",
487 RtlInitUnicodeString (&UnicodeString1
,
490 Status
= xHalpQueryDriveLayout (&UnicodeString1
,
492 if (!NT_SUCCESS(Status
))
494 DPRINT1("xHalpQueryDriveLayout() failed (Status = 0x%lx)\n",
499 DPRINT("Logical partitions: %d\n",
500 LayoutInfo
->PartitionCount
);
502 /* search for extended partitions */
503 for (j
= PARTITION_TBL_SIZE
; j
< LayoutInfo
->PartitionCount
; j
++)
505 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%lu count:%lu\n",
507 LayoutInfo
->PartitionEntry
[j
].PartitionNumber
,
508 LayoutInfo
->PartitionEntry
[j
].BootIndicator
,
509 LayoutInfo
->PartitionEntry
[j
].PartitionType
,
510 LayoutInfo
->PartitionEntry
[j
].StartingOffset
.u
.LowPart
,
511 LayoutInfo
->PartitionEntry
[j
].PartitionLength
.u
.LowPart
);
513 if (IsUsablePartition(LayoutInfo
->PartitionEntry
[j
].PartitionType
) &&
514 (LayoutInfo
->PartitionEntry
[j
].PartitionNumber
!= 0))
517 L
"\\Device\\Harddisk%d\\Partition%d",
519 LayoutInfo
->PartitionEntry
[j
].PartitionNumber
);
520 RtlInitUnicodeString (&UnicodeString2
,
524 DPRINT(" %wZ\n", &UnicodeString2
);
525 HalpAssignDrive (&UnicodeString2
, &DriveMap
, AUTO_DRIVE
);
529 ExFreePool (LayoutInfo
);
532 /* Assign floppy drives */
533 DPRINT("Floppy drives: %d\n", ConfigInfo
->FloppyCount
);
534 for (i
= 0; i
< ConfigInfo
->FloppyCount
; i
++)
537 L
"\\Device\\Floppy%d",
539 RtlInitUnicodeString (&UnicodeString1
,
542 /* assign drive letters A: or B: or first free drive letter */
543 DPRINT(" %wZ\n", &UnicodeString1
);
544 HalpAssignDrive (&UnicodeString1
,
546 (i
< 2) ? i
: AUTO_DRIVE
);
549 /* Assign cdrom drives */
550 DPRINT("CD-Rom drives: %d\n", ConfigInfo
->CDRomCount
);
551 for (i
= 0; i
< ConfigInfo
->CDRomCount
; i
++)
554 L
"\\Device\\Cdrom%d",
556 RtlInitUnicodeString (&UnicodeString1
,
559 /* assign first free drive letter */
560 DPRINT(" %wZ\n", &UnicodeString1
);
561 HalpAssignDrive (&UnicodeString1
,
566 /* Anything else ?? */
569 ExFreePool (Buffer2
);
570 ExFreePool (Buffer1
);
576 xHalIoReadPartitionTable (
577 PDEVICE_OBJECT DeviceObject
,
579 BOOLEAN ReturnRecognizedPartitions
,
580 PDRIVE_LAYOUT_INFORMATION
* PartitionBuffer
584 IO_STATUS_BLOCK StatusBlock
;
585 ULARGE_INTEGER Offset
;
589 PPARTITION_TABLE PartitionTable
;
590 PDRIVE_LAYOUT_INFORMATION LayoutBuffer
;
594 BOOLEAN ExtendedFound
= FALSE
;
596 DPRINT("xHalIoReadPartitionTable(%p %lu %x %p)\n",
599 ReturnRecognizedPartitions
,
602 *PartitionBuffer
= NULL
;
604 SectorBuffer
= (PUCHAR
)ExAllocatePool (PagedPool
,
606 if (SectorBuffer
== NULL
)
608 return STATUS_INSUFFICIENT_RESOURCES
;
611 LayoutBuffer
= (PDRIVE_LAYOUT_INFORMATION
)ExAllocatePool (NonPagedPool
,
613 if (LayoutBuffer
== NULL
)
615 ExFreePool (SectorBuffer
);
616 return STATUS_INSUFFICIENT_RESOURCES
;
619 RtlZeroMemory (LayoutBuffer
, 0x1000);
625 KeInitializeEvent (&Event
,
629 Irp
= IoBuildSynchronousFsdRequest (IRP_MJ_READ
,
633 (PLARGE_INTEGER
)&Offset
,
637 Status
= IoCallDriver (DeviceObject
,
639 if (Status
== STATUS_PENDING
)
641 KeWaitForSingleObject (&Event
,
646 Status
= StatusBlock
.Status
;
649 if (!NT_SUCCESS(Status
))
651 DPRINT1("xHalIoReadPartitonTable failed (Status = 0x%08lx)\n",
653 ExFreePool (SectorBuffer
);
654 ExFreePool (LayoutBuffer
);
658 PartitionTable
= (PPARTITION_TABLE
)(SectorBuffer
+PARTITION_OFFSET
);
660 /* check the boot sector id */
661 DPRINT("Magic %x\n", PartitionTable
->Magic
);
662 if (PartitionTable
->Magic
!= PARTITION_MAGIC
)
664 DPRINT1("Invalid partition table magic\n");
665 ExFreePool (SectorBuffer
);
666 // ExFreePool (LayoutBuffer);
667 // return STATUS_UNSUCCESSFUL;
669 *PartitionBuffer
= LayoutBuffer
;
670 return STATUS_SUCCESS
;
674 for (i
= 0; i
< PARTITION_TBL_SIZE
; i
++)
676 DPRINT(" %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
678 PartitionTable
->Partition
[i
].BootFlags
,
679 PartitionTable
->Partition
[i
].PartitionType
,
680 PartitionTable
->Partition
[i
].StartingHead
,
681 PartitionTable
->Partition
[i
].StartingSector
,
682 PartitionTable
->Partition
[i
].StartingCylinder
,
683 PartitionTable
->Partition
[i
].EndingHead
,
684 PartitionTable
->Partition
[i
].EndingSector
,
685 PartitionTable
->Partition
[i
].EndingCylinder
,
686 PartitionTable
->Partition
[i
].StartingBlock
,
687 PartitionTable
->Partition
[i
].SectorCount
);
691 /* FIXME: Set the correct value */
692 if (ExtendedFound
== FALSE
);
694 LayoutBuffer
->Signature
= 0xdeadbeef;
697 ExtendedFound
= FALSE
;
698 for (i
= 0; i
< PARTITION_TBL_SIZE
; i
++)
700 /* handle normal partition */
701 DPRINT("Partition %u: Normal Partition\n", i
);
702 Count
= LayoutBuffer
->PartitionCount
;
703 DPRINT("Logical Partition %u\n", Count
);
705 if (PartitionTable
->Partition
[i
].StartingBlock
)
707 LayoutBuffer
->PartitionEntry
[Count
].StartingOffset
.QuadPart
=
708 (ULONGLONG
)Offset
.QuadPart
+
709 ((ULONGLONG
)PartitionTable
->Partition
[i
].StartingBlock
* (ULONGLONG
)SectorSize
);
713 LayoutBuffer
->PartitionEntry
[Count
].StartingOffset
.QuadPart
= 0;
715 LayoutBuffer
->PartitionEntry
[Count
].PartitionLength
.QuadPart
=
716 (ULONGLONG
)PartitionTable
->Partition
[i
].SectorCount
* (ULONGLONG
)SectorSize
;
717 LayoutBuffer
->PartitionEntry
[Count
].HiddenSectors
= 0;
719 if (IsUsablePartition(PartitionTable
->Partition
[i
].PartitionType
))
721 LayoutBuffer
->PartitionEntry
[Count
].PartitionNumber
= Number
;
726 LayoutBuffer
->PartitionEntry
[Count
].PartitionNumber
= 0;
729 LayoutBuffer
->PartitionEntry
[Count
].PartitionType
=
730 PartitionTable
->Partition
[i
].PartitionType
;
731 LayoutBuffer
->PartitionEntry
[Count
].BootIndicator
=
732 (PartitionTable
->Partition
[i
].BootFlags
& 0x80)?TRUE
:FALSE
;
733 LayoutBuffer
->PartitionEntry
[Count
].RecognizedPartition
=
734 IsRecognizedPartition (PartitionTable
->Partition
[i
].PartitionType
);
735 LayoutBuffer
->PartitionEntry
[Count
].RewritePartition
= FALSE
;
737 DPRINT(" Offset: 0x%I64x", Offset
.QuadPart
);
739 if (IsUsablePartition(PartitionTable
->Partition
[i
].PartitionType
))
741 Offset
.QuadPart
= (ULONGLONG
)Offset
.QuadPart
+
742 (((ULONGLONG
)PartitionTable
->Partition
[i
].StartingBlock
+ (ULONGLONG
)PartitionTable
->Partition
[i
].SectorCount
)* (ULONGLONG
)SectorSize
);
745 if (IsExtendedPartition(PartitionTable
->Partition
[i
].PartitionType
))
747 ExtendedFound
= TRUE
;
750 DPRINT(" %ld: nr: %d boot: %1x type: %x start: 0x%I64x count: 0x%I64x\n",
752 LayoutBuffer
->PartitionEntry
[Count
].PartitionNumber
,
753 LayoutBuffer
->PartitionEntry
[Count
].BootIndicator
,
754 LayoutBuffer
->PartitionEntry
[Count
].PartitionType
,
755 LayoutBuffer
->PartitionEntry
[Count
].StartingOffset
.QuadPart
,
756 LayoutBuffer
->PartitionEntry
[Count
].PartitionLength
.QuadPart
);
758 LayoutBuffer
->PartitionCount
++;
761 while (ExtendedFound
== TRUE
);
763 *PartitionBuffer
= LayoutBuffer
;
764 ExFreePool (SectorBuffer
);
766 return STATUS_SUCCESS
;