5c7680b17aecd9e89e2f634a2d11ea63240fb263
[reactos.git] / reactos / boot / freeldr / freeldr / arch / i386 / xboxhw.c
1 /* $Id$
2 *
3 * FreeLoader
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
22 #define NDEBUG
23 #include <debug.h>
24
25 static CHAR Hex[] = "0123456789ABCDEF";
26 //static unsigned int delay_count = 1;
27
28 extern ULONG reactos_disk_count;
29 extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
30 extern char reactos_arc_strings[32][256];
31
32 static PCM_PARTIAL_RESOURCE_LIST
33 GetHarddiskConfigurationData(ULONG DriveNumber, ULONG* pSize)
34 {
35 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
36 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
37 EXTENDED_GEOMETRY ExtGeometry;
38 GEOMETRY Geometry;
39 ULONG Size;
40
41 //
42 // Initialize returned size
43 //
44 *pSize = 0;
45
46 /* Set 'Configuration Data' value */
47 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
48 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
49 PartialResourceList = MmHeapAlloc(Size);
50 if (PartialResourceList == NULL)
51 {
52 DPRINTM(DPRINT_HWDETECT,
53 "Failed to allocate a full resource descriptor\n");
54 return NULL;
55 }
56
57 memset(PartialResourceList, 0, Size);
58 PartialResourceList->Version = 1;
59 PartialResourceList->Revision = 1;
60 PartialResourceList->Count = 1;
61 PartialResourceList->PartialDescriptors[0].Type =
62 CmResourceTypeDeviceSpecific;
63 // PartialResourceList->PartialDescriptors[0].ShareDisposition =
64 // PartialResourceList->PartialDescriptors[0].Flags =
65 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
66 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
67
68 /* Get pointer to geometry data */
69 DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
70
71 /* Get the disk geometry */
72 ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY);
73
74 if(MachDiskGetDriveGeometry(DriveNumber, &Geometry))
75 {
76 DiskGeometry->BytesPerSector = Geometry.BytesPerSector;
77 DiskGeometry->NumberOfCylinders = Geometry.Cylinders;
78 DiskGeometry->SectorsPerTrack = Geometry.Sectors;
79 DiskGeometry->NumberOfHeads = Geometry.Heads;
80 }
81 else
82 {
83 DPRINTM(DPRINT_HWDETECT, "Reading disk geometry failed\n");
84 MmHeapFree(PartialResourceList);
85 return NULL;
86 }
87 DPRINTM(DPRINT_HWDETECT,
88 "Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
89 DriveNumber,
90 DiskGeometry->NumberOfCylinders,
91 DiskGeometry->NumberOfHeads,
92 DiskGeometry->SectorsPerTrack,
93 DiskGeometry->BytesPerSector);
94
95 //
96 // Return configuration data
97 //
98 *pSize = Size;
99 return PartialResourceList;
100 }
101
102 typedef struct tagDISKCONTEXT
103 {
104 ULONG DriveNumber;
105 ULONG SectorSize;
106 ULONGLONG SectorOffset;
107 ULONGLONG SectorCount;
108 ULONGLONG SectorNumber;
109 } DISKCONTEXT;
110
111 static LONG DiskClose(ULONG FileId)
112 {
113 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
114
115 MmHeapFree(Context);
116 return ESUCCESS;
117 }
118
119 static LONG DiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
120 {
121 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
122
123 RtlZeroMemory(Information, sizeof(FILEINFORMATION));
124 Information->EndingAddress.QuadPart = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
125 Information->CurrentAddress.LowPart = (Context->SectorOffset + Context->SectorNumber) * Context->SectorSize;
126
127 return ESUCCESS;
128 }
129
130 static LONG DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
131 {
132 DISKCONTEXT* Context;
133 ULONG DriveNumber, DrivePartition, SectorSize;
134 ULONGLONG SectorOffset = 0;
135 ULONGLONG SectorCount = 0;
136 PARTITION_TABLE_ENTRY PartitionTableEntry;
137 CHAR FileName[1];
138
139 if (!DissectArcPath(Path, FileName, &DriveNumber, &DrivePartition))
140 return EINVAL;
141 SectorSize = (DrivePartition == 0xff ? 2048 : 512);
142 if (DrivePartition != 0xff && DrivePartition != 0)
143 {
144 if (!XboxDiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
145 return EINVAL;
146 SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
147 SectorCount = PartitionTableEntry.PartitionSectorCount;
148 }
149 else
150 {
151 SectorCount = 0; /* FIXME */
152 }
153
154 Context = MmHeapAlloc(sizeof(DISKCONTEXT));
155 if (!Context)
156 return ENOMEM;
157 Context->DriveNumber = DriveNumber;
158 Context->SectorSize = SectorSize;
159 Context->SectorOffset = SectorOffset;
160 Context->SectorCount = SectorCount;
161 Context->SectorNumber = 0;
162 FsSetDeviceSpecific(*FileId, Context);
163
164 return ESUCCESS;
165 }
166
167 static LONG DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
168 {
169 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
170 UCHAR* Ptr = (UCHAR*)Buffer;
171 ULONG i, Length, Sectors;
172 BOOLEAN ret;
173
174 *Count = 0;
175 i = 0;
176 while (N > 0)
177 {
178 Length = N;
179 if (Length > DISKREADBUFFER_SIZE)
180 Length = DISKREADBUFFER_SIZE;
181 Sectors = (Length + Context->SectorSize - 1) / Context->SectorSize;
182 ret = MachDiskReadLogicalSectors(
183 Context->DriveNumber,
184 Context->SectorNumber + Context->SectorOffset + i,
185 Sectors,
186 (PVOID)DISKREADBUFFER);
187 if (!ret)
188 return EIO;
189 RtlCopyMemory(Ptr, (PVOID)DISKREADBUFFER, Length);
190 Ptr += Length;
191 *Count += Length;
192 N -= Length;
193 i += Sectors;
194 }
195
196 return ESUCCESS;
197 }
198
199 static LONG DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
200 {
201 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
202
203 if (SeekMode != SeekAbsolute)
204 return EINVAL;
205 if (Position->LowPart & (Context->SectorSize - 1))
206 return EINVAL;
207
208 /* FIXME: take HighPart into account */
209 Context->SectorNumber = Position->LowPart / Context->SectorSize;
210 return ESUCCESS;
211 }
212
213 static const DEVVTBL DiskVtbl = {
214 DiskClose,
215 DiskGetFileInformation,
216 DiskOpen,
217 DiskRead,
218 DiskSeek,
219 };
220
221 static VOID
222 GetHarddiskIdentifier(PCHAR Identifier,
223 ULONG DriveNumber)
224 {
225 PMASTER_BOOT_RECORD Mbr;
226 ULONG *Buffer;
227 ULONG i;
228 ULONG Checksum;
229 ULONG Signature;
230 CHAR ArcName[256];
231 PARTITION_TABLE_ENTRY PartitionTableEntry;
232
233 /* Read the MBR */
234 if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, (PVOID)DISKREADBUFFER))
235 {
236 DPRINTM(DPRINT_HWDETECT, "Reading MBR failed\n");
237 return;
238 }
239
240 Buffer = (ULONG*)DISKREADBUFFER;
241 Mbr = (PMASTER_BOOT_RECORD)DISKREADBUFFER;
242
243 Signature = Mbr->Signature;
244 DPRINTM(DPRINT_HWDETECT, "Signature: %x\n", Signature);
245
246 /* Calculate the MBR checksum */
247 Checksum = 0;
248 for (i = 0; i < 128; i++)
249 {
250 Checksum += Buffer[i];
251 }
252 Checksum = ~Checksum + 1;
253 DPRINTM(DPRINT_HWDETECT, "Checksum: %x\n", Checksum);
254
255 /* Fill out the ARC disk block */
256 reactos_arc_disk_info[reactos_disk_count].Signature = Signature;
257 reactos_arc_disk_info[reactos_disk_count].CheckSum = Checksum;
258 sprintf(ArcName, "multi(0)disk(0)rdisk(%lu)", reactos_disk_count);
259 strcpy(reactos_arc_strings[reactos_disk_count], ArcName);
260 reactos_arc_disk_info[reactos_disk_count].ArcName =
261 reactos_arc_strings[reactos_disk_count];
262 reactos_disk_count++;
263
264 sprintf(ArcName, "multi(0)disk(0)rdisk(%lu)partition(0)", DriveNumber - 0x80);
265 FsRegisterDevice(ArcName, &DiskVtbl);
266
267 /* Add partitions */
268 i = 1;
269 DiskReportError(FALSE);
270 while (XboxDiskGetPartitionEntry(DriveNumber, i, &PartitionTableEntry))
271 {
272 if (PartitionTableEntry.SystemIndicator != PARTITION_ENTRY_UNUSED)
273 {
274 sprintf(ArcName, "multi(0)disk(0)rdisk(%lu)partition(%lu)", DriveNumber - 0x80, i);
275 FsRegisterDevice(ArcName, &DiskVtbl);
276 }
277 i++;
278 }
279 DiskReportError(TRUE);
280
281 /* Convert checksum and signature to identifier string */
282 Identifier[0] = Hex[(Checksum >> 28) & 0x0F];
283 Identifier[1] = Hex[(Checksum >> 24) & 0x0F];
284 Identifier[2] = Hex[(Checksum >> 20) & 0x0F];
285 Identifier[3] = Hex[(Checksum >> 16) & 0x0F];
286 Identifier[4] = Hex[(Checksum >> 12) & 0x0F];
287 Identifier[5] = Hex[(Checksum >> 8) & 0x0F];
288 Identifier[6] = Hex[(Checksum >> 4) & 0x0F];
289 Identifier[7] = Hex[Checksum & 0x0F];
290 Identifier[8] = '-';
291 Identifier[9] = Hex[(Signature >> 28) & 0x0F];
292 Identifier[10] = Hex[(Signature >> 24) & 0x0F];
293 Identifier[11] = Hex[(Signature >> 20) & 0x0F];
294 Identifier[12] = Hex[(Signature >> 16) & 0x0F];
295 Identifier[13] = Hex[(Signature >> 12) & 0x0F];
296 Identifier[14] = Hex[(Signature >> 8) & 0x0F];
297 Identifier[15] = Hex[(Signature >> 4) & 0x0F];
298 Identifier[16] = Hex[Signature & 0x0F];
299 Identifier[17] = '-';
300 Identifier[18] = 'A';
301 Identifier[19] = 0;
302 DPRINTM(DPRINT_HWDETECT, "Identifier: %s\n", Identifier);
303 }
304
305 static VOID
306 DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA SystemKey,
307 PCONFIGURATION_COMPONENT_DATA BusKey)
308 {
309 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
310 PCM_INT13_DRIVE_PARAMETER Int13Drives;
311 GEOMETRY Geometry;
312 PCONFIGURATION_COMPONENT_DATA DiskKey, ControllerKey;
313 ULONG DiskCount;
314 ULONG Size;
315 ULONG i;
316 BOOLEAN Changed;
317
318 /* Count the number of visible drives */
319 DiskReportError(FALSE);
320 DiskCount = 0;
321
322 /* There are some really broken BIOSes out there. There are even BIOSes
323 * that happily report success when you ask them to read from non-existent
324 * harddisks. So, we set the buffer to known contents first, then try to
325 * read. If the BIOS reports success but the buffer contents haven't
326 * changed then we fail anyway */
327 memset((PVOID) DISKREADBUFFER, 0xcd, 512);
328 while (MachDiskReadLogicalSectors(0x80 + DiskCount, 0ULL, 1, (PVOID)DISKREADBUFFER))
329 {
330 Changed = FALSE;
331 for (i = 0; ! Changed && i < 512; i++)
332 {
333 Changed = ((PUCHAR)DISKREADBUFFER)[i] != 0xcd;
334 }
335 if (! Changed)
336 {
337 DPRINTM(DPRINT_HWDETECT, "BIOS reports success for disk %d but data didn't change\n",
338 (int)DiskCount);
339 break;
340 }
341 DiskCount++;
342 memset((PVOID) DISKREADBUFFER, 0xcd, 512);
343 }
344 DiskReportError(TRUE);
345 DPRINTM(DPRINT_HWDETECT, "BIOS reports %d harddisk%s\n",
346 (int)DiskCount, (DiskCount == 1) ? "": "s");
347
348 //DetectBiosFloppyController(BusKey);
349
350 /* Allocate resource descriptor */
351 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
352 sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount;
353 PartialResourceList = MmHeapAlloc(Size);
354 if (PartialResourceList == NULL)
355 {
356 DPRINTM(DPRINT_HWDETECT,
357 "Failed to allocate resource descriptor\n");
358 return;
359 }
360
361 /* Initialize resource descriptor */
362 memset(PartialResourceList, 0, Size);
363 PartialResourceList->Version = 1;
364 PartialResourceList->Revision = 1;
365 PartialResourceList->Count = 1;
366 PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
367 PartialResourceList->PartialDescriptors[0].ShareDisposition = 0;
368 PartialResourceList->PartialDescriptors[0].Flags = 0;
369 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
370 sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount;
371
372 /* Get harddisk Int13 geometry data */
373 Int13Drives = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
374 for (i = 0; i < DiskCount; i++)
375 {
376 if (MachDiskGetDriveGeometry(0x80 + i, &Geometry))
377 {
378 Int13Drives[i].DriveSelect = 0x80 + i;
379 Int13Drives[i].MaxCylinders = Geometry.Cylinders - 1;
380 Int13Drives[i].SectorsPerTrack = Geometry.Sectors;
381 Int13Drives[i].MaxHeads = Geometry.Heads - 1;
382 Int13Drives[i].NumberDrives = DiskCount;
383
384 DPRINTM(DPRINT_HWDETECT,
385 "Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
386 0x80 + i,
387 Geometry.Cylinders - 1,
388 Geometry.Heads -1,
389 Geometry.Sectors,
390 Geometry.BytesPerSector);
391 }
392 }
393
394 FldrCreateComponentKey(BusKey,
395 ControllerClass,
396 DiskController,
397 Output | Input,
398 0,
399 0xFFFFFFFF,
400 NULL,
401 PartialResourceList,
402 Size,
403 &ControllerKey);
404 DPRINTM(DPRINT_HWDETECT, "Created key: DiskController\\0\n");
405
406 MmHeapFree(PartialResourceList);
407
408 /* Create and fill subkey for each harddisk */
409 for (i = 0; i < DiskCount; i++)
410 {
411 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
412 ULONG Size;
413 CHAR Identifier[20];
414
415 /* Get disk values */
416 PartialResourceList = GetHarddiskConfigurationData(0x80 + i, &Size);
417 GetHarddiskIdentifier(Identifier, 0x80 + i);
418
419 /* Create disk key */
420 FldrCreateComponentKey(ControllerKey,
421 PeripheralClass,
422 DiskPeripheral,
423 Output | Input,
424 0,
425 0xFFFFFFFF,
426 Identifier,
427 PartialResourceList,
428 Size,
429 &DiskKey);
430
431 if (PartialResourceList)
432 MmHeapFree(PartialResourceList);
433 }
434 }
435
436 static VOID
437 DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
438 {
439 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
440 PCONFIGURATION_COMPONENT_DATA BusKey;
441 ULONG Size;
442
443 /* Set 'Configuration Data' value */
444 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
445 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
446 PartialResourceList = MmHeapAlloc(Size);
447 if (PartialResourceList == NULL)
448 {
449 DPRINTM(DPRINT_HWDETECT,
450 "Failed to allocate resource descriptor\n");
451 return;
452 }
453
454 /* Initialize resource descriptor */
455 memset(PartialResourceList, 0, Size);
456 PartialResourceList->Version = 1;
457 PartialResourceList->Revision = 1;
458 PartialResourceList->Count = 0;
459
460 /* Create new bus key */
461 FldrCreateComponentKey(SystemKey,
462 AdapterClass,
463 MultiFunctionAdapter,
464 0x0,
465 0x0,
466 0xFFFFFFFF,
467 "ISA",
468 PartialResourceList,
469 Size,
470 &BusKey);
471
472 /* Increment bus number */
473 (*BusNumber)++;
474
475 MmHeapFree(PartialResourceList);
476
477 /* Detect ISA/BIOS devices */
478 DetectBiosDisks(SystemKey, BusKey);
479
480
481 /* FIXME: Detect more ISA devices */
482 }
483
484 PCONFIGURATION_COMPONENT_DATA
485 XboxHwDetect(VOID)
486 {
487 PCONFIGURATION_COMPONENT_DATA SystemKey;
488 ULONG BusNumber = 0;
489
490 DPRINTM(DPRINT_HWDETECT, "DetectHardware()\n");
491
492 /* Create the 'System' key */
493 FldrCreateSystemKey(&SystemKey);
494
495 /* TODO: Build actual xbox's hardware configuration tree */
496 DetectIsaBios(SystemKey, &BusNumber);
497
498 DPRINTM(DPRINT_HWDETECT, "DetectHardware() Done\n");
499 return SystemKey;
500 }
501
502 /* EOF */