b4247ca22495df3d91f2231bc7661746b67f9022
[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
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
22 #define NDEBUG
23 #include <debug.h>
24
25 BOOL DiskGetActivePartitionEntry(ULONG DriveNumber,
26 PPARTITION_TABLE_ENTRY PartitionTableEntry,
27 ULONG *ActivePartition)
28 {
29 ULONG BootablePartitionCount = 0;
30 MASTER_BOOT_RECORD MasterBootRecord;
31
32 *ActivePartition = 0;
33 // Read master boot record
34 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
35 {
36 return FALSE;
37 }
38
39 // Count the bootable partitions
40 if (MasterBootRecord.PartitionTable[0].BootIndicator == 0x80)
41 {
42 BootablePartitionCount++;
43 *ActivePartition = 1;
44 }
45 if (MasterBootRecord.PartitionTable[1].BootIndicator == 0x80)
46 {
47 BootablePartitionCount++;
48 *ActivePartition = 2;
49 }
50 if (MasterBootRecord.PartitionTable[2].BootIndicator == 0x80)
51 {
52 BootablePartitionCount++;
53 *ActivePartition = 3;
54 }
55 if (MasterBootRecord.PartitionTable[3].BootIndicator == 0x80)
56 {
57 BootablePartitionCount++;
58 *ActivePartition = 4;
59 }
60
61 // Make sure there was only one bootable partition
62 if (BootablePartitionCount == 0)
63 {
64 DbgPrint((DPRINT_DISK, "No bootable (active) partitions found.\n"));
65 return FALSE;
66 }
67 else if (BootablePartitionCount != 1)
68 {
69 DbgPrint((DPRINT_DISK, "Too many bootable (active) partitions found.\n"));
70 return FALSE;
71 }
72
73 // Copy the partition table entry
74 RtlCopyMemory(PartitionTableEntry,
75 &MasterBootRecord.PartitionTable[*ActivePartition - 1],
76 sizeof(PARTITION_TABLE_ENTRY));
77
78 return TRUE;
79 }
80
81 BOOL DiskGetPartitionEntry(ULONG DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
82 {
83 MASTER_BOOT_RECORD MasterBootRecord;
84 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
85 ULONG ExtendedPartitionNumber;
86 ULONG ExtendedPartitionOffset;
87 ULONG Index;
88
89 // Read master boot record
90 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
91 {
92 return FALSE;
93 }
94
95 // If they are asking for a primary
96 // partition then things are easy
97 if (PartitionNumber < 5)
98 {
99 // PartitionNumber is one-based and we need it zero-based
100 PartitionNumber--;
101
102 // Copy the partition table entry
103 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[PartitionNumber], sizeof(PARTITION_TABLE_ENTRY));
104
105 return TRUE;
106 }
107 else
108 {
109 // They want an extended partition entry so we will need
110 // to loop through all the extended partitions on the disk
111 // and return the one they want.
112
113 ExtendedPartitionNumber = PartitionNumber - 5;
114
115 // Set the initial relative starting sector to 0
116 // This is because extended partition starting
117 // sectors a numbered relative to their parent
118 ExtendedPartitionOffset = 0;
119
120 for (Index=0; Index<=ExtendedPartitionNumber; Index++)
121 {
122 // Get the extended partition table entry
123 if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord, &ExtendedPartitionTableEntry))
124 {
125 return FALSE;
126 }
127
128 // Adjust the relative starting sector of the partition
129 ExtendedPartitionTableEntry.SectorCountBeforePartition += ExtendedPartitionOffset;
130 if (ExtendedPartitionOffset == 0)
131 {
132 // Set the start of the parrent extended partition
133 ExtendedPartitionOffset = ExtendedPartitionTableEntry.SectorCountBeforePartition;
134 }
135 // Read the partition boot record
136 if (!DiskReadBootRecord(DriveNumber, ExtendedPartitionTableEntry.SectorCountBeforePartition, &MasterBootRecord))
137 {
138 return FALSE;
139 }
140
141 // Get the first real partition table entry
142 if (!DiskGetFirstPartitionEntry(&MasterBootRecord, PartitionTableEntry))
143 {
144 return FALSE;
145 }
146
147 // Now correct the start sector of the partition
148 PartitionTableEntry->SectorCountBeforePartition += ExtendedPartitionTableEntry.SectorCountBeforePartition;
149 }
150
151 // When we get here we should have the correct entry
152 // already stored in PartitionTableEntry
153 // so just return TRUE
154 return TRUE;
155 }
156
157 }
158
159 BOOL DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
160 {
161 ULONG Index;
162
163 for (Index=0; Index<4; Index++)
164 {
165 // Check the system indicator
166 // If it's not an extended or unused partition
167 // then we're done
168 if ((MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_ENTRY_UNUSED) &&
169 (MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_EXTENDED) &&
170 (MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_XINT13_EXTENDED))
171 {
172 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
173 return TRUE;
174 }
175 }
176
177 return FALSE;
178 }
179
180 BOOL DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
181 {
182 ULONG Index;
183
184 for (Index=0; Index<4; Index++)
185 {
186 // Check the system indicator
187 // If it an extended partition then we're done
188 if ((MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_EXTENDED) ||
189 (MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_XINT13_EXTENDED))
190 {
191 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
192 return TRUE;
193 }
194 }
195
196 return FALSE;
197 }
198
199 BOOL DiskReadBootRecord(ULONG DriveNumber, ULONGLONG LogicalSectorNumber, PMASTER_BOOT_RECORD BootRecord)
200 {
201 char ErrMsg[64];
202 #ifdef DEBUG
203 ULONG Index;
204 #endif
205
206 // Read master boot record
207 if (!MachDiskReadLogicalSectors(DriveNumber, LogicalSectorNumber, 1, (PVOID)DISKREADBUFFER))
208 {
209 return FALSE;
210 }
211 RtlCopyMemory(BootRecord, (PVOID)DISKREADBUFFER, sizeof(MASTER_BOOT_RECORD));
212
213
214 #ifdef DEBUG
215
216 DbgPrint((DPRINT_DISK, "Dumping partition table for drive 0x%x:\n", DriveNumber));
217 DbgPrint((DPRINT_DISK, "Boot record logical start sector = %d\n", LogicalSectorNumber));
218 DbgPrint((DPRINT_DISK, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD)));
219
220 for (Index=0; Index<4; Index++)
221 {
222 DbgPrint((DPRINT_DISK, "-------------------------------------------\n"));
223 DbgPrint((DPRINT_DISK, "Partition %d\n", (Index + 1)));
224 DbgPrint((DPRINT_DISK, "BootIndicator: 0x%x\n", BootRecord->PartitionTable[Index].BootIndicator));
225 DbgPrint((DPRINT_DISK, "StartHead: 0x%x\n", BootRecord->PartitionTable[Index].StartHead));
226 DbgPrint((DPRINT_DISK, "StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].StartSector));
227 DbgPrint((DPRINT_DISK, "StartCylinder: 0x%x\n", BootRecord->PartitionTable[Index].StartCylinder));
228 DbgPrint((DPRINT_DISK, "SystemIndicator: 0x%x\n", BootRecord->PartitionTable[Index].SystemIndicator));
229 DbgPrint((DPRINT_DISK, "EndHead: 0x%x\n", BootRecord->PartitionTable[Index].EndHead));
230 DbgPrint((DPRINT_DISK, "EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].EndSector));
231 DbgPrint((DPRINT_DISK, "EndCylinder: 0x%x\n", BootRecord->PartitionTable[Index].EndCylinder));
232 DbgPrint((DPRINT_DISK, "SectorCountBeforePartition: 0x%x\n", BootRecord->PartitionTable[Index].SectorCountBeforePartition));
233 DbgPrint((DPRINT_DISK, "PartitionSectorCount: 0x%x\n", BootRecord->PartitionTable[Index].PartitionSectorCount));
234 }
235
236 #endif // defined DEBUG
237
238 // Check the partition table magic value
239 if (BootRecord->MasterBootRecordMagic != 0xaa55)
240 {
241 sprintf(ErrMsg, "Invalid partition table magic 0x%x found on drive 0x%x",
242 BootRecord->MasterBootRecordMagic, DriveNumber);
243 DiskError(ErrMsg, 0);
244 return FALSE;
245 }
246
247 return TRUE;
248 }