IDE: Add LBA28 addressing support

LBA28 is obsolete at this point, but we prefer to use it over LBA48
whenever we can because LBA28 is faster.
This commit is contained in:
TheOddGarlic 2022-08-17 15:10:00 +03:00
parent f993f6d7b9
commit 9329059510
4 changed files with 57 additions and 51 deletions

View file

@ -73,6 +73,9 @@ const ALT_STATUS_OFFSET: u16 = 2;
/// ATA identification command /// ATA identification command
const CMD_IDENTIFY: u8 = 0xEC; const CMD_IDENTIFY: u8 = 0xEC;
/// ATA read using LBA28 DMA command
const CMD_READ_DMA: u8 = 0xC8;
/// 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;
@ -154,10 +157,8 @@ impl PciIde {
continue; continue;
} }
if (buffer[167] >> 2) & 1 != 1 { // FIXME: CHS support
// FIXME: 24-bit LBA and CHS support let lba48 = (buffer[167] >> 2) & 1 == 1;
error!("IDE drive {channel:?}/{drive:?} does not support 48-bit LBA");
}
let size = buffer[200] as u64 let size = buffer[200] as u64
| (buffer[201] as u64) << 8 | (buffer[201] as u64) << 8
@ -173,6 +174,7 @@ impl PciIde {
channel, channel,
drive, drive,
size, size,
lba48_support: lba48,
}); });
} }
} }
@ -260,9 +262,19 @@ impl PciIde {
drive: Drive, drive: Drive,
lba: u64, lba: u64,
sector_count: u16, sector_count: u16,
) -> Result<Vec<u8>, TryFromIntError> { buffer: &mut Vec<u8>,
) -> Result<(), TryFromIntError> {
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 // FIXME: make this an error
assert!(lba < 0xFFFFFFFFFFFF); assert!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF));
let byte_count = sector_count * SECTOR_SIZE; let byte_count = sector_count * SECTOR_SIZE;
// prepare PRD table // prepare PRD table
@ -285,8 +297,14 @@ impl PciIde {
self.set_read(channel); self.set_read(channel);
self.clear_bmi_status(channel); self.clear_bmi_status(channel);
select_drive(drive, channel); select_drive(drive, channel);
set_lba(channel, lba, sector_count); set_lba(channel, lba, sector_count, lba48);
ata_send_command(CMD_READ_DMA_EXT, channel);
if lba48 {
ata_send_command(CMD_READ_DMA_EXT, channel);
} else {
ata_send_command(CMD_READ_DMA, channel);
}
self.start(channel); self.start(channel);
} }
@ -309,13 +327,12 @@ impl PciIde {
self.clear_bmi_status(channel); self.clear_bmi_status(channel);
} }
let mut buffer = Vec::with_capacity(byte_count as usize); for i in 0..byte_count as u64 {
for i in 0..512 {
let addr = (BUFFER_START + i) as *mut u8; let addr = (BUFFER_START + i) as *mut u8;
buffer.push(unsafe { *addr }); buffer.push(unsafe { *addr });
} }
Ok(buffer) Ok(())
} }
pub fn device_info(&self) -> PciDeviceInfo { pub fn device_info(&self) -> PciDeviceInfo {
@ -474,30 +491,33 @@ unsafe fn ata_delay(channel: Channel) {
} }
/// Set LBA and sector count registers. sector_count of 0 means 65536 sectors /// Set LBA and sector count registers. sector_count of 0 means 65536 sectors
unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16) { unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16, lba48: bool) {
// FIXME: CHS and LBA24 support
assert!(lba < 0xFFFFFFFFFFFF);
let command_block = if channel.secondary() { let command_block = if channel.secondary() {
SECONDARY_COMMAND SECONDARY_COMMAND
} else { } else {
PRIMARY_COMMAND PRIMARY_COMMAND
}; };
let mut seccount = Port::new(command_block + SECCOUNT_OFFSET); let mut seccount = Port::new(command_block + SECCOUNT_OFFSET);
let mut lba0 = Port::new(command_block + LBA0_OFFSET); let mut lba0 = Port::new(command_block + LBA0_OFFSET);
let mut lba1 = Port::new(command_block + LBA1_OFFSET); let mut lba1 = Port::new(command_block + LBA1_OFFSET);
let mut lba2 = Port::new(command_block + LBA2_OFFSET); let mut lba2 = Port::new(command_block + LBA2_OFFSET);
let mut head = Port::new(command_block + DRIVE_HEAD_OFFSET);
let head_value: u8 = head.read();
let lba_bytes = lba.to_le_bytes(); let lba_bytes = lba.to_le_bytes();
let sector_count_bytes = sector_count.to_le_bytes(); let sector_count_bytes = sector_count.to_le_bytes();
// write the new LBA & sector count registers // write the new LBA & sector count registers
// if LBA48 { // FIXME: CHS support
seccount.write(sector_count_bytes[1]); if lba48 {
lba0.write(lba_bytes[3]); seccount.write(sector_count_bytes[1]);
lba1.write(lba_bytes[4]); lba0.write(lba_bytes[3]);
lba2.write(lba_bytes[5]); lba1.write(lba_bytes[4]);
// } lba2.write(lba_bytes[5]);
} else {
head.write(head_value | (lba_bytes[3] & 0x0F));
}
seccount.write(sector_count_bytes[0]); seccount.write(sector_count_bytes[0]);
lba0.write(lba_bytes[0]); lba0.write(lba_bytes[0]);
lba1.write(lba_bytes[1]); lba1.write(lba_bytes[1]);
@ -522,10 +542,11 @@ struct IdeDevice {
pub channel: Channel, pub channel: Channel,
pub drive: Drive, pub drive: Drive,
pub size: u64, // in sectors pub size: u64, // in sectors
// FIXME: model pub lba48_support: bool,
// FIXME: model
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Channel { pub enum Channel {
Primary, Primary,
Secondary, Secondary,
@ -537,7 +558,7 @@ impl Channel {
} }
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Drive { pub enum Drive {
Master, Master,
Slave, Slave,

View file

@ -132,7 +132,8 @@ pub fn scratchpad() {
{ {
let mut pci_ide_device = pci_ide_device.lock(); let mut pci_ide_device = pci_ide_device.lock();
if let PciDevice::Ide(device) = &mut *pci_ide_device { if let PciDevice::Ide(device) = &mut *pci_ide_device {
let first_sector = device.read(Channel::Primary, Drive::Master, 0, 1).unwrap(); let mut first_sector = Vec::with_capacity(512);
device.read(Channel::Primary, Drive::Master, 0, 1, &mut first_sector).unwrap();
trace!("IDE Primary/Master sector 0: {first_sector:?}"); trace!("IDE Primary/Master sector 0: {first_sector:?}");
} }
} }

View file

@ -135,14 +135,14 @@ fn test_push_number() {
assert_eq!( assert_eq!(
bytes, bytes,
vec![ vec![
0b0101_1010, // 90 0b0101_1010, // 90
0b1001_1010, // 154 0b1001_1010, // 154
0b1100_1011, // 203 0b1100_1011, // 203
0b0110_1101, // 109 0b0110_1101, // 109
0b01_1001_00, // 100 0b01_1001_00, // 100
0b0111_1001, // 121 0b0111_1001, // 121
0b0111_0001, // 113 0b0111_0001, // 113
0b1000_0000, // 128 0b1000_0000, // 128
] ]
); );
} }
@ -357,10 +357,7 @@ mod numeric_tests {
fn test_iso_18004_2006_example_1() { fn test_iso_18004_2006_example_1() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_numeric_data(b"01234567"), Ok(())); assert_eq!(bits.push_numeric_data(b"01234567"), Ok(()));
assert_eq!( assert_eq!(bits.into_bytes(), vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b0110_0001, 0b1000_0000]);
bits.into_bytes(),
vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b0110_0001, 0b1000_0000]
);
} }
#[test] #[test]
@ -389,16 +386,7 @@ mod numeric_tests {
assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(()));
assert_eq!( assert_eq!(
bits.into_bytes(), bits.into_bytes(),
vec![ vec![0b0010_0000, 0b00000110, 0b0010_1011, 0b0011_0101, 0b0011_0111, 0b0000_1010, 0b01110101, 0b0010_1000,]
0b0010_0000,
0b00000110,
0b0010_1011,
0b0011_0101,
0b0011_0111,
0b0000_1010,
0b01110101,
0b0010_1000,
]
); );
} }
@ -465,10 +453,7 @@ mod alphanumeric_tests {
fn test_iso_18004_2006_example() { fn test_iso_18004_2006_example() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(())); assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(()));
assert_eq!( assert_eq!(bits.into_bytes(), vec![0b0010_0000, 0b0010_1001, 0b11001110, 0b11100111, 0b0010_0001, 0b0000_0000]);
bits.into_bytes(),
vec![0b0010_0000, 0b0010_1001, 0b11001110, 0b11100111, 0b0010_0001, 0b0000_0000]
);
} }
#[test] #[test]

View file

@ -1,7 +1,6 @@
//! Find the optimal data mode sequence to encode a piece of data. //! Find the optimal data mode sequence to encode a piece of data.
use crate::types::{Mode, Version}; use crate::types::{Mode, Version};
use core::slice::Iter; use core::slice::Iter;
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
@ -155,7 +154,7 @@ impl<'a> Iterator for Parser<'a> {
#[cfg(test)] #[cfg(test)]
mod parse_tests { mod parse_tests {
use alloc::vec::{Vec}; use alloc::vec::Vec;
use crate::optimize::{Parser, Segment}; use crate::optimize::{Parser, Segment};
use crate::types::Mode; use crate::types::Mode;