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

pcdisk.c
Go to the documentation of this file.
00001 /*
00002  *  FreeLoader
00003  *  Copyright (C) 1998-2003  Brian Palmer  <brianp@sginet.com>
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License along
00016  *  with this program; if not, write to the Free Software Foundation, Inc.,
00017  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018  */
00019 
00020 #include <freeldr.h>
00021 #include <debug.h>
00022 
00023 DBG_DEFAULT_CHANNEL(DISK);
00024 
00025 #include <pshpack2.h>
00026 typedef struct
00027 {
00028     UCHAR       PacketSize;             // 00h - Size of packet (10h or 18h)
00029     UCHAR       Reserved;               // 01h - Reserved (0)
00030     USHORT      LBABlockCount;          // 02h - Number of blocks to transfer (max 007Fh for Phoenix EDD)
00031     USHORT      TransferBufferOffset;   // 04h - Transfer buffer offset (seg:off)
00032     USHORT      TransferBufferSegment;  //       Transfer buffer segment (seg:off)
00033     ULONGLONG       LBAStartBlock;          // 08h - Starting absolute block number
00034     //ULONGLONG     TransferBuffer64;       // 10h - (EDD-3.0, optional) 64-bit flat address of transfer buffer
00035                                     //       used if DWORD at 04h is FFFFh:FFFFh
00036                                     //       Commented since some earlier BIOSes refuse to work with
00037                                     //       such extended structure
00038 } I386_DISK_ADDRESS_PACKET, *PI386_DISK_ADDRESS_PACKET;
00039 #include <poppack.h>
00040 
00042 // FUNCTIONS
00044 
00045 static BOOLEAN PcDiskResetController(UCHAR DriveNumber)
00046 {
00047     REGS    RegsIn;
00048     REGS    RegsOut;
00049 
00050     WARN("PcDiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber);
00051 
00052     // BIOS Int 13h, function 0 - Reset disk system
00053     // AH = 00h
00054     // DL = drive (if bit 7 is set both hard disks and floppy disks reset)
00055     // Return:
00056     // AH = status
00057     // CF clear if successful
00058     // CF set on error
00059     RegsIn.b.ah = 0x00;
00060     RegsIn.b.dl = DriveNumber;
00061 
00062     // Reset the disk controller
00063     Int386(0x13, &RegsIn, &RegsOut);
00064 
00065     return INT386_SUCCESS(RegsOut);
00066 }
00067 
00068 static BOOLEAN PcDiskReadLogicalSectorsLBA(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
00069 {
00070     REGS                        RegsIn;
00071     REGS                        RegsOut;
00072     ULONG                           RetryCount;
00073     PI386_DISK_ADDRESS_PACKET   Packet = (PI386_DISK_ADDRESS_PACKET)(BIOSCALLBUFFER);
00074 
00075     TRACE("PcDiskReadLogicalSectorsLBA() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n", DriveNumber, SectorNumber, SectorCount, Buffer);
00076     ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
00077 
00078     // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
00079     RegsIn.b.ah = 0x42;                 // Subfunction 42h
00080     RegsIn.b.dl = DriveNumber;          // Drive number in DL (0 - floppy, 0x80 - harddisk)
00081     RegsIn.x.ds = BIOSCALLBUFSEGMENT;   // DS:SI -> disk address packet
00082     RegsIn.w.si = BIOSCALLBUFOFFSET;
00083 
00084     // Setup disk address packet
00085     RtlZeroMemory(Packet, sizeof(I386_DISK_ADDRESS_PACKET));
00086     Packet->PacketSize = sizeof(I386_DISK_ADDRESS_PACKET);
00087     Packet->Reserved = 0;
00088     Packet->LBABlockCount = (USHORT)SectorCount;
00089     ASSERT(Packet->LBABlockCount == SectorCount);
00090     Packet->TransferBufferOffset = ((ULONG_PTR)Buffer) & 0x0F;
00091     Packet->TransferBufferSegment = (USHORT)(((ULONG_PTR)Buffer) >> 4);
00092     Packet->LBAStartBlock = SectorNumber;
00093 
00094     // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
00095     // Return:
00096     // CF clear if successful
00097     // AH = 00h
00098     // CF set on error
00099     // AH = error code
00100     // disk address packet's block count field set to the
00101     // number of blocks successfully transferred
00102 
00103     // Retry 3 times
00104     for (RetryCount=0; RetryCount<3; RetryCount++)
00105     {
00106         Int386(0x13, &RegsIn, &RegsOut);
00107 
00108         // If it worked return TRUE
00109         if (INT386_SUCCESS(RegsOut))
00110         {
00111             return TRUE;
00112         }
00113         // If it was a corrected ECC error then the data is still good
00114         else if (RegsOut.b.ah == 0x11)
00115         {
00116             return TRUE;
00117         }
00118         // If it failed the do the next retry
00119         else
00120         {
00121             PcDiskResetController(DriveNumber);
00122 
00123             continue;
00124         }
00125     }
00126 
00127     // If we get here then the read failed
00128     ERR("Disk Read Failed in LBA mode: %x (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n", RegsOut.b.ah, DriveNumber, SectorNumber, SectorCount);
00129 
00130     return FALSE;
00131 }
00132 
00133 static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
00134 {
00135     UCHAR           PhysicalSector;
00136     UCHAR           PhysicalHead;
00137     ULONG           PhysicalTrack;
00138     GEOMETRY    DriveGeometry;
00139     ULONG           NumberOfSectorsToRead;
00140     REGS        RegsIn;
00141     REGS        RegsOut;
00142     ULONG           RetryCount;
00143 
00144     TRACE("PcDiskReadLogicalSectorsCHS()\n");
00145 
00146     //
00147     // Get the drive geometry
00148     //
00149     if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry) ||
00150         DriveGeometry.Sectors == 0 ||
00151         DriveGeometry.Heads == 0)
00152     {
00153         return FALSE;
00154     }
00155 
00156     while (SectorCount)
00157     {
00158 
00159         //
00160         // Calculate the physical disk offsets
00161         // Note: DriveGeometry.Sectors < 64
00162         //
00163         PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.Sectors);
00164         PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
00165         PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);
00166 
00167         //
00168         // Calculate how many sectors we need to read this round
00169         //
00170         if (PhysicalSector > 1)
00171         {
00172             if (SectorCount >= (DriveGeometry.Sectors - (PhysicalSector - 1)))
00173                 NumberOfSectorsToRead = (DriveGeometry.Sectors - (PhysicalSector - 1));
00174             else
00175                 NumberOfSectorsToRead = SectorCount;
00176         }
00177         else
00178         {
00179             if (SectorCount >= DriveGeometry.Sectors)
00180                 NumberOfSectorsToRead = DriveGeometry.Sectors;
00181             else
00182                 NumberOfSectorsToRead = SectorCount;
00183         }
00184 
00185         //
00186         // Make sure the read is within the geometry boundaries
00187         //
00188         if ((PhysicalHead >= DriveGeometry.Heads) ||
00189             (PhysicalTrack >= DriveGeometry.Cylinders) ||
00190             ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
00191             (PhysicalSector > DriveGeometry.Sectors))
00192         {
00193             DiskError("Disk read exceeds drive geometry limits.", 0);
00194             return FALSE;
00195         }
00196 
00197         // BIOS Int 13h, function 2 - Read Disk Sectors
00198         // AH = 02h
00199         // AL = number of sectors to read (must be nonzero)
00200         // CH = low eight bits of cylinder number
00201         // CL = sector number 1-63 (bits 0-5)
00202         //      high two bits of cylinder (bits 6-7, hard disk only)
00203         // DH = head number
00204         // DL = drive number (bit 7 set for hard disk)
00205         // ES:BX -> data buffer
00206         // Return:
00207         // CF set on error
00208         // if AH = 11h (corrected ECC error), AL = burst length
00209         // CF clear if successful
00210         // AH = status
00211         // AL = number of sectors transferred
00212         //  (only valid if CF set for some BIOSes)
00213         RegsIn.b.ah = 0x02;
00214         RegsIn.b.al = (UCHAR)NumberOfSectorsToRead;
00215         RegsIn.b.ch = (PhysicalTrack & 0xFF);
00216         RegsIn.b.cl = (UCHAR)(PhysicalSector + ((PhysicalTrack & 0x300) >> 2));
00217         RegsIn.b.dh = PhysicalHead;
00218         RegsIn.b.dl = DriveNumber;
00219         RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
00220         RegsIn.w.bx = ((ULONG_PTR)Buffer) & 0x0F;
00221 
00222         //
00223         // Perform the read
00224         // Retry 3 times
00225         //
00226         for (RetryCount=0; RetryCount<3; RetryCount++)
00227         {
00228             Int386(0x13, &RegsIn, &RegsOut);
00229 
00230             // If it worked break out
00231             if (INT386_SUCCESS(RegsOut))
00232             {
00233                 break;
00234             }
00235             // If it was a corrected ECC error then the data is still good
00236             else if (RegsOut.b.ah == 0x11)
00237             {
00238                 break;
00239             }
00240             // If it failed the do the next retry
00241             else
00242             {
00243                 PcDiskResetController(DriveNumber);
00244 
00245                 continue;
00246             }
00247         }
00248 
00249         // If we retried 3 times then fail
00250         if (RetryCount >= 3)
00251         {
00252             ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x\n", RegsOut.b.ah);
00253             return FALSE;
00254         }
00255 
00256         // I have learned that not all bioses return
00257         // the sector read count in the AL register (at least mine doesn't)
00258         // even if the sectors were read correctly. So instead
00259         // of checking the sector read count we will rely solely
00260         // on the carry flag being set on error
00261 
00262         Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
00263         SectorCount -= NumberOfSectorsToRead;
00264         SectorNumber += NumberOfSectorsToRead;
00265     }
00266 
00267     return TRUE;
00268 }
00269 
00270 BOOLEAN PcDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
00271 {
00272     BOOLEAN ExtensionsSupported;
00273 
00274     TRACE("PcDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n", DriveNumber, SectorNumber, SectorCount, Buffer);
00275 
00276     //
00277     // Check to see if it is a fixed disk drive
00278     // If so then check to see if Int13 extensions work
00279     // If they do then use them, otherwise default back to BIOS calls
00280     //
00281     ExtensionsSupported = DiskInt13ExtensionsSupported(DriveNumber);
00282 
00283     if ((DriveNumber >= 0x80) && ExtensionsSupported)
00284     {
00285         TRACE("Using Int 13 Extensions for read. DiskInt13ExtensionsSupported(%d) = %s\n", DriveNumber, ExtensionsSupported ? "TRUE" : "FALSE");
00286 
00287         //
00288         // LBA is easy, nothing to calculate
00289         // Just do the read
00290         //
00291         return PcDiskReadLogicalSectorsLBA(DriveNumber, SectorNumber, SectorCount, Buffer);
00292     }
00293     else
00294     {
00295         // LBA is not supported default to the CHS calls
00296         return PcDiskReadLogicalSectorsCHS(DriveNumber, SectorNumber, SectorCount, Buffer);
00297     }
00298 
00299     return TRUE;
00300 }
00301 
00302 BOOLEAN
00303 PcDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
00304 {
00305   EXTENDED_GEOMETRY ExtGeometry;
00306   REGS RegsIn;
00307   REGS RegsOut;
00308   ULONG Cylinders;
00309 
00310   TRACE("DiskGetDriveGeometry()\n");
00311 
00312   /* Try to get the extended geometry first */
00313   ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY);
00314   if (DiskGetExtendedDriveParameters(DriveNumber, &ExtGeometry, ExtGeometry.Size))
00315   {
00316     Geometry->Cylinders = ExtGeometry.Cylinders;
00317     Geometry->Heads = ExtGeometry.Heads;
00318     Geometry->Sectors = ExtGeometry.SectorsPerTrack;
00319     Geometry->BytesPerSector = ExtGeometry.BytesPerSector;
00320 
00321     return TRUE;
00322   }
00323 
00324   /* BIOS Int 13h, function 08h - Get drive parameters
00325    * AH = 08h
00326    * DL = drive (bit 7 set for hard disk)
00327    * ES:DI = 0000h:0000h to guard against BIOS bugs
00328    * Return:
00329    * CF set on error
00330    * AH = status (07h)
00331    * CF clear if successful
00332    * AH = 00h
00333    * AL = 00h on at least some BIOSes
00334    * BL = drive type (AT/PS2 floppies only)
00335    * CH = low eight bits of maximum cylinder number
00336    * CL = maximum sector number (bits 5-0)
00337    *      high two bits of maximum cylinder number (bits 7-6)
00338    * DH = maximum head number
00339    * DL = number of drives
00340    * ES:DI -> drive parameter table (floppies only)
00341    */
00342   RegsIn.b.ah = 0x08;
00343   RegsIn.b.dl = DriveNumber;
00344   RegsIn.w.es = 0x0000;
00345   RegsIn.w.di = 0x0000;
00346 
00347   /* Get drive parameters */
00348   Int386(0x13, &RegsIn, &RegsOut);
00349 
00350   if (! INT386_SUCCESS(RegsOut))
00351     {
00352       return FALSE;
00353     }
00354 
00355   Cylinders = (RegsOut.b.cl & 0xC0) << 2;
00356   Cylinders += RegsOut.b.ch;
00357   Cylinders++;
00358   Geometry->Cylinders = Cylinders;
00359   Geometry->Heads = RegsOut.b.dh + 1;
00360   Geometry->Sectors = RegsOut.b.cl & 0x3F;
00361   Geometry->BytesPerSector = 512;            /* Just assume 512 bytes per sector */
00362 
00363   return TRUE;
00364 }
00365 
00366 ULONG
00367 PcDiskGetCacheableBlockCount(UCHAR DriveNumber)
00368 {
00369   GEOMETRY  Geometry;
00370 
00371   /* If LBA is supported then the block size will be 64 sectors (32k)
00372    * If not then the block size is the size of one track */
00373   if (DiskInt13ExtensionsSupported(DriveNumber))
00374     {
00375       return 64;
00376     }
00377   /* Get the disk geometry
00378    * If this fails then we will just return 1 sector to be safe */
00379   else if (! PcDiskGetDriveGeometry(DriveNumber, &Geometry))
00380     {
00381       return 1;
00382     }
00383   else
00384     {
00385       return Geometry.Sectors;
00386     }
00387 }
00388 
00389 BOOLEAN
00390 PcDiskGetBootPath(char *BootPath, unsigned Size)
00391 {
00392   if (PxeInit())
00393     {
00394       strcpy(BootPath, "net(0)");
00395       return 0;
00396     }
00397   return DiskGetBootPath(BootPath, Size);
00398 }
00399 
00400 /* EOF */

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.