LBA přímo z IO portů? – Assembler – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

LBA přímo z IO portů? – Assembler – Fórum – Programujte.comLBA přímo z IO portů? – Assembler – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
Matěj Andrle+1
Grafoman
28. 1. 2014   #1
-
0
-

Dobrý den,
žil jsem v domění, že musím udělat CHS -> LBA convertor. Ale pořád se mi to nedařilo (problém s geometrií disku atp.) a tak po opakovaném čtení informací o portech 0x1F0 - 0x1F7 mi začíná docházet, že by LBA mělo jít bez mnou napsaných převodů do CHS. Jak tedy udělat LBA čtení a zápis?

	mov dx, 0x1F2 ; Sector count port
	mov al, 938 ; Read one sector
	out dx, al

	mov dx, 0x1F3 ; Sector number port
	mov al, 1 ; Read sector one
	out dx, al

	mov dx, 0x1F4 ; Cylinder low port
	mov al, 0 ; Cylinder 0
	out dx, al

	mov dx, 0x1F5 ; Cylinder high port
	mov al, 0 ; The rest of the cylinder 0
	out dx, al

	mov dx, 0x1F6 ; Drive and head port
	mov al, 0xA0 ; Drive 0,  head 0
	out dx, al

	mov dx, 0x1F7 ; Command port
	mov al, 0x20 ; Read with retry.
	out dx, al

stillGoing:

	in al, dx
	test al, 8 ; This means the sector buffer requires
	; servicing.
	jz stillGoing ; Don't continue until the sector buffer
	; is ready.

	mov cx, 512 / 2 ; One sector / 2
	mov di, outAddress
	mov dx, 0x1F0 ; Data port - data comes in and out of here.
	rep insw

Ovšem:

http://wiki.osdev.org/ATA_PIO_Mode

LBAlo, LBAmid, LBAhi,... Takže stačí nějak přepnout mód - jak?
Děkuji.

Nahlásit jako SPAM
IP: 78.136.176.–
z
~ Anonymní uživatel
268 příspěvků
28. 1. 2014   #2
-
0
-

Přesně tak, jak se píše na tom odkazovaném dokumentu.

device/head port, bit 6

Nahlásit jako SPAM
IP: 78.156.159.–
Matěj Andrle+1
Grafoman
28. 1. 2014   #3
-
0
-

#2 z
Prosím - ukaž mi to na nějakém kódu - co jsi poslal nedává smysl, tam je to také na 2 části: Drive / Head Port Used to select a drive and/or head. May supports extra address/flag bits. -> Jestli je toto k nějakému přepínání, či tak, kde vyberu zařízení pro zápis/čtení?
Děkuji.

Nahlásit jako SPAM
IP: 2a01:8c00:ff00:814b:d899:...–
z
~ Anonymní uživatel
268 příspěvků
28. 1. 2014   #4
-
0
-

Bit 6 je přece mimo dolních 5 "adresních". Proč si ten dokument nepřečteš celý?

Připojen obrázek.

Nahlásit jako SPAM
IP: 88.101.8.–
Matěj Andrle+1
Grafoman
29. 1. 2014   #5
-
0
-

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.

Nahlásit jako SPAM
IP: 78.136.139.–
Matěj Andrle+1
Grafoman
1. 2. 2014   #6
-
0
-

Už to skoro chápu:

	mov ebp, 27
	mov edi, BMP
	mov ebx, 38
	mov esi, .imageStruct
	call ATA.Read

...

.imageStruct:

	dd 965			; total sectors count
	dd 0				; LBA set
	dw 0x1F0			; Data port 1F0 master, 170 slave
	dw 0				; DCR
	db 0xE0			; 0xE0 for the "master" or 0xF0 for the "slave"

...

%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:

	jg short .read48			; test the flags from the eax cmp's above

	mov dword [.call], PIO28.Read - (.call + 4)
	jmp .read

.read48:

	mov dword [.call], PIO48.Read - (.call + 4)

