OSDev.org https://forum.osdev.org/ |
|
ATA DMA Implementation with QEMU Version 2.5.0 https://forum.osdev.org/viewtopic.php?f=1&t=32621 |
Page 1 of 1 |
Author: | arysef [ Tue Dec 05, 2017 11:19 am ] |
Post subject: | ATA DMA Implementation with QEMU Version 2.5.0 |
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:
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(()); } |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |