OSDev.org

The Place to Start for Operating System Developers
It is currently Mon Oct 21, 2019 11:54 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: [ATA PIO] Garbage output from disk
PostPosted: Sun Feb 17, 2019 3:08 am 
Offline
User avatar

Joined: Thu Jan 05, 2017 9:01 am
Posts: 4
I have been trying to write a ATA PIO driver to load files from protected mode, but it would seem that all the data I recieve from the port is garbage (0xffff).

This is my first time writing a PIO driver so Iam not really sure what I'm doing is correct. I have been following the link from OsDev to get 28 bit PIO working. (https://wiki.osdev.org/ATA_PIO_Mode#28_bit_PIO)

Here is the code snippet which tries to load the first sector using PIO reads.

Code:
extern void ata_disk_wait();
extern void ata_drq_wait();

void read_sector(uint32_t sector)
{
    ata_disk_wait(); // wait BSY to 0 and RDY to 1
    outb(0x1F6, sector >> 24 | 0xE0);// Master drive
    outb(0x1F2, 1); // Read one sector
    outb(0x1F3, sector);
    outb(0x1F4, sector >> 8);
    outb(0x1F5, sector >> 16);
    // Make a read call
    outb(0x1F7, 0x20);
    // transfere
}

void read_kernel(uint32_t address, uint32_t sector)
{
    read_sector(sector);
    ata_disk_wait();
    ata_drq_wait();// wait DRQ to 1
    // copy to address
    // insw(0x1F0, (uint32_t)address, 512/2);
}

void
boot_main()
{
    byte *address = (byte *)0x10000; // Save kernel at address
    read_kernel((uint32_t)address, 1);
}   


and from my asm I call this like so:

Code:
mov     sp, 07c00h
call    boot_main

;; get data from port
mov     dx, 01F0h
xor     eax, eax
in      al, dx
mov     [010000h], al


Here are the disk_wait and drq_wait functions:

Code:
  global ata_drq_wait
ata_drq_wait:
    pusha
    xor al, al
    mov dx, 01F7h
.loop:   
    in  al, dx
    test al, 008h
    jz .loop
.end:
    popa
    ret


    global ata_disk_wait
ata_disk_wait:
    pusha
    xor ax, ax
    mov dx, 01F7h
.loop:
    in  al, dx
    and al, 0C0h
    cmp al, 040h
    jne .loop
.end:
    popa
    ret


But all the data which I receive seems to be 0xffff.

I have checked the boot_disk value in my boot loader. and the value of dl is 080h so qemu does boot from hard disk.


Top
 Profile  
 
 Post subject: Re: [ATA PIO] Garbage output from disk
PostPosted: Sun Feb 17, 2019 10:04 am 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 565
Location: USA
qwn wrote:
But all the data which I receive seems to be 0xffff.

Hi,

When reading from a non-existent port, the return value is usually 0xFF. You are probably reading from a non-existent hard drive port address.

Some time ago, years in fact, you could assume there was a hard drive at address 0x1F0. However, this was because of an ISA bus. The ISA bus has been gone for some time and only emulated by newer hardware. In fact, the newer hardware (PCI and the BIOS) would even default the first hard drive to 0x1F0 for this backward compatibility. However, now you cannot and should not rely upon this. You really need to enumerate the PCI(e) and see if and where a hard drive exists. In fact, it could even be an non ATA emulating AHCI controller.

qwn wrote:
I have checked the boot_disk value in my boot loader. and the value of dl is 080h so qemu does boot from hard disk.

The 0x80 in DL has absolutely nothing to do with the type of hard drive and location of this drive. This is a firmware (in this case, the Legacy BIOS) identity byte.

How new/old is your test machine. Are you using an actual test machine or are you using an emulator such as QEMU or Bochs? If you are using one of these emulators, they do, be default, emulate the ISA address of 0x1F0.

Please don't think I am criticizing your code with the following questions, I am just curious.

Why do you call assembly routines for your ata_disk_wait() functions? A good C compiler can and probably will produce as good or better code than you can. Also, by doing it the way you have, there is no way of changing the location of the port address. i.e.: You have hard-coded the address.

Does your insw() function actually use the insw instruction? If so, this isn't recommended. There is not enough of a delay between the reading of each word with this instruction. A loop and the single inpw instruction is required/recommended.

When you wait for the controller to not be busy *and* for the DRQ bit to be set, you can do this with one read while in a loop. No need to check for busy, then check for DRQ. What if the busy bit becomes set between the function calls? i.e.: Check for non-busy *and* DRQ asserted at the same time.

While in real mode, the following
Code:
  mov     [010000h], al

won't do what you think it does. In fact, the assembler should return an error. If it does not, it is truncating the value to 0000h and depending what DS points to, may be overwriting your IVT.

Please read up on 16-bit real-mode, the mode the CPU boots into, and also how to enumerate the PCI.

One more thing, if this is actually your boot code, why not let the firmware (Legacy BIOS or EFI) do the disk access for you? I.e: Call the BIOS to read from the disk?

- Ben
http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
 Post subject: Re: [ATA PIO] Garbage output from disk
