b33a9daa3824c3880b188e960d7235e4592cc307
[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 #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(ULONG DriveNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
30 {
31 ULONG BootablePartitionCount = 0;
32 ULONG ActivePartition = 0;
33 MASTER_BOOT_RECORD MasterBootRecord;
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 = 0;
46 }
47 if (MasterBootRecord.PartitionTable[1].BootIndicator == 0x80)
48 {
49 BootablePartitionCount++;
50 ActivePartition = 1;
51 }
52 if (MasterBootRecord.PartitionTable[2].BootIndicator == 0x80)
53 {
54 BootablePartitionCount++;
55 ActivePartition = 2;
56 }
57 if (MasterBootRecord.PartitionTable[3].BootIndicator == 0x80)
58 {
59 BootablePartitionCount++;
60 ActivePartition = 3;
61 }
62
63 // Make sure there was only one bootable partition
64 if (BootablePartitionCount == 0)
65 {
66 DiskError("No bootable (active) partitions found.", 0);
67 return FALSE;
68 }
69 else if (BootablePartitionCount != 1)
70 {
71 DiskError("Too many bootable (active) partitions found.", 0);
72 return FALSE;
73 }
74
75 // Copy the partition table entry
76 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[ActivePartition], 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 }