ReactOS 0.4.16-dev-1946-g52006dd
pcdisk.c File Reference
#include <freeldr.h>
#include <debug.h>
#include <pshpack1.h>
#include <poppack.h>
Include dependency graph for pcdisk.c:

Go to the source code of this file.

Classes

struct  I386_DISK_ADDRESS_PACKET
 
struct  I386_CDROM_SPEC_PACKET
 
struct  _EXTENDED_GEOMETRY
 
struct  _PC_DISK_DRIVE
 

Typedefs

typedef struct I386_DISK_ADDRESS_PACKETPI386_DISK_ADDRESS_PACKET
 
typedef struct I386_CDROM_SPEC_PACKETPI386_CDROM_SPEC_PACKET
 
typedef struct _EXTENDED_GEOMETRY EXTENDED_GEOMETRY
 
typedef struct _EXTENDED_GEOMETRYPEXTENDED_GEOMETRY
 
typedef struct _PC_DISK_DRIVE PC_DISK_DRIVE
 
typedef struct _PC_DISK_DRIVEPPC_DISK_DRIVE
 

Functions

 DBG_DEFAULT_CHANNEL (DISK)
 
LONG DiskReportError (BOOLEAN bShowError)
 
static PCSTR DiskGetErrorCodeString (ULONG ErrorCode)
 
static VOID DiskError (PCSTR ErrorString, ULONG ErrorCode)
 
BOOLEAN DiskResetController (UCHAR DriveNumber)
 
static BOOLEAN DiskIsDriveRemovable (UCHAR DriveNumber)
 
static BOOLEAN DiskInt13ExtensionsSupported (IN UCHAR DriveNumber)
 
static BOOLEAN DiskGetExtendedDriveParameters (_In_ UCHAR DriveNumber, _In_ PPC_DISK_DRIVE DiskDrive, _Out_ PVOID Buffer, _In_ USHORT BufferSize)
 
CONFIGURATION_TYPE DiskGetConfigType (_In_ UCHAR DriveNumber)
 
static BOOLEAN InitDriveGeometry (IN UCHAR DriveNumber, IN PPC_DISK_DRIVE DiskDrive)
 
static BOOLEAN PcDiskDriveInit (IN UCHAR DriveNumber, IN OUT PPC_DISK_DRIVE DiskDrive)
 
static PPC_DISK_DRIVE PcDiskDriveNumberToDrive (IN UCHAR DriveNumber)
 
