OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Apr 23, 2024 2:58 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2
Author Message
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Thu Jan 09, 2020 10:36 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5143
Assuming you're not using the "q35" machine type, it's easiest to use the "-hda" option to attach your disk, which would look something like this:

-hda disk.img

You shouldn't get any warnings about raw disk images with your qcow2 disk image, but you will if you're using a raw disk image. You need a slightly longer command if you want to override the warning when you're using raw disk images:

-drive file=disk.img,index=0,media=disk,format=raw

Either of these choices will attach your disk to an IDE controller on the default i440fx machine.


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Thu Jan 09, 2020 2:44 pm 
Offline
Member
Member

Joined: Sun Jun 23, 2019 5:36 pm
Posts: 618
Location: North Dakota, United States
Octocontrabass wrote:
Assuming you're not using the "q35" machine type, it's easiest to use the "-hda" option to attach your disk, which would look something like this:

-hda disk.img

You shouldn't get any warnings about raw disk images with your qcow2 disk image, but you will if you're using a raw disk image. You need a slightly longer command if you want to override the warning when you're using raw disk images:

-drive file=disk.img,index=0,media=disk,format=raw

Either of these choices will attach your disk to an IDE controller on the default i440fx machine.

So, I think I know why its not working. The way that Cargo xrun is launching Qemu is like this:
Code:
qemu-system-x86_64 -drive format=raw,file=target/x86_64-kernel-none/debug/bootimage-kernel.bin -serial stdio -soundhw all -no-reboot -hdb disk.img -cpu max -s -m 1G

I had to use -hdb and not -hda because -hda is taken up by the kernel. Apparently the kernel is a hard disk image. Is there a way I can detect qemu from within my kernel and make my system probe from -hdb, and how would I probe -hdb and not -hda? I'm getting the correct sector count; the boot image is 505856 bytes, exactly 988 sectors (assuming a 512-byte count per sector). If I probe the correct image, assuming a 512-byte sector size, I should be getting approximately 204800 sectors.
Update: just figured it out. The actual disk I'm looking for is 0xB0 and 0x50, respectively. 0xA0 is the kernel itself, which explains the ridiculously low sector count. Now to consult INCITS 452-2009 (R 2019) for how to write and read data. I still am unsure how to detect whether I'm in qemu or not. Then I would be able to skip reading the master and read the slave instead.
Edit: OK, so I'm able to read words from the disk. Yay! Thanks for the help :)!


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Thu Jan 09, 2020 3:17 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5143
Ethin wrote:
The actual disk I'm looking for is 0xB0 and 0x50, respectively.

Where are you getting 0x50 from? You should always set bits 7 and 5 in the drive/head register. Bit 4 selects the slave drive when set.

Ethin wrote:
I still am unsure how to detect whether I'm in qemu or not. Then I would be able to skip reading the master and read the slave instead.

Read the first sector of the master. Compare it to your bootloader. If it's a match, skip the master.


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Thu Jan 09, 2020 4:39 pm 
Offline
Member
Member

Joined: Sun Jun 23, 2019 5:36 pm
Posts: 618
Location: North Dakota, United States
Octocontrabass wrote:
Ethin wrote:
The actual disk I'm looking for is 0xB0 and 0x50, respectively.

Where are you getting 0x50 from? You should always set bits 7 and 5 in the drive/head register. Bit 4 selects the slave drive when set.

Its in the ATA PIO mode article:
Quote:
48 bit PIO

Reading sectors using 48 bit PIO is very similar to the 28 bit method:

(Notes: A sector count of 0 means 65536 sectors = 32MB. Try not to send bytes to the same IO port twice in a row. Doing so is much slower than doing two outb() commands to different IO ports. The important thing is that the high byte of the sector count, features and LBA bytes 4, 5, & 6 go to their respective ports before the low bytes.)

Assume you have a sectorcount uint16_t and a 6 byte LBA value. Mentally number the LBA bytes as 1 to 6, from low to high. Send the 2 byte sector count to port 0x1F2 (high byte first), and the six LBA byte pairs to ports 0x1F3 through 0x1F5 in some appropriate order.

