0a0e4e4a922e436495e08b1edcf995e6d9c7d338
[reactos.git] / 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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <freeldr.h>
21 #include <disk.h>
22 #include <rtl.h>
23 #include <mm.h>
24 #include <debug.h>
25 #include <arch.h>
26 #include <machine.h>
27
28
29 BOOL DiskGetActivePartitionEntry(U32 DriveNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
30 {
31 U32 BootablePartitionCount = 0;
32 MASTER_BOOT_RECORD MasterBootRecord;
33
34 // Read master boot record
35 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
36 {
37 return FALSE;
38 }
39
40 // Count the bootable partitions
41 if (MasterBootRecord.PartitionTable[0].BootIndicator == 0x80)
42 {
43 BootablePartitionCount++;
44 BootPartition = 0;
45 }
46 if (MasterBootRecord.PartitionTable[1].BootIndicator == 0x80)
47 {
48 BootablePartitionCount++;
49 BootPartition = 1;
50 }
51 if (MasterBootRecord.PartitionTable[2].BootIndicator == 0x80)
52 {
53 BootablePartitionCount++;
54 BootPartition = 2;
55 }
56 if (MasterBootRecord.PartitionTable[3].BootIndicator == 0x80)
57 {
58 BootablePartitionCount++;
59 BootPartition = 3;
60 }
61
62 // Make sure there was only one bootable partition
63 if (BootablePartitionCount == 0)
64 {
65 DiskError("No bootable (active) partitions found.", 0);
66 return FALSE;
67 }
68 else if (BootablePartitionCount != 1)
69 {
70 DiskError("Too many bootable (active) partitions found.", 0);
71 return FALSE;
72 }
73
74 // Copy the partition table entry
75 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[BootPartition], sizeof(PARTITION_TABLE_ENTRY));
76
77 return TRUE;
78 }
79
80 BOOL DiskGetPartitionEntry(U32 DriveNumber, U32 PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
81 {
82 MASTER_BOOT_RECORD MasterBootRecord;
83 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
84 U32 ExtendedPartitionNumber;
85 U32 ExtendedPartitionOffset;
86 U32 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 BOOL DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
159 {
160 U32 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 BOOL DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
180 {
181 U32 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 BOOL DiskReadBootRecord(U32 DriveNumber, U64 LogicalSectorNumber, PMASTER_BOOT_RECORD BootRecord)
199 {
200 char ErrMsg[64];
201 #ifdef DEBUG
202 U32 Index;
203 #endif
204
205 // Read master boot record
206 if (!MachDiskReadLogicalSectors(DriveNumber, LogicalSectorNumber, 1, (PVOID)DISKREADBUFFER))
207 {
208 return FALSE;
209 }
210 RtlCopyMemory(BootRecord, (PVOID)DISKREADBUFFER, sizeof(MASTER_BOOT_RECORD));
211
212
213 #ifdef DEBUG
214
215 DbgPrint((DPRINT_DISK, "Dumping partition table for drive 0x%x:\n", DriveNumber));
216 DbgPrint((DPRINT_DISK, "Boot record logical start sector = %d\n", LogicalSectorNumber));
217 DbgPrint((DPRINT_DISK, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD)));
218
219 for (Index=0; Index<4; Index++)
220 {
221 DbgPrint((DPRINT_DISK, "-------------------------------------------\n"));
222 DbgPrint((DPRINT_DISK, "Partition %d\n", (Index + 1)));
223 DbgPrint((DPRINT_DISK, "BootIndicator: 0x%x\n", BootRecord->PartitionTable[Index].BootIndicator));
224 DbgPrint((DPRINT_DISK, "StartHead: 0x%x\n", BootRecord->PartitionTable[Index].StartHead));
225 DbgPrint((DPRINT_DISK, "StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].StartSector));
226 DbgPrint((DPRINT_DISK, "StartCylinder: 0x%x\n", BootRecord->PartitionTable[Index].StartCylinder));
227 DbgPrint((DPRINT_DISK, "SystemIndicator: 0x%x\n", BootRecord->PartitionTable[Index].SystemIndicator));
228 DbgPrint((DPRINT_DISK, "EndHead: 0x%x\n", BootRecord->PartitionTable[Index].EndHead));
229 DbgPrint((DPRINT_DISK, "EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].EndSector));
230 DbgPrint((DPRINT_DISK, "EndCylinder: 0x%x\n", BootRecord->PartitionTable[Index].EndCylinder));
231 DbgPrint((DPRINT_DISK, "SectorCountBeforePartition: 0x%x\n", BootRecord->PartitionTable[Index].SectorCountBeforePartition));
232 DbgPrint((DPRINT_DISK, "PartitionSectorCount: 0x%x\n", BootRecord->PartitionTable[Index].PartitionSectorCount));
233 }
234
235 #endif // defined DEBUG
236
237 // Check the partition table magic value
238 if (BootRecord->MasterBootRecordMagic != 0xaa55)
239 {
240 sprintf(ErrMsg, "Invalid partition table magic 0x%x found on drive 0x%x",
241 BootRecord->MasterBootRecordMagic, DriveNumber);
242 DiskError(ErrMsg, 0);
243 return FALSE;
244 }
245
246 return TRUE;
247 }