ReactOS 0.4.16-dev-2613-g9533ad7
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)
 
PCSTR DiskGetErrorCodeString (_In_ 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
 

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  )

◆ DiskGetConfigType()

CONFIGURATION_TYPE DiskGetConfigType ( _In_ UCHAR  DriveNumber)

Definition at line 381 of file pcdisk.c.

383{
384 if ((DriveNumber == FrldrBootDrive)/* && DiskIsDriveRemovable(DriveNumber) */ && (FrldrBootPartition == 0xFF))
385 return CdromController; /* This is our El Torito boot CD-ROM */
386 else if (DiskIsDriveRemovable(DriveNumber))
388 else
389 return DiskPeripheral;
390}
static BOOLEAN DiskIsDriveRemovable(UCHAR DriveNumber)
Definition: pcdisk.c:199
@ DiskPeripheral
Definition: arc.h:138
@ FloppyDiskPeripheral
Definition: arc.h:139
@ CdromController
Definition: arc.h:128
UCHAR FrldrBootDrive
Definition: uefidisk.c:57
ULONG FrldrBootPartition
Definition: uefidisk.c:58

Referenced by DiskOpen().

◆ DiskGetErrorCodeString()

PCSTR DiskGetErrorCodeString ( _In_ ULONG  ErrorCode)

Definition at line 136 of file pcdisk.c.

138{
139 switch (ErrorCode)
140 {
141 case 0x00: return "No error";
142 case 0x01: return "Bad command passed to driver";
143 case 0x02: return "Address mark not found or bad sector";
144 case 0x03: return "Diskette write protect error";
145 case 0x04: return "Sector not found";
146 case 0x05: return "Fixed disk reset failed";
147 case 0x06: return "Diskette changed or removed";
148 case 0x07: return "Bad fixed disk parameter table";
149 case 0x08: return "DMA overrun";
150 case 0x09: return "DMA access across 64k boundary";
151 case 0x0A: return "Bad fixed disk sector flag";
152 case 0x0B: return "Bad fixed disk cylinder";
153 case 0x0C: return "Unsupported track/invalid media";
154 case 0x0D: return "Invalid number of sectors on fixed disk format";
155 case 0x0E: return "Fixed disk controlled data address mark detected";
156 case 0x0F: return "Fixed disk DMA arbitration level out of range";
157 case 0x10: return "ECC/CRC error on disk read";
158 case 0x11: return "Recoverable fixed disk data error, data fixed by ECC";
159 case 0x20: return "Controller error (NEC for floppies)";
160 case 0x40: return "Seek failure";
161 case 0x80: return "Time out, drive not ready";
162 case 0xAA: return "Fixed disk drive not ready";
163 case 0xBB: return "Fixed disk undefined error";
164 case 0xCC: return "Fixed disk write fault on selected drive";
165 case 0xE0: return "Fixed disk status error/Error reg = 0";
166 case 0xFF: return "Sense operation failed";
167
168 default: return "Unknown error code";
169 }
170}
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436

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 292 of file pcdisk.c.

