Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhwdisk.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
1.7.6.1
|