Page 1 of 1

Cannot read data from hard disk

Posted: Thu Sep 22, 2011 12:39 pm
by ElasticRaven
I am trying to load a file (my kernel) from disk. I think I've followed the instructions at http://wiki.osdev.org/ATA_PIO_Mode correctly, but my data is never loaded. Instead, the destination memory space is filled with zeros. I am checking the error bit, etc. but they are always clear.

I am using the 28-bit LBA address method. My file begins at byte 2048 on the drive. I am just reading one sector for now. Am I correct in thinking that my LBA address should be 5 [EDIT: should have been 4 because LBA addresses start with 0 instead of 1] and my sectorcount should be 1?

I am confused by the statement "A sectorcount of 0 means 256 sectors = 128K," to the point that I don't really trust it. 128K seems like a huge amount of data for what appears to be the smallest possible read size. Is there any way that I can read just a few sectors?

Any help would be appreciated.

Re: Cannot read data from hard disk

Posted: Thu Sep 22, 2011 1:29 pm
by intx13
ElasticRaven wrote:I am confused by the statement "A sectorcount of 0 means 256 sectors = 128K," to the point that I don't really trust it. 128K seems like a huge amount of data for what appears to be the smallest possible read size. Is there any way that I can read just a few sectors?
A read of 0 sectors wouldn't be very useful, so 0 is reused as the largest read size. So instead of being able to read up to 255 sectors at a time you can read up to 256 sectors at a time. This is common for a lot of IO on a lot of different devices where 0 doesn't make much sense.

Re: Cannot read data from hard disk

Posted: Thu Sep 22, 2011 2:57 pm
by gerryg400
ElasticRaven wrote:I am confused by the statement "A sectorcount of 0 means 256 sectors = 128K," to the point that I don't really trust it. 128K seems like a huge amount of data for what appears to be the smallest possible read size. Is there any way that I can read just a few sectors?

Any help would be appreciated.
It goes like this

Code: Select all

int read_sectors(uint8_t sectorcount) {

    if (sectorcount == 0) {
        read 256 sectors
    }
    else {
        read sectorcount sectors
    }
}

Re: Cannot read data from hard disk

Posted: Fri Sep 23, 2011 2:04 am
by Combuster
Actually the BIOS would do things more like the following:

Code: Select all

do
{
    read_sector();
    sector_count--;
} while (sector_count)
Now see what happens if you pass in sector_count=0 at the start :wink:

Re: Cannot read data from hard disk

Posted: Fri Sep 23, 2011 6:39 am
by ElasticRaven
Ok, thanks. So sectorcount makes sense, but what about the LBA address? It's just the sector number from the beginning of the disk, right? I'm still getting a bunch of zeros.

Code: Select all

ATARead:
  ;read bl sectors from primary ATA controller master into [edi]
  ;starting at LBA [esi]
  push edi
  push eax
  push ecx
  push edx

  mov  dx,0x1F7     ;status register
.busy_loop:
  in   al,dx        ;set AL to status register
  and  al,10000000b ;check MSB of al (BSY)
  jnz  .busy_loop   ;poll again if BSY=1

  mov  dx,0x1F7     ;status register
