EchoXTeknology
EchoXTeknology

Reputation: 67

LBA 24-Bit Read Issue with I/O Port 0x1F0 : QEMU [UPDATED - SOLVED -CONTINUOUS THREAD]

General Backstory:

I am utilizing NASM 2.15.05 real-mode instructions with qemu-system-x86_64 as my current virtual machine for software debugging and serial output.

I have generated a disk image of 128MiB using dd Linux command instruction. I have also generated a Master Boot Record (MBR) partition table. The partition table has been initialized with 3 defined entries, in this case we should only worry about the first partition at LBA 2048 (this is partition 1).

Initial Loading Routine:

LBA 1 is defined as the Master Disk Record (MDR) this first 512-byte sector contains the partition table and basic code to load the Master Boot Record (MBR) at LBA 2048. The MDR has no other use but to load the MBR. For those that may be inclined to know the code does load at 0x07C0:0x0000 and copies itself to 0x07C0:0x0200 (0x07E0:0x0000 notice the MDR copies itself 512 bytes directly above the MBR). The MDR will load the MBR at 0x07C0:0x0000.

Second Loading Routine:

LBA 2048 is defined as the Master Boot Record (MBR) this 512-byte sector contains the BIOS Parameter Block (BPB) of a FAT16 (the filesystem is not of particular concern rather the absolute amount of reserved sectors following LBA 2048 in this case 16 sectors - 1 sector (the subbed sector is the MBR's sector). The MBR loads the Extended Boot Record (the 15 sectors following the MBR's sector) to 0x0550:0x0000.

Third Loading Routine:

Extended Boot Record (EBR) is loaded at 0x0550:0x0000 and performs BIOS extension service INT 0x13 AH=0x48 (BIOS service Extensions.GetDiskParameters(). I have simplified the code as the Physical I/O Port the filesystem is attached to is 0x1F0. I have defined the basic operations (refer to the code below) to load the MDR's sector to 0x0800:0x0000 but I am perplexed to find the controller has only loaded the MBR's sector? I would like to know why this is happening (I have tested this issue by removing the complexities and simplifying the code to load the same first LBA to the exact same address using similar testing environments but to no unveil it has replicated the exact issue.

The Code in question:

JMP _glEntry

_glEntry:
    CLI
    MOV AX, 0x0550
    MOV DS, AX
    XOR SI, SI
    XOR DI, DI
    STI

; Code that would've gathered the I/O port of the IDE controller.
; I have omitted this code as it would provide no change to the issue...

read_service:
    MOV DX, 0x01F6  ; I/O port is 0x1F0 but we need to push LBA mode to the correct I/O port to handle this
    MOV AL, 0xE0    ; The 6th bit is set for LBA mode
    OUT DX, AL
    
    MOV DX, 0x01F2  ; I/O port to push sector count to read
    MOV AL, 0x01    ; 1 Sector to Read from the File System
    OUT DX, AL

    MOV DX, 0x01F3  ; I/O port to push the 0-7 bits of LBA 24-bit value
    MOV AL, [lba]   ; 0-7 bits read to AL for push
    OUT DX, AL

    MOV CX, 0x01F4  ; I/O port to push the 8-15 bits of the LBA 24-bit value
    MOV AL, [lba+1] ; 8-15 bits read to AL for push
    OUT DX, AL

    MOV DX, 0x01F5  ; I/O port to push the 16-23 bits of the LBA 24-bit value
    MOV AL, [lba+2] ; 16-23 bits read to AL for push
    OUT DX, AL

    MOV DX, 0x01F7  ; I/O port to push what service to perform
    MOV AL, 0x20    ; Push AL as 0x20 for READ_SECTOR(S)_SERVICE
    OUT DX, AL

wait_status_r:
    MOV DX, 0x01F7  ; Ensure DX is the correct I/O port to grab info...
wait_busy_r:
    IN AL, DX
    TEST AL, 0x80   ; Test if DX has pushed the BUSY command
    JNZ wait_busy_r
wait_drq_r:
    IN AL, DX
    TEST AL, 0x08   ; Test if DX has pushed the DRQ command
    JZ wait_drq_r

    MOV AX, 0x0800  ; Set AX for ES later
    MOV ES, AX      ; ES is set to 0x0800 SEGMENT
    XOR DI, DI      ; DI is zeroized
    MOV CX, 256     ; CX is set to 256 for the WORD count to read from DATA_PORT
    MOV DX, 0x01F0  ; DX should be the I/O port for data streams...

read_loop:
    IN AX, DX
    MOV WORD [ES:DI], AX
    ADD DI, 2
    LOOP read_loop

; The data that's being imported to AX at 'IN AX, DX'
; should be the WORD data blocks stream from the MDR
; The data that's being imported to AX is actually
; MBR data in this case.
; This is the issue I am trying to solve.

CLI
HLT

Upvotes: 0

Views: 89

Answers (1)

EchoXTeknology
EchoXTeknology

Reputation: 67

I was able to solve the problem at hand; I was priorly utilizing the INT 0x13 AH=0x42 Extended Read service which utilizes QWORD LBA values (in this case the ATA PIO is reading 48-bit LBA values). The upper values of the 48-bits were never initialized and had previous garbage data in the controller's memory (Voltage patterns were set but never cleared). I tested the code with a cache flush beforehand and without a cache flush of the controller but didn't affect the outcome. I tested with real hardware and Qemu VM and both systems worked without any issues.

I recommend for other developers having this issue to develop a system to save the last BIOS function or just to manually use 48-bit LBA as a standard instead of 24-bit LBA ATA PIO reads. I may add development code of a system I create to help future developers solve this issue as well internally within code for legacy and modern reads (24-bit or 48-bit).

Upvotes: 0

Related Questions