.read:

	mov dx, [esi + 8]			; dx = IO data port - master/slave

	db 0xE8					; read up to 0x100 more sectors, updating registers
	.call dd 0

	test ebx, ebx				; no more sectors to read?
	jne short .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					; 2 = sectorcount port
	out dx, al
	mov al, cl				; ecx currently holds LBA
	inc edx					; 3 = LBAlow
	out dx, al
	mov al, ch
	inc edx					; 4 = 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, [esi + 12]			; master/slave flag
	inc edx					; 6 = Drive / Head Port
	out dx, al
 
	inc edx					; 7 = command/status
	mov al, 0x20				; 0x20 = read, 0x30 = write
	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
	jmp PIO.Read
 
;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

	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, [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

PIO.Read:

	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 PIO.Read

; 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					; 7 = Command port / Regular Status port
	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 ebx, ebx				; check if "sectorcount" just decremented to 0
	jnz 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

Jen nevím co je DCR a snad to jediné mi brání v tom, aby to fungovalo. Tak se ptám - co je DCR?
Děkuji.

Nahlásit jako SPAM
IP: 78.136.190.–
z
~ Anonymní uživatel
268 příspěvků
1. 2. 2014   #7
-
0
-

DCR je Device Control Register. Zápisem nastavuješ DCR, čtením dostáváš ASR (Alternate Status Register, = Regular Status Port). Ta 4 nastavuje bit 2 (SRST). Taky je to popsáno v tom článku.

Nahlásit jako SPAM
IP: 88.101.8.–
Matěj Andrle+1
Grafoman
1. 2. 2014   #8
-
0
-

#7 z
A jakou hodnotu má mít ta struktura? 0x1F7?

.imageStruct:

	dd 965			; total sectors count
	dd 0				; LBA set
	dw 0x1F0			; Data port 1F0 master, 170 slave
	dw 0				; DCR
	db 0xE0			; 0xE0 for the "master" or 0xF0 for the "slave"
Nahlásit jako SPAM
IP: 78.136.190.–
z
~ Anonymní uživatel
268 příspěvků
1. 2. 2014   #9
-
0
-

To DCR? 0x3F6.

Nahlásit jako SPAM
IP: 88.101.8.–
Matěj Andrle+1
Grafoman
1. 2. 2014   #10
-
0
-

Pak nechápu, proč mi to nefunguje...

Nahlásit jako SPAM
IP: 78.136.190.–
Matěj Andrle+1
Grafoman
2. 2. 2014   #11
-
0
-

Dost věcí nechápu - je to fakt humus co mnozí vydávají za programový kód... :D

; delay 400ns to allow drive to set new values of BSY and DRQ
%macro delay 0

	times 4 in al, dx

%endmacro

; flags: zero flag set on success, carry set on failure (redundant)
ATA.Read:

	pushad

	mov ebx, [esi + 8]
	mov edx, [esi + 18]
	mov edi, [esi + 12]
	mov ebp, [esi]

	test ebx, ebx				; ebx < 0 => "reset" request from software
	js short .reset

	in al, dx					; get the current status
	test al, 10001000B			; 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
	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:

	jg short .read48			; test the flags from the eax cmp's above

	mov dword [.call], PIO28.Read - (.call + 4)
	jmp .read

.read48:

	mov dword [.call], PIO48.Read - (.call + 4)

.read:

	mov dx, [esi + 16]			; IO data port - master/slave

	db 0xE8					; Opcode call relative
	.call dd 0

	test ebx, ebx				; no more sectors to read?
	jne short .read

.done:

	popad
	ret

;ATA PI0 28bit singletasking disk read function (up to 0x100 sectors)
; 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					; 2 = sectorcount port
	out dx, al
	mov al, cl				; ecx currently holds LBA
	inc dx					; 3 = LBAlow
	out dx, al
	mov al, ch
	inc dx					; 4 = LBAmid
	out dx, al
	bswap ecx
	mov al, ch				; bits 16 to 23 of LBA
	inc dx					; port 1F5 -- LBAhigh
	out dx, al
	mov al, cl				; bits 24 to 28 of LBA
	or al, [esi + 20]			; master/slave flag
	inc dx					; 6 = Drive / Head Port
	out dx, al
 
	inc dx					; 7 = command/status
	mov al, 0x20				; 0x20 = read, 0x30 = write
	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
	jmp PIO.Read
 
;ATA PI0 33bit singletasking disk read function (up to 64K sectors, using 48bit mode)
; 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

	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 dx
	out dx, al				; LBA4 = LBAlow, high byte (1F3)
	inc dx
	mov al, ah				; LBA5 was calculated above
	out dx, al				; LBA5 = LBAmid, high byte (1F4)
	inc dx
	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 dx
	out dx, al				; LBA1 = LBAlow, low byte (1F3)
	mov al, ah				; LBA2
	inc dx
	out dx, al				; LBA2 = LBAmid, low byte (1F4)
	mov al, ch				; LBA3
	inc dx
	out dx, al				; LBA3 = LBAhigh, low byte (1F5)
 
	mov al, [esi + 20]			; master/slave flag | 0xe0
	inc dx
	and al, 0x50				; get rid of extraneous LBA28 bits in drive selector
	out dx, al				; drive select (1F6)
 
	inc dx					; 7 = Command port
	mov al, 0x24				; send "read ext" 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

PIO.Read:

	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 PIO.Read

; 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					; 7 = Command port / Regular Status port
	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 ebx, ebx				; 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]				; 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, 100001B			; 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

