3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * TODO: This is here where we should add support for GPT partitions
22 * as well as partitionless disks!
30 DBG_DEFAULT_CHANNEL(DISK
);
32 /* This function serves to retrieve a partition entry for devices that handle partitions differently */
33 DISK_GET_PARTITION_ENTRY DiskGetPartitionEntry
= DiskGetMbrPartitionEntry
;
35 BOOLEAN
DiskGetActivePartitionEntry(UCHAR DriveNumber
,
36 PPARTITION_TABLE_ENTRY PartitionTableEntry
,
37 ULONG
*ActivePartition
)
39 ULONG BootablePartitionCount
= 0;
40 ULONG CurrentPartitionNumber
;
42 MASTER_BOOT_RECORD MasterBootRecord
;
43 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry
;
47 // Read master boot record
48 if (!DiskReadBootRecord(DriveNumber
, 0, &MasterBootRecord
))
53 CurrentPartitionNumber
= 0;
54 for (Index
=0; Index
<4; Index
++)
56 ThisPartitionTableEntry
= &MasterBootRecord
.PartitionTable
[Index
];
58 if (ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_ENTRY_UNUSED
&&
59 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_EXTENDED
&&
60 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_XINT13_EXTENDED
)
62 CurrentPartitionNumber
++;
64 // Test if this is the bootable partition
65 if (ThisPartitionTableEntry
->BootIndicator
== 0x80)
67 BootablePartitionCount
++;
68 *ActivePartition
= CurrentPartitionNumber
;
70 // Copy the partition table entry
71 RtlCopyMemory(PartitionTableEntry
,
72 ThisPartitionTableEntry
,
73 sizeof(PARTITION_TABLE_ENTRY
));
78 // Make sure there was only one bootable partition
79 if (BootablePartitionCount
== 0)
81 ERR("No bootable (active) partitions found.\n");
84 else if (BootablePartitionCount
!= 1)
86 ERR("Too many bootable (active) partitions found.\n");
93 BOOLEAN
DiskGetMbrPartitionEntry(UCHAR DriveNumber
, ULONG PartitionNumber
, PPARTITION_TABLE_ENTRY PartitionTableEntry
)
95 MASTER_BOOT_RECORD MasterBootRecord
;
96 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry
;
97 ULONG ExtendedPartitionNumber
;
98 ULONG ExtendedPartitionOffset
;
100 ULONG CurrentPartitionNumber
;
101 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry
;
103 // Read master boot record
104 if (!DiskReadBootRecord(DriveNumber
, 0, &MasterBootRecord
))
109 CurrentPartitionNumber
= 0;
110 for (Index
=0; Index
<4; Index
++)
112 ThisPartitionTableEntry
= &MasterBootRecord
.PartitionTable
[Index
];
114 if (ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_ENTRY_UNUSED
&&
115 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_EXTENDED
&&
116 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_XINT13_EXTENDED
)
118 CurrentPartitionNumber
++;
121 if (PartitionNumber
== CurrentPartitionNumber
)
123 RtlCopyMemory(PartitionTableEntry
, ThisPartitionTableEntry
, sizeof(PARTITION_TABLE_ENTRY
));
128 // They want an extended partition entry so we will need
129 // to loop through all the extended partitions on the disk
130 // and return the one they want.
132 ExtendedPartitionNumber
= PartitionNumber
- CurrentPartitionNumber
- 1;
134 // Set the initial relative starting sector to 0
135 // This is because extended partition starting
136 // sectors a numbered relative to their parent
137 ExtendedPartitionOffset
= 0;
139 for (Index
=0; Index
<=ExtendedPartitionNumber
; Index
++)
141 // Get the extended partition table entry
142 if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord
, &ExtendedPartitionTableEntry
))
147 // Adjust the relative starting sector of the partition
148 ExtendedPartitionTableEntry
.SectorCountBeforePartition
+= ExtendedPartitionOffset
;
149 if (ExtendedPartitionOffset
== 0)
151 // Set the start of the parrent extended partition
152 ExtendedPartitionOffset
= ExtendedPartitionTableEntry
.SectorCountBeforePartition
;
154 // Read the partition boot record
155 if (!DiskReadBootRecord(DriveNumber
, ExtendedPartitionTableEntry
.SectorCountBeforePartition
, &MasterBootRecord
))
160 // Get the first real partition table entry
161 if (!DiskGetFirstPartitionEntry(&MasterBootRecord
, PartitionTableEntry
))
166 // Now correct the start sector of the partition
167 PartitionTableEntry
->SectorCountBeforePartition
+= ExtendedPartitionTableEntry
.SectorCountBeforePartition
;
170 // When we get here we should have the correct entry
171 // already stored in PartitionTableEntry
172 // so just return TRUE
176 BOOLEAN
DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord
, PPARTITION_TABLE_ENTRY PartitionTableEntry
)
180 for (Index
=0; Index
<4; Index
++)
182 // Check the system indicator
183 // If it's not an extended or unused partition
185 if ((MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_ENTRY_UNUSED
) &&
186 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_EXTENDED
) &&
187 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_XINT13_EXTENDED
))
189 RtlCopyMemory(PartitionTableEntry
, &MasterBootRecord
->PartitionTable
[Index
], sizeof(PARTITION_TABLE_ENTRY
));
197 BOOLEAN
DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord
, PPARTITION_TABLE_ENTRY PartitionTableEntry
)
201 for (Index
=0; Index
<4; Index
++)
203 // Check the system indicator
204 // If it an extended partition then we're done
205 if ((MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
== PARTITION_EXTENDED
) ||
206 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
== PARTITION_XINT13_EXTENDED
))
208 RtlCopyMemory(PartitionTableEntry
, &MasterBootRecord
->PartitionTable
[Index
], sizeof(PARTITION_TABLE_ENTRY
));
216 BOOLEAN
DiskReadBootRecord(UCHAR DriveNumber
, ULONGLONG LogicalSectorNumber
, PMASTER_BOOT_RECORD BootRecord
)
220 // Read master boot record
221 if (!MachDiskReadLogicalSectors(DriveNumber
, LogicalSectorNumber
, 1, DiskReadBuffer
))
225 RtlCopyMemory(BootRecord
, DiskReadBuffer
, sizeof(MASTER_BOOT_RECORD
));
227 TRACE("Dumping partition table for drive 0x%x:\n", DriveNumber
);
228 TRACE("Boot record logical start sector = %d\n", LogicalSectorNumber
);
229 TRACE("sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD
));
231 for (Index
=0; Index
<4; Index
++)
233 TRACE("-------------------------------------------\n");
234 TRACE("Partition %d\n", (Index
+ 1));
235 TRACE("BootIndicator: 0x%x\n", BootRecord
->PartitionTable
[Index
].BootIndicator
);
236 TRACE("StartHead: 0x%x\n", BootRecord
->PartitionTable
[Index
].StartHead
);
237 TRACE("StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord
->PartitionTable
[Index
].StartSector
);
238 TRACE("StartCylinder: 0x%x\n", BootRecord
->PartitionTable
[Index
].StartCylinder
);
239 TRACE("SystemIndicator: 0x%x\n", BootRecord
->PartitionTable
[Index
].SystemIndicator
);
240 TRACE("EndHead: 0x%x\n", BootRecord
->PartitionTable
[Index
].EndHead
);
241 TRACE("EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord
->PartitionTable
[Index
].EndSector
);
242 TRACE("EndCylinder: 0x%x\n", BootRecord
->PartitionTable
[Index
].EndCylinder
);
243 TRACE("SectorCountBeforePartition: 0x%x\n", BootRecord
->PartitionTable
[Index
].SectorCountBeforePartition
);
244 TRACE("PartitionSectorCount: 0x%x\n", BootRecord
->PartitionTable
[Index
].PartitionSectorCount
);
247 // Check the partition table magic value
248 if (BootRecord
->MasterBootRecordMagic
!= 0xaa55)
260 IN PDEVICE_OBJECT DeviceObject
,
261 IN ULONGLONG LogicalSectorNumber
,
263 OUT PMASTER_BOOT_RECORD BootRecord
)
265 ULONG_PTR FileId
= (ULONG_PTR
)DeviceObject
;
266 LARGE_INTEGER Position
;
270 Position
.QuadPart
= LogicalSectorNumber
* SectorSize
;
271 Status
= ArcSeek(FileId
, &Position
, SeekAbsolute
);
272 if (Status
!= ESUCCESS
)
273 return STATUS_IO_DEVICE_ERROR
;
275 Status
= ArcRead(FileId
, BootRecord
, SectorSize
, &BytesRead
);
276 if (Status
!= ESUCCESS
|| BytesRead
!= SectorSize
)
277 return STATUS_IO_DEVICE_ERROR
;
279 return STATUS_SUCCESS
;
284 IopCopyPartitionRecord(
285 IN BOOLEAN ReturnRecognizedPartitions
,
287 IN PPARTITION_TABLE_ENTRY PartitionTableEntry
,
288 OUT PARTITION_INFORMATION
*PartitionEntry
)
290 BOOLEAN IsRecognized
;
292 IsRecognized
= TRUE
; /* FIXME */
293 if (!IsRecognized
&& ReturnRecognizedPartitions
)
296 PartitionEntry
->StartingOffset
.QuadPart
= (ULONGLONG
)PartitionTableEntry
->SectorCountBeforePartition
* SectorSize
;
297 PartitionEntry
->PartitionLength
.QuadPart
= (ULONGLONG
)PartitionTableEntry
->PartitionSectorCount
* SectorSize
;
298 PartitionEntry
->HiddenSectors
= 0;
299 PartitionEntry
->PartitionNumber
= 0; /* Will be filled later */
300 PartitionEntry
->PartitionType
= PartitionTableEntry
->SystemIndicator
;
301 PartitionEntry
->BootIndicator
= (PartitionTableEntry
->BootIndicator
& 0x80) ? TRUE
: FALSE
;
302 PartitionEntry
->RecognizedPartition
= IsRecognized
;
303 PartitionEntry
->RewritePartition
= FALSE
;
310 IoReadPartitionTable(
311 IN PDEVICE_OBJECT DeviceObject
,
313 IN BOOLEAN ReturnRecognizedPartitions
,
314 OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
316 PMASTER_BOOT_RECORD MasterBootRecord
;
317 PDRIVE_LAYOUT_INFORMATION Partitions
;
318 ULONG NbPartitions
, i
, Size
;
321 *PartitionBuffer
= NULL
;
323 if (SectorSize
< sizeof(MASTER_BOOT_RECORD
))
324 return STATUS_NOT_SUPPORTED
;
326 MasterBootRecord
= ExAllocatePool(NonPagedPool
, SectorSize
);
327 if (!MasterBootRecord
)
328 return STATUS_NO_MEMORY
;
331 ret
= IopReadBootRecord(DeviceObject
, 0, SectorSize
, MasterBootRecord
);
332 if (!NT_SUCCESS(ret
))
334 ExFreePool(MasterBootRecord
);
338 /* Check validity of boot record */
339 if (MasterBootRecord
->MasterBootRecordMagic
!= 0xaa55)
341 ExFreePool(MasterBootRecord
);
342 return STATUS_NOT_SUPPORTED
;
345 /* Count number of partitions */
347 for (i
= 0; i
< 4; i
++)
351 if (MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_EXTENDED
||
352 MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_XINT13_EXTENDED
)
354 /* FIXME: unhandled case; count number of partitions */
359 if (NbPartitions
== 0)
361 ExFreePool(MasterBootRecord
);
362 return STATUS_NOT_SUPPORTED
;
365 /* Allocation space to store partitions */
366 Size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
, PartitionEntry
) +
367 NbPartitions
* sizeof(PARTITION_INFORMATION
);
368 Partitions
= ExAllocatePool(NonPagedPool
, Size
);
371 ExFreePool(MasterBootRecord
);
372 return STATUS_NO_MEMORY
;
375 /* Count number of partitions */
377 for (i
= 0; i
< 4; i
++)
379 if (IopCopyPartitionRecord(ReturnRecognizedPartitions
,
381 &MasterBootRecord
->PartitionTable
[i
],
382 &Partitions
->PartitionEntry
[NbPartitions
]))
384 Partitions
->PartitionEntry
[NbPartitions
].PartitionNumber
= NbPartitions
+ 1;
388 if (MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_EXTENDED
||
389 MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_XINT13_EXTENDED
)
391 /* FIXME: unhandled case; copy partitions */
396 Partitions
->PartitionCount
= NbPartitions
;
397 Partitions
->Signature
= MasterBootRecord
->Signature
;
398 ExFreePool(MasterBootRecord
);
400 *PartitionBuffer
= Partitions
;
401 return STATUS_SUCCESS
;