An example:

Send 0x40 for the "master" or 0x50 for the "slave" to port 0x1F6: outb(0x1F6, 0x40 | (slavebit << 4))
outb (0x1F2, sectorcount high byte)
outb (0x1F3, LBA4)
outb (0x1F4, LBA5)
outb (0x1F5, LBA6)
outb (0x1F2, sectorcount low byte)
outb (0x1F3, LBA1)
outb (0x1F4, LBA2)
outb (0x1F5, LBA3)
Send the "READ SECTORS EXT" command (0x24) to port 0x1F7: outb(0x1F7, 0x24)

Note on the "magic bits" sent to port 0x1f6: Bit 6 (value = 0x40) is the LBA bit. This must be set for either LBA28 or LBA48 transfers. It must be clear for CHS transfers. Any drive that can support LBA48 will ignore all other bits on this port for an LBA48 command. You can set them if it will make your code cleaner (to use the same magic bits as LBA28).

To write sectors in 48 bit PIO mode, send command "WRITE SECTORS EXT" (0x34), instead. (As before, do not use REP OUTSW when writing.) And remember to do a Cache Flush after each write command completes.

After the command byte is sent, transfer each sector of data in exactly the same way as for a 28 bit PIO Read/Write command.

If this data is incorrect, then what is the "proper" procedure to read and write data? I don't have the transport specifications (ATA8 APT and ATA8 aST) and ATA8 AAM, so I'm relying on the wiki for this part. Should I acquire ATA8 AAM, AST and APT and work off of those like I'm doing with ATA8 ACS?
Ethin wrote:
I still am unsure how to detect whether I'm in qemu or not. Then I would be able to skip reading the master and read the slave instead.

Read the first sector of the master. Compare it to your bootloader. If it's a match, skip the master.[/quote]
Easier said than done. The bootloader is built *after* my kernel. If it were built *before* it, I could just include is bytes into my kernel and do a comparison with that. But I can't really do that.


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Fri Jan 10, 2020 2:20 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5143
Ethin wrote:
Its in the ATA PIO mode article:

Drives are supposed to ignore bits 5 and 7, but hardware tends to be stupid. Even though the article says 0x40/0x50 should work fine, I'd still recommend using 0xE0/0xF0 instead.

Ethin wrote:
If it were built *before* it, I could just include is bytes into my kernel and do a comparison with that. But I can't really do that.

You can cheat. Cut the first 512 bytes out of one of your kernel disk images and use that.


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Fri Jan 10, 2020 4:29 pm 
Offline
Member
Member

Joined: Sun Jun 23, 2019 5:36 pm
Posts: 618
Location: North Dakota, United States
Octocontrabass wrote:
Ethin wrote:
Its in the ATA PIO mode article:

Drives are supposed to ignore bits 5 and 7, but hardware tends to be stupid. Even though the article says 0x40/0x50 should work fine, I'd still recommend using 0xE0/0xF0 instead.

Will do. I'm kinda curious why we use 0xA0 and 0xB0 when calling identify device but use 0xE0 and 0xF0/0x40 and 0x50 for reading and writing to sectors. Shouldn't I use 0xE0 and 0xF0 everywhere?
Octocontrabass wrote:
Ethin wrote:
If it were built *before* it, I could just include is bytes into my kernel and do a comparison with that. But I can't really do that.

You can cheat. Cut the first 512 bytes out of one of your kernel disk images and use that.

Good advice, will do too! Thanks!


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Fri Jan 10, 2020 11:00 pm 
Offline
Member
Member

