Add structures representing specific devices on a port
This commit is contained in:
parent
4f6eb0080b
commit
55c78c4fc3
@ -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
24
src/atapi_dev.rs
Normal 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()
|
||||
}
|
||||
}
|
107
src/main.rs
107
src/main.rs
@ -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
|
||||
};
|
||||
|
||||
match device {
|
||||
port::DeviceEnum::Ata(device) => {
|
||||
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)
|
||||
device.phys_no(),
|
||||
device.identify_data().model,
|
||||
device.identify_data().serial,
|
||||
device.identify_data().firmware,
|
||||
humansize::format_size(device.capacity(), humansize::BINARY)
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
let regs = port.regs().unwrap();
|
||||
|
||||
if regs.lba1 != 0x14 || regs.lba2 != 0xEB {
|
||||
syslog_client
|
||||
.send_text_message(
|
||||
"ahci",
|
||||
format!("Port {} failed to identify", port.phys_no()),
|
||||
)
|
||||
.unwrap();
|
||||
continue;
|
||||
}
|
||||
|
||||
let Ok(identify_data) =
|
||||
port.issue_data_in_command(&IdentifyPacketCommand, &mut ident_buf)
|
||||
else {
|
||||
syslog_client
|
||||
.send_text_message(
|
||||
"ahci",
|
||||
format!("Port {} failed to identify", port.phys_no()),
|
||||
)
|
||||
.unwrap();
|
||||
continue;
|
||||
};
|
||||
|
||||
port::DeviceEnum::Atapi(device) => {
|
||||
syslog_client
|
||||
.send_text_message(
|
||||
"ahci",
|
||||
format!(
|
||||
"Port {}: {} {}, firmware {}",
|
||||
port.phys_no(),
|
||||
identify_data.model,
|
||||
identify_data.serial,
|
||||
identify_data.firmware
|
||||
device.phys_no(),
|
||||
device.identify_data().model,
|
||||
device.identify_data().serial,
|
||||
device.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 {
|
||||
|
54
src/port.rs
54
src/port.rs
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user