Tak už jsem opravdu zoufalý... :D Kde dělám chybu?
bits 32
Kernel:
mov ebp, 27
mov edi, BMP
mov ebx, 938
mov esi, .imageStruct
call ATA.Read
call ReadKey
mov eax, 300
mov ebx, 200
call DrawImage
call ReadKey
call ReadKey
mov edx, 0
call ClearScreen
jmp short Kernel
.imageStruct:
partitionLength dd 965 ; total sectors count
stateLBA dd 0
taskFile dw 0
DCR dw 0
masterOrSlave db 0xE0
...
%macro delay 0
times 4 in al, dx ; delay 400ns to allow drive to set new values of BSY and DRQ
%endmacro
; do a singletasking PIO ATA read
; inputs: ebx = # of sectors to read, edi -> dest buffer, esi -> driver data struct, ebp = 4b LBA
; Note: ebp is a "relative" LBA -- the offset from the beginning of the partition
; outputs: ebp, edi incremented past read; ebx = 0
; flags: zero flag set on success, carry set on failure (redundant)
ATA.Read:
pushad
test ebx, ebx ; # of sectors < 0 is a "reset" request from software
js short .reset
cmp ebx, 0x3FFFFF ; read will be bigger than 2GB? (error)
stc
jg short .done
mov edx, [esi] ; get the total partition length (sectors)
dec edx ; (to avoid handling "equality" case)
cmp edx, ebp ; verify ebp is legal (within partition limit)
jb short .done ; (carry is set automatically on an error)
cmp edx, ebx ; verify ebx is legal (forget about the ebx = edx case)
jb short .done
sub edx, ebx ; verify ebp + ebx - 1 is legal
inc edx
cmp edx, ebp ; (the test actually checks ebp <= edx - ebx + 1)
jb short .done
mov dx, [esi + 10] ; dx = alt status/DCR
in al, dx ; get the current status
test al, 0x88 ; check the BSY and DRQ bits -- both must be clear
je short .stateOK
.reset:
call ATA.SoftwareReset
test ebx, ebx ; bypass any read on a "reset" request
jns short .stateOK
xor ebx, ebx ; force zero flag on, carry clear
jmp short .done
; preferentially use the 28bit routine, because it's a little faster
; if ebp > 28bit or esi.stLBA > 28bit or stLBA+ebp > 28bit or stLBA+ebp+ebx > 28bit, use 48 bit
.stateOK:
cmp ebp, 0xFFFFFFF
jg short .setRegister
mov eax, [esi + 4]
cmp eax, 0xFFFFFFF
jg short .setRegister
add eax, ebp
cmp eax, 0xFFFFFFF
jg short .setRegister
add eax, ebx
cmp eax, 0xFFFFFFF
.setRegister:
mov dx, [esi + 8] ; dx = IO port base ("task file")
jle short .read28 ; test the flags from the eax cmp's above
.read48:
test ebx, ebx ; no more sectors to read?
je short .done
call PIO48.Read ; read up to 0x100 more sectors, updating registers
je short .read48 ; if successful, is there more to read?
jmp short .done
.read28:
test ebx, ebx ; no more sectors to read?
je short .done
call PIO28.Read ; read up to 0x100 more sectors, updating registers
je short .read28 ; if successful, is there more to read?
.done:
popad
ret
;ATA PI0 28bit singletasking disk read function (up to 0x100 sectors)
; inputs: ESI -> driverdata info, EDI -> destination buffer
; BL = sectors to read, DX = base bus I/O port (0x1F0, 0x170, ...), EBP = 28bit "relative" LBA
; BSY and DRQ ATA status bits must already be known to be clear on both slave and master
; outputs: data stored in EDI; EDI and EBP advanced, EBX decremented
; flags: on success Zero flag set, Carry clear
PIO28.Read:
add ebp, [esi + 4] ; convert relative LBA to absolute LBA
mov ecx, ebp ; save a working copy
mov al, bl ; set al= sector count (0 means 0x100 sectors)
or dl, 2 ; dx = sectorcount port -- usually port 1f2
out dx, al
mov al, cl ; ecx currently holds LBA
inc edx ; port 1f3 -- LBAlow
out dx, al
mov al, ch
inc edx ; port 1f4 -- LBAmid
out dx, al
bswap ecx
mov al, ch ; bits 16 to 23 of LBA
inc edx ; port 1f5 -- LBAhigh
out dx, al
mov al, cl ; bits 24 to 28 of LBA
or al, byte [esi + 12] ; master/slave flag | 0xe0
inc edx ; port 1f6 -- drive select
out dx, al
inc edx ; port 1f7 -- command/status
mov al, 0x20 ; send "read" command to drive
out dx, al
; ignore the error bit for the first 4 status reads -- ie. implement 400ns delay on ERR only
; wait for BSY clear and DRQ set
mov ecx, 4
.lp1:
in al, dx ; grab a status byte
test al, 0x80 ; BSY flag set?
jne short .retry
test al, 8 ; DRQ set?
jne short .dataReady
.retry:
dec ecx
jg short .lp1
; need to wait some more -- loop until BSY clears or ERR sets (error exit if ERR sets)
.waitUntil:
in al, dx ; grab a status byte
test al, 0x80 ; BSY flag set?
jne short .waitUntil ; (all other flags are meaningless if BSY is set)
test al, 0x21 ; ERR or DF set?
jne short .fail
.dataReady:
; if BSY and ERR are clear then DRQ must be set -- go and read the data
sub dl, 7 ; read from data port (ie. 0x1f0)
mov cx, 0x100
rep insw ; gulp one 512b sector into edi
or dl, 7 ; "point" dx back at the status register
delay
; After each DRQ data block it is mandatory to either:
; receive and ack the IRQ -- or poll the status port all over again
inc ebp ; increment the current absolute LBA
dec ebx ; decrement the "sectors to read" count
test bl, bl ; check if the low byte just turned 0 (more sectors to read?)
jne short .waitUntil
sub dx, 7 ; "point" dx back at the base IO port, so it's unchanged
sub ebp, [esi + 4] ; convert absolute lba back to relative
; "test" sets the zero flag for a "success" return -- also clears the carry flag
test al, 0x21 ; test the last status ERR bits
je short .done
.fail:
stc
.done:
ret
;ATA PI0 33bit singletasking disk read function (up to 64K sectors, using 48bit mode)
; inputs: bx = sectors to read (0 means 64K sectors), edi -> destination buffer
; esi -> driverdata info, dx = base bus I/O port (0x1F0, 0x170, ...), ebp = 32bit "relative" LBA
; BSY and DRQ ATA status bits must already be known to be clear on both slave and master
; outputs: data stored in edi; edi and ebp advanced, ebx decremented
; flags: on success Zero flag set, Carry clear
PIO48.Read:
xor eax, eax
add ebp, [esi + 4] ; convert relative LBA to absolute LBA
; special case: did the addition overflow 32 bits (carry set)?
adc ah, 0 ; if so, ah = LBA byte #5 = 1
mov ecx, ebp ; save a working copy of 32 bit absolute LBA
; for speed purposes, never OUT to the same port twice in a row -- avoiding it is messy but best
;outb (0x1F2, sectorcount high)
;outb (0x1F3, LBA4)
;outb (0x1F4, LBA5) -- value = 0 or 1 only
;outb (0x1F5, LBA6) -- value = 0 always
;outb (0x1F2, sectorcount low)
;outb (0x1F3, LBA1)
;outb (0x1F4, LBA2)
;outb (0x1F5, LBA3)
bswap ecx ; make LBA4 and LBA3 easy to access (cl, ch)
or dl, 2 ; dx = sectorcount port -- usually port 1f2
mov al, bh ; sectorcount -- high byte
out dx, al
mov al, cl
inc edx
out dx, al ; LBA4 = LBAlow, high byte (1f3)
inc edx
mov al, ah ; LBA5 was calculated above
out dx, al ; LBA5 = LBAmid, high byte (1f4)
inc edx
mov al, 0 ; LBA6 is always 0 in 32 bit mode
out dx, al ; LBA6 = LBAhigh, high byte (1f5)
sub dl, 3
mov al, bl ; sectorcount -- low byte (1f2)
out dx, al
mov ax, bp ; get LBA1 and LBA2 into ax
inc edx
out dx, al ; LBA1 = LBAlow, low byte (1f3)
mov al, ah ; LBA2
inc edx
out dx, al ; LBA2 = LBAmid, low byte (1f4)
mov al, ch ; LBA3
inc edx
out dx, al ; LBA3 = LBAhigh, low byte (1f5)
mov al, byte [esi + 12] ; master/slave flag | 0xe0
inc edx
and al, 0x50 ; get rid of extraneous LBA28 bits in drive selector
out dx, al ; drive select (1f6)
inc edx
mov al, 0x24 ; send "read ext" command to drive
out dx, al ; command (1f7)
; ignore the error bit for the first 4 status reads -- ie. implement 400ns delay on ERR only
; wait for BSY clear and DRQ set
mov ecx, 4
.lp1:
in al, dx ; grab a status byte
test al, 0x80 ; BSY flag set?
jne short .retry
test al, 8 ; DRQ set?
jne short .dataReady
.retry:
dec ecx
jg short .lp1
; need to wait some more -- loop until BSY clears or ERR sets (error exit if ERR sets)
.waitUntil:
in al, dx ; grab a status byte
test al, 0x80 ; BSY flag set?
jne short .waitUntil ; (all other flags are meaningless if BSY is set)
test al, 0x21 ; ERR or DF set?
jne short .fail
.dataReady:
; if BSY and ERR are clear then DRQ must be set -- go and read the data
sub dl, 7 ; read from data port (ie. 0x1f0)
mov cx, 0x100
rep insw ; gulp one 512b sector into edi
or dl, 7 ; "point" dx back at the status register
delay
; After each DRQ data block it is mandatory to either:
; receive and ack the IRQ -- or poll the status port all over again
inc ebp ; increment the current absolute LBA (overflowing is OK!)
dec ebx ; decrement the "sectors to read" count
test bx, bx ; check if "sectorcount" just decremented to 0
jne short .waitUntil
sub dx, 7 ; "point" dx back at the base IO port, so it's unchanged
sub ebp, [esi + 4] ; convert absolute LBA back to relative
; this sub handles the >32bit overflow cases correcty, too
; "test" sets the zero flag for a "success" return -- also clears the carry flag
test al, 0x21 ; test the last status ERR bits
je short .done
.fail:
stc
.done:
ret
; do a singletasking PIO ata "software reset" with DCR in dx
ATA.SoftwareReset:
push eax
mov al, 4
out dx, al ; do a "software reset" on the bus
xor eax, eax
out dx, al ; reset the bus to normal operation
delay
.lpReady:
in al, dx
and al, 0xC0 ; check BSY and RDY
cmp al, 0x40 ; want BSY clear and RDY set
jne short .lpReady
pop eax
ret
(Potřebuji načíst obrázek ze sektoru 27 při velikosti 938 sektorů za předpokladu, že sektor skýtá 512 byte.)
Děkuji.