; DCR = Device Control Register:
; Bit	 Abbreviation	 Function
;  0		ERR		Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset).
;  3		DRQ		Set when the drive has PIO data to transfer, or is ready to accept PIO data.
;  4		SRV		Overlapped Mode Service Request.
;  5		DF		Drive Fault Error (does not set ERR).
;  6		RDY		Bit is clear when drive is spun down, or after an error. Set otherwise.
;  7		BSY		Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset.

.testDrive:

	in al, dx
	and al, 11000000B			; check BSY and RDY
	cmp al, 10000000B			; want BSY clear and RDY set
	je short .testDrive

	pop eax
	ret

Smazal jsem nesmyslné testy a jiné nesmysly, pročež nyní uvažuji nad: "test ebx, ebx                ; ebx < 0 => "reset" request from software" Co to je za blbost? (Výsledek & jako záporné číslo?) Předtím to navíc bylo zacyklené zde:

.testDrive:

	in al, dx
	and al, 11000000B			; check BSY and RDY
	cmp al, 10000000B			; want BSY clear and RDY set
	je short .testDrive

Jne jne fakt blbost - z toho komentu to jasně vyplývá... (want BSY clear and RDY set) Ale stala se mi podivná věc:

.read:

	mov dx, [esi + 16]			; IO data port - master/slave

	db 0xE8					; Opcode call relative
	.call dd 0

	test ebx, ebx				; no more sectors to read?
	jne short .read

Volání probíhá v nekonečném cyklu - na to snad přijdu proč, ale pod voláním se kód vůbec neprovede... :D (Přitom skok pod tím ano...) Vidím to tak, že za chvíli z toho bude polovina oproti tomu, co mají oni a ještě navíc to bude fungovat mnohem lépe... :D Byl by někdo ochotný vyhledat chyby? Datová struktura nyní vypadá takto:

.imageStruct:

	dd 27			; Start in partition
	dd 0				; Start of partition
	dd 38			; Sectors to load
	dd BMP			; Out address
	dw 0x1F0			; Data port 1F0 master, 170 slave
	dw 0x3F6			; DCR
	db 0xE0			; 0xE0 for the "master" or 0xF0 for the "slave"

Děkuji.

Nahlásit jako SPAM
IP: 78.136.172.–
z
~ Anonymní uživatel
268 příspěvků
2. 2. 2014   #12
-
0
-

Nechce se mi to celé studovat a kontrolovat, takže jen k věcem, které připomínkuješ:

- Ta procedura pro čtení zjevně byla navržena tak, že záporný počet sektorů znamená požadavek o reset.

- V tom čekání na ready status byly konstanty 0xC0 (BSY,RDY) a 0x40 (RDY), takže jne bylo správně. Změna na 0xC0 a 0x80 je nejspíš od tebe.

- V tom cyklu se nemění ebx. Takže proběhne jednou, nebo poběží pořád, dokud ten call nevyžere stack. A nulový offset toho callu nedává smysl.

Vidím to tak, že za chvíli z toho bude polovina oproti tomu, co mají oni a ještě navíc to bude fungovat mnohem lépe... :D

Původní kód nechápeš, upravuješ ho špatně a nefunguje ti vůbec. Trochu pokory... :D

Nahlásit jako SPAM
IP: 88.101.8.–
Matěj Andrle+1
Grafoman
2. 2. 2014   #13
-
0
-

#12 z
Schválně jsem si testy předělal do binárky - takže je to logicky správně:

; delay 400ns to allow drive to set new values of BSY and DRQ
%macro delay 0

	times 4 in al, dx

%endmacro

; flags: zero flag set on success, carry set on failure (redundant)
ATA.Read:

	pushad

	mov ebp, [esi]
	mov ebx, [esi + 8]
	mov edi, [esi + 12]
	mov edx, [esi + 18]

	test ebx, ebx				; ebx < 0 => "reset" request from software
	js short .reset

	in al, dx					; get the current status
	test al, 10001000B			; 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
	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:

	mov eax, [esi + 4]
	add eax, ebp
	add eax, ebx
	cmp eax, 0xFFFFFFF

	jg short .read48

	mov dword [.call], PIO28.Read - (.call + 4)
	jmp short .read

.read48:

	mov dword [.call], PIO48.Read - (.call + 4)

.read:

	mov dx, [esi + 16]			; IO data port - master/slave

	db 0xE8					; Opcode call relative
	.call dd 0

	test ebx, ebx				; no more sectors to read?
	jne short .read

.done:

	popad
	ret

;ATA PI0 28bit singletasking disk read function (up to 256 sectors)
; 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 256 sectors)
	or dl, 2					; 2 = sectorcount port
	out dx, al
	mov al, cl				; ecx currently holds LBA
	inc dx					; 3 = LBAlow
	out dx, al
	mov al, ch
	inc dx					; 4 = LBAmid
	out dx, al
	bswap ecx
	mov al, ch				; bits 16 to 23 of LBA
	inc dx					; port 1F5 -- LBAhigh
	out dx, al
	mov al, cl				; bits 24 to 28 of LBA
	or al, [esi + 20]			; master/slave flag
	inc dx					; 6 = Drive / Head Port
	out dx, al
 
	inc dx					; 7 = command/status
	mov al, 0x20				; 0x20 = read, 0x30 = write
	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
	jmp PIO.Read
 
;ATA PI0 33bit singletasking disk read function (up to 64K sectors, using 48bit mode)
; 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

	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 dx
	out dx, al				; LBA4 = LBAlow, high byte (1F3)
	inc dx
	mov al, ah				; LBA5 was calculated above
	out dx, al				; LBA5 = LBAmid, high byte (1F4)
	inc dx
	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 dx
	out dx, al				; LBA1 = LBAlow, low byte (1F3)
	mov al, ah				; LBA2
	inc dx
	out dx, al				; LBA2 = LBAmid, low byte (1F4)
	mov al, ch				; LBA3
	inc dx
	out dx, al				; LBA3 = LBAhigh, low byte (1F5)
 
	mov al, [esi + 20]			; master/slave flag | 0xe0
	inc dx
	and al, 0x50				; get rid of extraneous LBA28 bits in drive selector
	out dx, al				; drive select (1F6)
 
	inc dx					; 7 = Command port
	mov al, 0x24				; send "read ext" 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

