Пример #1
0
static
BOOLEAN
GetEbdaLocation(
    PULONG BaseAddress,
    PULONG Size)
{
    REGS Regs;

    /* Get the address of the Extended BIOS Data Area (EBDA).
     * Int 15h, AH=C1h
     * SYSTEM - RETURN EXTENDED-BIOS DATA-AREA SEGMENT ADDRESS (PS)
     *
     * Return:
     * CF set on error
     * CF clear if successful
     * ES = segment of data area
     */
    Regs.x.eax = 0x0000C100;
    Int386(0x15, &Regs, &Regs);

    /* If the function fails, there is no EBDA */
    if (!INT386_SUCCESS(Regs))
    {
        return FALSE;
    }

    /* Get Base address and (maximum) size */
    *BaseAddress = (ULONG)Regs.w.es << 4;
    *Size = 0xA0000 - *BaseAddress;
    return TRUE;
}
Пример #2
0
static BOOLEAN
FindPciBios(PPCI_REGISTRY_INFO BusData)
{
    REGS  RegsIn;
    REGS  RegsOut;

    RegsIn.b.ah = 0xB1; /* Subfunction B1h */
    RegsIn.b.al = 0x01; /* PCI BIOS present */

    Int386(0x1A, &RegsIn, &RegsOut);

    if (INT386_SUCCESS(RegsOut) &&
        (RegsOut.d.edx == 0x20494350) &&
        (RegsOut.b.ah == 0))
    {
        TRACE("Found PCI bios\n");

        TRACE("AL: %x\n", RegsOut.b.al);
        TRACE("BH: %x\n", RegsOut.b.bh);
        TRACE("BL: %x\n", RegsOut.b.bl);
        TRACE("CL: %x\n", RegsOut.b.cl);

        BusData->NoBuses = RegsOut.b.cl + 1;
        BusData->MajorRevision = RegsOut.b.bh;
        BusData->MinorRevision = RegsOut.b.bl;
        BusData->HardwareMechanism = RegsOut.b.al;

        return TRUE;
    }

    TRACE("No PCI bios found\n");

    return FALSE;
}
Пример #3
0
BOOLEAN
PcDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
{
    EXTENDED_GEOMETRY ExtGeometry;
    REGS RegsIn, RegsOut;
    ULONG Cylinders;

    TRACE("DiskGetDriveGeometry()\n");

    /* Try to get the extended geometry first */
    ExtGeometry.Size = sizeof(ExtGeometry);
    if (DiskGetExtendedDriveParameters(DriveNumber, &ExtGeometry, ExtGeometry.Size))
    {
        Geometry->Cylinders = ExtGeometry.Cylinders;
        Geometry->Heads = ExtGeometry.Heads;
        Geometry->Sectors = ExtGeometry.SectorsPerTrack;
        Geometry->BytesPerSector = ExtGeometry.BytesPerSector;
        return TRUE;
    }

    /*
     * BIOS Int 13h, function 08h - Get drive parameters
     * AH = 08h
     * DL = drive (bit 7 set for hard disk)
     * ES:DI = 0000h:0000h to guard against BIOS bugs
     * Return:
     * CF set on error
     * AH = status (07h)
     * CF clear if successful
     * AH = 00h
     * AL = 00h on at least some BIOSes
     * BL = drive type (AT/PS2 floppies only)
     * CH = low eight bits of maximum cylinder number
     * CL = maximum sector number (bits 5-0)
     *      high two bits of maximum cylinder number (bits 7-6)
     * DH = maximum head number
     * DL = number of drives
     * ES:DI -> drive parameter table (floppies only)
     */
    RegsIn.b.ah = 0x08;
    RegsIn.b.dl = DriveNumber;
    RegsIn.w.es = 0x0000;
    RegsIn.w.di = 0x0000;

    /* Get drive parameters */
    Int386(0x13, &RegsIn, &RegsOut);
    if (!INT386_SUCCESS(RegsOut))
        return FALSE;

    Cylinders = (RegsOut.b.cl & 0xC0) << 2;
    Cylinders += RegsOut.b.ch;
    Cylinders++;
    Geometry->Cylinders = Cylinders;
    Geometry->Heads = RegsOut.b.dh + 1;
    Geometry->Sectors = RegsOut.b.cl & 0x3F;
    Geometry->BytesPerSector = 512;     /* Just assume 512 bytes per sector */

    return TRUE;
}
Пример #4
0
BOOLEAN DiskResetController(UCHAR DriveNumber)
{
    REGS    RegsIn;
    REGS    RegsOut;

    WARN("DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber);

    // BIOS Int 13h, function 0 - Reset disk system
    // AH = 00h
    // DL = drive (if bit 7 is set both hard disks and floppy disks reset)
    // Return:
    // AH = status
    // CF clear if successful
    // CF set on error
    RegsIn.b.ah = 0x00;
    RegsIn.b.dl = DriveNumber;

    // Reset the disk controller
    Int386(0x13, &RegsIn, &RegsOut);

    return INT386_SUCCESS(RegsOut);
}
Пример #5
0
static
BOOLEAN
GetExtendedMemoryConfiguration(ULONG* pMemoryAtOneMB /* in KB */, ULONG* pMemoryAtSixteenMB /* in 64KB */)
{
    REGS     RegsIn;
    REGS     RegsOut;

    TRACE("GetExtendedMemoryConfiguration()\n");

    *pMemoryAtOneMB = 0;
    *pMemoryAtSixteenMB = 0;

    // Int 15h AX=E801h
    // Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS
    //
    // AX = E801h
    // Return:
    // CF clear if successful
    // AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
    // BX = extended memory above 16M, in 64K blocks
    // CX = configured memory 1M to 16M, in K
    // DX = configured memory above 16M, in 64K blocks
    // CF set on error
    RegsIn.w.ax = 0xE801;
    Int386(0x15, &RegsIn, &RegsOut);

    TRACE("Int15h AX=E801h\n");
    TRACE("AX = 0x%x\n", RegsOut.w.ax);
    TRACE("BX = 0x%x\n", RegsOut.w.bx);
    TRACE("CX = 0x%x\n", RegsOut.w.cx);
    TRACE("DX = 0x%x\n", RegsOut.w.dx);
    TRACE("CF set = %s\n\n", (RegsOut.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");

    if (INT386_SUCCESS(RegsOut))
    {
        // If AX=BX=0000h the use CX and DX
        if (RegsOut.w.ax == 0)
        {
            // Return extended memory size in K
            *pMemoryAtSixteenMB = RegsOut.w.dx;
            *pMemoryAtOneMB = RegsOut.w.cx;
            return TRUE;
        }
        else
        {
            // Return extended memory size in K
            *pMemoryAtSixteenMB = RegsOut.w.bx;
            *pMemoryAtOneMB = RegsOut.w.ax;
            return TRUE;
        }
    }

    // If we get here then Int15 Func E801h didn't work
    // So try Int15 Func 88h
    // Int 15h AH=88h
    // SYSTEM - GET EXTENDED MEMORY SIZE (286+)
    //
    // AH = 88h
    // Return:
    // CF clear if successful
    // AX = number of contiguous KB starting at absolute address 100000h
    // CF set on error
    // AH = status
    // 80h invalid command (PC,PCjr)
    // 86h unsupported function (XT,PS30)
    RegsIn.b.ah = 0x88;
    Int386(0x15, &RegsIn, &RegsOut);

    TRACE("Int15h AH=88h\n");
    TRACE("AX = 0x%x\n", RegsOut.w.ax);
    TRACE("CF set = %s\n\n", (RegsOut.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");

    if (INT386_SUCCESS(RegsOut) && RegsOut.w.ax != 0)
    {
        *pMemoryAtOneMB = RegsOut.w.ax;
        return TRUE;
    }

    // If we get here then Int15 Func 88h didn't work
    // So try reading the CMOS
    WRITE_PORT_UCHAR((PUCHAR)0x70, 0x31);
    *pMemoryAtOneMB = READ_PORT_UCHAR((PUCHAR)0x71);
    *pMemoryAtOneMB = (*pMemoryAtOneMB & 0xFFFF);
    *pMemoryAtOneMB = (*pMemoryAtOneMB << 8);

    TRACE("Int15h Failed\n");
    TRACE("CMOS reports: 0x%x\n", *pMemoryAtOneMB);

    if (*pMemoryAtOneMB != 0)
    {
        return TRUE;
    }

    return FALSE;
}
Пример #6
0
static
ULONG
PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
{
    REGS Regs;
    ULONG MapCount = 0;
    ULONGLONG RealBaseAddress, RealSize;
    TYPE_OF_MEMORY MemoryType;
    ULONG Size;
    ASSERT(PcBiosMapCount == 0);

    TRACE("GetBiosMemoryMap()\n");

    /* Make sure the usable memory is large enough. To do this we check the 16
       bit value at address 0x413 inside the BDA, which gives us the usable size
       in KB */
    Size = (*(PUSHORT)(ULONG_PTR)0x413) * 1024;
    if (Size < MEMORY_MARGIN)
    {
        FrLdrBugCheckWithMessage(
            MEMORY_INIT_FAILURE,
            __FILE__,
            __LINE__,
            "The BIOS reported a usable memory range up to 0x%x, which is too small!\n\n"
            "If you see this, please report to the ReactOS team!",
            Size);
    }

    /* Get the address of the Extended BIOS Data Area (EBDA).
     * Int 15h, AH=C1h
     * SYSTEM - RETURN EXTENDED-BIOS DATA-AREA SEGMENT ADDRESS (PS)
     *
     * Return:
     * CF set on error
     * CF clear if successful
     * ES = segment of data area
     */
    Regs.x.eax = 0x0000C100;
    Int386(0x15, &Regs, &Regs);

    /* If the function fails, there is no EBDA */
    if (INT386_SUCCESS(Regs))
    {
        /* Check if this is high enough */
        ULONG EbdaBase = (ULONG)Regs.w.es << 4;
        if (EbdaBase < MEMORY_MARGIN)
        {
            FrLdrBugCheckWithMessage(
                MEMORY_INIT_FAILURE,
                __FILE__,
                __LINE__,
                "The location of your EBDA is 0x%lx, which is too low!\n\n"
                "If you see this, please report to the ReactOS team!",
                EbdaBase);
        }

        /* Calculate the (max) size of the EBDA */
        Size = 0xA0000 - EbdaBase;

        /* Add the descriptor */
        MapCount = AddMemoryDescriptor(PcMemoryMap,
                                       MAX_BIOS_DESCRIPTORS,
                                       (EbdaBase / MM_PAGE_SIZE),
                                       (Size / MM_PAGE_SIZE),
                                       LoaderFirmwarePermanent);
    }

    /* Int 15h AX=E820h
     * Newer BIOSes - GET SYSTEM MEMORY MAP
     *
     * AX = E820h
     * EAX = 0000E820h
     * EDX = 534D4150h ('SMAP')
     * EBX = continuation value or 00000000h to start at beginning of map
     * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
     * ES:DI -> buffer for result
     * Return:
     * CF clear if successful
     * EAX = 534D4150h ('SMAP')
     * ES:DI buffer filled
     * EBX = next offset from which to copy or 00000000h if all done
     * ECX = actual length returned in bytes
     * CF set on error
     * AH = error code (86h)
     */
    Regs.x.ebx = 0x00000000;

    while (PcBiosMapCount < MAX_BIOS_DESCRIPTORS)
    {
        /* Setup the registers for the BIOS call */
        Regs.x.eax = 0x0000E820;
        Regs.x.edx = 0x534D4150; /* ('SMAP') */
        /* Regs.x.ebx = 0x00000001;  Continuation value already set */
        Regs.x.ecx = sizeof(BIOS_MEMORY_MAP);
        Regs.w.es = BIOSCALLBUFSEGMENT;
        Regs.w.di = BIOSCALLBUFOFFSET;
        Int386(0x15, &Regs, &Regs);

        TRACE("Memory Map Entry %d\n", PcBiosMapCount);
        TRACE("Int15h AX=E820h\n");
        TRACE("EAX = 0x%x\n", Regs.x.eax);
        TRACE("EBX = 0x%x\n", Regs.x.ebx);
        TRACE("ECX = 0x%x\n", Regs.x.ecx);
        TRACE("CF set = %s\n", (Regs.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");

        /* If the BIOS didn't return 'SMAP' in EAX then
         * it doesn't support this call. If CF is set, we're done */
        if (Regs.x.eax != 0x534D4150 || !INT386_SUCCESS(Regs))
        {
            break;
        }

        /* Copy data to global buffer */
        RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, Regs.x.ecx);

        TRACE("BaseAddress: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
        TRACE("Length: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].Length);
        TRACE("Type: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Type);
        TRACE("Reserved: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Reserved);
        TRACE("\n");

        /* Check if this is free memory */
        if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryUsable)
        {
            MemoryType = LoaderFree;

            /* Align up base of memory area */
            RealBaseAddress = PcBiosMemoryMap[PcBiosMapCount].BaseAddress & ~(MM_PAGE_SIZE - 1ULL);

            /* Calculate the length after aligning the base */
            RealSize = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
                       PcBiosMemoryMap[PcBiosMapCount].Length - RealBaseAddress;
            RealSize = (RealSize + MM_PAGE_SIZE - 1) & ~(MM_PAGE_SIZE - 1ULL);
        }
        else
        {
            if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryReserved)
                MemoryType = LoaderFirmwarePermanent;
            else
                MemoryType = LoaderSpecialMemory;

            /* Align down base of memory area */
            RealBaseAddress = PcBiosMemoryMap[PcBiosMapCount].BaseAddress & ~(MM_PAGE_SIZE - 1ULL);
            /* Calculate the length after aligning the base */
            RealSize = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
                       PcBiosMemoryMap[PcBiosMapCount].Length - RealBaseAddress;
            RealSize = (RealSize + MM_PAGE_SIZE - 1) & ~(MM_PAGE_SIZE - 1ULL);
        }

        /* Check if we can add this descriptor */
        if ((RealSize >= MM_PAGE_SIZE) && (MapCount < MaxMemoryMapSize))
        {
            /* Add the descriptor */
            MapCount = AddMemoryDescriptor(PcMemoryMap,
                                           MAX_BIOS_DESCRIPTORS,
                                           (PFN_NUMBER)(RealBaseAddress / MM_PAGE_SIZE),
                                           (PFN_NUMBER)(RealSize / MM_PAGE_SIZE),
                                           MemoryType);
        }

        PcBiosMapCount++;

        /* If the continuation value is zero or the
         * carry flag is set then this was
         * the last entry so we're done */
        if (Regs.x.ebx == 0x00000000)
        {
            TRACE("End Of System Memory Map!\n\n");
            break;
        }

    }

    return MapCount;
}
Пример #7
0
BOOLEAN DiskGetExtendedDriveParameters(UCHAR DriveNumber, PVOID Buffer, USHORT BufferSize)
{
    REGS RegsIn, RegsOut;
    PUSHORT Ptr = (PUSHORT)(BIOSCALLBUFFER);

    TRACE("DiskGetExtendedDriveParameters()\n");

    if (!DiskInt13ExtensionsSupported(DriveNumber))
        return FALSE;

    /* Initialize transfer buffer */
    *Ptr = BufferSize;

    /*
     * BIOS Int 13h, function 48h - Get drive parameters
     * AH = 48h
     * DL = drive (bit 7 set for hard disk)
     * DS:SI = result buffer
     * Return:
     * CF set on error
     * AH = status (07h)
     * CF clear if successful
     * AH = 00h
     * DS:SI -> result buffer
     */
    RegsIn.b.ah = 0x48;
    RegsIn.b.dl = DriveNumber;
    RegsIn.x.ds = BIOSCALLBUFSEGMENT;   // DS:SI -> result buffer
    RegsIn.w.si = BIOSCALLBUFOFFSET;

    /* Get drive parameters */
    Int386(0x13, &RegsIn, &RegsOut);
    if (!INT386_SUCCESS(RegsOut))
        return FALSE;

    memcpy(Buffer, Ptr, BufferSize);

#if DBG
    TRACE("size of buffer:                          %x\n", Ptr[0]);
    TRACE("information flags:                       %x\n", Ptr[1]);
    TRACE("number of physical cylinders on drive:   %u\n", *(PULONG)&Ptr[2]);
    TRACE("number of physical heads on drive:       %u\n", *(PULONG)&Ptr[4]);
    TRACE("number of physical sectors per track:    %u\n", *(PULONG)&Ptr[6]);
    TRACE("total number of sectors on drive:        %I64u\n", *(unsigned long long*)&Ptr[8]);
    TRACE("bytes per sector:                        %u\n", Ptr[12]);
    if (Ptr[0] >= 0x1e)
    {
        TRACE("EED configuration parameters:            %x:%x\n", Ptr[13], Ptr[14]);
        if (Ptr[13] != 0xffff && Ptr[14] != 0xffff)
        {
           PUCHAR SpecPtr = (PUCHAR)(ULONG_PTR)((Ptr[13] << 4) + Ptr[14]);
           TRACE("SpecPtr:                                 %x\n", SpecPtr);
           TRACE("physical I/O port base address:          %x\n", *(PUSHORT)&SpecPtr[0]);
           TRACE("disk-drive control port address:         %x\n", *(PUSHORT)&SpecPtr[2]);
           TRACE("drive flags:                             %x\n", SpecPtr[4]);
           TRACE("proprietary information:                 %x\n", SpecPtr[5]);
           TRACE("IRQ for drive:                           %u\n", SpecPtr[6]);
           TRACE("sector count for multi-sector transfers: %u\n", SpecPtr[7]);
           TRACE("DMA control:                             %x\n", SpecPtr[8]);
           TRACE("programmed I/O control:                  %x\n", SpecPtr[9]);
           TRACE("drive options:                           %x\n", *(PUSHORT)&SpecPtr[10]);
        }
    }
    if (Ptr[0] >= 0x42)
    {
        TRACE("signature:                             %x\n", Ptr[15]);
    }
#endif

    return TRUE;
}
Пример #8
0
static BOOLEAN DiskInt13ExtensionsSupported(UCHAR DriveNumber)
{
    static UCHAR LastDriveNumber = 0xff;
    static BOOLEAN LastSupported;
    REGS RegsIn, RegsOut;

    TRACE("DiskInt13ExtensionsSupported()\n");

    if (DriveNumber == LastDriveNumber)
    {
        TRACE("Using cached value %s for drive 0x%x\n",
              LastSupported ? "TRUE" : "FALSE", DriveNumber);
        return LastSupported;
    }

    /*
     * Some BIOSes report that extended disk access functions are not supported
     * when booting from a CD (e.g. Phoenix BIOS v6.00PG and Insyde BIOS shipping
     * with Intel Macs). Therefore we just return TRUE if we're booting from a CD -
     * we can assume that all El Torito capable BIOSes support INT 13 extensions.
     * We simply detect whether we're booting from CD by checking whether the drive
     * number is >= 0x8A. It's 0x90 on the Insyde BIOS, and 0x9F on most other BIOSes.
     */
    if (DriveNumber >= 0x8A)
    {
        LastSupported = TRUE;
        return TRUE;
    }

    LastDriveNumber = DriveNumber;

    /*
     * IBM/MS INT 13 Extensions - INSTALLATION CHECK
     * AH = 41h
     * BX = 55AAh
     * DL = drive (80h-FFh)
     * Return:
     * CF set on error (extensions not supported)
     * AH = 01h (invalid function)
     * CF clear if successful
     * BX = AA55h if installed
     * AH = major version of extensions
     * 01h = 1.x
     * 20h = 2.0 / EDD-1.0
     * 21h = 2.1 / EDD-1.1
     * 30h = EDD-3.0
     * AL = internal use
     * CX = API subset support bitmap
     * DH = extension version (v2.0+ ??? -- not present in 1.x)
     *
     * Bitfields for IBM/MS INT 13 Extensions API support bitmap
     * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
     * Bit 1, removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported
     * Bit 2, enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
     *        extended drive parameter table is valid
     * Bits 3-15 reserved
     */
    RegsIn.b.ah = 0x41;
    RegsIn.w.bx = 0x55AA;
    RegsIn.b.dl = DriveNumber;

    /* Reset the disk controller */
    Int386(0x13, &RegsIn, &RegsOut);

    if (!INT386_SUCCESS(RegsOut))
    {
        /* CF set on error (extensions not supported) */
        LastSupported = FALSE;
        return FALSE;
    }

    if (RegsOut.w.bx != 0xAA55)
    {
        /* BX = AA55h if installed */
        LastSupported = FALSE;
        return FALSE;
    }

    if (!(RegsOut.w.cx & 0x0001))
    {
        /*
         * CX = API subset support bitmap.
         * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported.
         */
        DbgPrint("Suspicious API subset support bitmap 0x%x on device 0x%lx\n",
                 RegsOut.w.cx, DriveNumber);
        LastSupported = FALSE;
        return FALSE;
    }

    LastSupported = TRUE;
    return TRUE;
}
Пример #9
0
static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
{
    UCHAR PhysicalSector;
    UCHAR PhysicalHead;
    ULONG PhysicalTrack;
    GEOMETRY DriveGeometry;
    ULONG NumberOfSectorsToRead;
    REGS RegsIn, RegsOut;
    ULONG RetryCount;

    TRACE("PcDiskReadLogicalSectorsCHS()\n");

    /* Get the drive geometry */
    if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry) ||
        DriveGeometry.Sectors == 0 ||
        DriveGeometry.Heads == 0)
    {
        return FALSE;
    }

    while (SectorCount)
    {
        /*
         * Calculate the physical disk offsets.
         * Note: DriveGeometry.Sectors < 64
         */
        PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.Sectors);
        PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
        PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);

        /* Calculate how many sectors we need to read this round */
        if (PhysicalSector > 1)
        {
            if (SectorCount >= (DriveGeometry.Sectors - (PhysicalSector - 1)))
                NumberOfSectorsToRead = (DriveGeometry.Sectors - (PhysicalSector - 1));
            else
                NumberOfSectorsToRead = SectorCount;
        }
        else
        {
            if (SectorCount >= DriveGeometry.Sectors)
                NumberOfSectorsToRead = DriveGeometry.Sectors;
            else
                NumberOfSectorsToRead = SectorCount;
        }

        /* Make sure the read is within the geometry boundaries */
        if ((PhysicalHead >= DriveGeometry.Heads) ||
            (PhysicalTrack >= DriveGeometry.Cylinders) ||
            ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
            (PhysicalSector > DriveGeometry.Sectors))
        {
            DiskError("Disk read exceeds drive geometry limits.", 0);
            return FALSE;
        }

        /*
         * BIOS Int 13h, function 2 - Read Disk Sectors
         * AH = 02h
         * AL = number of sectors to read (must be nonzero)
         * CH = low eight bits of cylinder number
         * CL = sector number 1-63 (bits 0-5)
         *      high two bits of cylinder (bits 6-7, hard disk only)
         * DH = head number
         * DL = drive number (bit 7 set for hard disk)
         * ES:BX -> data buffer
         * Return:
         * CF set on error
         * if AH = 11h (corrected ECC error), AL = burst length
         * CF clear if successful
         * AH = status
         * AL = number of sectors transferred
         *  (only valid if CF set for some BIOSes)
         */
        RegsIn.b.ah = 0x02;
        RegsIn.b.al = (UCHAR)NumberOfSectorsToRead;
        RegsIn.b.ch = (PhysicalTrack & 0xFF);
        RegsIn.b.cl = (UCHAR)(PhysicalSector + ((PhysicalTrack & 0x300) >> 2));
        RegsIn.b.dh = PhysicalHead;
        RegsIn.b.dl = DriveNumber;
        RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
        RegsIn.w.bx = ((ULONG_PTR)Buffer) & 0x0F;

        /* Perform the read. Retry 3 times. */
        for (RetryCount=0; RetryCount<3; RetryCount++)
        {
            Int386(0x13, &RegsIn, &RegsOut);

            /* If it worked break out */
            if (INT386_SUCCESS(RegsOut))
            {
                break;
            }
            /* If it was a corrected ECC error then the data is still good */
            else if (RegsOut.b.ah == 0x11)
            {
                break;
            }
            /* If it failed the do the next retry */
            else
            {
                DiskResetController(DriveNumber);
                continue;
            }
        }

        /* If we retried 3 times then fail */
        if (RetryCount >= 3)
        {
            ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x\n", RegsOut.b.ah);
            return FALSE;
        }

        // I have learned that not all BIOSes return
        // the sector read count in the AL register (at least mine doesn't)
        // even if the sectors were read correctly. So instead
        // of checking the sector read count we will rely solely
        // on the carry flag being set on error

        Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
        SectorCount -= NumberOfSectorsToRead;
        SectorNumber += NumberOfSectorsToRead;
    }

    return TRUE;
}
Пример #10
0
static BOOLEAN PcDiskReadLogicalSectorsLBA(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
{
    REGS RegsIn, RegsOut;
    ULONG RetryCount;
    PI386_DISK_ADDRESS_PACKET Packet = (PI386_DISK_ADDRESS_PACKET)(BIOSCALLBUFFER);

    TRACE("PcDiskReadLogicalSectorsLBA() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n", DriveNumber, SectorNumber, SectorCount, Buffer);
    ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);

    /* Setup disk address packet */
    RtlZeroMemory(Packet, sizeof(*Packet));
    Packet->PacketSize = sizeof(*Packet);
    Packet->Reserved = 0;
    Packet->LBABlockCount = (USHORT)SectorCount;
    ASSERT(Packet->LBABlockCount == SectorCount);
    Packet->TransferBufferOffset = ((ULONG_PTR)Buffer) & 0x0F;
    Packet->TransferBufferSegment = (USHORT)(((ULONG_PTR)Buffer) >> 4);
    Packet->LBAStartBlock = SectorNumber;

    /*
     * BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
     * Return:
     * CF clear if successful
     * AH = 00h
     * CF set on error
     * AH = error code
     * Disk address packet's block count field set to the
     * number of blocks successfully transferred.
     */
    RegsIn.b.ah = 0x42;                 // Subfunction 42h
    RegsIn.b.dl = DriveNumber;          // Drive number in DL (0 - floppy, 0x80 - harddisk)
    RegsIn.x.ds = BIOSCALLBUFSEGMENT;   // DS:SI -> disk address packet
    RegsIn.w.si = BIOSCALLBUFOFFSET;

    /* Retry 3 times */
    for (RetryCount=0; RetryCount<3; RetryCount++)
    {
        Int386(0x13, &RegsIn, &RegsOut);

        /* If it worked return TRUE */
        if (INT386_SUCCESS(RegsOut))
        {
            return TRUE;
        }
        /* If it was a corrected ECC error then the data is still good */
        else if (RegsOut.b.ah == 0x11)
        {
            return TRUE;
        }
        /* If it failed then do the next retry */
        else
        {
            DiskResetController(DriveNumber);
            continue;
        }
    }

    /* If we get here then the read failed */
    ERR("Disk Read Failed in LBA mode: %x (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n", RegsOut.b.ah, DriveNumber, SectorNumber, SectorCount);

    return FALSE;
}
Пример #11
0
static
ULONG
PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
{
    REGS Regs;
    ULONGLONG RealBaseAddress, EndAddress, RealSize;
    TYPE_OF_MEMORY MemoryType;
    ULONG Size, RequiredSize;
    ASSERT(PcBiosMapCount == 0);

    TRACE("GetBiosMemoryMap()\n");

    /* Make sure the usable memory is large enough. To do this we check the 16
       bit value at address 0x413 inside the BDA, which gives us the usable size
       in KB */
    Size = (*(PUSHORT)(ULONG_PTR)0x413) * 1024;
    RequiredSize = FREELDR_BASE + FrLdrImageSize + PAGE_SIZE;
    if (Size < RequiredSize)
    {
        FrLdrBugCheckWithMessage(
            MEMORY_INIT_FAILURE,
            __FILE__,
            __LINE__,
            "The BIOS reported a usable memory range up to 0x%x, which is too small!\n"
            "Required size is 0x%x\n\n"
            "If you see this, please report to the ReactOS team!",
            Size, RequiredSize);
    }

    /* Int 15h AX=E820h
     * Newer BIOSes - GET SYSTEM MEMORY MAP
     *
     * AX = E820h
     * EAX = 0000E820h
     * EDX = 534D4150h ('SMAP')
     * EBX = continuation value or 00000000h to start at beginning of map
     * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
     * ES:DI -> buffer for result
     * Return:
     * CF clear if successful
     * EAX = 534D4150h ('SMAP')
     * ES:DI buffer filled
     * EBX = next offset from which to copy or 00000000h if all done
     * ECX = actual length returned in bytes
     * CF set on error
     * AH = error code (86h)
     */
    Regs.x.ebx = 0x00000000;

    while (PcBiosMapCount < MAX_BIOS_DESCRIPTORS)
    {
        /* Setup the registers for the BIOS call */
        Regs.x.eax = 0x0000E820;
        Regs.x.edx = 0x534D4150; /* ('SMAP') */
        /* Regs.x.ebx = 0x00000001;  Continuation value already set */
        Regs.x.ecx = sizeof(BIOS_MEMORY_MAP);
        Regs.w.es = BIOSCALLBUFSEGMENT;
        Regs.w.di = BIOSCALLBUFOFFSET;
        Int386(0x15, &Regs, &Regs);

        TRACE("Memory Map Entry %d\n", PcBiosMapCount);
        TRACE("Int15h AX=E820h\n");
        TRACE("EAX = 0x%x\n", Regs.x.eax);
        TRACE("EBX = 0x%x\n", Regs.x.ebx);
        TRACE("ECX = 0x%x\n", Regs.x.ecx);
        TRACE("CF set = %s\n", (Regs.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");

        /* If the BIOS didn't return 'SMAP' in EAX then
         * it doesn't support this call. If CF is set, we're done */
        if (Regs.x.eax != 0x534D4150 || !INT386_SUCCESS(Regs))
        {
            break;
        }

        /* Copy data to global buffer */
        RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, Regs.x.ecx);

        TRACE("BaseAddress: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
        TRACE("Length: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].Length);
        TRACE("Type: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Type);
        TRACE("Reserved: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Reserved);
        TRACE("\n");

        /* Check if this is free memory */
        if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryUsable)
        {
            MemoryType = LoaderFree;

            /* Align up base of memory range */
            RealBaseAddress = ALIGN_UP_BY(PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
                                          PAGE_SIZE);

            /* Calculate aligned EndAddress */
            EndAddress = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
                         PcBiosMemoryMap[PcBiosMapCount].Length;
            EndAddress = ALIGN_DOWN_BY(EndAddress, PAGE_SIZE);

            /* Check if there is anything left */
            if (EndAddress <= RealBaseAddress)
            {
                /* This doesn't span any page, so continue with next range */
                continue;
            }

            /* Calculate the length of the aligned range */
            RealSize = EndAddress - RealBaseAddress;
        }
        else
        {
            if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryReserved)
                MemoryType = LoaderFirmwarePermanent;
            else
                MemoryType = LoaderSpecialMemory;

            /* Align down base of memory area */
            RealBaseAddress = ALIGN_DOWN_BY(PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
                                            PAGE_SIZE);

            /* Calculate the length after aligning the base */
            RealSize = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
                       PcBiosMemoryMap[PcBiosMapCount].Length - RealBaseAddress;
            RealSize = ALIGN_UP_BY(RealSize, PAGE_SIZE);
        }

        /* Check if we can add this descriptor */
        if ((RealSize >= MM_PAGE_SIZE) && (PcMapCount < MaxMemoryMapSize))
        {
            /* Add the descriptor */
            PcMapCount = AddMemoryDescriptor(PcMemoryMap,
                                           MAX_BIOS_DESCRIPTORS,
                                           (PFN_NUMBER)(RealBaseAddress / MM_PAGE_SIZE),
                                           (PFN_NUMBER)(RealSize / MM_PAGE_SIZE),
                                           MemoryType);
        }

        PcBiosMapCount++;

        /* If the continuation value is zero or the
         * carry flag is set then this was
         * the last entry so we're done */
        if (Regs.x.ebx == 0x00000000)
        {
            TRACE("End Of System Memory Map!\n\n");
            break;
        }
    }

    TRACE("GetBiosMemoryMap end, PcBiosMapCount = %ld\n", PcBiosMapCount);
    return PcBiosMapCount;
}