[HAL]
[reactos.git] / reactos / 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 char ErrMsg[64];
201 ULONG Index;
202
203 // Read master boot record
204 if (!MachDiskReadLogicalSectors(DriveNumber, LogicalSectorNumber, 1, (PVOID)DISKREADBUFFER))
205 {
206 return FALSE;
207 }
208 RtlCopyMemory(BootRecord, (PVOID)DISKREADBUFFER, sizeof(MASTER_BOOT_RECORD));
209
210
211 DPRINTM(DPRINT_DISK, "Dumping partition table for drive 0x%x:\n", DriveNumber);
212 DPRINTM(DPRINT_DISK, "Boot record logical start sector = %d\n", LogicalSectorNumber);
213 DPRINTM(DPRINT_DISK, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD));
214
215 for (Index=0; Index<4; Index++)
216 {
217 DPRINTM(DPRINT_DISK, "-------------------------------------------\n");
218 DPRINTM(DPRINT_DISK, "Partition %d\n", (Index + 1));
219 DPRINTM(DPRINT_DISK, "BootIndicator: 0x%x\n", BootRecord->PartitionTable[Index].BootIndicator);
220 DPRINTM(DPRINT_DISK, "StartHead: 0x%x\n", BootRecord->PartitionTable[Index].StartHead);
221 DPRINTM(DPRINT_DISK, "StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].StartSector);
222 DPRINTM(DPRINT_DISK, "StartCylinder: 0x%x\n", BootRecord->PartitionTable[Index].StartCylinder);
223 DPRINTM(DPRINT_DISK, "SystemIndicator: 0x%x\n", BootRecord->PartitionTable[Index].SystemIndicator);
224 DPRINTM(DPRINT_DISK, "EndHead: 0x%x\n", BootRecord->PartitionTable[Index].EndHead);
225 DPRINTM(DPRINT_DISK, "EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].EndSector);
226 DPRINTM(DPRINT_DISK, "EndCylinder: 0x%x\n", BootRecord->PartitionTable[Index].EndCylinder);
227 DPRINTM(DPRINT_DISK, "SectorCountBeforePartition: 0x%x\n", BootRecord->PartitionTable[Index].SectorCountBeforePartition);
228 DPRINTM(DPRINT_DISK, "PartitionSectorCount: 0x%x\n", BootRecord->PartitionTable[Index].PartitionSectorCount);
229 }
230
231 // Check the partition table magic value
232 if (BootRecord->MasterBootRecordMagic != 0xaa55)
233 {
234 sprintf(ErrMsg, "Invalid partition table magic 0x%x found on drive 0x%lx",
235 BootRecord->MasterBootRecordMagic, DriveNumber);
236 DiskError(ErrMsg, 0);
237 return FALSE;
238 }
239
240 return TRUE;
241 }
242
243 NTSTATUS
244 NTAPI
245 IopReadBootRecord(
246 IN PDEVICE_OBJECT DeviceObject,
247 IN ULONGLONG LogicalSectorNumber,
248 IN ULONG SectorSize,
249 OUT PMASTER_BOOT_RECORD BootRecord)
250 {
251 ULONG FileId = (ULONG)DeviceObject;
252 LARGE_INTEGER Position;
253 ULONG BytesRead;
254 ULONG Status;
255
256 Position.QuadPart = LogicalSectorNumber * SectorSize;
257 Status = ArcSeek(FileId, &Position, SeekAbsolute);
258 if (Status != ESUCCESS)
259 return STATUS_IO_DEVICE_ERROR;
260
261 Status = ArcRead(FileId, BootRecord, SectorSize, &BytesRead);
262 if (Status != ESUCCESS || BytesRead != SectorSize)
263 return STATUS_IO_DEVICE_ERROR;
264
265 return STATUS_SUCCESS;
266 }
267
268 BOOLEAN
269 NTAPI
270 IopCopyPartitionRecord(
271 IN BOOLEAN ReturnRecognizedPartitions,
272 IN ULONG SectorSize,
273 IN PPARTITION_TABLE_ENTRY PartitionTableEntry,
274 OUT PARTITION_INFORMATION *PartitionEntry)
275 {
276 BOOLEAN IsRecognized;
277
278 IsRecognized = TRUE; /* FIXME */
279 if (!IsRecognized && ReturnRecognizedPartitions)
280 return FALSE;
281
282 PartitionEntry->StartingOffset.QuadPart = (ULONGLONG)PartitionTableEntry->SectorCountBeforePartition * SectorSize;
283 PartitionEntry->PartitionLength.QuadPart = (ULONGLONG)PartitionTableEntry->PartitionSectorCount * SectorSize;
284 PartitionEntry->HiddenSectors = 0;
285 PartitionEntry->PartitionNumber = 0; /* Will be filled later */
286 PartitionEntry->PartitionType = PartitionTableEntry->SystemIndicator;
287 PartitionEntry->BootIndicator = (PartitionTableEntry->BootIndicator & 0x80) ? TRUE : FALSE;
288 PartitionEntry->RecognizedPartition = IsRecognized;
289 PartitionEntry->RewritePartition = FALSE;
290
291 return TRUE;
292 }
293
294 NTKERNELAPI
295 NTSTATUS
296 FASTCALL
297 IoReadPartitionTable(
298 IN PDEVICE_OBJECT DeviceObject,
299 IN ULONG SectorSize,
300 IN BOOLEAN ReturnRecognizedPartitions,
301 OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
302 {
303 PMASTER_BOOT_RECORD MasterBootRecord;
304 PDRIVE_LAYOUT_INFORMATION Partitions;
305 ULONG NbPartitions, i, Size;
306 NTSTATUS ret;
307
308 *PartitionBuffer = NULL;
309
310 if (SectorSize < sizeof(MASTER_BOOT_RECORD))
311 return STATUS_NOT_SUPPORTED;
312
313 MasterBootRecord = ExAllocatePool(NonPagedPool, SectorSize);
314 if (!MasterBootRecord)
315 return STATUS_NO_MEMORY;
316
317 /* Read disk MBR */
318 ret = IopReadBootRecord(DeviceObject, 0, SectorSize, MasterBootRecord);
319 if (!NT_SUCCESS(ret))
320 {
321 ExFreePool(MasterBootRecord);
322 return ret;
323 }
324
325 /* Check validity of boot record */
326 if (MasterBootRecord->MasterBootRecordMagic != 0xaa55)
327 {
328 ExFreePool(MasterBootRecord);
329 return STATUS_NOT_SUPPORTED;
330 }
331
332 /* Count number of partitions */
333 NbPartitions = 0;
334 for (i = 0; i < 4; i++)
335 {
336 NbPartitions++;
337
338 if (MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_EXTENDED ||
339 MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_XINT13_EXTENDED)
340 {
341 /* FIXME: unhandled case; count number of partitions */
342 UNIMPLEMENTED;
343 }
344 }
345
346 if (NbPartitions == 0)
347 {
348 ExFreePool(MasterBootRecord);
349 return STATUS_NOT_SUPPORTED;
350 }
351
352 /* Allocation space to store partitions */
353 Size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) +
354 NbPartitions * sizeof(PARTITION_INFORMATION);
355 Partitions = ExAllocatePool(NonPagedPool, Size);
356 if (!Partitions)
357 {
358 ExFreePool(MasterBootRecord);
359 return STATUS_NO_MEMORY;
360 }
361
362 /* Count number of partitions */
363 NbPartitions = 0;
364 for (i = 0; i < 4; i++)
365 {
366 if (IopCopyPartitionRecord(ReturnRecognizedPartitions,
367 SectorSize,
368 &MasterBootRecord->PartitionTable[i],
369 &Partitions->PartitionEntry[NbPartitions]))
370 {
371 Partitions->PartitionEntry[NbPartitions].PartitionNumber = NbPartitions + 1;
372 NbPartitions++;
373 }
374
375 if (MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_EXTENDED ||
376 MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_XINT13_EXTENDED)
377 {
378 /* FIXME: unhandled case; copy partitions */
379 UNIMPLEMENTED;
380 }
381 }
382
383 Partitions->PartitionCount = NbPartitions;
384 Partitions->Signature = MasterBootRecord->Signature;
385 ExFreePool(MasterBootRecord);
386
387 *PartitionBuffer = Partitions;
388 return STATUS_SUCCESS;
389 }
390
391 #endif