PIO.Read:

	in al, dx					; grab a status byte
	test al, 10000000B			; BSY flag set?
	jne short .retry

	test al, 00001000B			; DRQ set?
	jne short .dataReady

.retry:

	dec ecx
	jg short PIO.Read

; 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, 10000000B			; BSY flag set?
	jne short .waitUntil			; (all other flags are meaningless if BSY is set)

	test al, 00100001B			; 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					; 7 = Command port / Regular Status port
	mov cx, 256
	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 ebx, ebx				; 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]				; 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, 00100001B			; ERR or DF set?
	je short .done

.fail:

	stc

.done:

	ret
 
; do a singletasking PIO ata "software reset" with DCR in dx

; DCR = Device Control Register:
; Bit	 Abbreviation	 Function
;  0		ERR		Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset).
;  3		DRQ		Set when the drive has PIO data to transfer, or is ready to accept PIO data.
;  4		SRV		Overlapped Mode Service Request.
;  5		DF		Drive Fault Error (does not set ERR).
;  6		RDY		Bit is clear when drive is spun down, or after an error. Set otherwise.
;  7		BSY		Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset.
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

.testDrive:

	in al, dx
	and al, 11000000B			; check BSY and RDY
	cmp al, 10000000B			; want BSY clear and RDY set
	je short .testDrive

	pop eax
	ret

Nulový offset tam je, jelikož vybírám PIO:

	mov dword [.call], PIO28.Read - (.call + 4)
	jmp short .read

.read48:

	mov dword [.call], PIO48.Read - (.call + 4)

Kód nyní chápu dokonale. ebx se rozhodně mění - v PIO.Read... Vše by mělo být OK - 10x jsem to kontroloval - přesto to přád nejde... Děkuji za vysvětlení sign flagu - to tedy nechám - jinak to byla hrůza... (Rozhodně to nemohlo fungovat - také, že mi to nefungovalo...) Pořád nevidím chybu - snad už to brzy spravím... Kód debugginguji - takže ho upravuji správně - chyba bude nějaká blbost...

Nahlásit jako SPAM
IP: 78.136.172.–
z
~ Anonymní uživatel
268 příspěvků
2. 2. 2014   #14
-
0
-

To, že tam ten offset doplňuješ jsem nezaregistroval. Tak OK.

Jinak tam nic zjevného nevidím.

Nahlásit jako SPAM
IP: 88.101.8.–
Matěj Andrle+1
Grafoman
2. 2. 2014   #15
-
0
-

Právě, že jsem to celé osekal a vůbec vyšperkoval - vše prošel - vše se provádí jak má - bez problémů mi to dojde až do PIO.Read a i tam se to tváří pěkně, jenže výsledek je nekonečný cyklus... Koukám do toho hodiny - šperkuji už opravdu blbosti - každé opcode jsem si prošel - jebe mi z toho... :D

Nahlásit jako SPAM
IP: 78.136.172.–
Matěj Andrle+1
Grafoman
2. 2. 2014   #16
-
0
-

#14 z
EDIT: Nejspíše chybný test - zítra si to znovu projdu celé... :D

Nahlásit jako SPAM
IP: 78.136.172.–
Matěj Andrle+1
Grafoman
4. 2. 2014   #17
-
0
-

Kontečně už vím, kde to vázne:

.waitUntil:

	in al, dx					; grab a status byte
	test al, 10000000B			; BSY flag set?
	jne short .waitUntil			; (all other flags are meaningless if BSY is set)

	test al, 00100001B			; ERR or DF set?
	jne short .fail

0x1F7 hází FF, pročež to uvízne v cyklu...

EDIT:

Problém je vysloveně v portech - vůbec asi nereagují. Mám VHD na primárním slotu SATA řadiče. Minimálně porty 0x1F7 a 0x3F6 hází FF - asi to tedy vůbec nekomunikuje s HW. Co to znamená a co s tím?
Děkuji.

Nahlásit jako SPAM
IP: 78.136.173.–
Matěj Andrle+1
Grafoman
5. 2. 2014   #18
-
0
-

   

