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

View file

@ -132,7 +132,8 @@ pub fn scratchpad() {
{
let mut pci_ide_device = pci_ide_device.lock();
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:?}");
}
}

View file

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

View file

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