static BOOLEAN PcDiskReadLogicalSectorsLBA (IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
 
static BOOLEAN PcDiskReadLogicalSectorsCHS (IN UCHAR DriveNumber, IN PPC_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
 
BOOLEAN PcDiskReadLogicalSectors (IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
 
BOOLEAN PcDiskGetDriveGeometry (UCHAR DriveNumber, PGEOMETRY Geometry)
 
ULONG PcDiskGetCacheableBlockCount (UCHAR DriveNumber)
 

Variables

static USHORT LastDriveNumber = 0xFFFF
 
static PC_DISK_DRIVE PcDiskDrive
 
static LONG lReportError = 0
 

Typedef Documentation

◆ EXTENDED_GEOMETRY

◆ PC_DISK_DRIVE

◆ PEXTENDED_GEOMETRY

◆ PI386_CDROM_SPEC_PACKET

◆ PI386_DISK_ADDRESS_PACKET

◆ PPC_DISK_DRIVE

Function Documentation

◆ DBG_DEFAULT_CHANNEL()

DBG_DEFAULT_CHANNEL ( DISK  )

◆ DiskError()

static VOID DiskError ( PCSTR  ErrorString,
ULONG  ErrorCode 
)
static

Definition at line 179 of file pcdisk.c.

180{
181 CHAR ErrorCodeString[200];
182
183 if (lReportError < 0)
184 return;
185
186 sprintf(ErrorCodeString, "%s\n\nError Code: 0x%lx\nError: %s",
188
189 ERR("%s\n", ErrorCodeString);
190 UiMessageBox(ErrorCodeString);
191}
#define ERR(fmt,...)
Definition: precomp.h:57
VOID UiMessageBox(_In_ PCSTR Format,...)
Definition: ui.c:359
#define sprintf
Definition: sprintf.c:45
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
static LONG lReportError
Definition: pcdisk.c:134
static PCSTR DiskGetErrorCodeString(ULONG ErrorCode)
Definition: pcdisk.c:144
char CHAR
Definition: xmlstorage.h:175

Referenced by PcDiskReadLogicalSectorsCHS(), and PcDiskReadLogicalSectorsLBA().

◆ DiskGetConfigType()

CONFIGURATION_TYPE DiskGetConfigType ( _In_ UCHAR  DriveNumber)

Definition at line 402 of file pcdisk.c.

404{
405 if ((DriveNumber == FrldrBootDrive)/* && DiskIsDriveRemovable(DriveNumber) */ && (FrldrBootPartition == 0xFF))
406 return CdromController; /* This is our El Torito boot CD-ROM */
407 else if (DiskIsDriveRemovable(DriveNumber))
409 else
410 return DiskPeripheral;
411}
static BOOLEAN DiskIsDriveRemovable(UCHAR DriveNumber)
Definition: pcdisk.c:220
@ DiskPeripheral
Definition: arc.h:138
@ FloppyDiskPeripheral
Definition: arc.h:139
@ CdromController
Definition: arc.h:128
UCHAR FrldrBootDrive
Definition: uefidisk.c:47
ULONG FrldrBootPartition
Definition: uefidisk.c:48

Referenced by DiskOpen(), and PcInitializeBootDevices().

◆ DiskGetErrorCodeString()

static PCSTR DiskGetErrorCodeString ( ULONG  ErrorCode)
static

Definition at line 144 of file pcdisk.c.

145{
146 switch (ErrorCode)
147 {
148 case 0x00: return "no error";
149 case 0x01: return "bad command passed to driver";
150 case 0x02: return "address mark not found or bad sector";
151 case 0x03: return "diskette write protect error";
152 case 0x04: return "sector not found";
153 case 0x05: return "fixed disk reset failed";
154 case 0x06: return "diskette changed or removed";
155 case 0x07: return "bad fixed disk parameter table";
156 case 0x08: return "DMA overrun";
157 case 0x09: return "DMA access across 64k boundary";
158 case 0x0A: return "bad fixed disk sector flag";
159 case 0x0B: return "bad fixed disk cylinder";
160 case 0x0C: return "unsupported track/invalid media";
161 case 0x0D: return "invalid number of sectors on fixed disk format";
162 case 0x0E: return "fixed disk controlled data address mark detected";
163 case 0x0F: return "fixed disk DMA arbitration level out of range";
164 case 0x10: return "ECC/CRC error on disk read";
165 case 0x11: return "recoverable fixed disk data error, data fixed by ECC";
166 case 0x20: return "controller error (NEC for floppies)";
167 case 0x40: return "seek failure";
168 case 0x80: return "time out, drive not ready";
169 case 0xAA: return "fixed disk drive not ready";
170 case 0xBB: return "fixed disk undefined error";
171 case 0xCC: return "fixed disk write fault on selected drive";
172 case 0xE0: return "fixed disk status error/Error reg = 0";
173 case 0xFF: return "sense operation failed";
174
175 default: return "unknown error code";
176 }
177}

Referenced by DiskError(), PcDiskReadLogicalSectorsCHS(), and PcDiskReadLogicalSectorsLBA().

◆ DiskGetExtendedDriveParameters()

static BOOLEAN DiskGetExtendedDriveParameters ( _In_ UCHAR  DriveNumber,
_In_ PPC_DISK_DRIVE  DiskDrive,
_Out_ PVOID  Buffer,
_In_ USHORT  BufferSize 
)
static

Definition at line 313 of file pcdisk.c.

318{
320 REGS RegsIn, RegsOut;
321
322 TRACE("DiskGetExtendedDriveParameters(0x%x)\n", DriveNumber);
323
324 if (!DiskDrive->Int13ExtensionsSupported || (BufferSize < sizeof(*Ptr)))
325 return FALSE;
326
327 /*
328 * Initialize the transfer buffer.
329 * NOTE: Zeroing out the buffer also helps avoiding the bug where Dell
330 * machines using PhoenixBIOS 4.0 Release 6.0 fail to correctly handle
331 * this function if Ptr->Flags is not 0 on entry.
332 */
333 RtlZeroMemory(Ptr, sizeof(*Ptr)); // BufferSize;
334 Ptr->Size = BufferSize;
335
336 /*
337 * BIOS Int 13h, function 48h - Get drive parameters
338 * AH = 48h
339 * DL = drive (bit 7 set for hard disk)
340 * DS:SI = result buffer
341 * Return:
342 * CF set on error
343 * AH = status (07h)
344 * CF clear if successful
345 * AH = 00h
346 * DS:SI -> result buffer
347 */
348 RegsIn.b.ah = 0x48;
349 RegsIn.b.dl = DriveNumber;
350 RegsIn.x.ds = BIOSCALLBUFSEGMENT;
351 RegsIn.w.si = BIOSCALLBUFOFFSET;
352
353 /* Get drive parameters */
354 Int386(0x13, &RegsIn, &RegsOut);
355 if (!INT386_SUCCESS(RegsOut))
356 return FALSE;
357
359
360#if DBG
361 TRACE("Size of buffer: 0x%x\n", Ptr->Size);
362 TRACE("Information flags: 0x%x\n", Ptr->Flags);
363 TRACE("Number of physical cylinders on drive: %u\n", Ptr->Cylinders);
364 TRACE("Number of physical heads on drive: %u\n", Ptr->Heads);
365 TRACE("Number of physical sectors per track: %u\n", Ptr->SectorsPerTrack);
366 TRACE("Total number of sectors on drive: %I64u\n", Ptr->Sectors);
367 TRACE("Bytes per sector: %u\n", Ptr->BytesPerSector);
368 if (Ptr->Size >= 0x1E)
369 {
370 // LOWORD(Ptr->PDPTE): offset, HIWORD(Ptr->PDPTE): segment
371 USHORT Off = (USHORT)(Ptr->PDPTE & 0xFFFF); // ((PUSHORT)&Ptr->PDPTE)[0];
372 USHORT Seg = (USHORT)((Ptr->PDPTE >> 16) & 0xFFFF); // ((PUSHORT)&Ptr->PDPTE)[1];
373 TRACE("EDD configuration parameters (DPTE): %x:%x\n", Seg, Off);
374
375 /* The DPTE pointer is valid if it's != FFFF:FFFF (per the Enhanced Disk
376 * Drive Specification), but also, when it's != 0000:0000 (broken BIOSes) */
377 if (Ptr->PDPTE != 0xFFFFFFFF && Ptr->PDPTE != 0)
378 {
379 PUCHAR SpecPtr = (PUCHAR)(ULONG_PTR)((Seg << 4) + Off);
380 TRACE("SpecPtr: 0x%x\n", SpecPtr);
381 TRACE("Physical I/O port base address: 0x%x\n", *(PUSHORT)&SpecPtr[0]);
382 TRACE("Disk-drive control port address: 0x%x\n", *(PUSHORT)&SpecPtr[2]);
383 TRACE("Head register upper nibble: 0x%x\n", SpecPtr[4]);
384 TRACE("BIOS Vendor-specific: 0x%x\n", SpecPtr[5]);
385 TRACE("IRQ for drive: %u\n", SpecPtr[6]);
386 TRACE("Sector count for multi-sector transfers: %u\n", SpecPtr[7]);
387 TRACE("DMA control: 0x%x\n", SpecPtr[8]);
388 TRACE("Programmed I/O control: 0x%x\n", SpecPtr[9]);
389 TRACE("Drive options: 0x%x\n", *(PUSHORT)&SpecPtr[10]);
390 }
391 }
392 if (Ptr->Size >= 0x42)
393 {
394 TRACE("Signature: 0x%x\n", ((PUSHORT)Ptr)[15]);
395 }
396#endif // DBG
397
398 return TRUE;
399}
Definition: bufpool.h:45
#define BufferSize
Definition: mmc.h:75
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
#define INT386_SUCCESS(regs)
Definition: pcbios.h:181
int __cdecl Int386(int ivec, REGS *in, REGS *out)
struct _EXTENDED_GEOMETRY * PEXTENDED_GEOMETRY
unsigned short USHORT
Definition: pedump.c:61
#define TRACE(s)
Definition: solgame.cpp:4
unsigned char dl
Definition: pcbios.h:142
unsigned char ah
Definition: pcbios.h:134
unsigned short ds
Definition: pcbios.h:102
unsigned short si
Definition: pcbios.h:118
uint16_t * PUSHORT
Definition: typedefs.h:56
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
Definition: pcbios.h:161
DWORDREGS x
Definition: pcbios.h:162
BYTEREGS b
Definition: pcbios.h:165
WORDREGS w
Definition: pcbios.h:164
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
#define BIOSCALLBUFSEGMENT
Definition: x86common.h:24
#define BIOSCALLBUFOFFSET
Definition: x86common.h:25
#define BIOSCALLBUFFER
Definition: x86common.h:12

Referenced by InitDriveGeometry().

◆ DiskInt13ExtensionsSupported()

static BOOLEAN DiskInt13ExtensionsSupported ( IN UCHAR  DriveNumber)
static

Definition at line 235 of file pcdisk.c.

236{
237 REGS RegsIn, RegsOut;
238
239 /*
240 * Some BIOSes report that extended disk access functions are not supported
241 * when booting from a CD (e.g. Phoenix BIOS v6.00PG and Insyde BIOS shipping
242 * with Intel Macs). Therefore we just return TRUE if we're booting from a CD
243 * - we can assume that all El Torito capable BIOSes support INT 13 extensions.
244 * We simply detect whether we're booting from CD by checking whether the drive
245 * number is >= 0x8A. It's 0x90 on the Insyde BIOS, and 0x9F on most other BIOSes.
246 */
247 if (DriveNumber >= 0x8A)
248 return TRUE;
249
250 /*
251 * IBM/MS INT 13 Extensions - INSTALLATION CHECK
252 * AH = 41h
253 * BX = 55AAh
254 * DL = drive (80h-FFh)
255 * Return:
256 * CF set on error (extensions not supported)
257 * AH = 01h (invalid function)
258 * CF clear if successful
259 * BX = AA55h if installed
260 * AH = major version of extensions
261 * 01h = 1.x
262 * 20h = 2.0 / EDD-1.0
263 * 21h = 2.1 / EDD-1.1
264 * 30h = EDD-3.0
265 * AL = internal use
266 * CX = API subset support bitmap
267 * DH = extension version (v2.0+ ??? -- not present in 1.x)
268 *
269 * Bitfields for IBM/MS INT 13 Extensions API support bitmap
270 * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
271 * Bit 1, removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported
272 * Bit 2, enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
273 * extended drive parameter table is valid
274 * Bits 3-15 reserved
275 */
276 RegsIn.b.ah = 0x41;
277 RegsIn.w.bx = 0x55AA;
278 RegsIn.b.dl = DriveNumber;
279
280 /* Reset the disk controller */
281 Int386(0x13, &RegsIn, &RegsOut);
282 if (!INT386_SUCCESS(RegsOut))
283 {
284 /* CF set on error (extensions not supported) */
285 return FALSE;
286 }
287
288 if (RegsOut.w.bx != 0xAA55)
289 {
290 /* BX = AA55h if installed */
291 return FALSE;
292 }
293
294#if DBG
295 TRACE("Drive 0x%x: INT 13h Extended version: 0x%02x, API bitmap: 0x%04x\n",
296 DriveNumber, RegsOut.b.ah, RegsOut.w.cx);
297#endif
298 if (!(RegsOut.w.cx & 0x0001))
299 {
300 /*
301 * CX = API subset support bitmap.
302 * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported.
303 */
304 WARN("Drive 0x%x: Suspicious API subset support bitmap 0x%04x\n",
305 DriveNumber, RegsOut.w.cx);
306 return FALSE;
307 }
308
309 return TRUE;
310}
#define WARN(fmt,...)
Definition: precomp.h:61
unsigned short cx
Definition: pcbios.h:115
unsigned short bx
Definition: pcbios.h:114

Referenced by PcDiskDriveInit().

◆ DiskIsDriveRemovable()

static BOOLEAN DiskIsDriveRemovable ( UCHAR  DriveNumber)
static

Definition at line 220 of file pcdisk.c.

221{
222 /*
223 * Hard disks use drive numbers >= 0x80 . So if the drive number
224 * indicates a hard disk then return FALSE.
225 * 0x49 is our magic ramdisk drive, so return FALSE for that too.
226 */
227 if ((DriveNumber >= 0x80) || (DriveNumber == 0x49))
228 return FALSE;
229
230 /* The drive is a floppy diskette so return TRUE */
231 return TRUE;
232}

Referenced by DiskGetConfigType(), and PcDiskDriveInit().

◆ DiskReportError()

LONG DiskReportError ( BOOLEAN  bShowError)

Definition at line 136 of file pcdisk.c.

137{
138 /* Set the reference count */
139 if (bShowError) ++lReportError;
140 else --lReportError;
141 return lReportError;
142}

Referenced by EnumerateHarddisks(), and GetHarddiskInformation().

◆ DiskResetController()

BOOLEAN DiskResetController ( UCHAR  DriveNumber)

Definition at line 195 of file pcdisk.c.

196{
197 REGS RegsIn, RegsOut;
198
199 WARN("DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber);
200
201 /*
202 * BIOS Int 13h, function 0 - Reset disk system
203 * AH = 00h
204 * DL = drive (if bit 7 is set both hard disks and floppy disks reset)
205 * Return:
206 * AH = status
207 * CF clear if successful
208 * CF set on error
209 */
210 RegsIn.b.ah = 0x00;
211 RegsIn.b.dl = DriveNumber;
212
213 /* Reset the disk controller */
214 Int386(0x13, &RegsIn, &RegsOut);
215
216 return INT386_SUCCESS(RegsOut);
217}

Referenced by DetectBiosFloppyPeripheral(), PcDiskReadLogicalSectorsCHS(), and PcDiskReadLogicalSectorsLBA().

◆ InitDriveGeometry()

static BOOLEAN InitDriveGeometry ( IN UCHAR  DriveNumber,
IN PPC_DISK_DRIVE  DiskDrive 
)
static

Definition at line 414 of file pcdisk.c.

417{
419 REGS RegsIn, RegsOut;
420 ULONG Cylinders;
421
422 /* Get the extended geometry first */
423 RtlZeroMemory(&DiskDrive->ExtGeometry, sizeof(DiskDrive->ExtGeometry));
424 Success = DiskGetExtendedDriveParameters(DriveNumber, DiskDrive,
425 &DiskDrive->ExtGeometry,
426 sizeof(DiskDrive->ExtGeometry));
427 if (Success)
428 {
429 TRACE("DiskGetExtendedDriveParameters(0x%x) returned:\n"
430 "Cylinders : 0x%x\n"
431 "Heads : 0x%x\n"
432 "Sects/Track: 0x%x\n"
433 "Total Sects: 0x%llx\n"
434 "Bytes/Sect : 0x%x\n",
435 DriveNumber,
436 DiskDrive->ExtGeometry.Cylinders,
437 DiskDrive->ExtGeometry.Heads,
438 DiskDrive->ExtGeometry.SectorsPerTrack,
439 DiskDrive->ExtGeometry.Sectors,
440 DiskDrive->ExtGeometry.BytesPerSector);
441 }
442
443 /* Now try the legacy geometry */
444 RtlZeroMemory(&DiskDrive->Geometry, sizeof(DiskDrive->Geometry));
445
446 /*
447 * BIOS Int 13h, function 08h - Get drive parameters
448 * AH = 08h
449 * DL = drive (bit 7 set for hard disk)
450 * ES:DI = 0000h:0000h to guard against BIOS bugs
451 * Return:
452 * CF set on error
453 * AH = status (07h)
454 * CF clear if successful
455 * AH = 00h
456 * AL = 00h on at least some BIOSes
457 * BL = drive type (AT/PS2 floppies only)
458 * CH = low eight bits of maximum cylinder number
459 * CL = maximum sector number (bits 5-0)
460 * high two bits of maximum cylinder number (bits 7-6)
461 * DH = maximum head number
462 * DL = number of drives
463 * ES:DI -> drive parameter table (floppies only)
464 */
465 RegsIn.b.ah = 0x08;
466 RegsIn.b.dl = DriveNumber;
467 RegsIn.w.es = 0x0000;
468 RegsIn.w.di = 0x0000;
469
470 /* Get drive parameters */
471 Int386(0x13, &RegsIn, &RegsOut);
472 if (!INT386_SUCCESS(RegsOut))
473 {
474 /* We failed, return the result of the previous call (extended geometry) */
475 return Success;
476 }
477 /* OR it with the old result, so that we return TRUE whenever either call succeeded */
478 Success |= TRUE;
479
480 Cylinders = (RegsOut.b.cl & 0xC0) << 2;
481 Cylinders += RegsOut.b.ch;
482 Cylinders++;
483 DiskDrive->Geometry.Cylinders = Cylinders;
484 DiskDrive->Geometry.Heads = RegsOut.b.dh + 1;
485 DiskDrive->Geometry.SectorsPerTrack = RegsOut.b.cl & 0x3F;
486 DiskDrive->Geometry.BytesPerSector = 512; /* Just assume 512 bytes per sector */
487
488 DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
489 DiskDrive->Geometry.Heads *
490 DiskDrive->Geometry.SectorsPerTrack;
491
492 TRACE("Regular Int13h(0x%x) returned:\n"
493 "Cylinders : 0x%x\n"
494 "Heads : 0x%x\n"
495 "Sects/Track: 0x%x\n"
496 "Total Sects: 0x%llx\n"
497 "Bytes/Sect : 0x%x\n",
498 DriveNumber,
499 DiskDrive->Geometry.Cylinders,
500 DiskDrive->Geometry.Heads,
501 DiskDrive->Geometry.SectorsPerTrack,
502 DiskDrive->Geometry.Sectors,
503 DiskDrive->Geometry.BytesPerSector);
504
505 return Success;
506}
unsigned char BOOLEAN
@ Success
Definition: eventcreate.c:712
static BOOLEAN DiskGetExtendedDriveParameters(_In_ UCHAR DriveNumber, _In_ PPC_DISK_DRIVE DiskDrive, _Out_ PVOID Buffer, _In_ USHORT BufferSize)
Definition: pcdisk.c:313
unsigned char ch
Definition: pcbios.h:140
unsigned char cl
Definition: pcbios.h:139
unsigned char dh
Definition: pcbios.h:143
unsigned short es
Definition: pcbios.h:123
unsigned short di
Definition: pcbios.h:119
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67

Referenced by PcDiskDriveInit().

◆ PcDiskDriveInit()

static BOOLEAN PcDiskDriveInit ( IN UCHAR  DriveNumber,
IN OUT PPC_DISK_DRIVE  DiskDrive 
)
static

Definition at line 509 of file pcdisk.c.

512{
513 DiskDrive->IsRemovable = DiskIsDriveRemovable(DriveNumber);
514
515 /*
516 * Check to see if it is a fixed disk drive.
517 * If so then check to see if INT 13h extensions work.
518 * If they do then use them, otherwise default back to BIOS calls.
519 */
520 DiskDrive->Int13ExtensionsSupported = DiskInt13ExtensionsSupported(DriveNumber);
521
522 if (!InitDriveGeometry(DriveNumber, DiskDrive))
523 return FALSE;
524
525 TRACE("\n"
526 "DriveNumber: 0x%x\n"
527 "IsRemovable = %s\n"
528 "Int13ExtensionsSupported = %s\n",
529 DriveNumber,
530 DiskDrive->IsRemovable ? "TRUE" : "FALSE",
531 DiskDrive->Int13ExtensionsSupported ? "TRUE" : "FALSE");
532
533 return TRUE;
534}
static BOOLEAN DiskInt13ExtensionsSupported(IN UCHAR DriveNumber)
Definition: pcdisk.c:235
static BOOLEAN InitDriveGeometry(IN UCHAR DriveNumber, IN PPC_DISK_DRIVE DiskDrive)
Definition: pcdisk.c:414

Referenced by PcDiskDriveNumberToDrive().

◆ PcDiskDriveNumberToDrive()

static PPC_DISK_DRIVE PcDiskDriveNumberToDrive ( IN UCHAR  DriveNumber)
inlinestatic

Definition at line 538 of file pcdisk.c.

539{
540#ifdef CACHE_MULTI_DRIVES
541 PPC_DISK_DRIVE DiskDrive;
542
543 ASSERT((0 <= DriveNumber) && (DriveNumber < RTL_NUMBER_OF(PcDiskDrive)));
544
545 /* Retrieve a slot */
546 DiskDrive = &PcDiskDrive[DriveNumber];
547
548 /* If the drive has not been initialized before... */
549 if (!DiskDrive->Initialized)
550 {
551 /* ... try to initialize it now. */
552 if (!PcDiskDriveInit(DriveNumber, DiskDrive))
553 {
554 /*
555 * If we failed, there is no drive at this number
556 * and flag it as such (set its high bit).
557 */
558 DiskDrive->Initialized |= 0x80;
559 return NULL;
560 }
561 DiskDrive->Initialized = TRUE;
562 }
563 else if (DiskDrive->Initialized & 0x80)
564 {
565 /*
566 * The disk failed to be initialized previously, reset its flag to give
567 * it chance to be initialized again later, but just fail for the moment.
568 */
569 DiskDrive->Initialized = FALSE;
570 return NULL;
571 }
572
573 return DiskDrive;
574#else
575 static PC_DISK_DRIVE NewDiskDrive;
576
577 ASSERT((0 <= DriveNumber) && (DriveNumber <= 0xFF));
578
579 /* Update cached information */
580
581 /* If the drive has not been accessed last before... */
582 if ((USHORT)DriveNumber != LastDriveNumber)
583 {
584 /* ... try to (re-)initialize and cache it now. */
585 RtlZeroMemory(&NewDiskDrive, sizeof(NewDiskDrive));
586 if (!PcDiskDriveInit(DriveNumber, &NewDiskDrive))
587 {
588 /*
589 * If we failed, there is no drive at this number.
590 * Keep the last-accessed valid drive cached.
591 */
592 return NULL;
593 }
594 /* We succeeded, cache the drive data */
595 PcDiskDrive = NewDiskDrive;
596 LastDriveNumber = (USHORT)DriveNumber;
597 }
598
599 return &PcDiskDrive;
600#endif /* CACHE_MULTI_DRIVES */
601}
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
#define NULL
Definition: types.h:112
#define ASSERT(a)
Definition: mode.c:44
static USHORT LastDriveNumber
Definition: pcdisk.c:128
static PC_DISK_DRIVE PcDiskDrive
Definition: pcdisk.c:129
static BOOLEAN PcDiskDriveInit(IN UCHAR DriveNumber, IN OUT PPC_DISK_DRIVE DiskDrive)
Definition: pcdisk.c:509

Referenced by PcDiskGetCacheableBlockCount(), PcDiskGetDriveGeometry(), and PcDiskReadLogicalSectors().

◆ PcDiskGetCacheableBlockCount()

ULONG PcDiskGetCacheableBlockCount ( UCHAR  DriveNumber)

Definition at line 856 of file pcdisk.c.

857{
858 PPC_DISK_DRIVE DiskDrive;
859
860 DiskDrive = PcDiskDriveNumberToDrive(DriveNumber);
861 if (!DiskDrive)
862 return 1; // Unknown count.
863
864 /*
865 * If LBA is supported then the block size will be 64 sectors (32k).
866 * If not then the block size is the size of one track.
867 */
868 if (DiskDrive->Int13ExtensionsSupported)
869 return 64;
870 else
871 return DiskDrive->Geometry.SectorsPerTrack;
872}
static PPC_DISK_DRIVE PcDiskDriveNumberToDrive(IN UCHAR DriveNumber)
Definition: pcdisk.c:538
ULONG SectorsPerTrack
Number of sectors per track.
Definition: disk.h:29
BOOLEAN Int13ExtensionsSupported
Definition: pcdisk.c:102
GEOMETRY Geometry
Definition: pcdisk.c:98

Referenced by MachInit().

◆ PcDiskGetDriveGeometry()

BOOLEAN PcDiskGetDriveGeometry ( UCHAR  DriveNumber,
PGEOMETRY  Geometry 
)

Definition at line 826 of file pcdisk.c.

827{
828 PPC_DISK_DRIVE DiskDrive;
829
830 TRACE("PcDiskGetDriveGeometry(0x%x)\n", DriveNumber);
831
832 DiskDrive = PcDiskDriveNumberToDrive(DriveNumber);
833 if (!DiskDrive)
834 return FALSE;
835
836 /* Try to get the extended geometry first */
837 if (DiskDrive->ExtGeometry.Size == sizeof(DiskDrive->ExtGeometry))
838 {
839 /* Extended geometry has been initialized, return it */
840 Geometry->Cylinders = DiskDrive->ExtGeometry.Cylinders;
841 Geometry->Heads = DiskDrive->ExtGeometry.Heads;
842 Geometry->SectorsPerTrack = DiskDrive->ExtGeometry.SectorsPerTrack;
843 Geometry->BytesPerSector = DiskDrive->ExtGeometry.BytesPerSector;
844 Geometry->Sectors = DiskDrive->ExtGeometry.Sectors;
845 }
846 else
847 /* Fall back to legacy BIOS geometry */
848 {
849 *Geometry = DiskDrive->Geometry;
850 }
851
852 return TRUE;
853}
ULONGLONG Sectors
Definition: pcdisk.c:88
USHORT BytesPerSector
Definition: pcdisk.c:89
ULONG SectorsPerTrack
Definition: pcdisk.c:87
ULONG Cylinders
Definition: pcdisk.c:85
ULONG BytesPerSector
Number of bytes per sector.
Definition: disk.h:30
ULONG Cylinders
Number of cylinders on the disk.
Definition: disk.h:27
ULONGLONG Sectors
Total number of disk sectors/LBA blocks.
Definition: disk.h:31
ULONG Heads
Number of heads on the disk.
Definition: disk.h:28
EXTENDED_GEOMETRY ExtGeometry
Definition: pcdisk.c:99

Referenced by MachInit(), and PcGetHarddiskConfigurationData().

◆ PcDiskReadLogicalSectors()

BOOLEAN PcDiskReadLogicalSectors ( IN UCHAR  DriveNumber,
IN ULONGLONG  SectorNumber,
IN ULONG  SectorCount,
OUT PVOID  Buffer 
)

Definition at line 786 of file pcdisk.c.

791{
792 PPC_DISK_DRIVE DiskDrive;
793
794 TRACE("PcDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u Buffer: 0x%x\n",
795 DriveNumber, SectorNumber, SectorCount, Buffer);
796
797 /* 16-bit BIOS addressing limitation */
798 ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
799
800 DiskDrive = PcDiskDriveNumberToDrive(DriveNumber);
801 if (!DiskDrive)
802 return FALSE;
803
804 if ((DriveNumber >= 0x80) && DiskDrive->Int13ExtensionsSupported)
805 {
806 /* LBA is easy, nothing to calculate. Just do the read. */
807 TRACE("--> Using LBA\n");
808 return PcDiskReadLogicalSectorsLBA(DriveNumber, SectorNumber, SectorCount, Buffer);
809 }
810 else
811 {
812 /* LBA is not supported, default to CHS */
813 TRACE("--> Using CHS\n");
814 return PcDiskReadLogicalSectorsCHS(DriveNumber, DiskDrive, SectorNumber, SectorCount, Buffer);
815 }
816}
ULONG SectorCount
Definition: part_xbox.c:31
static BOOLEAN PcDiskReadLogicalSectorsLBA(IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pcdisk.c:604
static BOOLEAN PcDiskReadLogicalSectorsCHS(IN UCHAR DriveNumber, IN PPC_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pcdisk.c:668

Referenced by MachInit().

◆ PcDiskReadLogicalSectorsCHS()

static BOOLEAN PcDiskReadLogicalSectorsCHS ( IN UCHAR  DriveNumber,
IN PPC_DISK_DRIVE  DiskDrive,
IN ULONGLONG  SectorNumber,
IN ULONG  SectorCount,
OUT PVOID  Buffer 
)
static

Definition at line 668 of file pcdisk.c.

674{
675 UCHAR PhysicalSector;
676 UCHAR PhysicalHead;
677 ULONG PhysicalTrack;
678 GEOMETRY DriveGeometry;
679 ULONG NumberOfSectorsToRead;
680 REGS RegsIn, RegsOut;
681 ULONG RetryCount;
682
683 DriveGeometry = DiskDrive->Geometry;
684 if (DriveGeometry.SectorsPerTrack == 0 || DriveGeometry.Heads == 0)
685 return FALSE;
686
687 while (SectorCount > 0)
688 {
689 /*
690 * Calculate the physical disk offsets.
691 * Note: DriveGeometry.SectorsPerTrack < 64
692 */
693 PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.SectorsPerTrack);
694 PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.SectorsPerTrack) % DriveGeometry.Heads);
695 PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.SectorsPerTrack) / DriveGeometry.Heads);
696
697 /* Calculate how many sectors we need to read this round */
698 if (PhysicalSector > 1)
699 {
700 NumberOfSectorsToRead = min(SectorCount,
701 (DriveGeometry.SectorsPerTrack - (PhysicalSector - 1)));
702 }
703 else
704 {
705 NumberOfSectorsToRead = min(SectorCount, DriveGeometry.SectorsPerTrack);
706 }
707
708 /* Make sure the read is within the geometry boundaries */
709 if ((PhysicalHead >= DriveGeometry.Heads) ||
710 (PhysicalTrack >= DriveGeometry.Cylinders) ||
711 ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.SectorsPerTrack + 1)) ||
712 (PhysicalSector > DriveGeometry.SectorsPerTrack))
713 {
714 DiskError("Disk read exceeds drive geometry limits.", 0);
715 return FALSE;
716 }
717
718 /*
719 * BIOS Int 13h, function 2 - Read Disk Sectors
720 * AH = 02h
721 * AL = number of sectors to read (must be nonzero)
722 * CH = low eight bits of cylinder number
723 * CL = sector number 1-63 (bits 0-5)
724 * high two bits of cylinder (bits 6-7, hard disk only)
725 * DH = head number
726 * DL = drive number (bit 7 set for hard disk)
727 * ES:BX -> data buffer
728 * Return:
729 * CF set on error
730 * if AH = 11h (corrected ECC error), AL = burst length
731 * CF clear if successful
732 * AH = status
733 * AL = number of sectors transferred
734 * (only valid if CF set for some BIOSes)
735 */
736 RegsIn.b.ah = 0x02;
737 RegsIn.b.al = (UCHAR)NumberOfSectorsToRead;
738 RegsIn.b.ch = (PhysicalTrack & 0xFF);
739 RegsIn.b.cl = (UCHAR)(PhysicalSector + ((PhysicalTrack & 0x300) >> 2));
740 RegsIn.b.dh = PhysicalHead;
741 RegsIn.b.dl = DriveNumber;
742 RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
743 RegsIn.w.bx = ((ULONG_PTR)Buffer) & 0x0F;
744
745 /* Perform the read. Retry 3 times. */
746 for (RetryCount = 0; RetryCount < 3; ++RetryCount)
747 {
748 Int386(0x13, &RegsIn, &RegsOut);
749
750 /* If it worked, or if it was a corrected ECC error
751 * and the data is still good, break out */
752 if (INT386_SUCCESS(RegsOut) || (RegsOut.b.ah == 0x11))
753 break;
754
755 /* It failed, do the next retry */
756 DiskResetController(DriveNumber);
757 }
758
759 /* If we retried 3 times then fail */
760 if (RetryCount >= 3)
761 {
762 DiskError("Disk Read Failed in CHS mode, after retrying 3 times", RegsOut.b.ah);
763 ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u)\n",
764 RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
765 DriveNumber, SectorNumber, SectorCount);
766 return FALSE;
767 }
768
769 /*
770 * I have learned that not all BIOSes return
771 * the sector read count in the AL register (at least mine doesn't)
772 * even if the sectors were read correctly. So instead
773 * of checking the sector read count we will rely solely
774 * on the carry flag being set on error.
775 */
776
777 Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
778 SectorCount -= NumberOfSectorsToRead;
779 SectorNumber += NumberOfSectorsToRead;
780 }
781
782 return TRUE;
783}
#define ULONG_PTR
Definition: config.h:101
#define min(a, b)
Definition: monoChain.cc:55
BOOLEAN DiskResetController(UCHAR DriveNumber)
Definition: pcdisk.c:195
static VOID DiskError(PCSTR ErrorString, ULONG ErrorCode)
Definition: pcdisk.c:179
unsigned char al
Definition: pcbios.h:133
Definition: disk.h:26
void * PVOID
Definition: typedefs.h:50
unsigned char UCHAR
Definition: xmlstorage.h:181