; delay 400ns to allow drive to set new values of BSY and DRQ
%macro delay 0

	times 4 in al, dx

%endmacro

; flags: zero flag set on success, carry set on failure (redundant)
ATA.Read:

	pushad

	mov ebp, [esi]
	mov ebx, [esi + 8]
	mov edi, [esi + 12]
	mov edx, [esi + 18]

	test ebx, ebx				; ebx < 0 => "reset" request from software
	js short .reset

	in al, dx					; get the current status
	test al, 10001000B			; 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
	jmp short .done

; preferentially use the 28bit routine, because it's a little faster
.stateOK:

	mov eax, [esi + 4]
	add eax, ebp
	add eax, ebx
	cmp eax, 0xFFFFFFF

	jg short .read48

	mov dword [.call], PIO28.Read - (.call + 4)
	jmp short .read

.read48:

	mov dword [.call], PIO48.Read - (.call + 4)

.read:

	mov dx, [esi + 16]			; IO data port - master/slave

	db 0xE8					; Opcode call relative
	.call dd 0

	test ebx, ebx				; no more sectors to read?
	jnz short .read

.done:

	popad
	ret

;ATA PI0 28bit singletasking disk read function (up to 256 sectors)
PIO28.Read:

	add ebp, [esi + 4]			; Convert relative LBA to absolute LBA
	mov ecx, ebp				; Save a working copy
	mov al, bl				; AL = sectors count (0 means 256 sectors)
	or dl, 2					; 2 = sectorcount port
	out dx, al
	mov al, cl				; ecx currently holds LBA
	inc dx					; 3 = LBAlow
	out dx, al
	mov al, ch
	inc dx					; 4 = LBAmid
	out dx, al
	bswap ecx
	mov al, ch				; bits 16 to 23 of LBA
	inc dx					; 5 = LBAhigh
	out dx, al
	mov al, cl				; bits 24 to 28 of LBA
	or al, [esi + 20]			; master/slave flag
	inc dx					; 6 = Drive / Head Port
	out dx, al
 
	inc dx					; 7 = command/status
	mov al, 0x20				; 0x20 = read, 0x30 = write
	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
	jmp PIO.Read
 
;ATA PI0 33bit singletasking disk read function (up to 64K sectors, using 48bit mode)
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

	bswap ecx				; make LBA4 and LBA3 easy to access (cl, ch)
	or dl, 2					; 2 = sectors count port
	mov al, bh				; High byte of sectors count
	out dx, al
	mov al, cl
	inc dx
	out dx, al				; LBA4 = LBAlow, high byte (1F3)
	inc dx
	mov al, ah				; LBA5 was calculated above
	out dx, al				; LBA5 = LBAmid, high byte (1F4)
	inc dx
	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				; Low byte of sectors count
	out dx, al
	mov ax, bp				; Get LBA1 and LBA2 into ax
	inc dx
	out dx, al				; LBA1 = LBAlow, low byte (1F3)
	mov al, ah				; LBA2
	inc dx
	out dx, al				; LBA2 = LBAmid, low byte (1F4)
	mov al, ch				; LBA3
	inc dx
	out dx, al				; LBA3 = LBAhigh, low byte (1F5)
 
	mov al, [esi + 20]			; master/slave flag | 0xE0
	inc dx					; 6 = drive select
	and al, 0x50				; Get rid of extraneous LBA28 bits in drive selector
	out dx, al
 
	inc dx					; 7 = Command port
	mov al, 0x24				; Send "read ext" 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

; outputs: data stored in EDI; EDI and EBP advanced, EBX decremented
; flags: on success Zero flag set, Carry clear
PIO.Read:

	in al, dx					; grab a status byte
	test al, 10000000B			; BSY flag set?
	jne short .retry

	test al, 00001000B			; DRQ set?
	jne short .dataReady

.retry:

	dec ecx
	jg short PIO.Read

