ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

hwdisk.c
Go to the documentation of this file.
00001 /*
00002  *  FreeLoader
00003  *
00004  *  Copyright (C) 2003, 2004  Eric Kohl
00005  *  Copyright (C) 2009  Hervé Poussineau
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License along
00018  *  with this program; if not, write to the Free Software Foundation, Inc.,
00019  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  */
00021 
00022 #include <freeldr.h>
00023 
00024 #define NDEBUG
00025 #include <debug.h>
00026 
00027 DBG_DEFAULT_CHANNEL(HWDETECT);
00028 
00029 typedef struct tagDISKCONTEXT
00030 {
00031     UCHAR DriveNumber;
00032     ULONG SectorSize;
00033     ULONGLONG SectorOffset;
00034     ULONGLONG SectorCount;
00035     ULONGLONG SectorNumber;
00036 } DISKCONTEXT;
00037 
00038 extern ULONG reactos_disk_count;
00039 extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
00040 extern char reactos_arc_strings[32][256];
00041 
00042 static CHAR Hex[] = "0123456789abcdef";
00043 UCHAR PcBiosDiskCount = 0;
00044 CHAR PcDiskIdentifier[32][20];
00045 
00046 
00047 static LONG DiskClose(ULONG FileId)
00048 {
00049     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
00050 
00051     MmHeapFree(Context);
00052     return ESUCCESS;
00053 }
00054 
00055 static LONG DiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
00056 {
00057     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
00058 
00059     RtlZeroMemory(Information, sizeof(FILEINFORMATION));
00060     Information->EndingAddress.QuadPart = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
00061     Information->CurrentAddress.QuadPart = (Context->SectorOffset + Context->SectorNumber) * Context->SectorSize;
00062 
00063     return ESUCCESS;
00064 }
00065 
00066 static LONG DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
00067 {
00068     DISKCONTEXT* Context;
00069     UCHAR DriveNumber;
00070     ULONG DrivePartition, SectorSize;
00071     ULONGLONG SectorOffset = 0;
00072     ULONGLONG SectorCount = 0;
00073     PARTITION_TABLE_ENTRY PartitionTableEntry;
00074     CHAR FileName[1];
00075 
00076     if (!DissectArcPath(Path, FileName, &DriveNumber, &DrivePartition))
00077         return EINVAL;
00078 
00079     if (DrivePartition == 0xff)
00080     {
00081         /* This is a CD-ROM device */
00082         SectorSize = 2048;
00083     }
00084     else
00085     {
00086         /* This is either a floppy disk device (DrivePartition == 0) or
00087          * a hard disk device (DrivePartition != 0 && DrivePartition != 0xFF) but
00088          * it doesn't matter which one because they both have 512 bytes per sector */
00089         SectorSize = 512;
00090     }
00091 
00092     if (DrivePartition != 0xff && DrivePartition != 0)
00093     {
00094         if (!DiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
00095             return EINVAL;
00096         SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
00097         SectorCount = PartitionTableEntry.PartitionSectorCount;
00098     }
00099 
00100     Context = MmHeapAlloc(sizeof(DISKCONTEXT));
00101     if (!Context)
00102         return ENOMEM;
00103     Context->DriveNumber = DriveNumber;
00104     Context->SectorSize = SectorSize;
00105     Context->SectorOffset = SectorOffset;
00106     Context->SectorCount = SectorCount;
00107     Context->SectorNumber = 0;
00108     FsSetDeviceSpecific(*FileId, Context);
00109 
00110     return ESUCCESS;
00111 }
00112 
00113 static LONG DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
00114 {
00115     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
00116     UCHAR* Ptr = (UCHAR*)Buffer;
00117     ULONG i, Length;
00118     BOOLEAN ret;
00119 
00120     *Count = 0;
00121     i = 0;
00122     while (N > 0)
00123     {
00124         Length = N;
00125         if (Length > Context->SectorSize)
00126             Length = Context->SectorSize;
00127         ret = MachDiskReadLogicalSectors(
00128             Context->DriveNumber,
00129             Context->SectorNumber + Context->SectorOffset + i,
00130             1,
00131             (PVOID)DISKREADBUFFER);
00132         if (!ret)
00133             return EIO;
00134         RtlCopyMemory(Ptr, (PVOID)DISKREADBUFFER, Length);
00135         Ptr += Length;
00136         *Count += Length;
00137         N -= Length;
00138         i++;
00139     }
00140 
00141     return ESUCCESS;
00142 }
00143 
00144 static LONG DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
00145 {
00146     DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
00147 
00148     if (SeekMode != SeekAbsolute)
00149         return EINVAL;
00150     if (Position->LowPart & (Context->SectorSize - 1))
00151         return EINVAL;
00152 
00153     /* FIXME: take HighPart into account */
00154     Context->SectorNumber = Position->LowPart / Context->SectorSize;
00155     return ESUCCESS;
00156 }
00157 
00158 static const DEVVTBL DiskVtbl = {
00159     DiskClose,
00160     DiskGetFileInformation,
00161     DiskOpen,
00162     DiskRead,
00163     DiskSeek,
00164 };
00165 
00166 PCHAR
00167 GetHarddiskIdentifier(
00168     UCHAR DriveNumber)
00169 {
00170     return PcDiskIdentifier[DriveNumber - 0x80];
00171 }
00172 
00173 VOID
00174 GetHarddiskInformation(
00175     UCHAR DriveNumber)
00176 {
00177     PMASTER_BOOT_RECORD Mbr;
00178     ULONG *Buffer;
00179     ULONG i;
00180     ULONG Checksum;
00181     ULONG Signature;
00182     CHAR ArcName[256];
00183     PARTITION_TABLE_ENTRY PartitionTableEntry;
00184     PCHAR Identifier = PcDiskIdentifier[DriveNumber - 0x80];
00185 
00186     /* Read the MBR */
00187     if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, (PVOID)DISKREADBUFFER))
00188     {
00189         ERR("Reading MBR failed\n");
00190         return;
00191     }
00192 
00193     Buffer = (ULONG*)DISKREADBUFFER;
00194     Mbr = (PMASTER_BOOT_RECORD)DISKREADBUFFER;
00195 
00196     Signature =  Mbr->Signature;
00197     TRACE("Signature: %x\n", Signature);
00198 
00199     /* Calculate the MBR checksum */
00200     Checksum = 0;
00201     for (i = 0; i < 128; i++)
00202     {
00203         Checksum += Buffer[i];
00204     }
00205     Checksum = ~Checksum + 1;
00206     TRACE("Checksum: %x\n", Checksum);
00207 
00208     /* Fill out the ARC disk block */
00209     reactos_arc_disk_info[reactos_disk_count].Signature = Signature;
00210     reactos_arc_disk_info[reactos_disk_count].CheckSum = Checksum;
00211     sprintf(ArcName, "multi(0)disk(0)rdisk(%lu)", reactos_disk_count);
00212     strcpy(reactos_arc_strings[reactos_disk_count], ArcName);
00213     reactos_arc_disk_info[reactos_disk_count].ArcName =
00214         reactos_arc_strings[reactos_disk_count];
00215     reactos_disk_count++;
00216 
00217     sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(0)", DriveNumber - 0x80);
00218     FsRegisterDevice(ArcName, &DiskVtbl);
00219 
00220     /* Add partitions */
00221     i = 1;
00222     DiskReportError(FALSE);
00223     while (DiskGetPartitionEntry(DriveNumber, i, &PartitionTableEntry))
00224     {
00225         if (PartitionTableEntry.SystemIndicator != PARTITION_ENTRY_UNUSED)
00226         {
00227             sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(%lu)", DriveNumber - 0x80, i);
00228             FsRegisterDevice(ArcName, &DiskVtbl);
00229         }
00230         i++;
00231     }
00232     DiskReportError(TRUE);
00233 
00234     /* Convert checksum and signature to identifier string */
00235     Identifier[0] = Hex[(Checksum >> 28) & 0x0F];
00236     Identifier[1] = Hex[(Checksum >> 24) & 0x0F];
00237     Identifier[2] = Hex[(Checksum >> 20) & 0x0F];
00238     Identifier[3] = Hex[(Checksum >> 16) & 0x0F];
00239     Identifier[4] = Hex[(Checksum >> 12) & 0x0F];
00240     Identifier[5] = Hex[(Checksum >> 8) & 0x0F];
00241     Identifier[6] = Hex[(Checksum >> 4) & 0x0F];
00242     Identifier[7] = Hex[Checksum & 0x0F];
00243     Identifier[8] = '-';
00244     Identifier[9] = Hex[(Signature >> 28) & 0x0F];
00245     Identifier[10] = Hex[(Signature >> 24) & 0x0F];
00246     Identifier[11] = Hex[(Signature >> 20) & 0x0F];
00247     Identifier[12] = Hex[(Signature >> 16) & 0x0F];
00248     Identifier[13] = Hex[(Signature >> 12) & 0x0F];
00249     Identifier[14] = Hex[(Signature >> 8) & 0x0F];
00250     Identifier[15] = Hex[(Signature >> 4) & 0x0F];
00251     Identifier[16] = Hex[Signature & 0x0F];
00252     Identifier[17] = '-';
00253     Identifier[18] = 'A';
00254     Identifier[19] = 0;
00255     TRACE("Identifier: %s\n", Identifier);
00256 }
00257 
00258 
00259 VOID
00260 HwInitializeBiosDisks(VOID)
00261 {
00262     UCHAR DiskCount, DriveNumber;
00263     ULONG i;
00264     BOOLEAN Changed;
00265     CHAR BootPath[512];
00266     BOOLEAN BootDriveReported = FALSE;
00267 
00268     /* Count the number of visible drives */
00269     DiskReportError(FALSE);
00270     DiskCount = 0;
00271     DriveNumber = 0x80;
00272 
00273     /* There are some really broken BIOSes out there. There are even BIOSes
00274         * that happily report success when you ask them to read from non-existent
00275         * harddisks. So, we set the buffer to known contents first, then try to
00276         * read. If the BIOS reports success but the buffer contents haven't
00277         * changed then we fail anyway */
00278     memset((PVOID) DISKREADBUFFER, 0xcd, 512);
00279     while (MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, (PVOID)DISKREADBUFFER))
00280     {
00281         Changed = FALSE;
00282         for (i = 0; ! Changed && i < 512; i++)
00283         {
00284             Changed = ((PUCHAR)DISKREADBUFFER)[i] != 0xcd;
00285         }
00286         if (! Changed)
00287         {
00288             TRACE("BIOS reports success for disk %d but data didn't change\n",
00289                       (int)DiskCount);
00290             break;
00291         }
00292 
00293         GetHarddiskInformation(DriveNumber);
00294 
00295         if (FrldrBootDrive == DriveNumber)
00296             BootDriveReported = TRUE;
00297 
00298         DiskCount++;
00299         DriveNumber++;
00300         memset((PVOID) DISKREADBUFFER, 0xcd, 512);
00301     }
00302     DiskReportError(TRUE);
00303     TRACE("BIOS reports %d harddisk%s\n",
00304           (int)DiskCount, (DiskCount == 1) ? "": "s");
00305 
00306     /* Get the drive we're booting from */
00307     MachDiskGetBootPath(BootPath, sizeof(BootPath));
00308 
00309     /* Add it, if it's a floppy or cdrom */
00310     if ((FrldrBootDrive >= 0x80 && !BootDriveReported) ||
00311         DiskIsDriveRemovable(FrldrBootDrive))
00312     {
00313         /* TODO: Check if it's really a cdrom drive */
00314         ULONG* Buffer;
00315         ULONG Checksum = 0;
00316 
00317         /* Read the MBR */
00318         if (!MachDiskReadLogicalSectors(FrldrBootDrive, 16ULL, 1, (PVOID)DISKREADBUFFER))
00319         {
00320           ERR("Reading MBR failed\n");
00321           return;
00322         }
00323 
00324         Buffer = (ULONG*)DISKREADBUFFER;
00325 
00326         /* Calculate the MBR checksum */
00327         for (i = 0; i < 2048 / sizeof(ULONG); i++) Checksum += Buffer[i];
00328         Checksum = ~Checksum + 1;
00329         TRACE("Checksum: %x\n", Checksum);
00330 
00331         /* Fill out the ARC disk block */
00332         reactos_arc_disk_info[reactos_disk_count].CheckSum = Checksum;
00333         strcpy(reactos_arc_strings[reactos_disk_count], BootPath);
00334         reactos_arc_disk_info[reactos_disk_count].ArcName =
00335             reactos_arc_strings[reactos_disk_count];
00336         reactos_disk_count++;
00337 
00338         FsRegisterDevice(BootPath, &DiskVtbl);
00339     }
00340 
00341     PcBiosDiskCount = DiskCount;
00342 }

Generated on Sun May 27 2012 04:19:08 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.