297{
299 REGS RegsIn, RegsOut;
300
301 TRACE("DiskGetExtendedDriveParameters(0x%x)\n", DriveNumber);
302
303 if (!DiskDrive->Int13ExtensionsSupported || (BufferSize < sizeof(*Ptr)))
304 return FALSE;
305
306 /*
307 * Initialize the transfer buffer.
308 * NOTE: Zeroing out the buffer also helps avoiding the bug where Dell
309 * machines using PhoenixBIOS 4.0 Release 6.0 fail to correctly handle
310 * this function if Ptr->Flags is not 0 on entry.
311 */
312 RtlZeroMemory(Ptr, sizeof(*Ptr)); // BufferSize;
313 Ptr->Size = BufferSize;
314
315 /*
316 * BIOS Int 13h, function 48h - Get drive parameters
317 * AH = 48h
318 * DL = drive (bit 7 set for hard disk)
319 * DS:SI = result buffer
320 * Return:
321 * CF set on error
322 * AH = status (07h)
323 * CF clear if successful
324 * AH = 00h
325 * DS:SI -> result buffer
326 */
327 RegsIn.b.ah = 0x48;
328 RegsIn.b.dl = DriveNumber;
329 RegsIn.x.ds = BIOSCALLBUFSEGMENT;
330 RegsIn.w.si = BIOSCALLBUFOFFSET;
331
332 /* Get drive parameters */
333 Int386(0x13, &RegsIn, &RegsOut);
334 if (!INT386_SUCCESS(RegsOut))
335 return FALSE;
336
338
339#if DBG
340 TRACE("Size of buffer: 0x%x\n", Ptr->Size);
341 TRACE("Information flags: 0x%x\n", Ptr->Flags);
342 TRACE("Number of physical cylinders on drive: %u\n", Ptr->Cylinders);
343 TRACE("Number of physical heads on drive: %u\n", Ptr->Heads);
344 TRACE("Number of physical sectors per track: %u\n", Ptr->SectorsPerTrack);
345 TRACE("Total number of sectors on drive: %I64u\n", Ptr->Sectors);
346 TRACE("Bytes per sector: %u\n", Ptr->BytesPerSector);
347 if (Ptr->Size >= 0x1E)
348 {
349 // LOWORD(Ptr->PDPTE): offset, HIWORD(Ptr->PDPTE): segment
350 USHORT Off = (USHORT)(Ptr->PDPTE & 0xFFFF); // ((PUSHORT)&Ptr->PDPTE)[0];
351 USHORT Seg = (USHORT)((Ptr->PDPTE >> 16) & 0xFFFF); // ((PUSHORT)&Ptr->PDPTE)[1];
352 TRACE("EDD configuration parameters (DPTE): %x:%x\n", Seg, Off);
353
354 /* The DPTE pointer is valid if it's != FFFF:FFFF (per the Enhanced Disk
355 * Drive Specification), but also, when it's != 0000:0000 (broken BIOSes) */
356 if (Ptr->PDPTE != 0xFFFFFFFF && Ptr->PDPTE != 0)
357 {
358 PUCHAR SpecPtr = (PUCHAR)(ULONG_PTR)((Seg << 4) + Off);
359 TRACE("SpecPtr: 0x%x\n", SpecPtr);
360 TRACE("Physical I/O port base address: 0x%x\n", *(PUSHORT)&SpecPtr[0]);
361 TRACE("Disk-drive control port address: 0x%x\n", *(PUSHORT)&SpecPtr[2]);
362 TRACE("Head register upper nibble: 0x%x\n", SpecPtr[4]);
363 TRACE("BIOS Vendor-specific: 0x%x\n", SpecPtr[5]);
364 TRACE("IRQ for drive: %u\n", SpecPtr[6]);
365 TRACE("Sector count for multi-sector transfers: %u\n", SpecPtr[7]);
366 TRACE("DMA control: 0x%x\n", SpecPtr[8]);
367 TRACE("Programmed I/O control: 0x%x\n", SpecPtr[9]);
368 TRACE("Drive options: 0x%x\n", *(PUSHORT)&SpecPtr[10]);
369 }
370 }
371 if (Ptr->Size >= 0x42)
372 {
373 TRACE("Signature: 0x%x\n", ((PUSHORT)Ptr)[15]);
374 }
375#endif // DBG
376
377 return TRUE;
378}
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 214 of file pcdisk.c.

