Add structures representing specific devices on a port

This commit is contained in:
pjht 2024-08-21 10:42:16 -05:00
parent 4f6eb0080b
commit 55c78c4fc3
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
4 changed files with 223 additions and 75 deletions

View File

@ -1 +1,100 @@
use crate::{
ata_command::ReadDmaExtCommand,
identify::IdentifyData,
port::{AhciPort, CommandIssueError},
};
pub struct AtaDevice<'a> {
port: &'a AhciPort,
#[allow(unused)]
identify_data: IdentifyData,
sector_size: usize,
capacity: usize,
}
#[derive(Copy, Clone, Debug)]
pub enum AtaNewError {
DeviceTooBig,
}
#[derive(Debug)]
pub enum AtaReadError {
NotAligned,
SizeNotSectMult,
SizeTooBig,
ReadOffEnd,
CommandError(#[allow(unused)] CommandIssueError),
}
impl From<CommandIssueError> for AtaReadError {
fn from(v: CommandIssueError) -> Self {
Self::CommandError(v)
}
}
impl<'a> AtaDevice<'a> {
pub fn new(port: &'a AhciPort, identify_data: IdentifyData) -> Result<Self, AtaNewError> {
let sect_sz_info_valid = identify_data.phys_log_sect_sz & 0xC000 == 0x4000;
let sector_size = if sect_sz_info_valid {
if identify_data.phys_log_sect_sz & 0x1000 == 0x1000 {
identify_data.log_sect_sz as usize
} else {
512
}
} else {
512
};
let num_sects = if identify_data.num_ua_log_sects != 0 {
identify_data.num_ua_log_sects as usize
} else {
identify_data.lba28_num_ua_log_sects as usize
};
let Some(capacity) = num_sects.checked_mul(sector_size) else {
return Err(AtaNewError::DeviceTooBig);
};
Ok(Self {
port,
identify_data,
sector_size,
capacity,
})
}
pub fn identify_data(&self) -> &IdentifyData {
&self.identify_data
}
pub fn phys_no(&self) -> usize {
self.port.phys_no()
}
pub fn read(&self, offset: usize, buf: &mut [u8]) -> Result<(), AtaReadError> {
if offset % self.sector_size != 0 {
return Err(AtaReadError::NotAligned);
};
if buf.len() % self.sector_size != 0 {
return Err(AtaReadError::SizeNotSectMult);
};
if buf.len() / self.sector_size > 65536 {
return Err(AtaReadError::SizeTooBig);
};
if offset + buf.len() > self.capacity {
return Err(AtaReadError::ReadOffEnd);
};
self.port.issue_data_in_command(
&ReadDmaExtCommand::new(
(offset / self.sector_size) as u64,
(buf.len() / self.sector_size) as u16,
),
buf,
)?;
Ok(())
}
pub fn capacity(&self) -> usize {
self.capacity
}
}

24
src/atapi_dev.rs Normal file
View File

@ -0,0 +1,24 @@
use crate::{identify::IdentifyPacketData, port::AhciPort};
pub struct AtapiDevice<'a> {
port: &'a AhciPort,
#[allow(unused)]
identify_data: IdentifyPacketData,
}
impl<'a> AtapiDevice<'a> {
pub fn new(port: &'a AhciPort, identify_data: IdentifyPacketData) -> Self {
Self {
port,
identify_data,
}
}
pub fn identify_data(&self) -> &IdentifyPacketData {
&self.identify_data
}
pub fn phys_no(&self) -> usize {
self.port.phys_no()
}
}

View File

