QEMU PIIX3 DMA IDE LBA calculation strangeness

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
venos
Posts: 5
Joined: Wed Oct 30, 2024 6:13 am

QEMU PIIX3 DMA IDE LBA calculation strangeness

Post by venos »

For the first time in a long time, hello OSDev forums! I've not been here since I was maybe 15 (I don't have access to that account any more, long dead email address), getting on for literally half my life ago. I was probably a bit of an annoying know-it-all so-and-so back then, as most teens are, and for that I can only apologise.

I'm getting rather a lot further this time, and am almost at the point where I can read in a file from its path, the longer way around (as in, enumerate ACPI, emumerate PCI bus, find and initialise IDE controllers, and so forth), giving me a solid foundation to build upon.

I'm experiencing some strangeness around LBA addresses. For addresses <255, I have to add 1 to it for some reason - attempting to read LBA 0 gives me an ABORT, but reading LBA 1 gives me the first sector.

For addresses >255, things seem to get all kinds of muddled. Attempting to read sector 465 (+1 when programming = 466) instead yields sector 1217, verified by outputting the hex, and comparing the disk image manually in a hex editor to find that particular string.

Neither of these things seem like they should be true, yet here we are, and for the life of me I can't work out what I've done wrong.

The device reports on the PCI bus as a PIIX3 IDE controller. Using debug printing I can confirm the sector I'm reading is indeed sector 466, taken 1 indexed, when programming the LBA registers.

The command line I'm using is:

Code: Select all

qemu-system-x86_64 -bios $OVMF_PURE_EFI -drive format=raw,file=uefi.img -accel kvm
The relevant code is below (Rust):

Code: Select all

const IDE_CTL_HOB: u8 = 1 << 7;

const IDE_CTL_REG: u16 = 0;
const IDE_REG_LBA0: u16 = 3;
const IDE_REG_LBA1: u16 = 4;
const IDE_REG_LBA2: u16 = 5;
const IDE_REG_SECCOUNT: u16 = 2;

impl IdeDrive {
    fn select_drive_and_set_xfer_params(&self, ctl: &RwLockWriteGuard<'_, IdeController>, offset: u64, size: u64) {
	self.select(&ctl);

	// debug to confirm I'm trying to read the sector I think I should be
	log::info!("Reading {}", offset);

	if self.ident.is_lba48() {
	    unsafe {
		let mut lba3_reg = Port::<u8>::new(ctl.io_base + IDE_REG_LBA0);
		let mut lba4_reg = Port::<u8>::new(ctl.io_base + IDE_REG_LBA1);
		let mut lba5_reg = Port::<u8>::new(ctl.io_base + IDE_REG_LBA2);
		let mut seccount1_reg = Port::<u8>::new(ctl.io_base + IDE_REG_SECCOUNT);
		let mut ctl_reg = Port::<u8>::new(ctl.control_base + IDE_CTL_REG);

		let control_word_high_order = ctl_reg.read() | IDE_CTL_HOB;
		ctl_reg.write(control_word_high_order);

		lba3_reg.write((offset >> 24) as u8);
		lba4_reg.write((offset >> 32) as u8);
		lba5_reg.write((offset >> 40) as u8);
		seccount1_reg.write((size >> 8) as u8);

		let control_word_low_order = ctl_reg.read() & !IDE_CTL_HOB;
		ctl_reg.write(control_word_low_order);
	    }
	}

	unsafe {
	    let mut lba0_reg = Port::<u8>::new(ctl.io_base + IDE_REG_LBA0);
	    let mut lba1_reg = Port::<u8>::new(ctl.io_base + IDE_REG_LBA1);
	    let mut lba2_reg = Port::<u8>::new(ctl.io_base + IDE_REG_LBA2);
	    let mut seccount0_reg = Port::<u8>::new(ctl.io_base + IDE_REG_SECCOUNT);
	    
	    lba0_reg.write(offset as u8);
	    lba1_reg.write((offset >> 8) as u8);
	    lba2_reg.write((offset >> 16) as u8);
	    seccount0_reg.write(size as u8);
	}
    }
}
The one thing I'm aware I should do is convert IdeController to a Mutex, not a RWLock, but that shouldn't affect this, as it's single threaded polling code (although I'm doing DMA, I'm not awaiting interrupts, I haven't implemented that yet, and I also haven't started any APs, this is BSP only).

Help would be greatly appreciated, as I'm at a genuine loss as to why it's behaving the way that it is.

Kind regards,
Venos :3
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: QEMU PIIX3 DMA IDE LBA calculation strangeness

Post by iansjack »

I may be missing something, but you appear to be reading the disk in CHS mode.
venos
Posts: 5
Joined: Wed Oct 30, 2024 6:13 am

Re: QEMU PIIX3 DMA IDE LBA calculation strangeness

Post by venos »

iansjack wrote: Wed Oct 30, 2024 9:24 am I may be missing something, but you appear to be reading the disk in CHS mode.
Oh, that was stupid. Yes, yes I was. Apparently I transposed a couple bits in my head when reading the register fields (that or got my bit shifts off by one, one of the two).

It now behaves exactly as I expect. Thanks for the help :)
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: QEMU PIIX3 DMA IDE LBA calculation strangeness

Post by Octocontrabass »

venos wrote: Wed Oct 30, 2024 6:45 amIDE_CTL_HOB
HOB only affects reading the IDE task file registers, not writing.
Post Reply