; 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, 10000000B			; BSY flag set?
	jne short .waitUntil			; (all other flags are meaningless if BSY is set)

	test al, 00100001B			; 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
	mov cx, 256				; 256 words = 512 byte
	rep insw					; gulp one 512b sector into edi
	or dl, 7					; 7 = Command port / Regular Status port
	delay

	inc ebp					; increment the current absolute LBA (overflowing is OK!)
	dec ebx					; decrement the "sectors to read" count

	test ebx, ebx				; check if "sectorcount" just decremented to 0
	jnz short .waitUntil
 
	sub dl, 7					; "point" dx back at the base IO port, so it's unchanged
	sub ebp, [esi + 4]			; Absolute LBA back to relative

; "test" sets the zero flag for a "success" return, also clears the carry flag
	test al, 00100001B			; ERR or DF set?
	jz short .done

.fail:

	stc

.done:

	ret
 
; do a singletasking PIO ata "software reset" with DCR in dx

; DCR = Device Control Register:
; Bit	 Abbreviation	 Function
;  0		ERR		Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset).
;  3		DRQ		Set when the drive has PIO data to transfer, or is ready to accept PIO data.
;  4		SRV		Overlapped Mode Service Request.
;  5		DF		Drive Fault Error (does not set ERR).
;  6		RDY		Bit is clear when drive is spun down, or after an error. Set otherwise.
;  7		BSY		Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset.
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

.testDrive:

	in al, dx
	and al, 11000000B			; check BSY and RDY
	cmp al, 10000000B			; want BSY clear and RDY set
	je short .testDrive

	pop eax
	ret

Toto by mělo být již naprosto správně. Vskutku je to porty - hledám tedy nějaké, co konečně začnou odpovídat...

Nahlásit jako SPAM
IP: 78.136.178.–
Řešení
Matěj Andrle+1
Grafoman
5. 2. 2014   #19
-
0
-
Vyřešeno Nejlepší odpověď

Halelujah! :D

; delay 400ns to allow drive to set new values of BSY and DRQ
%macro delay 0

	times 4 in al, dx

%endmacro

; flags: zero flag set on success, carry set on failure (redundant)
ATA.Read:

	pushad

	mov ebp, [esi]
	add ebp, [esi + 4]			; Convert relative LBA to absolute LBA
	mov ebx, [esi + 8]
	mov edi, [esi + 12]
	mov dx, [esi + 18]

	test ebx, ebx				; ebx < 0 => "reset" request from software
	js short .reset

	in al, dx					; get the current status
	test al, 10001000B			; 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
	jmp short .done

; preferentially use the 28bit routine, because it's a little faster
.stateOK:

	mov dx, [esi + 16]			; IO data port - master/slave
	add eax, ebp
	add eax, ebx
	cmp eax, 0xFFFFFFF

	jg short .read48

	mov dword [.call], PIO28.Read - (.call + 4)
	jmp short .read

.read48:

	mov dword [.call], PIO48.Read - (.call + 4)

.read:

	xor eax, eax
	push ebx
	db 0xE8					; Opcode call relative
	.call dd 0

	pop ebx

	jc .done

	sub ebx, [sectors]
	test ebx, ebx				; no more sectors to read?
	jnz short .read

.done:

	popad
	ret

;ATA PI0 28bit singletasking disk read function (up to 256 sectors)
PIO28.Read:

	sub ebx, 256
	js .signed

	mov ebx, 256
	jmp .unsigned

.signed:

	mov al, 255
	add al, bl
	mov ebx, eax

.unsigned:

	mov [sectors], ebx

	or dl, 2					; 2 = sectorcount port
	out dx, al
	mov ecx, ebp				; Save a working copy
	mov al, cl				; ecx currently holds LBA
	inc dx					; 3 = LBAlow
	out dx, al
	mov al, ch
	inc dx					; 4 = LBAmid
	out dx, al
	bswap ecx
	mov al, ch				; bits 16 to 23 of LBA
	inc dx					; 5 = LBAhigh
	out dx, al
	mov al, cl				; bits 24 to 28 of LBA
	or al, [esi + 20]			; master/slave flag
	inc dx					; 6 = Drive / Head Port
	out dx, al
 
	inc dx					; 7 = command/status
	mov al, 0x20				; 0x20 = read, 0x30 = write
	out dx, al
 
 	jmp PIO.Read
 