Joined: Sun Jun 23, 2019 5:36 pm
Posts: 618
Location: North Dakota, United States
OK, so this is just weird. I'm trying to search for the EFI signature part of a GPT (I mounted my QCOW2 image as an NBD using qemu-nbd and created a GPT partition on it with gdisk, and formatted that partition as ext2). The weirdness is that the first 8 bytes of the disk, at least from what I'm getting, are 5C010052504945, not 5452415020494645. Reversing the order in which I create the array of bytes (hi then lo) I get 54412046. I'm trying to pack this into a 64-bit integer so I don't need to go through the array of 8 bytes and verify it, and the fact that I'm gettin 54412046 is a good sign, but that would mean that the signature is 9 bytes, not 8. I doubt getting the hi and then lo bytes from the read-in words is the right way -- that's BE, not LE. I'm not really what I'm doing wrong. I'm using rusts u64::from_le_bytes function. The code for that isn't exactly intuitive. Trying to use bit shifting got me bit shift overflows (bit shifting to the left by 56), so I'm not really what I'm doingwrong now.Thoughts? Am I just over-thinking the problem?
Edit: here's my code for reading sectors:
Code:
pub unsafe fn read_sectors_ext(drive: u8, lba: u64, count: u16)->[u8; 512] {
match drive {
0 => outb(0xE0, DRIVESEL),
1 => outb(0xF0, DRIVESEL),
2 => outb(0xE0, DRIVESEL2),
3 => outb(0xF0, DRIVESEL2),
d => panic!("ATA: read sector(s) extended got invalid drive number {}", d)
}
outb(count.get_bits(8 ..= 15) as u8, SECTOR_COUNT);
outb(lba.get_bits(24 .. 32) as u8, LBAL);
outb(lba.get_bits(32 .. 40) as u8, LBAM);
outb(lba.get_bits(40 .. 48) as u8, LBAH);
outb(count.get_bits(0 .. 8) as u8, SECTOR_COUNT);
outb(lba.get_bits(0 .. 8) as u8, LBAL);
outb(lba.get_bits(8 .. 16) as u8, LBAM);
outb(lba.get_bits(16 .. 24) as u8, LBAH);
outb(ATACommand::ReadSectorsExt as u8, COMMAND);
while inb(STATUS).get_bit(BSY) {
hlt();
}
let mut sector: [u8; 512] = [0; 512];
for i in 0 .. 511 {
let word = inw(DATA);
sector[i] = word.get_bits(0 .. 8) as u8;
sector[i + 1] = word.get_bits(8 .. 16) as u8;
}
sector
}


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Sat Jan 11, 2020 2:28 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5143
Ethin wrote:
I'm kinda curious why we use 0xA0 and 0xB0 when calling identify device but use 0xE0 and 0xF0/0x40 and 0x50 for reading and writing to sectors. Shouldn't I use 0xE0 and 0xF0 everywhere?

It doesn't matter which one you use for the identify command, since bit 6 is used to select LBA addressing and the identify command doesn't use the address. Ancient hardware that doesn't support LBA will misbehave if bit 6 is set.

Ethin wrote:
The weirdness is that the first 8 bytes of the disk, at least from what I'm getting, are 5C010052504945, not 5452415020494645.

The iterator you're using to fill the sector buffer is reading 512 words and inadvertently discarding half of each, instead of the intended 256 words. The results you're getting are every other byte on the disk. I don't know enough Rust to suggest a fix.


Top
 Profile  
 
 Post subject: Re: ATA read returning 0xFF...
PostPosted: Sat Jan 11, 2020 11:36 am 
Offline
Member
Member

Joined: Sun Jun 23, 2019 5:36 pm
Posts: 618
Location: North Dakota, United States
Thanks for that. The iterator I'm using isn't discarding anything, at least from what I can tell. I was extracting way too many words, so I'll fix that, but what I was trying to do was extract the bytes from the words so I could work with the bytes and not words (because working with bytes is a bit easier than working with words). Should I extract the words from the DATA port, and then extract the lobyte and hibyte and return the extracted bytes?
Edit: think I figured it out. I'll edit this post if it turns out I haven't. Thanks for all the help thus far! :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2

All times are UTC - 6 hours


Who is online

Users browsing this forum: hgruniaux, Majestic-12 [Bot], SemrushBot [Bot] and 104 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