@ -22,15 +22,16 @@
mod ahci_structs;
mod ata_command;
mod ata_dev;
mod atapi_dev;
mod hba;
mod identify;
mod port;
use std::os::mikros::{address_space::ACTIVE_SPACE, syscalls};
use ata_command::{IdentifyCommand, IdentifyPacketCommand, ReadDmaExtCommand};
use hba::Hba;
use itertools::Itertools;
use port::DeviceEnum;
use uuid::Uuid;
use x86_64::structures::paging::PageTableFlags;
@ -83,91 +84,68 @@ fn main() {
let hba = unsafe { Hba::new(reg_base, syslog_client) }.unwrap();
for port in hba.ports() {
if !port.has_device() {
let Ok(device) = port.get_device() else {
syslog_client
.send_text_message(
"ahci",
format!("Port {}: Failed to identify", port.phys_no()),
)
.unwrap();
continue;
};
let Some(device) = device else {
syslog_client
.send_text_message("ahci", format!("Port {}: Empty", port.phys_no()))
.unwrap();
continue;
}
};
let mut ident_buf = [0; 512];
if let Ok(identify_data) = port.issue_data_in_command(&IdentifyCommand, &mut ident_buf) {
let sect_sz_info_valid = identify_data.phys_log_sect_sz & 0xC000 == 0x4000;
let sect_size = if sect_sz_info_valid {
if identify_data.phys_log_sect_sz & 0x1000 == 0x1000 {
identify_data.log_sect_sz as usize
} else {
512
}
} else {
512
};
let capacity = if identify_data.num_ua_log_sects != 0 {
identify_data.num_ua_log_sects as usize
} else {
identify_data.lba28_num_ua_log_sects as usize
};
syslog_client
.send_text_message(
"ahci",
format!(
"Port {}: {} {}, firmware {} ({})",
port.phys_no(),
identify_data.model,
identify_data.serial,
identify_data.firmware,
humansize::format_size(capacity * sect_size, humansize::BINARY)
),
)
.unwrap();
} else {
let regs = port.regs().unwrap();
if regs.lba1 != 0x14 || regs.lba2 != 0xEB {
match device {
port::DeviceEnum::Ata(device) => {
syslog_client
.send_text_message(
"ahci",
format!("Port {} failed to identify", port.phys_no()),
format!(
"Port {}: {} {}, firmware {} ({})",
device.phys_no(),
device.identify_data().model,
device.identify_data().serial,
device.identify_data().firmware,
humansize::format_size(device.capacity(), humansize::BINARY)
),
)
.unwrap();
continue;
}
let Ok(identify_data) =
port.issue_data_in_command(&IdentifyPacketCommand, &mut ident_buf)
else {
port::DeviceEnum::Atapi(device) => {
syslog_client
.send_text_message(
"ahci",
format!("Port {} failed to identify", port.phys_no()),
format!(
"Port {}: {} {}, firmware {}",
device.phys_no(),
device.identify_data().model,
device.identify_data().serial,
device.identify_data().firmware
),
)
.unwrap();
continue;
};
syslog_client
.send_text_message(
"ahci",
format!(
"Port {}: {} {}, firmware {}",
port.phys_no(),
identify_data.model,
identify_data.serial,
identify_data.firmware
),
)
.unwrap();
}
port::DeviceEnum::Other => {
syslog_client
.send_text_message("ahci", format!("Port {}: Unknown", port.phys_no()))
.unwrap();
}
}
}
let mut mbr = [0; 512];
hba.ports()[0]
.issue_data_in_command(&ReadDmaExtCommand::new(0, 1), &mut mbr)
.unwrap();
let DeviceEnum::Ata(ata_dev) = hba.ports()[0].get_device().unwrap().unwrap() else {
panic!();
};
ata_dev.read(0, &mut mbr).unwrap();
let mbr_entries = (0..4)
.map(|i| {
@ -206,9 +184,7 @@ fn main() {
let mut gpt_header = [0; 512];
hba.ports()[0]
.issue_data_in_command(&ReadDmaExtCommand::new(1, 1), &mut gpt_header)
.unwrap();
ata_dev.read(512, &mut gpt_header).unwrap();
if &gpt_header[0..8] != b"EFI PART" {
println!("Invalid GPT signature!");
@ -239,13 +215,10 @@ fn main() {
println!("Partition entries ending LBA: {part_table_end_lba}");
let mut gpt_part_table = vec![0; part_table_num_lbas * 512];
let mut gpt_part_table = vec![0; part_table_len.next_multiple_of(512)];
hba.ports()[0]
.issue_data_in_command(
&ReadDmaExtCommand::new(part_table_start_lba as u64, part_table_num_lbas as u16),
gpt_part_table.as_mut_slice(),
)
ata_dev
.read(part_table_start_lba * 512, &mut gpt_part_table)
.unwrap();
for i in 0..num_parts {

View File

@ -8,7 +8,9 @@ use crate::{
CommandHeader, CommandTableHeader, DeviceRegsRead, FisBuf, PortRegs, Prd, PxCMD, PxIS,
PxSERR, PxSSTS, PxTFD, RegH2DFis,
},
ata_command::AtaCommandDataIn,
ata_command::{AtaCommandDataIn, IdentifyCommand, IdentifyPacketCommand},
ata_dev::{AtaDevice, AtaNewError},
atapi_dev::AtapiDevice,
};
#[allow(clippy::module_name_repetitions)]
@ -30,6 +32,30 @@ pub enum CommandIssueError {
DataTooSmall,
}
#[derive(Copy, Clone, Debug)]
pub enum GetDeviceError {
CommandIssueError(CommandIssueError),
AtaNewError(AtaNewError),
}
impl From<AtaNewError> for GetDeviceError {
fn from(v: AtaNewError) -> Self {
Self::AtaNewError(v)
}
}
impl From<CommandIssueError> for GetDeviceError {
fn from(v: CommandIssueError) -> Self {
Self::CommandIssueError(v)
}
}
pub enum DeviceEnum<'a> {
Ata(AtaDevice<'a>),
Atapi(AtapiDevice<'a>),
Other,
}
impl AhciPort {
pub fn new(
regs: &'static PortRegs,
@ -213,6 +239,32 @@ impl AhciPort {
Ok(command.process_data(buf))
}
pub fn get_device(&self) -> Result<Option<DeviceEnum>, GetDeviceError> {
if !self.has_device() {
return Ok(None);
}
let mut ident_buf = [0; 512];
if let Ok(identify_data) = self.issue_data_in_command(&IdentifyCommand, &mut ident_buf) {
Ok(Some(DeviceEnum::Ata(AtaDevice::new(self, identify_data)?)))
} else {
let regs = self.regs().unwrap();
if regs.lba1 != 0x14 || regs.lba2 != 0xEB {
return Ok(Some(DeviceEnum::Other));
}
let identify_data =
self.issue_data_in_command(&IdentifyPacketCommand, &mut ident_buf)?;
Ok(Some(DeviceEnum::Atapi(AtapiDevice::new(
self,
identify_data,
))))
}
}
fn has_fatal_error(&self) -> bool {
self.regs.PxIS.read(PxIS::HBFS) > 0
|| self.regs.PxIS.read(PxIS::HBDS) > 0