Bochs works but Qemu doesn't

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
muisei
Member
Member
Posts: 79
Joined: Sat Sep 23, 2006 2:10 pm
Location: Bulgaria
Contact:

Bochs works but Qemu doesn't

Post by muisei »

This is a code snipet from my procedure for reading the HDD.
When I execute the OS with Bochs, everything is going well.
But when I try to run it with Qemu, then it reads nothing from the HDD.
Am I missing something? :shock:

Code: Select all

        mov    dx,0x1f7                  ;This is the command port
        mov    al,0x20
        out      dx,al                           ;Send the 0x20 command(Read sector with retry)
.loop1:
        in         al,dx
        bt         ax,3                              ;Here we check if we are ready to read
        jnc       .loop1

        mov     ecx,256                        ;We will read 256 words
        mov     dx,0x1f0                       ;This is the data port
        cld                                               ;Set the direction(increment EDI)
        rep     insw                                ;Read 256 words from the data port
User avatar
Touch
Member
Member
Posts: 56
Joined: Sun Oct 22, 2006 10:33 am
Location: England

Post by Touch »

Maybe its just a setup problem, with QEMU. Im not sure about the code.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Post by Pype.Clicker »

your access sequence seems extremely short compared to what i'm used to see (e.g. setting sector count, register address, etc.) I'd suggest you double-check your code against HALE's code found on ata-atapi.com (iirc -- see the FAQ otherwise).

You may also want to grab the sources of QEMU and see how it interpretes your command to find out what you're missing (with emulators, it often proves to be the fastest way to correct your errors provided that you're fluent enough in C ... and that you don't start messing with the emu itself.
User avatar
muisei
Member
Member
Posts: 79
Joined: Sat Sep 23, 2006 2:10 pm
Location: Bulgaria
Contact:

Post by muisei »

Here is the full sorce for the procedure.It's written in NASM:

Code: Select all

;----------------------------------------------------------;
; Read number of sectors from HDD to the                   ;
; memory                                                   ;
; Input:                                                   ;
; EAX=LBA address to read data from                        ;
; EBX=Memory address to read data to                       ;
; CH=Which drive to use (0x0 master,0x1 slave)             ;
; CL=Number of sectors to read                             ;
;----------------------------------------------------------;
ata_read:
	pushad
	push	ebp
	mov	ebp,esp
	sub	esp,12

; Save the input values
	mov	DWORD [ebp-4],eax		;This is the LBA address
	mov	DWORD [ebp-8],ebx		;Memory to store the data
	shl	ecx,16				;This will zero the high word of ECX
	shr	ecx,16
	mov	DWORD [ebp-12],ecx		;The drive to use and number of sectors to read
; Try the MSB of the status register(BUSY)
; and loop if the bit is set
	mov	dx,0x1f7
.loop1:
	in	al,dx
	bt	ax,7
	jc	.loop1

	cli
; Try bit 6(Device ready) and loop if the bit is 0
	mov	dx,0x1f7
.loop2:
	in	al,dx
	bt	ax,6
	jnc	.loop2
	
; The following code will read from HDD to memory
	mov	eax,[ebp-12]
	mov	dx,0x1f2
	out	dx,al				;Set the # of sectors to read
	
	mov	eax,[ebp-4]			;EAX=LBA address
	call	lba2chs				;Calculate CHS translation.ECX=Sector
	mov	eax,ecx
	mov	dx,0x1f3
	out	dx,al				;Set the starting sector sector
	
	mov	eax,[ebp-4]			;EAX=LBA address
	call	lba2chs				;Calculate CHS translation.EAX=Cylinder	
	mov	dx,0x1f4
	out	dx,al				;Set the low cylinder port
	mov	dx,0x1f5
	shr	ax,8				;Move AH->AL.Now AL=cylinder high
	out	dx,al				;Set the high cylinder port
	
	mov	eax,[ebp-4]			;EAX=LBA address
	call	lba2chs				;Calculate the CHS translation.EBX=head
	mov	eax,[ebp-12]			;Store the drive wanted in AH
	mov	al,bl				;Store the head number in AL
	shl	ah,4				;Move the dreive head bit 4 positions left
	or	al,0xa0				;Set the reserved flags
	or	al,ah				;Set the drive bit
	mov	dx,0x1f6
	out	dx,al				;Set the Head/Drive register

	mov	dx,0x1f7
	mov	al,0x20
	out	dx,al				;Set the 0x20 command(Read sector with retry)
.loop3:
	in	al,dx
	bt	ax,3
	jnc	.loop3

	mov	eax,[ebp-12]
	shl	eax,24				;This set to zero all except the # of sectors to read
	shr	eax,24				;AX=number of sectors to read
	mov	cx,512				;CX=number of bytes in a sector
	mul	cx				;DX:AX=AX*CX.This tell us how many bytes to read
	shl	eax,16				;MSW of the EAX now hold the AX
	mov	ax,dx				;AX=DX
	rol	eax,16				;Now EAX=DX:AX the result from the multiplication
	mov	ebx,4				;When divide EAX of 4 then we will know how many DWORDs
	xor	edx,edx				;we need to read from the HDD port
	div	ebx				;EAX=(EDX:EAX)/EBX

	mov	ecx,eax
	mov	edi,[ebp-8]			;This is the destination of the read sector
	mov	dx,0x1f0			;This is the data port
	cld
	rep        insd
	
	add	esp,12
	pop	ebp
	popad
	ret
	
;----------------------------------------------------------;
; Convert LBA to CHS.                                      ;
; Input:                                                   ;
; EAX=LBA address                                          ;
; Output:                                                  ;
; EAX=Cylinder, EBX=Head, ECX= Sector                      ;
;----------------------------------------------------------;
lba2chs:
	push	ebp
	mov	ebp,esp
	sub	esp,4
	
	mov	ebx,PHed*PSec	;Cylinder=LBA/(PHed*PSec)
	xor	edx,edx		;This is needed for the DIV instruction
	div	ebx		;EAX=quotient(Cylinder) EDX=reminder
	mov	[ebp-4],eax	;Save the Cylinder

	mov	eax,edx		;EAX=temp variable
	xor	edx,edx		;Needed for the DIV instruction
	mov	ebx,PSec	;EBX is divider
	div	ebx		;EAX=quotient(Head) EDX=reminder(Sector)
	
	mov	ebx,eax		;EBX=EAX(Head)
	mov	ecx,edx		;ECX=EDX(Sector)+1
	inc	ecx		
	mov	eax,[ebp-4]	;EAX=[EBP-4] which is the Cylinder

	mov	esp,ebp
	pop	ebp
	ret
	
PCyl	equ	20
PHed	equ	16
PSec	equ	63
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Post by Pype.Clicker »

1. i'm a bit surprised that you're using lba2chs while ATA drive supports LBA natively ... well, that's probably not where the fault stands.

2. ATA interface typically provide 16-bit data transfers and i see you doing "rep insd" ... that may work in some case (e.g. when the controller can do the translation), but i'd still recommend you stick to "rep insw" for your first tests.

Otherwise, i'm rather out of idea right now. QEMU sources might reveal you something, as i said above.
Post Reply