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 reactos_arc_disk_info
[];
40 extern CHAR reactos_arc_strings
[32][256];
42 static CHAR Hex
[] = "0123456789abcdef";
43 UCHAR PcBiosDiskCount
= 0;
44 CHAR PcDiskIdentifier
[32][20];
47 static LONG
DiskClose(ULONG FileId
)
49 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
55 static LONG
DiskGetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
57 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
59 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
60 Information
->EndingAddress
.QuadPart
= (Context
->SectorOffset
+ Context
->SectorCount
) * Context
->SectorSize
;
61 Information
->CurrentAddress
.QuadPart
= (Context
->SectorOffset
+ Context
->SectorNumber
) * Context
->SectorSize
;
66 static LONG
DiskOpen(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
70 ULONG DrivePartition
, SectorSize
;
71 ULONGLONG SectorOffset
= 0;
72 ULONGLONG SectorCount
= 0;
73 PARTITION_TABLE_ENTRY PartitionTableEntry
;
76 if (!DissectArcPath(Path
, FileName
, &DriveNumber
, &DrivePartition
))
79 if (DrivePartition
== 0xff)
81 /* This is a CD-ROM device */
86 /* This is either a floppy disk device (DrivePartition == 0) or
87 * a hard disk device (DrivePartition != 0 && DrivePartition != 0xFF) but
88 * it doesn't matter which one because they both have 512 bytes per sector */
92 if (DrivePartition
!= 0xff && DrivePartition
!= 0)
94 if (!DiskGetPartitionEntry(DriveNumber
, DrivePartition
, &PartitionTableEntry
))
96 SectorOffset
= PartitionTableEntry
.SectorCountBeforePartition
;
97 SectorCount
= PartitionTableEntry
.PartitionSectorCount
;
100 Context
= MmHeapAlloc(sizeof(DISKCONTEXT
));
103 Context
->DriveNumber
= DriveNumber
;
104 Context
->SectorSize
= SectorSize
;
105 Context
->SectorOffset
= SectorOffset
;
106 Context
->SectorCount
= SectorCount
;
107 Context
->SectorNumber
= 0;
108 FsSetDeviceSpecific(*FileId
, Context
);
113 static LONG
DiskRead(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
115 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
116 UCHAR
* Ptr
= (UCHAR
*)Buffer
;
117 ULONG Length
, TotalSectors
, MaxSectors
, ReadSectors
;
119 ULONGLONG SectorOffset
;
121 TotalSectors
= (N
+ Context
->SectorSize
- 1) / Context
->SectorSize
;
122 MaxSectors
= DISKREADBUFFER_SIZE
/ Context
->SectorSize
;
123 SectorOffset
= Context
->SectorNumber
+ Context
->SectorOffset
;
129 ReadSectors
= TotalSectors
;
130 if (ReadSectors
> MaxSectors
)
131 ReadSectors
= MaxSectors
;
133 ret
= MachDiskReadLogicalSectors(
134 Context
->DriveNumber
,
137 (PVOID
)DISKREADBUFFER
);
141 Length
= ReadSectors
* Context
->SectorSize
;
145 RtlCopyMemory(Ptr
, (PVOID
)DISKREADBUFFER
, Length
);
149 SectorOffset
+= ReadSectors
;
150 TotalSectors
-= ReadSectors
;
153 *Count
= (ULONG
)(Ptr
- (UCHAR
*)Buffer
);
155 return (!ret
) ? EIO
: ESUCCESS
;
158 static LONG
DiskSeek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
160 DISKCONTEXT
* Context
= FsGetDeviceSpecific(FileId
);
162 if (SeekMode
!= SeekAbsolute
)
164 if (Position
->LowPart
& (Context
->SectorSize
- 1))
167 Context
->SectorNumber
= (ULONG
)(Position
->QuadPart
/ Context
->SectorSize
);
171 static const DEVVTBL DiskVtbl
= {
173 DiskGetFileInformation
,
180 GetHarddiskIdentifier(
183 return PcDiskIdentifier
[DriveNumber
- 0x80];
187 GetHarddiskInformation(
190 PMASTER_BOOT_RECORD Mbr
;
196 PARTITION_TABLE_ENTRY PartitionTableEntry
;
197 PCHAR Identifier
= PcDiskIdentifier
[DriveNumber
- 0x80];
200 if (!MachDiskReadLogicalSectors(DriveNumber
, 0ULL, 1, (PVOID
)DISKREADBUFFER
))
202 ERR("Reading MBR failed\n");
206 Buffer
= (ULONG
*)DISKREADBUFFER
;
207 Mbr
= (PMASTER_BOOT_RECORD
)DISKREADBUFFER
;
209 Signature
= Mbr
->Signature
;
210 TRACE("Signature: %x\n", Signature
);
212 /* Calculate the MBR checksum */
214 for (i
= 0; i
< 128; i
++)
216 Checksum
+= Buffer
[i
];
218 Checksum
= ~Checksum
+ 1;
219 TRACE("Checksum: %x\n", Checksum
);
221 /* Fill out the ARC disk block */
222 reactos_arc_disk_info
[reactos_disk_count
].Signature
= Signature
;
223 reactos_arc_disk_info
[reactos_disk_count
].CheckSum
= Checksum
;
224 sprintf(ArcName
, "multi(0)disk(0)rdisk(%lu)", reactos_disk_count
);
225 strcpy(reactos_arc_strings
[reactos_disk_count
], ArcName
);
226 reactos_arc_disk_info
[reactos_disk_count
].ArcName
=
227 reactos_arc_strings
[reactos_disk_count
];
228 reactos_disk_count
++;
230 sprintf(ArcName
, "multi(0)disk(0)rdisk(%u)partition(0)", DriveNumber
- 0x80);
231 FsRegisterDevice(ArcName
, &DiskVtbl
);
235 DiskReportError(FALSE
);
236 while (DiskGetPartitionEntry(DriveNumber
, i
, &PartitionTableEntry
))
238 if (PartitionTableEntry
.SystemIndicator
!= PARTITION_ENTRY_UNUSED
)
240 sprintf(ArcName
, "multi(0)disk(0)rdisk(%u)partition(%lu)", DriveNumber
- 0x80, i
);
241 FsRegisterDevice(ArcName
, &DiskVtbl
);
245 DiskReportError(TRUE
);
247 /* Convert checksum and signature to identifier string */
248 Identifier
[0] = Hex
[(Checksum
>> 28) & 0x0F];
249 Identifier
[1] = Hex
[(Checksum
>> 24) & 0x0F];
250 Identifier
[2] = Hex
[(Checksum
>> 20) & 0x0F];
251 Identifier
[3] = Hex
[(Checksum
>> 16) & 0x0F];
252 Identifier
[4] = Hex
[(Checksum
>> 12) & 0x0F];
253 Identifier
[5] = Hex
[(Checksum
>> 8) & 0x0F];
254 Identifier
[6] = Hex
[(Checksum
>> 4) & 0x0F];
255 Identifier
[7] = Hex
[Checksum
& 0x0F];
257 Identifier
[9] = Hex
[(Signature
>> 28) & 0x0F];
258 Identifier
[10] = Hex
[(Signature
>> 24) & 0x0F];
259 Identifier
[11] = Hex
[(Signature
>> 20) & 0x0F];
260 Identifier
[12] = Hex
[(Signature
>> 16) & 0x0F];
261 Identifier
[13] = Hex
[(Signature
>> 12) & 0x0F];
262 Identifier
[14] = Hex
[(Signature
>> 8) & 0x0F];
263 Identifier
[15] = Hex
[(Signature
>> 4) & 0x0F];
264 Identifier
[16] = Hex
[Signature
& 0x0F];
265 Identifier
[17] = '-';
266 Identifier
[18] = 'A';
268 TRACE("Identifier: %s\n", Identifier
);
273 HwInitializeBiosDisks(VOID
)
275 UCHAR DiskCount
, DriveNumber
;
279 BOOLEAN BootDriveReported
= FALSE
;
281 /* Count the number of visible drives */
282 DiskReportError(FALSE
);
286 /* There are some really broken BIOSes out there. There are even BIOSes
287 * that happily report success when you ask them to read from non-existent
288 * harddisks. So, we set the buffer to known contents first, then try to
289 * read. If the BIOS reports success but the buffer contents haven't
290 * changed then we fail anyway */
291 memset((PVOID
) DISKREADBUFFER
, 0xcd, 512);
292 while (MachDiskReadLogicalSectors(DriveNumber
, 0ULL, 1, (PVOID
)DISKREADBUFFER
))
295 for (i
= 0; ! Changed
&& i
< 512; i
++)
297 Changed
= ((PUCHAR
)DISKREADBUFFER
)[i
] != 0xcd;
301 TRACE("BIOS reports success for disk %d but data didn't change\n",
306 GetHarddiskInformation(DriveNumber
);
308 if (FrldrBootDrive
== DriveNumber
)
309 BootDriveReported
= TRUE
;
313 memset((PVOID
) DISKREADBUFFER
, 0xcd, 512);
315 DiskReportError(TRUE
);
317 /* Get the drive we're booting from */
318 MachDiskGetBootPath(BootPath
, sizeof(BootPath
));
320 /* Add it, if it's a floppy or cdrom */
321 if ((FrldrBootDrive
>= 0x80 && !BootDriveReported
) ||
322 DiskIsDriveRemovable(FrldrBootDrive
))
324 /* TODO: Check if it's really a cdrom drive */
329 if (!MachDiskReadLogicalSectors(FrldrBootDrive
, 16ULL, 1, (PVOID
)DISKREADBUFFER
))
331 ERR("Reading MBR failed\n");
335 Buffer
= (ULONG
*)DISKREADBUFFER
;
337 /* Calculate the MBR checksum */
338 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) Checksum
+= Buffer
[i
];
339 Checksum
= ~Checksum
+ 1;
340 TRACE("Checksum: %x\n", Checksum
);
342 /* Fill out the ARC disk block */
343 reactos_arc_disk_info
[reactos_disk_count
].CheckSum
= Checksum
;
344 strcpy(reactos_arc_strings
[reactos_disk_count
], BootPath
);
345 reactos_arc_disk_info
[reactos_disk_count
].ArcName
=
346 reactos_arc_strings
[reactos_disk_count
];
347 reactos_disk_count
++;
349 FsRegisterDevice(BootPath
, &DiskVtbl
);
353 PcBiosDiskCount
= DiskCount
;
354 TRACE("BIOS reports %d harddisk%s\n",
355 (int)DiskCount
, (DiskCount
== 1) ? "": "s");
357 return DiskCount
!= 0;