215{
216 REGS RegsIn, RegsOut;
217
218 /*
219 * Some BIOSes report that extended disk access functions are not supported
220 * when booting from a CD (e.g. Phoenix BIOS v6.00PG and Insyde BIOS shipping
221 * with Intel Macs). Therefore we just return TRUE if we're booting from a CD
222 * - we can assume that all El Torito capable BIOSes support INT 13 extensions.
223 * We simply detect whether we're booting from CD by checking whether the drive
224 * number is >= 0x8A. It's 0x90 on the Insyde BIOS, and 0x9F on most other BIOSes.
225 */
226 if (DriveNumber >= 0x8A)
227 return TRUE;
228
229 /*
230 * IBM/MS INT 13 Extensions - INSTALLATION CHECK
231 * AH = 41h
232 * BX = 55AAh
233 * DL = drive (80h-FFh)
234 * Return:
235 * CF set on error (extensions not supported)
236 * AH = 01h (invalid function)
237 * CF clear if successful
238 * BX = AA55h if installed
239 * AH = major version of extensions
240 * 01h = 1.x
241 * 20h = 2.0 / EDD-1.0
242 * 21h = 2.1 / EDD-1.1
243 * 30h = EDD-3.0
244 * AL = internal use
245 * CX = API subset support bitmap
246 * DH = extension version (v2.0+ ??? -- not present in 1.x)
247 *
248 * Bitfields for IBM/MS INT 13 Extensions API support bitmap
249 * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
250 * Bit 1, removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported
251 * Bit 2, enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
252 * extended drive parameter table is valid
253 * Bits 3-15 reserved
254 */
255 RegsIn.b.ah = 0x41;
256 RegsIn.w.bx = 0x55AA;
257 RegsIn.b.dl = DriveNumber;
258
259 /* Reset the disk controller */
260 Int386(0x13, &RegsIn, &RegsOut);
261 if (!INT386_SUCCESS(RegsOut))
262 {
263 /* CF set on error (extensions not supported) */
264 return FALSE;
265 }
266
267 if (RegsOut.w.bx != 0xAA55)
268 {
269 /* BX = AA55h if installed */
270 return FALSE;
271 }
272
273#if DBG
274 TRACE("Drive 0x%x: INT 13h Extended version: 0x%02x, API bitmap: 0x%04x\n",
275 DriveNumber, RegsOut.b.ah, RegsOut.w.cx);
276#endif
277 if (!(RegsOut.w.cx & 0x0001))
278 {
279 /*
280 * CX = API subset support bitmap.
281 * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported.
282 */
283 WARN("Drive 0x%x: Suspicious API subset support bitmap 0x%04x\n",
284 DriveNumber, RegsOut.w.cx);
285 return FALSE;
286 }
287
288 return TRUE;
289}
#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 199 of file pcdisk.c.

200{
201 /*
202 * Hard disks use drive numbers >= 0x80 . So if the drive number
203 * indicates a hard disk then return FALSE.
204 * 0x49 is our magic ramdisk drive, so return FALSE for that too.
205 */
206 if ((DriveNumber >= 0x80) || (DriveNumber == 0x49))
207 return FALSE;
208
209 /* The drive is a floppy diskette so return TRUE */
210 return TRUE;
211}

Referenced by DiskGetConfigType(), and PcDiskDriveInit().

◆ DiskResetController()

BOOLEAN DiskResetController ( UCHAR  DriveNumber)

Definition at line 174 of file pcdisk.c.