Referenced by PcDiskReadLogicalSectors().

◆ PcDiskReadLogicalSectorsLBA()

static BOOLEAN PcDiskReadLogicalSectorsLBA ( IN UCHAR  DriveNumber,
IN ULONGLONG  SectorNumber,
IN ULONG  SectorCount,
OUT PVOID  Buffer 
)
static

Definition at line 604 of file pcdisk.c.

609{
611 REGS RegsIn, RegsOut;
612 ULONG RetryCount;
613
614 /* Setup disk address packet */
615 RtlZeroMemory(Packet, sizeof(*Packet));
616 Packet->PacketSize = sizeof(*Packet);
617 Packet->Reserved = 0;
618 // Packet->LBABlockCount set in the loop.
619 Packet->TransferBufferOffset = ((ULONG_PTR)Buffer) & 0x0F;
620 Packet->TransferBufferSegment = (USHORT)(((ULONG_PTR)Buffer) >> 4);
621 Packet->LBAStartBlock = SectorNumber;
622
623 /*
624 * BIOS Int 13h, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
625 * Return:
626 * CF clear if successful
627 * AH = 00h
628 * CF set on error
629 * AH = error code
630 * Disk address packet's block count field set to the
631 * number of blocks successfully transferred.
632 */
633 RegsIn.b.ah = 0x42;
634 RegsIn.b.dl = DriveNumber; // Drive number in DL (0 - floppy, 0x80 - harddisk)
635 RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> disk address packet
636 RegsIn.w.si = BIOSCALLBUFOFFSET;
637
638 /* Retry 3 times */
639 for (RetryCount = 0; RetryCount < 3; ++RetryCount)
640 {
641 /* Restore the number of blocks to transfer, since it gets reset
642 * on failure with the number of blocks that were successfully
643 * transferred (and which could be zero). */
644 Packet->LBABlockCount = (USHORT)SectorCount;
645 ASSERT(Packet->LBABlockCount == SectorCount);
646
647 Int386(0x13, &RegsIn, &RegsOut);
648
649 /* If it worked, or if it was a corrected ECC error
650 * and the data is still good, return success */
651 if (INT386_SUCCESS(RegsOut) || (RegsOut.b.ah == 0x11))
652 return TRUE;
653
654 /* It failed, do the next retry */
655 DiskResetController(DriveNumber);
656 }
657
658 /* If we get here then the read failed */
659 DiskError("Disk Read Failed in LBA mode", RegsOut.b.ah);
660 ERR("Disk Read Failed in LBA mode: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u)\n",
661 RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
662 DriveNumber, SectorNumber, SectorCount);
663
664 return FALSE;
665}
_In_ NDIS_HANDLE _In_ PNDIS_PACKET Packet
Definition: ndis.h:1549
struct I386_DISK_ADDRESS_PACKET * PI386_DISK_ADDRESS_PACKET

Referenced by PcDiskReadLogicalSectors().

Variable Documentation

◆ LastDriveNumber

USHORT LastDriveNumber = 0xFFFF
static

Definition at line 128 of file pcdisk.c.

Referenced by PcDiskDriveNumberToDrive().

◆ lReportError

LONG lReportError = 0
static

Definition at line 134 of file pcdisk.c.

Referenced by DiskError(), and DiskReportError().

◆ PcDiskDrive

PC_DISK_DRIVE PcDiskDrive
static

Definition at line 129 of file pcdisk.c.

Referenced by PcDiskDriveNumberToDrive().