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