biosint13.c

来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 1,444 行 · 第 1/4 页

C
1,444
字号
    DEBUG ((D_INIT, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n",Drive->Number,CarryFlag,Regs.h.AH));    
    if (CarryFlag || Regs.h.AH != 0x00) {
        Drive->ErrorCode = Regs.h.AH;
        SetMem(&Drive->Parameters, sizeof(Drive->Parameters), 0xaf);
        return FALSE;   
    } 
   
    //
    // We only have one buffer < 1MB, so copy into our instance data
    //
    CopyMem (
        &Drive->Parameters, 
        &GlobalLegacyDriverUnder1MB->Parameters,
        sizeof(Drive->Parameters)
        );    

    if (Drive->ATAPI_Floppy) {

        //
        // Sense Media Type
        //

        Regs.h.AH = 0x20;
        Regs.h.DL = Drive->Number;
        CarryFlag = Int86(0x13, &Regs);
        DEBUG ((D_INIT, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n",Drive->Number,CarryFlag,Regs.h.AL));    
        if (CarryFlag) {

            //
            // Media not present or unknown media present
            //

            if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
                Drive->MaxHead = (UINT8)(Drive->Parameters.MaxHeads - 1);
                Drive->MaxSector = (UINT8)Drive->Parameters.SectorsPerTrack;
                ASSERT(Drive->MaxSector != 0);
                Drive->MaxCylinder = (UINT16)Drive->Parameters.MaxCylinders - 1;
            } else {
                Drive->MaxHead = 0;
                Drive->MaxSector = 1;
                Drive->MaxCylinder = 0;
            }

        } else {

            //
            // Media Present
            //

            switch(Regs.h.AL) {
            case 0x03 :         // 720 KB
                Drive->MaxHead = 1;
                Drive->MaxSector = 9;
                Drive->MaxCylinder = 79;
                break;
            case 0x04 :         // 1.44MB
                Drive->MaxHead = 1;
                Drive->MaxSector = 18;
                Drive->MaxCylinder = 79;
                break;
            case 0x06 :         // 2.88MB
                Drive->MaxHead = 1;
                Drive->MaxSector = 36;
                Drive->MaxCylinder = 79;
                break;
            case 0x0C :         // 360 KB
                Drive->MaxHead = 1;
                Drive->MaxSector = 9;
                Drive->MaxCylinder = 39;
                break;
            case 0x0D :         // 1.2 MB
                Drive->MaxHead = 1;
                Drive->MaxSector = 15;
                Drive->MaxCylinder = 79;
                break;
            case 0x0E :         // Toshiba 3 mode
            case 0x0F :         // NEC 3 mode
            case 0x10 :         // Default Media
                if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
                    Drive->MaxHead = (UINT8)(Drive->Parameters.MaxHeads - 1);
                    Drive->MaxSector = (UINT8)Drive->Parameters.SectorsPerTrack;
                    ASSERT(Drive->MaxSector != 0);
                    Drive->MaxCylinder = (UINT16)Drive->Parameters.MaxCylinders - 1;
                } else {
                    Drive->MaxHead = 0;
                    Drive->MaxSector = 1;
                    Drive->MaxCylinder = 0;
                }
                break;
            default :         // Unknown media type.
                Drive->MaxHead = 0;
                Drive->MaxSector = 1;
                Drive->MaxCylinder = 0;
                break;
            }
        }
        Drive->Parameters.PhysicalSectors = (Drive->MaxHead + 1) * Drive->MaxSector * (Drive->MaxCylinder + 1);
        Drive->Parameters.BytesPerSector = 512;
    }

    //
    // This data comes from the BIOS so it may not allways be valid
    //  since the BIOS may reuse this buffer for future accesses
    // 
    PointerMath = _FP_SEG(Drive->Parameters.FDPT) << 4;
    PointerMath += _FP_OFF(Drive->Parameters.FDPT);
    Drive->FDPTPointer = (VOID *)PointerMath;
        
    return TRUE;
}   

//
// Block IO Routines
//

EFI_STATUS
EDD30BiosReadBlocks (
    IN  EFI_BLOCK_IO        *This,
    IN  UINT32              MediaId,
    IN  EFI_LBA             LBA,
    IN  UINTN               BufferSize,
    OUT VOID                *Buffer
    )
{
    EFI_BLOCK_IO_MEDIA          *Media;
    BIOS_BLK_IO_DEV             *BiosBlkIoDev;  
    EDD_DEVICE_ADDRESS_PACKET   *AddressPacket; // I exist only for readability
    IA32_RegisterSet_t          Regs;
    UINT64                      TransferBuffer;
    UINTN                       NumberOfBlocks;
    UINTN                       TransferByteSize;
    UINTN                       BlockSize;
    BIOS_LEGACY_DRIVE           *Bios;
    UINTN                       CarryFlag;
    UINTN                       MaxTransferBlocks;
    EFI_BLOCK_IO *BlkIo;

    Media = This->Media;
    BlockSize = Media->BlockSize;

    //
    //Check buffer alignment
    //
    if((Media->IoAlign > 1) && ((UINTN)Buffer & (UINTN)(Media->IoAlign -1 ))){
      return EFI_INVALID_PARAMETER;
    }
    
    if (MediaId != Media->MediaId) {    
        return EFI_MEDIA_CHANGED;
    }

    if (LBA > Media->LastBlock) {
        return EFI_INVALID_PARAMETER;
    }

    if ((LBA + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
        return EFI_INVALID_PARAMETER;
    }

    if (BufferSize % BlockSize != 0) {
        return EFI_BAD_BUFFER_SIZE;
    }

    if (Buffer == NULL) {    
        return EFI_INVALID_PARAMETER;
    }

    if (BufferSize == 0 ) {    
        return EFI_SUCCESS;
    }

    BiosBlkIoDev = BIOS_BLK_IO_FROM_THIS (This);
    AddressPacket = GlobalEDDBufferUnder1MB; 

    MaxTransferBlocks = MAX_EDD11_XFER/BlockSize;

    TransferBuffer = (UINT64)Buffer;
    for (;BufferSize > 0;) {
        NumberOfBlocks = BufferSize/BlockSize;
        NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks; // Max transfer MaxTransferBlocks
    
        AddressPacket->PacketSizeInBytes = sizeof(EDD_DEVICE_ADDRESS_PACKET); 
        AddressPacket->Zero = 0;
        AddressPacket->NumberOfBlocks = (UINT8)NumberOfBlocks;
        AddressPacket->Zero2 = 0; 
        AddressPacket->SegOffset = 0xffffffff;
        AddressPacket->LBA = (UINT64)LBA;
        AddressPacket->TransferBuffer = TransferBuffer;
    
        Regs.h.AH = 0x42;
        Regs.h.DL = BiosBlkIoDev->Bios.Number;
        Regs.x.SI = _FP_OFF (AddressPacket);
        Regs.x.DS = _FP_SEG (AddressPacket);
    
        CarryFlag = Int86 (0x13, &Regs);
        DEBUG ((D_BLKIO_ULTRA, "EDD30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n",BiosBlkIoDev->Bios.Number,CarryFlag,Regs.h.AH));    

        Media->MediaPresent = TRUE;
        if (CarryFlag) {
            //
            // Return Error Status
            //

            BiosBlkIoDev->Bios.ErrorCode = Regs.h.AH;
            if (BiosBlkIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
                Media->MediaId++;
                Bios = &BiosBlkIoDev->Bios;
                if (Int13GetDeviceParameters(Bios)) {
                    if (Int13Extensions (Bios)) {
                        Media->LastBlock = (EFI_LBA)Bios->Parameters.PhysicalSectors - 1;
                        Media->BlockSize = (UINT32)Bios->Parameters.BytesPerSector;
                    } else {
                        //
                        // Legacy Interfaces
                        //
                        Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
                        Media->BlockSize = 512;
                    }
                    Media->ReadOnly = FALSE;
                    BS->HandleProtocol (BiosBlkIoDev->Handle, &BlockIoProtocol, (VOID **)&BlkIo);
                    BS->ReinstallProtocolInterface (BiosBlkIoDev->Handle, &BlockIoProtocol, BlkIo, BlkIo);
                    return EFI_MEDIA_CHANGED;
                }
            } else if (BiosBlkIoDev->Bios.ErrorCode == BIOS_DRIVE_TIMEOUT &&
                       Media->RemovableMedia) {
              //
              // Treat this case as NO_MEDIA
              //
              Media->MediaPresent = FALSE;
              BS->HandleProtocol (BiosBlkIoDev->Handle, &BlockIoProtocol, (VOID **)&BlkIo);
              BS->ReinstallProtocolInterface (BiosBlkIoDev->Handle, &BlockIoProtocol, BlkIo, BlkIo);
              return EFI_NO_MEDIA;
            }

            if (Media->RemovableMedia) {
                Media->MediaPresent = FALSE;
            }

            return EFI_DEVICE_ERROR;
        } 

        TransferByteSize = NumberOfBlocks * BlockSize;
        BufferSize = BufferSize - TransferByteSize; 
        TransferBuffer += TransferByteSize;
        LBA += NumberOfBlocks;
    }
    
    return EFI_SUCCESS;
}

         
EFI_STATUS
EDD30BiosWriteBlocks (
    IN  EFI_BLOCK_IO        *This,
    IN  UINT32              MediaId,
    IN  EFI_LBA             LBA,
    IN  UINTN               BufferSize,
    OUT VOID                *Buffer
    )
{
    EFI_BLOCK_IO_MEDIA          *Media;
    BIOS_BLK_IO_DEV             *BiosBlkIoDev;  
    EDD_DEVICE_ADDRESS_PACKET   *AddressPacket; // I exist only for readability
    IA32_RegisterSet_t          Regs;
    UINT64                      TransferBuffer;
    UINTN                       NumberOfBlocks;
    UINTN                       TransferByteSize;
    UINTN                       BlockSize;    
    BIOS_LEGACY_DRIVE           *Bios;
    UINTN                       CarryFlag;
    UINTN                       MaxTransferBlocks;
    EFI_BLOCK_IO *BlkIo;

    Media = This->Media;
    BlockSize = Media->BlockSize;

    //
    //Check buffer alignment
    //
    if((Media->IoAlign > 1) && ((UINTN)Buffer & (UINTN)(Media->IoAlign -1 ))){
      return EFI_INVALID_PARAMETER;
    }

    if (MediaId != Media->MediaId) {    
        return EFI_MEDIA_CHANGED;
    }
    
    if (LBA > Media->LastBlock) {
        return EFI_DEVICE_ERROR;
    }

    if ((LBA + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
        return EFI_INVALID_PARAMETER;
    }

    if (BufferSize % BlockSize != 0) {
        return EFI_BAD_BUFFER_SIZE;
    }

    if (Buffer == NULL) {    
        return EFI_INVALID_PARAMETER;
    }

    if (BufferSize == 0 ) {    
        return EFI_SUCCESS;
    }

    BiosBlkIoDev = BIOS_BLK_IO_FROM_THIS (This);
    AddressPacket = GlobalEDDBufferUnder1MB; 
    
    MaxTransferBlocks = MAX_EDD11_XFER/BlockSize;

    TransferBuffer = (UINT64)Buffer;
    for (;BufferSize > 0;) {
        NumberOfBlocks = BufferSize/BlockSize;
        NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks; // Max transfer MaxTransferBlocks
        AddressPacket->PacketSizeInBytes = sizeof(EDD_DEVICE_ADDRESS_PACKET); 
        AddressPacket->Zero = 0;
        AddressPacket->NumberOfBlocks = (UINT8)NumberOfBlocks;
        AddressPacket->Zero2 = 0; 
        AddressPacket->SegOffset = 0xffffffff;
        AddressPacket->LBA = (UINT64)LBA;
        AddressPacket->TransferBuffer = TransferBuffer;
    
        Regs.h.AH = 0x43;
        Regs.h.AL = 0x00; // Write Verify Off
        Regs.h.DL = BiosBlkIoDev->Bios.Number;
        Regs.x.SI = _FP_OFF (AddressPacket);
        Regs.x.DS = _FP_SEG (AddressPacket);
    
        CarryFlag = Int86 (0x13, &Regs);
        DEBUG ((D_BLKIO_ULTRA, "EDD30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n",BiosBlkIoDev->Bios.Number,CarryFlag,Regs.h.AH));    

        Media->MediaPresent = TRUE;
        if (CarryFlag) {
            //
            // Return Error Status
            //

            BiosBlkIoDev->Bios.ErrorCode = Regs.h.AH;
            if (BiosBlkIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
                Media->MediaId++;
                Bios = &BiosBlkIoDev->Bios;
                if (Int13GetDeviceParameters(Bios)) {
                    if (Int13Extensions (Bios)) {
                        Media->LastBlock = (EFI_LBA)Bios->Parameters.PhysicalSectors - 1;
                        Media->BlockSize = (UINT32)Bios->Parameters.BytesPerSector;
                    } else {
                        //
                        // Legacy Interfaces
                        //
                        Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
                        Media->BlockSize = 512;
                    }
                    Media->ReadOnly = FALSE;
                    BS->HandleProtocol (BiosBlkIoDev->Handle, &BlockIoProtocol, (VOID **)&BlkIo);
                    BS->ReinstallProtocolInterface (BiosBlkIoDev->Handle, &BlockIoProtocol, BlkIo, BlkIo);
                    return EFI_MEDIA_CHANGED;
                }
            } else if (BiosBlkIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
                Media->ReadOnly = TRUE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?