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