;ATA PI0 33bit singletasking disk read function (up to 64K sectors, using 48bit mode)
PIO48.Read:

; 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
	bswap ecx				; make LBA4 and LBA3 easy to access (cl, ch)

	mov eax, 65535
	sub ebx, eax
	js .signed

	mov ebx, eax
	jmp .unsigned

.signed:

	add eax, ebx
	mov ebx, eax

.unsigned:

	mov [sectors], ebx

	or dl, 2					; 2 = sectors count port
	mov al, bh				; High byte of sectors count
	out dx, al
	mov al, cl
	inc dx
	out dx, al				; LBA4 = LBAlow, high byte (1F3)
	inc dx
	mov al, ah				; LBA5 was calculated above
	out dx, al				; LBA5 = LBAmid, high byte (1F4)
	inc dx
	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				; Low byte of sectors count
	out dx, al
	mov ax, bp				; Get LBA1 and LBA2 into ax
	inc dx
	out dx, al				; LBA1 = LBAlow, low byte (1F3)
	mov al, ah				; LBA2
	inc dx
	out dx, al				; LBA2 = LBAmid, low byte (1F4)
	mov al, ch				; LBA3
	inc dx
	out dx, al				; LBA3 = LBAhigh, low byte (1F5)
 
	mov al, [esi + 20]			; master/slave flag | 0xE0
	inc dx					; 6 = drive select
	and al, 0x50				; Get rid of extraneous LBA28 bits in drive selector
	out dx, al
 
	inc dx					; 7 = Command port
	mov al, 0x24				; Send "read ext" command to drive
	out dx, al

; outputs: data stored in EDI; EDI and EBP advanced, EBX decremented
; flags: on success Zero flag set, Carry clear
PIO.Read:

; 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

	in al, dx					; grab a status byte
	test al, 10000000B			; BSY flag set?
	jne short .retry

	test al, 00001000B			; DRQ set?
	jne short .dataReady

.retry:

	dec ecx
	jg short PIO.Read

; 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, 10000000B			; BSY flag set?
	jne short .waitUntil

	test al, 00100001B			; 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
	mov cx, 256				; 256 words = 512 byte
	rep insw					; gulp one 512b sector into edi
	or dl, 7					; 7 = Command port / Regular Status port
	delay

	inc ebp					; increment the current absolute LBA (overflowing is OK!)
	dec bx					; decrement the "sectors to read" count

	test bx, bx				; Is just sectors count 0?
	jnz short .waitUntil
 
	sub dl, 7					; Set DX back to the base IO port - 0

; "test" sets the zero flag for a "success" return, also clears the carry flag
	test al, 00100001B			; ERR or DF set?
	jz short .done

.fail:

	stc

.done:

	ret
 
 sectors dd 0
 
; do a singletasking PIO ata "software reset" with DCR in dx

; DCR = Device Control Register:
; Bit	 Abbreviation	 Function
;  0		ERR		Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset).
;  3		DRQ		Set when the drive has PIO data to transfer, or is ready to accept PIO data.
;  4		SRV		Overlapped Mode Service Request.
;  5		DF		Drive Fault Error (does not set ERR).
;  6		RDY		Bit is clear when drive is spun down, or after an error. Set otherwise.
;  7		BSY		Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset.
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

.testDrive:

	in al, dx
	and al, 11000000B			; check BSY and RDY
	cmp al, 10000000B			; want BSY clear and RDY set
	je short .testDrive

	pop eax
	ret

I když vím, jak je to nechutné, musím se pochválit - boží práce... :D z - tak nevím proč nemám být tak sebejistý...

Nahlásit jako SPAM
IP: 78.136.186.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 33 hostů

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý