IDE: Implement writing using Bus Mastering DMA
This commit is contained in:
parent
9329059510
commit
c6f7f7665c
|
@ -76,9 +76,15 @@ const CMD_IDENTIFY: u8 = 0xEC;
|
||||||
/// ATA read using LBA28 DMA command
|
/// ATA read using LBA28 DMA command
|
||||||
const CMD_READ_DMA: u8 = 0xC8;
|
const CMD_READ_DMA: u8 = 0xC8;
|
||||||
|
|
||||||
|
/// ATA write using LBA28 DMA command
|
||||||
|
const CMD_WRITE_DMA: u8 = 0xCA;
|
||||||
|
|
||||||
/// ATA read using LBA48 DMA command
|
/// ATA read using LBA48 DMA command
|
||||||
const CMD_READ_DMA_EXT: u8 = 0x25;
|
const CMD_READ_DMA_EXT: u8 = 0x25;
|
||||||
|
|
||||||
|
/// ATA write using LBA48 DMA command
|
||||||
|
const CMD_WRITE_DMA_EXT: u8 = 0x35;
|
||||||
|
|
||||||
pub struct PciIde {
|
pub struct PciIde {
|
||||||
device_info: PciDeviceInfo,
|
device_info: PciDeviceInfo,
|
||||||
ide_devices: Vec<IdeDevice>,
|
ide_devices: Vec<IdeDevice>,
|
||||||
|
@ -311,14 +317,14 @@ impl PciIde {
|
||||||
loop {
|
loop {
|
||||||
let status = unsafe { self.bmi_status(channel) };
|
let status = unsafe { self.bmi_status(channel) };
|
||||||
|
|
||||||
|
// FIXME: error handling
|
||||||
|
|
||||||
// Bit 2 (INT) set?
|
// Bit 2 (INT) set?
|
||||||
if (status >> 2) & 1 == 1 {
|
if (status >> 2) & 1 == 1 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: error handling
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Stop DMA
|
// Stop DMA
|
||||||
self.stop(channel);
|
self.stop(channel);
|
||||||
|
@ -335,6 +341,91 @@ impl PciIde {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write(
|
||||||
|
&mut self,
|
||||||
|
channel: Channel,
|
||||||
|
drive: Drive,
|
||||||
|
lba: u64,
|
||||||
|
data: &[u8],
|
||||||
|
) -> Result<(), TryFromIntError> {
|
||||||
|
// FIXME: make this an error
|
||||||
|
assert!(data.len() % SECTOR_SIZE as usize == 0);
|
||||||
|
|
||||||
|
let lba48_support = self
|
||||||
|
.ide_devices
|
||||||
|
.iter()
|
||||||
|
.find(|d| d.channel == channel && d.drive == drive)
|
||||||
|
.map(|d| d.lba48_support)
|
||||||
|
.unwrap(); // FIXME: make this an error
|
||||||
|
let lba48 = lba > 0xFFFFFFF && lba48_support;
|
||||||
|
|
||||||
|
// FIXME: make this an error
|
||||||
|
assert!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF));
|
||||||
|
|
||||||
|
let byte_count = data.len() as u16;
|
||||||
|
let sector_count = byte_count / SECTOR_SIZE;
|
||||||
|
|
||||||
|
// prepare PRD table
|
||||||
|
let prd = PRDT_START as *mut PhysRegionDescriptor;
|
||||||
|
unsafe {
|
||||||
|
(*prd).data_buffer = self.buffer_frames.as_ref().unwrap()[0]
|
||||||
|
.start_address()
|
||||||
|
.as_u64()
|
||||||
|
.try_into()?;
|
||||||
|
(*prd).byte_count = byte_count;
|
||||||
|
// this is the end of table
|
||||||
|
(*prd).eot = 1 << 7;
|
||||||
|
// this byte is reserved, we should probably set it to 0
|
||||||
|
(*prd)._0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the data over to the DMA buffer
|
||||||
|
for i in 0..byte_count {
|
||||||
|
let addr = (BUFFER_START + i as u64) as *mut u8;
|
||||||
|
unsafe {
|
||||||
|
*addr = *data.get(i as usize).unwrap_or(&0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.load_prdt(channel);
|
||||||
|
self.stop(channel);
|
||||||
|
self.set_write(channel);
|
||||||
|
self.clear_bmi_status(channel);
|
||||||
|
select_drive(drive, channel);
|
||||||
|
set_lba(channel, lba, sector_count, lba48);
|
||||||
|
|
||||||
|
if lba48 {
|
||||||
|
ata_send_command(CMD_WRITE_DMA_EXT, channel);
|
||||||
|
} else {
|
||||||
|
ata_send_command(CMD_WRITE_DMA, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.start(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let status = unsafe { self.bmi_status(channel) };
|
||||||
|
|
||||||
|
// FIXME: error handling
|
||||||
|
|
||||||
|
// Bit 2 (INT) set?
|
||||||
|
if (status >> 2) & 1 == 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// Stop DMA
|
||||||
|
self.stop(channel);
|
||||||
|
|
||||||
|
// Clear the interrupt bit
|
||||||
|
self.clear_bmi_status(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn device_info(&self) -> PciDeviceInfo {
|
pub fn device_info(&self) -> PciDeviceInfo {
|
||||||
self.device_info
|
self.device_info
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue