ReactOS  0.4.13-dev-235-g7373cb3
hwdisk.c
Go to the documentation of this file.
1 /*
2  * FreeLoader
3  *
4  * Copyright (C) 2003, 2004 Eric Kohl
5  * Copyright (C) 2009 Hervé Poussineau
6  *
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.
11  *
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.
16  *
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.
20  */
21 
22 #include <freeldr.h>
23 
24 #include <debug.h>
25 
26 DBG_DEFAULT_CHANNEL(HWDETECT);
27 
28 /*
29  * This is the common code for harddisk for both the PC and the XBOX.
30  */
31 
32 typedef struct tagDISKCONTEXT
33 {
39 } DISKCONTEXT;
40 
41 static const CHAR Hex[] = "0123456789abcdef";
42 
43 /* Data cache for BIOS disks pre-enumeration */
45 static CHAR PcDiskIdentifier[32][20];
46 
49 
50 
51 /* FUNCTIONS *****************************************************************/
52 
53 static ARC_STATUS
55 {
57 
59  return ESUCCESS;
60 }
61 
62 static ARC_STATUS
64 {
66 
68  Information->EndingAddress.QuadPart = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
69  Information->CurrentAddress.QuadPart = (Context->SectorOffset + Context->SectorNumber) * Context->SectorSize;
70 
71  return ESUCCESS;
72 }
73 
74 static ARC_STATUS
75 DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
76 {
78  UCHAR DriveNumber;
79  ULONG DrivePartition, SectorSize;
82  PARTITION_TABLE_ENTRY PartitionTableEntry;
83  CHAR FileName[1];
84 
85  if (!DissectArcPath(Path, FileName, &DriveNumber, &DrivePartition))
86  return EINVAL;
87 
88  if (DrivePartition == 0xff)
89  {
90  /* This is a CD-ROM device */
91  SectorSize = 2048;
92  }
93  else
94  {
95  /*
96  * This is either a floppy disk device (DrivePartition == 0) or
97  * a hard disk device (DrivePartition != 0 && DrivePartition != 0xFF)
98  * but it doesn't matter which one because they both have 512 bytes
99  * per sector.
100  */
101  SectorSize = 512;
102  }
103 
104  if (DrivePartition != 0xff && DrivePartition != 0)
105  {
106  if (!DiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
107  return EINVAL;
108 
109  SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
110  SectorCount = PartitionTableEntry.PartitionSectorCount;
111  }
112 #if 0 // FIXME: Investigate
113  else
114  {
115  SectorCount = 0; /* FIXME */
116  }
117 #endif
118 
120  if (!Context)
121  return ENOMEM;
122 
123  Context->DriveNumber = DriveNumber;
124  Context->SectorSize = SectorSize;
125  Context->SectorOffset = SectorOffset;
126  Context->SectorCount = SectorCount;
127  Context->SectorNumber = 0;
128  FsSetDeviceSpecific(*FileId, Context);
129 
130  return ESUCCESS;
131 }
132 
133 static ARC_STATUS
135 {
137  UCHAR* Ptr = (UCHAR*)Buffer;
138  ULONG Length, TotalSectors, MaxSectors, ReadSectors;
139  BOOLEAN ret;
141 
142  TotalSectors = (N + Context->SectorSize - 1) / Context->SectorSize;
143  MaxSectors = DiskReadBufferSize / Context->SectorSize;
144  SectorOffset = Context->SectorNumber + Context->SectorOffset;
145 
146  ret = TRUE;
147 
148  while (TotalSectors)
149  {
150  ReadSectors = TotalSectors;
151  if (ReadSectors > MaxSectors)
152  ReadSectors = MaxSectors;
153 
154  ret = MachDiskReadLogicalSectors(Context->DriveNumber,
155  SectorOffset,
156  ReadSectors,
158  if (!ret)
159  break;
160 
161  Length = ReadSectors * Context->SectorSize;
162  if (Length > N)
163  Length = N;
164 
166 
167  Ptr += Length;
168  N -= Length;
169  SectorOffset += ReadSectors;
170  TotalSectors -= ReadSectors;
171  }
172 
173  *Count = (ULONG)(Ptr - (UCHAR*)Buffer);
174 
175  return (!ret) ? EIO : ESUCCESS;
176 }
177 
178 static ARC_STATUS
180 {
182 
183  if (SeekMode != SeekAbsolute)
184  return EINVAL;
185  if (Position->LowPart & (Context->SectorSize - 1))
186  return EINVAL;
187 
188  Context->SectorNumber = Position->QuadPart / Context->SectorSize;
189  return ESUCCESS;
190 }
191 
192 static const DEVVTBL DiskVtbl =
193 {
194  DiskClose,
196  DiskOpen,
197  DiskRead,
198  DiskSeek,
199 };
200 
201 
202 PCHAR
204 {
205  return PcDiskIdentifier[DriveNumber - 0x80];
206 }
207 
208 static VOID
210 {
212  PULONG Buffer;
213  ULONG i;
214  ULONG Checksum;
216  BOOLEAN ValidPartitionTable;
217  CHAR ArcName[MAX_PATH];
218  PARTITION_TABLE_ENTRY PartitionTableEntry;
219  PCHAR Identifier = PcDiskIdentifier[DriveNumber - 0x80];
220 
221  /* Read the MBR */
222  if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, DiskReadBuffer))
223  {
224  ERR("Reading MBR failed\n");
225  /* We failed, use a default identifier */
226  sprintf(Identifier, "BIOSDISK%d", DriveNumber - 0x80 + 1);
227  return;
228  }
229 
232 
233  Signature = Mbr->Signature;
234  TRACE("Signature: %x\n", Signature);
235 
236  /* Calculate the MBR checksum */
237  Checksum = 0;
238  for (i = 0; i < 512 / sizeof(ULONG); i++)
239  {
240  Checksum += Buffer[i];
241  }
242  Checksum = ~Checksum + 1;
243  TRACE("Checksum: %x\n", Checksum);
244 
245  ValidPartitionTable = (Mbr->MasterBootRecordMagic == 0xAA55);
246 
247  /* Fill out the ARC disk block */
248  sprintf(ArcName, "multi(0)disk(0)rdisk(%u)", DriveNumber - 0x80);
249  AddReactOSArcDiskInfo(ArcName, Signature, Checksum, ValidPartitionTable);
250 
251  sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(0)", DriveNumber - 0x80);
252  FsRegisterDevice(ArcName, &DiskVtbl);
253 
254  /* Add partitions */
255  i = 1;
257  while (DiskGetPartitionEntry(DriveNumber, i, &PartitionTableEntry))
258  {
259  if (PartitionTableEntry.SystemIndicator != PARTITION_ENTRY_UNUSED)
260  {
261  sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(%lu)", DriveNumber - 0x80, i);
262  FsRegisterDevice(ArcName, &DiskVtbl);
263  }
264  i++;
265  }
267 
268  /* Convert checksum and signature to identifier string */
269  Identifier[0] = Hex[(Checksum >> 28) & 0x0F];
270  Identifier[1] = Hex[(Checksum >> 24) & 0x0F];
271  Identifier[2] = Hex[(Checksum >> 20) & 0x0F];
272  Identifier[3] = Hex[(Checksum >> 16) & 0x0F];
273  Identifier[4] = Hex[(Checksum >> 12) & 0x0F];
274  Identifier[5] = Hex[(Checksum >> 8) & 0x0F];
275  Identifier[6] = Hex[(Checksum >> 4) & 0x0F];
276  Identifier[7] = Hex[Checksum & 0x0F];
277  Identifier[8] = '-';
278  Identifier[9] = Hex[(Signature >> 28) & 0x0F];
279  Identifier[10] = Hex[(Signature >> 24) & 0x0F];
280  Identifier[11] = Hex[(Signature >> 20) & 0x0F];
281  Identifier[12] = Hex[(Signature >> 16) & 0x0F];
282  Identifier[13] = Hex[(Signature >> 12) & 0x0F];
283  Identifier[14] = Hex[(Signature >> 8) & 0x0F];
284  Identifier[15] = Hex[(Signature >> 4) & 0x0F];
285  Identifier[16] = Hex[Signature & 0x0F];
286  Identifier[17] = '-';
287  Identifier[18] = (ValidPartitionTable ? 'A' : 'X');
288  Identifier[19] = 0;
289  TRACE("Identifier: %s\n", Identifier);
290 }
291 
292 static UCHAR
293 EnumerateHarddisks(OUT PBOOLEAN BootDriveReported)
294 {
295  UCHAR DiskCount, DriveNumber;
296  ULONG i;
297  BOOLEAN Changed;
298 
299  *BootDriveReported = FALSE;
300 
301  /* Count the number of visible harddisk drives */
303  DiskCount = 0;
304  DriveNumber = 0x80;
305 
306  /*
307  * There are some really broken BIOSes out there. There are even BIOSes
308  * that happily report success when you ask them to read from non-existent
309  * harddisks. So, we set the buffer to known contents first, then try to
310  * read. If the BIOS reports success but the buffer contents haven't
311  * changed then we fail anyway.
312  */
314  while (MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, DiskReadBuffer))
315  {
316  Changed = FALSE;
317  for (i = 0; !Changed && i < DiskReadBufferSize; i++)
318  {
319  Changed = ((PUCHAR)DiskReadBuffer)[i] != 0xcd;
320  }
321  if (!Changed)
322  {
323  TRACE("BIOS reports success for disk %d (0x%02X) but data didn't change\n",
324  (int)DiskCount, DriveNumber);
325  break;
326  }
327 
328  /* Cache the BIOS hard disk information for later use */
329  GetHarddiskInformation(DriveNumber);
330 
331  /* Check if we have seen the boot drive */
332  if (FrldrBootDrive == DriveNumber)
333  *BootDriveReported = TRUE;
334 
335  DiskCount++;
336  DriveNumber++;
338  }
340 
341  PcBiosDiskCount = DiskCount;
342  TRACE("BIOS reports %d harddisk%s\n",
343  (int)DiskCount, (DiskCount == 1) ? "" : "s");
344 
345  return DiskCount;
346 }
347 
348 BOOLEAN
350 {
351  UCHAR DiskCount;
352  BOOLEAN BootDriveReported = FALSE;
353  ULONG i;
355 
356  DiskCount = EnumerateHarddisks(&BootDriveReported);
357 
358  /* Get the drive we're booting from */
360 
361  /* Add it, if it's a floppy or cdrom */
362  if ((FrldrBootDrive >= 0x80 && !BootDriveReported) ||
364  {
365  /* TODO: Check if it's really a CDROM drive */
366 
368  PULONG Buffer;
369  ULONG Checksum = 0;
371 
372  /* Read the MBR */
374  {
375  ERR("Reading MBR failed\n");
376  return FALSE;
377  }
378 
381 
382  Signature = Mbr->Signature;
383  TRACE("Signature: %x\n", Signature);
384 
385  /* Calculate the MBR checksum */
386  for (i = 0; i < 2048 / sizeof(ULONG); i++)
387  {
388  Checksum += Buffer[i];
389  }
390  Checksum = ~Checksum + 1;
391  TRACE("Checksum: %x\n", Checksum);
392 
393  /* Fill out the ARC disk block */
395 
397  DiskCount++; // This is not accounted for in the number of pre-enumerated BIOS drives!
398  TRACE("Additional boot drive detected: 0x%02X\n", (int)FrldrBootDrive);
399  }
400 
401  return (DiskCount != 0);
402 }
signed char * PCHAR
Definition: retypes.h:7
ULONG Signature
Definition: disk.h:75
#define MachDiskReadLogicalSectors(Drive, Start, Count, Buf)
Definition: machine.h:120
static ARC_STATUS DiskSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: hwdisk.c:179
USHORT MasterBootRecordMagic
Definition: disk.h:78
DISK_GET_PARTITION_ENTRY DiskGetPartitionEntry
Definition: partition.c:33
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
BOOLEAN DissectArcPath(CHAR *ArcPath, CHAR *BootPath, UCHAR *BootDrive, ULONG *BootPartition)
Definition: arcname.c:24
static ARC_STATUS DiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: hwdisk.c:75
VOID DiskReportError(BOOLEAN bError)
Definition: disk.c:33
Definition: arc.h:32
ULONG PartitionSectorCount
Definition: parttest.c:85
Definition: arc.h:39
static COORD Position
Definition: mouse.c:34
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
Definition: fs.h:22
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
ULONG ARC_STATUS
Definition: arc.h:4
ULONG SectorCountBeforePartition
Definition: parttest.c:84
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:474
Definition: arc.h:48
static VOID GetHarddiskInformation(UCHAR DriveNumber)
Definition: hwdisk.c:209
static const CHAR Hex[]
Definition: hwdisk.c:41
UCHAR SystemIndicator
Definition: parttest.c:80
#define PARTITION_ENTRY_UNUSED
Definition: disk.h:86
#define sprintf(buf, format,...)
Definition: sprintf.c:55
PCHAR GetHarddiskIdentifier(UCHAR DriveNumber)
Definition: hwdisk.c:203
while(1)
Definition: macro.lex.yy.c:740
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOLEAN PcInitializeBootDevices(VOID)
Definition: hwdisk.c:349
Definition: bidi.c:97
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:177
UCHAR DriveNumber
Definition: hwdisk.c:34
#define SectorOffset(L)
Definition: cdprocs.h:1632
unsigned char BOOLEAN
enum _SEEKMODE SEEKMODE
Definition: bufpool.h:45
#define ULL(a, b)
Definition: format_msg.c:27
static ARC_STATUS DiskGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: hwdisk.c:63
ULONG SectorSize
Definition: hwdisk.c:35
BOOLEAN DiskIsDriveRemovable(UCHAR DriveNumber)
Definition: disk.c:88
#define TRACE(s)
Definition: solgame.cpp:4
static ARC_STATUS DiskClose(ULONG FileId)
Definition: hwdisk.c:54
struct tagDISKCONTEXT DISKCONTEXT
uint64_t ULONGLONG
Definition: typedefs.h:65
#define MAX_PATH
Definition: compat.h:26
ULONGLONG SectorOffset
Definition: hwdisk.c:36
Definition: parttest.c:75
VOID FsSetDeviceSpecific(ULONG FileId, VOID *Specific)
Definition: fs.c:467
static CHAR PcDiskIdentifier[32][20]
Definition: hwdisk.c:45
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
SIZE_T DiskReadBufferSize
Definition: hwdisk.c:48
unsigned char UCHAR
Definition: xmlstorage.h:181
int ret
char * PBOOLEAN
Definition: retypes.h:11
ULONGLONG SectorNumber
Definition: hwdisk.c:38
VOID FsRegisterDevice(CHAR *Prefix, const DEVVTBL *FuncTable)
Definition: fs.c:441
ULONGLONG SectorCount
Definition: hwdisk.c:37
PVOID DiskReadBuffer
Definition: hwdisk.c:47
VOID AddReactOSArcDiskInfo(IN PSTR ArcName, IN ULONG Signature, IN ULONG Checksum, IN BOOLEAN ValidPartitionTable)
Definition: archwsup.c:29
static ARC_STATUS DiskRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: hwdisk.c:134
ULONG SectorCount
Definition: part_xbox.c:32
#define ERR(fmt,...)
Definition: debug.h:109
ULONG_PTR SIZE_T
Definition: typedefs.h:78
UCHAR PcBiosDiskCount
Definition: hwdisk.c:44
PRTL_UNICODE_STRING_BUFFER Path
DBG_DEFAULT_CHANNEL(HWDETECT)
#define MachDiskGetBootPath(Path, Size)
Definition: machine.h:118
unsigned int * PULONG
Definition: retypes.h:1
UCHAR FrldrBootDrive
Definition: arc.h:40
#define TAG_HW_DISK_CONTEXT
Definition: hardware.h:27
struct _MASTER_BOOT_RECORD * PMASTER_BOOT_RECORD
#define OUT
Definition: typedefs.h:39
struct tagContext Context
Definition: acpixf.h:1012
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
_In_ ULONG SectorSize
Definition: halfuncs.h:291
static UCHAR EnumerateHarddisks(OUT PBOOLEAN BootDriveReported)
Definition: hwdisk.c:293
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
static const WCHAR Signature[]
Definition: parser.c:141
enum _OPENMODE OPENMODE
static const DEVVTBL DiskVtbl
Definition: hwdisk.c:192
#define memset(x, y, z)
Definition: compat.h:39
Iosb Information
Definition: create.c:4377
char BootPath[0x100]
Definition: mach.c:35
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:186