1

After using Redox's ahcid as a reference implementation for writing an AHCI driver (which isn't an exact clone of that implementation but it's close) that is compatible with a kernel that began life by following Philipp Oppermann's Rust OS development tutorial and has since diverged greatly therefrom due to further research on my part, I attempted to initialize it like so, making use of the ACPI crate to attempt to find the AHCI controller address:

// snip
entry_point!(maink);

fn maink(boot_info: &'static mut BootInfo) -> ! {
// snip
    let rsdp = boot_info.rsdp_addr.clone().into_option().unwrap();
// snip

    info!("RSDP address: {:#x}", rsdp.clone());
// snip

    let tables = unsafe { AcpiTables::from_rsdp(KernelAcpi, rsdp.clone() as usize).unwrap() };
    let mcfg = match PciConfigRegions::new(&tables) {
        Ok(mcfg) => Some(mcfg),
        Err(_) => None,
    };
// snip
    let sata_ctrl = match mcfg {
        Some(mcfg) => mcfg.physical_address(0x0, 0x1, 0x6, 0x1),
        None => None,
    };
// snip
   if let Some(addr) = sata_ctrl {
        map_page!(
            addr,
            addr,
            Size2MiB,
            PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_CACHE
        );
        let (_, disks) = ahci::disks(addr as usize);
        info!("Found {:#?} disks", disks.len());
    }
// snip

Actually trying to run this returns this output ― note the 0xffffffff across the board:

QEMU output

Curiously, Googling AHCI did reveal that 0xffffffff is normal port behavior for disconnected drives, but I'm curious as to why cap, ghc, is, pi, vs, cap2, and bohc are all also 0xffffffff. What is masking these values and why? It shouldn't have these register masks all the way down to the ABAR root, and what must be done to get rid of them?

realkstrawn93
  • 722
  • 1
  • 6
  • 13

2 Answers2

2

The physical address space contains multiple things (RAM, ROM, memory mapped devices); but sometimes there's literally nothing at a physical address.

If you try to read from "literally nothing" (an area where there isn't any RAM, ROM or memory mapped device) modern computers return "all bits set" (e.g. 0xFFFFFFFF for a 32-bit read).

In other words; you think you're reading values from a memory mapped device (an AHCI controller) but somehow the physical address was wrong so you're actually reading from literally nothing.

For a guess; I'd assume the problem is that the physical address is 0xB0131000 which is not aligned to a 2 MiB boundary; but you try to map it as a 2 MiB "large page" that requires it to be on a 2 MiB boundary, so the lower bits get discarded; and you end up accessing the physical address 0xB0100000 and not 0xB0131000.

Brendan
  • 35,656
  • 2
  • 39
  • 66
1

As Brendan hinted at, the virtual address mapping needs to be properly page-aligned. The following, therefore, worked:

// snip
    if let Some(addr) = sata_ctrl {
        let test_page = Page::<Size2MiB>::containing_address(VirtAddr::new(addr + boot_info.physical_memory_offset.clone().into_option().unwrap().clone()));
        let virt = test_page.start_address().as_u64();
        map_page!(
            addr,
            virt,
            Size2MiB,
            PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_CACHE
        );
        let (_, disks) = ahci::disks(virt as usize);
        info!("Found {:#?} disks", disks.len());
    }
// snip
realkstrawn93
  • 722
  • 1
  • 6
  • 13