Sync up to trunk head.
[reactos.git] / boot / freeldr / freeldr / disk / partition.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
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.
9 *
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.
14 *
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.
18 */
19
20 #ifndef _M_ARM
21 #include <freeldr.h>
22 #include <debug.h>
23
24 BOOLEAN DiskGetActivePartitionEntry(ULONG DriveNumber,
25 PPARTITION_TABLE_ENTRY PartitionTableEntry,
26 ULONG *ActivePartition)
27 {
28 ULONG BootablePartitionCount = 0;
29 MASTER_BOOT_RECORD MasterBootRecord;
30
31 *ActivePartition = 0;
32 // Read master boot record
33 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
34 {
35 return FALSE;
36 }
37
38 // Count the bootable partitions
39 if (MasterBootRecord.PartitionTable[0].BootIndicator == 0x80)
40 {
41 BootablePartitionCount++;
42 *ActivePartition = 1;
43 }
44 if (MasterBootRecord.PartitionTable[1].BootIndicator == 0x80)
45 {
46 BootablePartitionCount++;
47 *ActivePartition = 2;
48 }
49 if (MasterBootRecord.PartitionTable[2].BootIndicator == 0x80)
50 {
51 BootablePartitionCount++;
52 *ActivePartition = 3;
53 }
54 if (MasterBootRecord.PartitionTable[3].BootIndicator == 0x80)
55 {
56 BootablePartitionCount++;
57 *ActivePartition = 4;
58 }
59
60 // Make sure there was only one bootable partition
61 if (BootablePartitionCount == 0)
62 {
63 DPRINTM(DPRINT_DISK, "No bootable (active) partitions found.\n");
64 return FALSE;
65 }
66 else if (BootablePartitionCount != 1)
67 {
68 DPRINTM(DPRINT_DISK, "Too many bootable (active) partitions found.\n");
69 return FALSE;
70 }
71
72 // Copy the partition table entry
73 RtlCopyMemory(PartitionTableEntry,
74 &MasterBootRecord.PartitionTable[*ActivePartition - 1],
75 sizeof(PARTITION_TABLE_ENTRY));
76
77 return TRUE;
78 }
79
80 BOOLEAN DiskGetPartitionEntry(ULONG DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
81 {
82 MASTER_BOOT_RECORD MasterBootRecord;
83 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
84 ULONG ExtendedPartitionNumber;
85 ULONG ExtendedPartitionOffset;
86 ULONG Index;
87
88 // Read master boot record
89 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
90 {
91 return FALSE;
92 }
93
94 // If they are asking for a primary
95 // partition then things are easy
96 if (PartitionNumber < 5)
97 {
98 // PartitionNumber is one-based and we need it zero-based
99 PartitionNumber--;
100
101 // Copy the partition table entry
102 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[PartitionNumber], sizeof(PARTITION_TABLE_ENTRY));
103
104 return TRUE;
105 }
106 else
107 {
108 // They want an extended partition entry so we will need
109 // to loop through all the extended partitions on the disk
110 // and return the one they want.
111
112 ExtendedPartitionNumber = PartitionNumber - 5;
113
114 // Set the initial relative starting sector to 0
115 // This is because extended partition starting
116 // sectors a numbered relative to their parent
117 ExtendedPartitionOffset = 0;
118
119 for (Index=0; Index<=ExtendedPartitionNumber; Index++)
120 {
121 // Get the extended partition table entry
122 if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord, &ExtendedPartitionTableEntry))
123 {
124 return FALSE;
125 }
126
127 // Adjust the relative starting sector of the partition
128 ExtendedPartitionTableEntry.SectorCountBeforePartition += ExtendedPartitionOffset;
129 if (ExtendedPartitionOffset == 0)
130 {
131 // Set the start of the parrent extended partition
132 ExtendedPartitionOffset = ExtendedPartitionTableEntry.SectorCountBeforePartition;
133 }
134 // Read the partition boot record
135 if (!DiskReadBootRecord(DriveNumber, ExtendedPartitionTableEntry.SectorCountBeforePartition, &MasterBootRecord))
136 {
137 return FALSE;
138 }
139
140 // Get the first real partition table entry
141 if (!DiskGetFirstPartitionEntry(&MasterBootRecord, PartitionTableEntry))
142 {
143 return FALSE;
144 }
145
146 // Now correct the start sector of the partition
147 PartitionTableEntry->SectorCountBeforePartition += ExtendedPartitionTableEntry.SectorCountBeforePartition;
148 }
149
150 // When we get here we should have the correct entry
151 // already stored in PartitionTableEntry
152 // so just return TRUE
153 return TRUE;
154 }
155
156 }
157
158 BOOLEAN DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
159 {
160 ULONG Index;
161
162 for (Index=0; Index<4; Index++)
163 {
164 // Check the system indicator
165 // If it's not an extended or unused partition
166 // then we're done
167 if ((MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_ENTRY_UNUSED) &&
168 (MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_EXTENDED) &&
169 (MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_XINT13_EXTENDED))
170 {
171 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
172 return TRUE;
173 }
174 }
175
176 return FALSE;
177 }
178
179 BOOLEAN DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
180 {
181 ULONG Index;
182
183 for (Index=0; Index<4; Index++)
184 {
185 // Check the system indicator
186 // If it an extended partition then we're done
187 if ((MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_EXTENDED) ||
188 (MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_XINT13_EXTENDED))
189 {
190 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
191 return TRUE;
192 }
193 }
194
195 return FALSE;
196 }
197
198 BOOLEAN DiskReadBootRecord(ULONG DriveNumber, ULONGLONG LogicalSectorNumber, PMASTER_BOOT_RECORD BootRecord)
199 {
200 ULONG Index;
201
202 // Read master boot record
203 if (!MachDiskReadLogicalSectors(DriveNumber, LogicalSectorNumber, 1, (PVOID)DISKREADBUFFER))
204 {
205 return FALSE;
206 }
207 RtlCopyMemory(BootRecord, (PVOID)DISKREADBUFFER, sizeof(MASTER_BOOT_RECORD));
208
209
210 DPRINTM(DPRINT_DISK, "Dumping partition table for drive 0x%x:\n", DriveNumber);
211 DPRINTM(DPRINT_DISK, "Boot record logical start sector = %d\n", LogicalSectorNumber);
212 DPRINTM(DPRINT_DISK, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD));
213
214 for (Index=0; Index<4; Index++)
215 {
216 DPRINTM(DPRINT_DISK, "-------------------------------------------\n");
217 DPRINTM(DPRINT_DISK, "Partition %d\n", (Index + 1));
218 DPRINTM(DPRINT_DISK, "BootIndicator: 0x%x\n", BootRecord->PartitionTable[Index].BootIndicator);
219 DPRINTM(DPRINT_DISK, "StartHead: 0x%x\n", BootRecord->PartitionTable[Index].StartHead);
220 DPRINTM(DPRINT_DISK, "StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].StartSector);
221 DPRINTM(DPRINT_DISK, "StartCylinder: 0x%x\n", BootRecord->PartitionTable[Index].StartCylinder);
222 DPRINTM(DPRINT_DISK, "SystemIndicator: 0x%x\n", BootRecord->PartitionTable[Index].SystemIndicator);
223 DPRINTM(DPRINT_DISK, "EndHead: 0x%x\n", BootRecord->PartitionTable[Index].EndHead);
224 DPRINTM(DPRINT_DISK, "EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].EndSector);
225 DPRINTM(DPRINT_DISK, "EndCylinder: 0x%x\n", BootRecord->PartitionTable[Index].EndCylinder);
226 DPRINTM(DPRINT_DISK, "SectorCountBeforePartition: 0x%x\n", BootRecord->PartitionTable[Index].SectorCountBeforePartition);
227 DPRINTM(DPRINT_DISK, "PartitionSectorCount: 0x%x\n", BootRecord->PartitionTable[Index].PartitionSectorCount);
228 }
229
230 // Check the partition table magic value
231 if (BootRecord->MasterBootRecordMagic != 0xaa55)
232 {
233 return FALSE;
234 }
235
236 return TRUE;
237 }
238
239 NTSTATUS
240 NTAPI
241 IopReadBootRecord(
242 IN PDEVICE_OBJECT DeviceObject,
243 IN ULONGLONG LogicalSectorNumber,
244 IN ULONG SectorSize,
245 OUT PMASTER_BOOT_RECORD BootRecord)
246 {
247 ULONG FileId = (ULONG)DeviceObject;
248 LARGE_INTEGER Position;
249 ULONG BytesRead;
250 ULONG Status;
251
252 Position.QuadPart = LogicalSectorNumber * SectorSize;
253 Status = ArcSeek(FileId, &Position, SeekAbsolute);
254 if (Status != ESUCCESS)
255 return STATUS_IO_DEVICE_ERROR;
256
257 Status = ArcRead(FileId, BootRecord, SectorSize, &BytesRead);
258 if (Status != ESUCCESS || BytesRead != SectorSize)
259 return STATUS_IO_DEVICE_ERROR;
260
261 return STATUS_SUCCESS;
262 }
263
264 BOOLEAN
265 NTAPI
266 IopCopyPartitionRecord(
267 IN BOOLEAN ReturnRecognizedPartitions,
268 IN ULONG SectorSize,
269 IN PPARTITION_TABLE_ENTRY PartitionTableEntry,
270 OUT PARTITION_INFORMATION *PartitionEntry)
271 {
272 BOOLEAN IsRecognized;
273
274 IsRecognized = TRUE; /* FIXME */
275 if (!IsRecognized && ReturnRecognizedPartitions)
276 return FALSE;
277
278 PartitionEntry->StartingOffset.QuadPart = (ULONGLONG)PartitionTableEntry->SectorCountBeforePartition * SectorSize;
279 PartitionEntry->PartitionLength.QuadPart = (ULONGLONG)PartitionTableEntry->PartitionSectorCount * SectorSize;
280 PartitionEntry->HiddenSectors = 0;
281 PartitionEntry->PartitionNumber = 0; /* Will be filled later */
282 PartitionEntry->PartitionType = PartitionTableEntry->SystemIndicator;
283 PartitionEntry->BootIndicator = (PartitionTableEntry->BootIndicator & 0x80) ? TRUE : FALSE;
284 PartitionEntry->RecognizedPartition = IsRecognized;
285 PartitionEntry->RewritePartition = FALSE;
286
287 return TRUE;
288 }
289
290 NTKERNELAPI
291 NTSTATUS
292 FASTCALL
293 IoReadPartitionTable(
294 IN PDEVICE_OBJECT DeviceObject,
295 IN ULONG SectorSize,
296 IN BOOLEAN ReturnRecognizedPartitions,
297 OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
298 {
299 PMASTER_BOOT_RECORD MasterBootRecord;
300 PDRIVE_LAYOUT_INFORMATION Partitions;
301 ULONG NbPartitions, i, Size;
302 NTSTATUS ret;
303
304 *PartitionBuffer = NULL;
305
306 if (SectorSize < sizeof(MASTER_BOOT_RECORD))
307 return STATUS_NOT_SUPPORTED;
308
309 MasterBootRecord = ExAllocatePool(NonPagedPool, SectorSize);
310 if (!MasterBootRecord)
311 return STATUS_NO_MEMORY;
312
313 /* Read disk MBR */
314 ret = IopReadBootRecord(DeviceObject, 0, SectorSize, MasterBootRecord);
315 if (!NT_SUCCESS(ret))
316 {
317 ExFreePool(MasterBootRecord);
318 return ret;
319 }
320
321 /* Check validity of boot record */
322 if (MasterBootRecord->MasterBootRecordMagic != 0xaa55)
323 {
324 ExFreePool(MasterBootRecord);
325 return STATUS_NOT_SUPPORTED;
326 }
327
328 /* Count number of partitions */
329 NbPartitions = 0;
330 for (i = 0; i < 4; i++)
331 {
332 NbPartitions++;
333
334 if (MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_EXTENDED ||
335 MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_XINT13_EXTENDED)
336 {
337 /* FIXME: unhandled case; count number of partitions */
338 UNIMPLEMENTED;
339 }
340 }
341
342 if (NbPartitions == 0)
343 {
344 ExFreePool(MasterBootRecord);
345 return STATUS_NOT_SUPPORTED;
346 }
347
348 /* Allocation space to store partitions */
349 Size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) +
350 NbPartitions * sizeof(PARTITION_INFORMATION);
351 Partitions = ExAllocatePool(NonPagedPool, Size);
352 if (!Partitions)
353 {
354 ExFreePool(MasterBootRecord);
355 return STATUS_NO_MEMORY;
356 }
357
358 /* Count number of partitions */
359 NbPartitions = 0;
360 for (i = 0; i < 4; i++)
361 {
362 if (IopCopyPartitionRecord(ReturnRecognizedPartitions,
363 SectorSize,
364 &MasterBootRecord->PartitionTable[i],
365 &Partitions->PartitionEntry[NbPartitions]))
366 {
367 Partitions->PartitionEntry[NbPartitions].PartitionNumber = NbPartitions + 1;
368 NbPartitions++;
369 }
370
371 if (MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_EXTENDED ||
372 MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_XINT13_EXTENDED)
373 {
374 /* FIXME: unhandled case; copy partitions */
375 UNIMPLEMENTED;
376 }
377 }
378
379 Partitions->PartitionCount = NbPartitions;
380 Partitions->Signature = MasterBootRecord->Signature;
381 ExFreePool(MasterBootRecord);
382
383 *PartitionBuffer = Partitions;
384 return STATUS_SUCCESS;
385 }
386
387 #endif