flat assembler
Message board for the users of flat assembler.

Index > OS Construction > ATA Port IO

Author
Thread Post new topic Reply to topic
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
Tyler 15 Apr 2010, 06:24
I've found a bunch of different examples all over the net and kinda joined them together into something that looks correct. It doesn't work in VMware though. I'm trying to read in pmode, but I want to avoid chs like MiniDos uses. Otherwise I would've just looked at it.
Code:
 mov       ebx,dword[current_sector]   ; 28bit LBA into ebx
      mov       dx,1f2h
      mov       al,1
      out       dx,al  ; 1f2: sector count
      mov       al,bl
      add       dx,1
      out       dx,al  ; 1f3: low byte of LBA
      mov       al,bh
      add       dx,1
      out       dx,al   ; 1f4: middle byte of LBA
      bswap     ebx
      mov       al,bh
      add       dx,1
      out       dx,al   ; 1f5: high byte of LBA
      mov       al,bl  ; last nibble of LBA
      or        al,0e0h  ; OR with master drive
      or        al,64    ; set 28 bit LBA bit
      add       dx,1
      out       dx,al   ; 1f6: tell it to read from master and specify last nibble of 28bit LBA
      add       dx,1
      mov       al,20h  ; read sector command
      out       dx,al   ; 1f7: command port
      .busy:
         in        al,dx  
         test      al,8
         jz        .busy
      mov     cx,256          ; 256 words in a sector
      mov     edi,0b8000h
      mov     dx,1f0h         ;Data port - data comes in and out of here.
      rep     insw       
    

What makes me think it's not working, is that, when I try to copy the first dword from the buffer to b8000, nothing shows up.

Thanks in advance.

[edit]added comments[/edit]


Last edited by Tyler on 15 Apr 2010, 22:41; edited 1 time in total
Post 15 Apr 2010, 06:24
View user's profile Send private message Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 15 Apr 2010, 09:44
First of all, you are using C/H/S.