PostPosted: Mon Feb 18, 2019 10:59 am 
Offline
User avatar

Joined: Thu Jan 05, 2017 9:01 am
Posts: 4
Hi Ben,
Thanks for your inputs.
Quote:
Are you using an actual test machine or are you using an emulator such as QEMU or Bochs?

Yes I test on QEMU

Quote:
Why do you call assembly routines for your ata_disk_wait() functions? A good C compiler can and probably will produce as good or better code than you can

Hahah actually I had written them in C but just to rule out possibility of some error in my C code I tried rewriting in NASM. TBH i'm not really comfortable with inline assembly so I had a nagging thought that maybe its my implementation of inline assembly which is wrong. But yes you are right, I shall re write in C.

Quote:
Does your insw() function actually use the insw instruction?

Oh! I shall make that correction as well. The wiki actually suggests using rep insw. Strange

Quote:
it is truncating the value to 0000h and depending what DS points to, may be overwriting your IVT.

I'm in protected mode in this context

Quote:
if this is actually your boot code, why not let the firmware (Legacy BIOS or EFI) do the disk access for you? I.e: Call the BIOS to read from the disk?

I could switch to real mode to call INT13 but I wanted to try to write this driver for fun :)


Top
 Profile  
 
 Post subject: Re: [ATA PIO] Garbage output from disk
PostPosted: Mon Feb 18, 2019 3:16 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 565
Location: USA
qwn wrote:
I'm in protected mode in this context
Quote:
if this is actually your boot code, why not let the firmware (Legacy BIOS or EFI) do the disk access for you? I.e: Call the BIOS to read from the disk?

I could switch to real mode to call INT13 but I wanted to try to write this driver for fun :)

"for fun", then I have no objections. That is exactly why we do this in the first place. Go for it.

However, I would like to leave you with a few thoughts for you to think about at a later time.

The firmware (the legacy BIOS or the UEFI) is specifically designed and included for the sole purpose to allow your boot code/loader/start of your kernel to load from the included media (hard drive) without having to have any knowledge of what kind of media it is, i.e.: not having to write an ATA driver just to boot. This is its sole purpose.

The Legacy BIOS loades 512 bytes only. Nothing more. You cannot write a sufficient ATA driver to read from the hard drive *and* a file system driver within 512 bytes. This is the reason you rely upon the firmware's disk read ability. Once you have loaded said boot code/loader/start of kernel with the firmware, you can then use a well written ATA driver because your loader found that you needed to and loaded that driver for you, of course using the firmware's disk reading services.

The firmware is a necessary evil. You must use it to load enough of a system to detect what you need to load, but just as soon as you have, completely ignore/forget about the firmware. This also goes with other things like video and keyboard/mouse input. Once you have used the firmware's abilities to load your own drivers, forget about the firmware all together. (just my opinion. Others may have a different opinion).

However, "for fun" is a good reason. So go for it...

Ben
- http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
 Post subject: Re: [ATA PIO] Garbage output from disk
PostPosted: Mon Feb 18, 2019 3:18 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 1664
BenLunt wrote:
Does your insw() function actually use the insw instruction? If so, this isn't recommended. There is not enough of a delay between the reading of each word with this instruction. A loop and the single inpw instruction is required/recommended.

Where did you hear this? As far as I can tell, it's not true. I've looked at Linux, Windows, and BIOS code and they all use REP INSW and REP OUTSW for PIO.

Intel's manuals do warn that you should ensure writing to the destination address doesn't cause a fault, since the CPU may read the port and discard the result in that situation. (That includes page faults, so your pages must be present and writable.)


Top
 Profile  
 
 Post subject: Re: [ATA PIO] Garbage output from disk
PostPosted: Tue Feb 19, 2019 7:25 am 
Offline
User avatar

Joined: Thu Jan 05, 2017 9:01 am
Posts: 4
FIXED! The issue was that after switching to protected mode I had not cleared interrupt flag. After disabling the interrupts it worked fine

Quote:
The Legacy BIOS loades 512 bytes only. Nothing more. You cannot write a sufficient ATA driver to read from the hard drive *and* a file system driver within 512 bytes

Ah, no this code is actually part of my second stage boot loader which I've read to 0x7e00 using INT13h from the first stage bootloader

Thanks for all your help guys :)


Top
 Profile  
 
 Post subject: Re: [ATA PIO] Garbage output from disk
PostPosted: Tue Feb 19, 2019 9:26 am 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 565
Location: USA
Octocontrabass wrote:
BenLunt wrote:
Does your insw() function actually use the insw instruction? If so, this isn't recommended. There is not enough of a delay between the reading of each word with this instruction. A loop and the single inpw instruction is required/recommended.

Where did you hear this? As far as I can tell, it's not true. I've looked at Linux, Windows, and BIOS code and they all use REP INSW and REP OUTSW for PIO.

Hi Octocontrabass,

I don't remember where I read it. It is in my notes and I only add to my notes what I read from a valuable/reliable source. I will have to see if I can find it again. Also, it will be interesting to do a few tests and see what happens.

- Ben
http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 11 guests


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 post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group