175{
176 REGS RegsIn, RegsOut;
177
178 WARN("DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber);
179
180 /*
181 * BIOS Int 13h, function 0 - Reset disk system
182 * AH = 00h
183 * DL = drive (if bit 7 is set both hard disks and floppy disks reset)
184 * Return:
185 * AH = status
186 * CF clear if successful
187 * CF set on error
188 */
189 RegsIn.b.ah = 0x00;
190 RegsIn.b.dl = DriveNumber;
191
192 /* Reset the disk controller */
193 Int386(0x13, &RegsIn, &RegsOut);
194
195 return INT386_SUCCESS(RegsOut);
196}

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

◆ InitDriveGeometry()

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

Definition at line 393 of file pcdisk.c.

396{
398 REGS RegsIn, RegsOut;
399 ULONG Cylinders;
400
401 /* Get the extended geometry first */
402 RtlZeroMemory(&DiskDrive->ExtGeometry, sizeof(DiskDrive->ExtGeometry));
403 Success = DiskGetExtendedDriveParameters(DriveNumber, DiskDrive,
404 &DiskDrive->ExtGeometry,
405 sizeof(DiskDrive->ExtGeometry));
406 if (Success)
407 {
408 TRACE("DiskGetExtendedDriveParameters(0x%x) returned:\n"
409 "Cylinders : 0x%x\n"
410 "Heads : 0x%x\n"
411 "Sects/Track: 0x%x\n"
412 "Total Sects: 0x%llx\n"
413 "Bytes/Sect : 0x%x\n",
414 DriveNumber,
415 DiskDrive->ExtGeometry.Cylinders,
416 DiskDrive->ExtGeometry.Heads,
417 DiskDrive->ExtGeometry.SectorsPerTrack,
418 DiskDrive->ExtGeometry.Sectors,
419 DiskDrive->ExtGeometry.BytesPerSector);
420 }
421
422 /* Now try the legacy geometry */
423 RtlZeroMemory(&DiskDrive->Geometry, sizeof(DiskDrive->Geometry));
424
425 /*
426 * BIOS Int 13h, function 08h - Get drive parameters
427 * AH = 08h
428 * DL = drive (bit 7 set for hard disk)
429 * ES:DI = 0000h:0000h to guard against BIOS bugs
430 * Return:
431 * CF set on error
432 * AH = status (07h)
433 * CF clear if successful
434 * AH = 00h
435 * AL = 00h on at least some BIOSes
436 * BL = drive type (AT/PS2 floppies only)
437 * CH = low eight bits of maximum cylinder number
438 * CL = maximum sector number (bits 5-0)
439 * high two bits of maximum cylinder number (bits 7-6)
440 * DH = maximum head number
441 * DL = number of drives
442 * ES:DI -> drive parameter table (floppies only)
443 */
444 RegsIn.b.ah = 0x08;
445 RegsIn.b.dl = DriveNumber;
446 RegsIn.w.es = 0x0000;
447 RegsIn.w.di = 0x0000;
448
449 /* Get drive parameters */
450 Int386(0x13, &RegsIn, &RegsOut);
451 if (!INT386_SUCCESS(RegsOut))
452 {
453 /* We failed, return the result of the previous call (extended geometry) */
454 return Success;
455 }
456 /* OR it with the old result, so that we return TRUE whenever either call succeeded */
457 Success |= TRUE;
458
459 Cylinders = (RegsOut.b.cl & 0xC0) << 2;
460 Cylinders += RegsOut.b.ch;
461 Cylinders++;
462 DiskDrive->Geometry.Cylinders = Cylinders;
463 DiskDrive->Geometry.Heads = RegsOut.b.dh + 1;
464 DiskDrive->Geometry.SectorsPerTrack = RegsOut.b.cl & 0x3F;
465 DiskDrive->Geometry.BytesPerSector = 512; /* Just assume 512 bytes per sector */
466
467 DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
468 DiskDrive->Geometry.Heads *
469 DiskDrive->Geometry.SectorsPerTrack;
470
471 TRACE("Regular Int13h(0x%x) returned:\n"
472 "Cylinders : 0x%x\n"
473 "Heads : 0x%x\n"
474 "Sects/Track: 0x%x\n"
475 "Total Sects: 0x%llx\n"
476 "Bytes/Sect : 0x%x\n",
477 DriveNumber,
478 DiskDrive->Geometry.Cylinders,
479 DiskDrive->Geometry.Heads,
480 DiskDrive->Geometry.SectorsPerTrack,
481 DiskDrive->Geometry.Sectors,
482 DiskDrive->Geometry.BytesPerSector);
483
484 return Success;
485}
unsigned char BOOLEAN
Definition: actypes.h:127
@ 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:292
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 488 of file pcdisk.c.

491{
492 DiskDrive->IsRemovable = DiskIsDriveRemovable(DriveNumber);
493
494 /*
495 * Check to see if it is a fixed disk drive.
496 * If so then check to see if INT 13h extensions work.
497 * If they do then use them, otherwise default back to BIOS calls.
498 */
499 DiskDrive->Int13ExtensionsSupported = DiskInt13ExtensionsSupported(DriveNumber);
500
501 if (!InitDriveGeometry(DriveNumber, DiskDrive))
502 return FALSE;
503
504 TRACE("\n"
505 "DriveNumber: 0x%x\n"
506 "IsRemovable = %s\n"
507 "Int13ExtensionsSupported = %s\n",
508 DriveNumber,
509 DiskDrive->IsRemovable ? "TRUE" : "FALSE",
510 DiskDrive->Int13ExtensionsSupported ? "TRUE" : "FALSE");
511
512 return TRUE;
513}
static BOOLEAN DiskInt13ExtensionsSupported(IN UCHAR DriveNumber)
Definition: pcdisk.c:214
static BOOLEAN InitDriveGeometry(IN UCHAR DriveNumber, IN PPC_DISK_DRIVE DiskDrive)
Definition: pcdisk.c:393

Referenced by PcDiskDriveNumberToDrive().

◆ PcDiskDriveNumberToDrive()

static PPC_DISK_DRIVE PcDiskDriveNumberToDrive ( IN UCHAR  DriveNumber)
inlinestatic

Definition at line 517 of file pcdisk.c.

518{
519#ifdef CACHE_MULTI_DRIVES
520 PPC_DISK_DRIVE DiskDrive;
521
522 ASSERT((0 <= DriveNumber) && (DriveNumber < RTL_NUMBER_OF(PcDiskDrive)));
523
524 /* Retrieve a slot */
525 DiskDrive = &PcDiskDrive[DriveNumber];
526
527 /* If the drive has not been initialized before... */
528 if (!DiskDrive->Initialized)
529 {
530 /* ... try to initialize it now. */
531 if (!PcDiskDriveInit(DriveNumber, DiskDrive))
532 {
533 /*
534 * If we failed, there is no drive at this number
535 * and flag it as such (set its high bit).
536 */
537 DiskDrive->Initialized |= 0x80;
538 return NULL;
539 }
540 DiskDrive->Initialized = TRUE;
541 }
542 else if (DiskDrive->Initialized & 0x80)
543 {
544 /*
545 * The disk failed to be initialized previously, reset its flag to give
546 * it chance to be initialized again later, but just fail for the moment.
547 */
548 DiskDrive->Initialized = FALSE;
549 return NULL;
550 }
551
552 return DiskDrive;
553#else
554 static PC_DISK_DRIVE NewDiskDrive;
555
556 ASSERT((0 <= DriveNumber) && (DriveNumber <= 0xFF));
557
558 /* Update cached information */
559
560 /* If the drive has not been accessed last before... */
561 if ((USHORT)DriveNumber != LastDriveNumber)
562 {
563 /* ... try to (re-)initialize and cache it now. */
564 RtlZeroMemory(&NewDiskDrive, sizeof(NewDiskDrive));
565 if (!PcDiskDriveInit(DriveNumber, &NewDiskDrive))
566 {
567 /*
568 * If we failed, there is no drive at this number.
569 * Keep the last-accessed valid drive cached.
570 */
571 return NULL;
572 }
573 /* We succeeded, cache the drive data */
574 PcDiskDrive = NewDiskDrive;
575 LastDriveNumber = (USHORT)DriveNumber;
576 }
577
578 return &PcDiskDrive;
579#endif /* CACHE_MULTI_DRIVES */
580}
#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:488

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

◆ PcDiskGetCacheableBlockCount()

ULONG PcDiskGetCacheableBlockCount ( UCHAR  DriveNumber)

Definition at line 835 of file pcdisk.c.

836{
837 PPC_DISK_DRIVE DiskDrive;
838
839 DiskDrive = PcDiskDriveNumberToDrive(DriveNumber);
840 if (!DiskDrive)
841 return 1; // Unknown count.
842
843 /*
844 * If LBA is supported then the block size will be 64 sectors (32k).
845 * If not then the block size is the size of one track.
846 */
847 if (DiskDrive->Int13ExtensionsSupported)
848 return 64;
849 else
850 return DiskDrive->Geometry.SectorsPerTrack;
851}
static PPC_DISK_DRIVE PcDiskDriveNumberToDrive(IN UCHAR DriveNumber)
Definition: pcdisk.c:517
ULONG SectorsPerTrack
Number of sectors per track.
Definition: disk.h:27
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 805 of file pcdisk.c.

806{
807 PPC_DISK_DRIVE DiskDrive;
808
809 TRACE("PcDiskGetDriveGeometry(0x%x)\n", DriveNumber);
810
811 DiskDrive = PcDiskDriveNumberToDrive(DriveNumber);
812 if (!DiskDrive)
813 return FALSE;
814
815 /* Try to get the extended geometry first */
816 if (DiskDrive->ExtGeometry.Size == sizeof(DiskDrive->ExtGeometry))
817 {
818 /* Extended geometry has been initialized, return it */
819 Geometry->Cylinders = DiskDrive->ExtGeometry.Cylinders;
820 Geometry->Heads = DiskDrive->ExtGeometry.Heads;
821 Geometry->SectorsPerTrack = DiskDrive->ExtGeometry.SectorsPerTrack;
822 Geometry->BytesPerSector = DiskDrive->ExtGeometry.BytesPerSector;
823 Geometry->Sectors = DiskDrive->ExtGeometry.Sectors;
824 }
825 else
826 /* Fall back to legacy BIOS geometry */
827 {
828 *Geometry = DiskDrive->Geometry;
829 }
830
831 return TRUE;
832}
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:28
ULONG Cylinders
Number of cylinders on the disk.
Definition: disk.h:25
ULONGLONG Sectors
Total number of disk sectors/LBA blocks.
Definition: disk.h:29
ULONG Heads
Number of heads on the disk.
Definition: disk.h:26
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 765 of file pcdisk.c.

770{
771 PPC_DISK_DRIVE DiskDrive;
772
773 TRACE("PcDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u Buffer: 0x%x\n",
774 DriveNumber, SectorNumber, SectorCount, Buffer);
775
776 /* 16-bit BIOS addressing limitation */
777 ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
778
779 DiskDrive = PcDiskDriveNumberToDrive(DriveNumber);
780 if (!DiskDrive)
781 return FALSE;
782
783 if ((DriveNumber >= 0x80) && DiskDrive->Int13ExtensionsSupported)
784 {
785 /* LBA is easy, nothing to calculate. Just do the read. */
786 TRACE("--> Using LBA\n");
787 return PcDiskReadLogicalSectorsLBA(DriveNumber, SectorNumber, SectorCount, Buffer);
788 }
789 else
790 {
791 /* LBA is not supported, default to CHS */
792 TRACE("--> Using CHS\n");
793 return PcDiskReadLogicalSectorsCHS(DriveNumber, DiskDrive, SectorNumber, SectorCount, Buffer);
794 }
795}
ULONG SectorCount
Definition: part_brfr.c:22
static BOOLEAN PcDiskReadLogicalSectorsLBA(IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pcdisk.c:583
static BOOLEAN PcDiskReadLogicalSectorsCHS(IN UCHAR DriveNumber, IN PPC_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pcdisk.c:647

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 647 of file pcdisk.c.

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

Referenced by PcDiskReadLogicalSectors().

◆ PcDiskReadLogicalSectorsLBA()

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

Definition at line 583 of file pcdisk.c.

588{
590 REGS RegsIn, RegsOut;
591 ULONG RetryCount;
592
593 /* Setup disk address packet */
594 RtlZeroMemory(Packet, sizeof(*Packet));
595 Packet->PacketSize = sizeof(*Packet);
596 Packet->Reserved = 0;
597 // Packet->LBABlockCount set in the loop.
598 Packet->TransferBufferOffset = ((ULONG_PTR)Buffer) & 0x0F;
599 Packet->TransferBufferSegment = (USHORT)(((ULONG_PTR)Buffer) >> 4);
600 Packet->LBAStartBlock = SectorNumber;
601
602 /*
603 * BIOS Int 13h, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
604 * Return:
605 * CF clear if successful
606 * AH = 00h
607 * CF set on error
608 * AH = error code
609 * Disk address packet's block count field set to the
610 * number of blocks successfully transferred.
611 */
612 RegsIn.b.ah = 0x42;
613 RegsIn.b.dl = DriveNumber; // Drive number in DL (0 - floppy, 0x80 - harddisk)
614 RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> disk address packet
615 RegsIn.w.si = BIOSCALLBUFOFFSET;
616
617 /* Retry 3 times */
618 for (RetryCount = 0; RetryCount < 3; ++RetryCount)
619 {
620 /* Restore the number of blocks to transfer, since it gets reset
621 * on failure with the number of blocks that were successfully
622 * transferred (and which could be zero). */
623 Packet->LBABlockCount = (USHORT)SectorCount;
624 ASSERT(Packet->LBABlockCount == SectorCount);
625
626 Int386(0x13, &RegsIn, &RegsOut);
627
628 /* If it worked, or if it was a corrected ECC error
629 * and the data is still good, return success */
630 if (INT386_SUCCESS(RegsOut) || (RegsOut.b.ah == 0x11))
631 return TRUE;
632
633 /* It failed, do the next retry */
634 DiskResetController(DriveNumber);
635 }
636
637 /* If we get here then the read failed */
638 DiskError("Disk Read Failed in LBA mode", RegsOut.b.ah);
639 ERR("Disk Read Failed in LBA mode: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u)\n",
640 RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
641 DriveNumber, SectorNumber, SectorCount);
642
643 return FALSE;
644}
_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().

◆ PcDiskDrive

PC_DISK_DRIVE PcDiskDrive
static

Definition at line 129 of file pcdisk.c.

Referenced by PcDiskDriveNumberToDrive().