Now for the code...
In the 2nd and 3rd out operations, you send the sector and cylinder. Does the first word in current_sector (also bl and bh) contain these two?
In the 4th operation, you send the rest of the cylinder. Does the high part of current_sector (also ebx) - which becomes the low part after bswap - contain that?
In the 5th operation, you send the drive (bit 4) and head (bits 0-3) to be read. Bits 5-7 should always be 101b (they're reserved as such), but you have 111b. So it should be 0xa0 instead of 0xe0.

As for the add dx,1, is there any reason you're not just doing inc dx? And please next time, add a comment for everyone of these lines to show the current port used for the out operation. It'd be much easier to read.

And finally, even if the buffer is successfully filled with a sector, it may contain no printable characters at all.
Post 15 Apr 2010, 09:44
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 15 Apr 2010, 10:37
maybe, i just say maybe... we need a function that will do the ATA disk read/writes.

something in fasm, simple to use, and that works great. then, nobody will have to rewrite the ATA driver.

something like this code that dosin gave to me some mounth ago.
Code:
        org 0x0600
     use16 

start:
      mov [DriveNo],dl
      xor   ax,ax 
      mov   ds,ax 
      mov   es,ax 
      mov   ss,ax 
      mov   sp,0x7c00 
      sti
      cld
      mov si,sp
      mov di,0600h
      mov cx,438;512/2
      rep movsw

     jmp 0000:main
    
main:
    
     mov dx,0x3F2 
     mov al,0 
     out dx,al 
     mov [hdbase],0x1F0 
     mov [hdid],0x00
     
     mov  eax,0x0 
     call hdd_read 
     mov  si,buffer                     ;move MBR to SI
 
                                        
     add  si,446                        ;add si 446 to start of portion
find_portion:
     cmp  byte[si],00h          ;00h only one portion can be set bootable at a time
     jne  boot_portion1    ;cmp until we find match.
     add  si,16                         ;if not set bootable check next portion
p2:  cmp  byte[si],00h          
     jne  boot_portion2
     add  si,16                         ;if not set bootable check next portion
p3:  cmp  byte[si],00h          
     jne  boot_portion3
     add  si,16                         ;if not set bootable check next portion
p4:  cmp  byte[si],00h          
     jne  boot_portion4
     jmp  fin


boot_portion1:  jmp p11
boot_portion2:  jmp p21
boot_portion3:  jmp p31
boot_portion4:  jmp p41
        
p11:    add  si,16                 ;This is the were we get our lba info
                jmp nxt            ;it tells us the location of the bootable
p21:    add  si,16+16      ;portion
        jmp nxt 
p31:    add  si,16+16+16
        jmp nxt 
p41:    add  si,16+16+16+16
 
nxt:    mov  di,lba                ;copy it to LBA
        add  si,8                               
        mov  bx,word[si] 
        mov  word[di],bx 
        add  si,2
        mov  bx,word[si] 
        mov  word[di+2],bx 
          
        mov eax,dword[lba] ;load the lba sector
        call hdd_read 
     
        mov sp,buffer      ;our buffer now has the LBA bootable portion!
        sti
        cld
        mov si,sp
        mov di,0x7c00
        mov cx,512/2
        rep movsw

        mov dl,[DriveNo]                
        xor ecx,ecx
        xor ebx,ebx
        xor eax,eax
     
        jmp 0000:7C00h          ;here we jmp to it!
fin: ;if no bootable portion
     ;you may want to put an error msg here!
            jmp $ 

lba        dd 0x00000000 
hdid       db 0x00 
hdbase     dd 0x00 

DriveNo: db 0


default:   db 0
newln:     db 13,10,0

hdd_read: 
   pushad 
   push eax 
newhd_read: 
    
   mov edx,[hdbase] 
   inc edx 
   mov al,0 
   out dx,al 

   inc edx 
   mov al,1 
   out dx,al 

   inc edx 
   pop ax 
   out dx,al 

   inc edx 
   shr ax,8 
   out dx,al 

   inc edx 
   pop ax 
   out dx,al 

   inc edx 
   shr ax,8 
   and al,1+2+4+8 
   add al,[hdid] 
   add al,128+64+32 
   out dx,al 

   inc edx 
   mov al,20h 
   out dx,al 
hddwait: 
   in al,dx 
   test al,128 
jnz hddwait 
   mov edi,buffer 
   mov ecx,256 
   mov edx,[hdbase] 
    
   cld 
   rep insw 
    
   popad 
   ret 



print:
      mov   ah,0Eh                       ; Request display
again1:
          lodsb                              ; load a byte into AL from DS:SI
      or   al,al                         ; Or AL
      jz   done1                         ; Jump 0, to label done1
          int  10h                           ; Call interrupt service
      jmp  again1                        ; Jump to label again1
done1:
          ret                                 


times 510 - ($-start) db 0 
dw 0xaa55 
buffer rb 512 
    

i tried to convert it as a simple function, but some testing bored me until i gave up. maybe it is time to restart this project.
Post 15 Apr 2010, 10:37
View user's profile Send private message Visit poster's website Reply with quote
sinsi



Joined: 10 Aug 2007
Posts: 789
Location: Adelaide
sinsi 15 Apr 2010, 11:02
Remember that INSW will write to [es:edi], not ds.
The code works for me in virtualpc - reading lba 0 gets me an mbr.
Post 15 Apr 2010, 11:02
View user's profile Send private message Reply with quote
XanClic



Joined: 06 Sep 2009
Posts: 16
Location: Germany
XanClic 15 Apr 2010, 13:59
ManOfSteel wrote:
As for the add dx,1, is there any reason you're not just doing inc dx?

Because it's at least equal when comparing speed if not faster. There's a reason why GCC compiles “i++” to something like “add ...,1” instead of “inc ...”.
Post 15 Apr 2010, 13:59
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20299
Location: In your JS exploiting you and your system
revolution 15 Apr 2010, 14:08
Any code executing INSW is hardly a candidate for trying to optimise for speed. You're doing it wrong if you think add reg,1 will give any speed boost, the INSW will completely dominate the runtime.

If you want performance for that code then forget about 'add reg,1' vs 'inc reg'. Instead change to whole procedure to use DMA.
Post 15 Apr 2010, 14:08
View user's profile Send private message Visit poster's website Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 15 Apr 2010, 17:32
Exactly. The whole reason I proposed inc instead of add is that it's more readable (IMO, at least).
Post 15 Apr 2010, 17:32
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 618
cod3b453 15 Apr 2010, 18:25
Could be your wait loop - I have this for my CD driver:

Code:
        mov dx,ATA_REG_COMMAND

    @@:

        in al,dx

        test al,0x80
        jnz @b

    @@:

        in al,dx

        test al,0x08
        jnz @f
    


Also you might need to assert es is correct and put cld before rep insw
Post 15 Apr 2010, 18:25
View user's profile Send private message Reply with quote
XanClic



Joined: 06 Sep 2009
Posts: 16
Location: Germany
XanClic 15 Apr 2010, 20:50
ManOfSteel wrote:
Exactly. The whole reason I proposed inc instead of add is that it's more readable (IMO, at least).

Well, you asked for “any” reason. Wink
Post 15 Apr 2010, 20:50
View user's profile Send private message Visit poster's website Reply with quote
score_under



Joined: 27 Aug 2009
Posts: 27
score_under 15 Apr 2010, 22:09
XanClic wrote:
ManOfSteel wrote:
Exactly. The whole reason I proposed inc instead of add is that it's more readable (IMO, at least).

Well, you asked for “any” reason. Wink

Tested on my processor (AMD Athlon X2 64, running in 32bit mode) under Windows (none of my optical drives or floppy drives are working, I can't boot off anything), they take exactly the same amount of time. Looped 10000 times.


Last edited by score_under on 20 Apr 2010, 20:04; edited 1 time in total
Post 15 Apr 2010, 22:09
View user's profile Send private message Reply with quote
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
Tyler 15 Apr 2010, 22:30
I didn't use DMA because this is for my bootloader, DMA, from what little I read, seems like overkill for a bootloader. Then again, so was add *,1.
Post 15 Apr 2010, 22:30
View user's profile Send private message Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 15 Apr 2010, 23:12
Talking directly to the controller in your bootloader is overkill. Keep all the fun stuff for your PM device drivers, and use the BIOS for anything RM instead.
Post 15 Apr 2010, 23:12
View user's profile Send private message Reply with quote
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
Tyler 15 Apr 2010, 23:47
I'm trying to avoid using the bios, for no other reason than to learn how to do things on the small scale to make doing it in the kernel slightly easier. I guess I'll use the bios for this though. Thanks for the suggestions and I'll keep in mind how trivial add *,1 can be.
Post 15 Apr 2010, 23:47
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.