OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Feb 23, 2018 12:45 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: ATA DMA Implementation with QEMU Version 2.5.0
PostPosted: Tue Dec 05, 2017 11:19 am 
Offline

Joined: Sat Dec 02, 2017 6:40 pm
Posts: 2
I'm trying out using PCI Busmastering ATA DMA to read from a hard disk.
I've been having trouble getting it to do reads. A single interrupt occurs and the status byte for DMA reads 0x04, but no data is transferred to the space in memory designated by the PRD. For testing, I'm currently using a PRDT with a single PRD in it.

The order of steps I'm taking:

    Clear the command byte
    Set bit 3 in the status byte
    Send the appropriate values to the to PCI config register
    Set bit 2 in the PCI command register
    Allocate a frame and retrieve its start address
    Create a PRDT (physical region descriptor table) with one PRD, and retrieve its start address
    Send the PRDT address to the DMA_PRDT_ADDR register
    Reset IRQ status by setting bit 2 in the DMA status byte
    Set bit 3 in the DMA command byte to set data transfer direction to read
    Clear bits 0 and 2 in the DMA status byte
    Set the PRIMARY_BUS_SELECT register for the drive with the drive value, the sector count, and the most significant 8 bits of the LBA
    Set the SECTOR_COUNT register and the other 3 LBA registers
    Set the COMMAND_IO register to 0xC8 in the drive to set it to DMA read
    Set bit 1 of the command byte to start the transfer

The largest issue has been figuring out how to debug the problem, because I'm unaware of many intermediary steps where progress can be checked to narrow down the issue.

Thanks for the help and time!


Code:
pub fn read_from_disk_v2(drive: u8, lba: u32, sector_count: u32) -> Result<PhysicalAddress, ()> {

    //Resetting bus master command register,
    unsafe{
    DMA_PRIM_COMMAND_BYTE.outb(0);
    DMA_PRIM_STATUS_BYTE.outb(4);
    }

    //selects the PCI command register: the device is currently hardcoded to bus 0, slot 1, function 1, and the value to access the command register is an offset of 4
    //following steps for this as outlined in http://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231
    PCI_CONFIG_ADDRESS_PORT.outb((1 << 11) | (1 << 8) | (4 & 0xFC) | 0x8000_0000);
    //writes the value in the PCI data register to have it transferred to the selected PCI register, using this to set bit 2 in the command register
    PCI_DATA_ADDRESS_PORT.outb(4);


    //Frame allocation occurs here
     if let Some(frame) = allocate_frame() {
        let addr = frame.start_address();
        let start_addr: u32 = addr as u32;
       
        //prdt table defined: currently one PRD in PRDT for testing
        //sector count is multiplied by 512 because 512 bytes in a sector
        let prdt: [u64;1] = [start_addr as u64 | (sector_count as u64) *512 << 32 | 1 << 63];
        let prdt_ref = &prdt[0] as *const u64;

        //gets the physical address of the prdt and sends that to the DMA prdt register
        let prdt_paddr = assign_prdt_paddr();
 
        DMA_PRIM_PRDT_ADDR.outl(prdt_paddr);
        DMA_PRIM_STATUS_BYTE.outb(0x04); // to reset the interrupt 0x14 status

   

        //set bit 3 to set direction of controller for "read"
        //http://wiki.osdev.org/ATA/ATAPI_using_DMA#The_Command_Byte states bit 3 value = 8, need to check if that's a typo
        DMA_PRIM_COMMAND_BYTE.outb(0x08);

        //get original value in the DMA status register and clear bits 0 and 2
        let original_status = DMA_PRIM_STATUS_BYTE.inb();
        //0xFA is value to clear bits 0 and 2 (0b11111010 in binary)
        unsafe{DMA_PRIM_STATUS_BYTE.outb(original_status & 0xFA);}
       
        //selects the drive (0xE0 for primary in this case) and sends top 8 bits of LBA (0 for testing)  and sector count(1 in this case) to appropriate registers
        let master_select: u8 = 0xE0 | (0 << 4) | ((lba >> 24) & 0x0F) as u8;
        PRIMARY_BUS_SELECT.outl(master_select);
       
        //enters the sector count and the other 3 bytes of the LBA to the appropriate registers
        SECTORCOUNT.outb(1);
        LBALO.outb(lba);
        LBAMID.outb(lba>>8);
        LBAHI.outb(lba>>16);
         
        //sets the value in the command_io register to 0xC8, the code for DMA read
        COMMAND_IO.outb(0xC8);
       
        //setting bit 1 of the command byte starts the transfer
        DMA_PRIM_COMMAND_BYTE.outb(0x08 | 0x01);
        return Ok(start_addr);
     }
    return Err(());
}


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: akasei, ShukantPal and 6 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