.drdy_loop:
  in   al,dx        ;set al to status register
  and  al,01000000b ;check 2nd bit of al (DRDY)
  jz  .drdy_loop    ;poll again if DRDY=0

  mov  dx,0x1F6     ;device/head register
  mov  ecx,esi      ;copy lba address
  shr  ecx,24
  and  ecx,0x0F     ;highest 4 bits of LBA
  mov  al,0xE0      ;device 0 (master)
  or   al,cl        ;ORed with highest 4 bits of LBA
  out  dx,al        ;select device

  mov  dx,0x1F1     ;features/error info register
  mov  al,0
  out  dx,al        ;clear features/error info register (ignored anyway)

  mov  dx,0x1F2     ;sector count register
  mov  al,bl        ;sector count
  out  dx,al        ;set sector sount

  mov  eax,esi      ;load lba
  mov  dx,0x1F3     ;low lba register
  out  dx,al        ;set low lba address
  shr  eax,8        ;al becomes middle lba address
  mov  dx,0x1F4     ;middle lba register
  out  dx,al        ;set middle lba address
  shr  eax,8        ;al becomes high lba address
  mov  dx,0x1F5     ;high lba register
  out  dx,al        ;set high lba address

  mov  dx,0x1F7     ;command register
  mov  al,0x20      ;read sectors command
  out  dx,al        ;send read sectors command

  mov  dx,0x3F6     ;alternate status register
  in   al,dx        ;wait 100ns
  mov  dx,0x3F6     ;alternate status register
  in   al,dx        ;wait 100ns
  mov  dx,0x3F6     ;alternate status register
  in   al,dx        ;wait 100ns
  mov  dx,0x3F6     ;alternate status register
  in   al,dx        ;wait 100ns

  mov  dx,0x1F7     ;status register
.bsy_loop2:
  in   al,dx        ;set al to status register
  and  al,10000000b ;check BSY bit
  jnz  .bsy_loop2   ;poll again if BSY=1

  mov  dx,0x1F7     ;status register
.drq_loop:
  in   al,dx        ;set al to status register
  and  al,00000001b ;check ERR bit
  jnz  .err         ;error
  in   al,dx        ;set al to status register
  and  al,00001000b ;check DRQ bit
  jz   .drq_loop    ;poll again if DRQ=0

  mov  dx,0x1F0     ;data register
  mov  ecx,256d     ;number of words to read
  cld               ;clear direction flag so insw increments edi
  rep  insw         ;read words from data register

  jmp .end

.err:
  push esi
  mov  esi,ReadErrorString
  call PrintStringVideo32
  pop  esi
  jmp .end

.end:
  pop  edx
  pop  ecx
  pop  eax
  pop  edi

  ret
I'm calling it with

Code: Select all

mov  esi,5               ;sector number
mov  edi,0x00010000      ;destination address
mov  bl,1                ;sector count
mov  byte [edi+1],'X'
call ATARead             ;read from disk
mov  al,[edi+1]
call PrintCharVideo32
But 'X' gets replaced by 0x0, when it should be replaced by 'E' (since I'm reading an ELF file).

Re: Cannot read data from hard disk

Posted: Fri Sep 23, 2011 11:49 am
by guyfawkes
Should this not be 0xA0

Code: Select all

mov  al,0xE0      ;device 0 (master)
  or   al,cl        ;ORed with highest 4 bits of LBA
  out  dx,al        ;select device

Re: Cannot read data from hard disk

Posted: Fri Sep 23, 2011 1:40 pm
by ElasticRaven
guyfawkes wrote:Should this not be 0xA0

Code: Select all

mov  al,0xE0      ;device 0 (master)
  or   al,cl        ;ORed with highest 4 bits of LBA
  out  dx,al        ;select device
I tried both 0xE0 and 0xA0. The wiki page I linked to says use 0xE0 (it says use 0xA0 for IDENTIFY, though).

EDIT: Figured it out.

Re: Cannot read data from hard disk

Posted: Sun Feb 01, 2015 5:30 pm
by danielbj
First of all: I am sorry to bump a four year old thread, but this is the only one I could find, that matches my problem.

The good thing about a forum, is that answers and knowledge is not lost. Not even years after that knowledge has been revealed.
The bad thing is when the answers and solutions are never posted. This is, in my opinion, against the purpose of a forum.

Now I'm reading this thread, knowing that the dear Mr(s). ElasticRaven has the solution to my problem. Unfortunately that very same user is no longer active on this forum, making it rather difficult for me to find him. The last time he paid us a visit was Fri Oct 07, 2011 11:37 am. He might as well be gone forever.

And the worst part?
I WILL NEVER KNOW HIS SECRET.

Re: Cannot read data from hard disk

Posted: Mon Feb 02, 2015 5:16 am
by zhiayang
There was truly never any more appropriate time for this xkcd to appear.
Image