4 * Copyright (C) 2003, 2004 Eric Kohl
5 * Copyright (C) 2009 Hervé Poussineau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 DBG_DEFAULT_CHANNEL(HWDETECT
);
29 typedef struct tagDISKCONTEXT
33 ULONGLONG SectorOffset
;
34 ULONGLONG SectorCount
;
35 ULONGLONG SectorNumber
;
38 extern ULONG reactos_disk_count
;
39 extern ARC_DISK_SIGNATURE_EX reactos_arc_disk_info
[];
41 static CHAR Hex
[] = "0123456789abcdef";
42 UCHAR PcBiosDiskCount
= 0;
43 CHAR PcDiskIdentifier
[32][20];
45 SIZE_T DiskReadBufferSize
;
48 static ARC_STATUS
DiskClose(ULONG FileId
)
50 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
52 FrLdrTempFree(Context
, TAG_HW_DISK_CONTEXT
);
56 static ARC_STATUS
DiskGetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
58 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
60 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
61 Information
->EndingAddress
.QuadPart
= (Context
->SectorOffset
+ Context
->SectorCount
) * Context
->SectorSize
;
62 Information
->CurrentAddress
.QuadPart
= (Context
->SectorOffset
+ Context
->SectorNumber
) * Context
->SectorSize
;
67 static ARC_STATUS
DiskOpen(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
71 ULONG DrivePartition
, SectorSize
;
72 ULONGLONG SectorOffset
= 0;
73 ULONGLONG SectorCount
= 0;
74 PARTITION_TABLE_ENTRY PartitionTableEntry
;
77 if (!DissectArcPath(Path
, FileName
, &DriveNumber
, &DrivePartition
))
80 if (DrivePartition
== 0xff)
82 /* This is a CD-ROM device */
87 /* This is either a floppy disk device (DrivePartition == 0) or
88 * a hard disk device (DrivePartition != 0 && DrivePartition != 0xFF) but
89 * it doesn't matter which one because they both have 512 bytes per sector */
93 if (DrivePartition
!= 0xff && DrivePartition
!= 0)
95 if (!DiskGetPartitionEntry(DriveNumber
, DrivePartition
, &PartitionTableEntry
))
97 SectorOffset
= PartitionTableEntry
.SectorCountBeforePartition
;
98 SectorCount
= PartitionTableEntry
.PartitionSectorCount
;
101 Context
= FrLdrTempAlloc(sizeof(DISKCONTEXT
), TAG_HW_DISK_CONTEXT
);
104 Context
->DriveNumber
= DriveNumber
;
105 Context
->SectorSize
= SectorSize
;
106 Context
->SectorOffset
= SectorOffset
;
107 Context
->SectorCount
= SectorCount
;
108 Context
->SectorNumber
= 0;
109 FsSetDeviceSpecific(*FileId
, Context
);
114 static ARC_STATUS
DiskRead(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
116 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
117 UCHAR
* Ptr
= (UCHAR
*)Buffer
;
118 ULONG Length
, TotalSectors
, MaxSectors
, ReadSectors
;
120 ULONGLONG SectorOffset
;
122 TotalSectors
= (N
+ Context
->SectorSize
- 1) / Context
->SectorSize
;
123 MaxSectors
= DiskReadBufferSize
/ Context
->SectorSize
;
124 SectorOffset
= Context
->SectorNumber
+ Context
->SectorOffset
;
130 ReadSectors
= TotalSectors
;
131 if (ReadSectors
> MaxSectors
)
132 ReadSectors
= MaxSectors
;
134 ret
= MachDiskReadLogicalSectors(
135 Context
->DriveNumber
,
142 Length
= ReadSectors
* Context
->SectorSize
;
146 RtlCopyMemory(Ptr
, DiskReadBuffer
, Length
);
150 SectorOffset
+= ReadSectors
;
151 TotalSectors
-= ReadSectors
;
154 *Count
= (ULONG
)(Ptr
- (UCHAR
*)Buffer
);
156 return (!ret
) ? EIO
: ESUCCESS
;
159 static ARC_STATUS
DiskSeek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
161 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
163 if (SeekMode
!= SeekAbsolute
)
165 if (Position
->LowPart
& (Context
->SectorSize
- 1))
168 Context
->SectorNumber
= (ULONG
)(Position
->QuadPart
/ Context
->SectorSize
);
172 static const DEVVTBL DiskVtbl
= {
174 DiskGetFileInformation
,
181 GetHarddiskIdentifier(
184 return PcDiskIdentifier
[DriveNumber
- 0x80];
188 GetHarddiskInformation(
191 PMASTER_BOOT_RECORD Mbr
;
196 CHAR ArcName
[MAX_PATH
];
197 PARTITION_TABLE_ENTRY PartitionTableEntry
;
198 PCHAR Identifier
= PcDiskIdentifier
[DriveNumber
- 0x80];
201 if (!MachDiskReadLogicalSectors(DriveNumber
, 0ULL, 1, DiskReadBuffer
))
203 ERR("Reading MBR failed\n");
207 Buffer
= (ULONG
*)DiskReadBuffer
;
208 Mbr
= (PMASTER_BOOT_RECORD
)DiskReadBuffer
;
210 Signature
= Mbr
->Signature
;
211 TRACE("Signature: %x\n", Signature
);
213 /* Calculate the MBR checksum */
215 for (i
= 0; i
< 512 / sizeof(ULONG
); i
++)
217 Checksum
+= Buffer
[i
];
219 Checksum
= ~Checksum
+ 1;
220 TRACE("Checksum: %x\n", Checksum
);
222 /* Fill out the ARC disk block */
223 reactos_arc_disk_info
[reactos_disk_count
].DiskSignature
.Signature
= Signature
;
224 reactos_arc_disk_info
[reactos_disk_count
].DiskSignature
.CheckSum
= Checksum
;
225 sprintf(ArcName
, "multi(0)disk(0)rdisk(%lu)", reactos_disk_count
);
226 strcpy(reactos_arc_disk_info
[reactos_disk_count
].ArcName
, ArcName
);
227 reactos_arc_disk_info
[reactos_disk_count
].DiskSignature
.ArcName
=
228 reactos_arc_disk_info
[reactos_disk_count
].ArcName
;
229 reactos_disk_count
++;
231 sprintf(ArcName
, "multi(0)disk(0)rdisk(%u)partition(0)", DriveNumber
- 0x80);
232 FsRegisterDevice(ArcName
, &DiskVtbl
);
236 DiskReportError(FALSE
);
237 while (DiskGetPartitionEntry(DriveNumber
, i
, &PartitionTableEntry
))
239 if (PartitionTableEntry
.SystemIndicator
!= PARTITION_ENTRY_UNUSED
)
241 sprintf(ArcName
, "multi(0)disk(0)rdisk(%u)partition(%lu)", DriveNumber
- 0x80, i
);
242 FsRegisterDevice(ArcName
, &DiskVtbl
);
246 DiskReportError(TRUE
);
248 /* Convert checksum and signature to identifier string */
249 Identifier
[0] = Hex
[(Checksum
>> 28) & 0x0F];
250 Identifier
[1] = Hex
[(Checksum
>> 24) & 0x0F];
251 Identifier
[2] = Hex
[(Checksum
>> 20) & 0x0F];
252 Identifier
[3] = Hex
[(Checksum
>> 16) & 0x0F];
253 Identifier
[4] = Hex
[(Checksum
>> 12) & 0x0F];
254 Identifier
[5] = Hex
[(Checksum
>> 8) & 0x0F];
255 Identifier
[6] = Hex
[(Checksum
>> 4) & 0x0F];
256 Identifier
[7] = Hex
[Checksum
& 0x0F];
258 Identifier
[9] = Hex
[(Signature
>> 28) & 0x0F];
259 Identifier
[10] = Hex
[(Signature
>> 24) & 0x0F];
260 Identifier
[11] = Hex
[(Signature
>> 20) & 0x0F];
261 Identifier
[12] = Hex
[(Signature
>> 16) & 0x0F];
262 Identifier
[13] = Hex
[(Signature
>> 12) & 0x0F];
263 Identifier
[14] = Hex
[(Signature
>> 8) & 0x0F];
264 Identifier
[15] = Hex
[(Signature
>> 4) & 0x0F];
265 Identifier
[16] = Hex
[Signature
& 0x0F];
266 Identifier
[17] = '-';
267 Identifier
[18] = 'A';
269 TRACE("Identifier: %s\n", Identifier
);
274 HwInitializeBiosDisks(VOID
)
276 UCHAR DiskCount
, DriveNumber
;
279 BOOLEAN BootDriveReported
= FALSE
;
280 CHAR BootPath
[MAX_PATH
];
282 /* Count the number of visible drives */
283 DiskReportError(FALSE
);
288 * There are some really broken BIOSes out there. There are even BIOSes
289 * that happily report success when you ask them to read from non-existent
290 * harddisks. So, we set the buffer to known contents first, then try to
291 * read. If the BIOS reports success but the buffer contents haven't
292 * changed then we fail anyway.
294 memset(DiskReadBuffer
, 0xcd, DiskReadBufferSize
);
295 while (MachDiskReadLogicalSectors(DriveNumber
, 0ULL, 1, DiskReadBuffer
))
298 for (i
= 0; !Changed
&& i
< DiskReadBufferSize
; i
++)
300 Changed
= ((PUCHAR
)DiskReadBuffer
)[i
] != 0xcd;
304 TRACE("BIOS reports success for disk %d but data didn't change\n",
309 GetHarddiskInformation(DriveNumber
);
311 /* Check if we have seen the boot drive */
312 if (FrldrBootDrive
== DriveNumber
)
313 BootDriveReported
= TRUE
;
317 memset(DiskReadBuffer
, 0xcd, 512);
319 DiskReportError(TRUE
);
321 /* Get the drive we're booting from */
322 MachDiskGetBootPath(BootPath
, sizeof(BootPath
));
324 /* Add it, if it's a floppy or cdrom */
325 if ((FrldrBootDrive
>= 0x80 && !BootDriveReported
) ||
326 DiskIsDriveRemovable(FrldrBootDrive
))
328 /* TODO: Check if it's really a CDROM drive */
330 PMASTER_BOOT_RECORD Mbr
;
336 if (!MachDiskReadLogicalSectors(FrldrBootDrive
, 16ULL, 1, DiskReadBuffer
))
338 ERR("Reading MBR failed\n");
342 Buffer
= (ULONG
*)DiskReadBuffer
;
343 Mbr
= (PMASTER_BOOT_RECORD
)DiskReadBuffer
;
345 Signature
= Mbr
->Signature
;
346 TRACE("Signature: %x\n", Signature
);
348 /* Calculate the MBR checksum */
349 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) Checksum
+= Buffer
[i
];
350 Checksum
= ~Checksum
+ 1;
351 TRACE("Checksum: %x\n", Checksum
);
353 /* Fill out the ARC disk block */
354 reactos_arc_disk_info
[reactos_disk_count
].DiskSignature
.Signature
= Signature
;
355 reactos_arc_disk_info
[reactos_disk_count
].DiskSignature
.CheckSum
= Checksum
;
356 strcpy(reactos_arc_disk_info
[reactos_disk_count
].ArcName
, BootPath
);
357 reactos_arc_disk_info
[reactos_disk_count
].DiskSignature
.ArcName
=
358 reactos_arc_disk_info
[reactos_disk_count
].ArcName
;
359 reactos_disk_count
++;
361 FsRegisterDevice(BootPath
, &DiskVtbl
);
365 PcBiosDiskCount
= DiskCount
;
366 TRACE("BIOS reports %d harddisk%s\n",
367 (int)DiskCount
, (DiskCount
== 1) ? "": "s");
369 return DiskCount
!= 0;