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