move AHCI driver to isomorphic_drivers crate

master
WangRunji 6 years ago
parent a1ae2af269
commit 847664fda1

3
kernel/Cargo.lock generated

@ -192,8 +192,9 @@ dependencies = [
[[package]] [[package]]
name = "isomorphic_drivers" name = "isomorphic_drivers"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rcore-os/isomorphic_drivers#836e91fca59e4f4eb86a1f10c246d9c8cb5d1fad" source = "git+https://github.com/rcore-os/isomorphic_drivers#35c14cb75145c6f5d9050d664df3922bf5f275c7"
dependencies = [ dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",

@ -2,335 +2,18 @@
//! //!
//! Spec: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1-3-1.pdf //! Spec: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1-3-1.pdf
use alloc::alloc::{alloc_zeroed, Layout};
use alloc::boxed::Box;
use alloc::string::String; use alloc::string::String;
use alloc::sync::Arc; use alloc::sync::Arc;
use alloc::vec::Vec;
use core::mem::size_of;
use core::slice;
use core::sync::atomic::spin_loop_hint;
use bit_field::*; use isomorphic_drivers::block::ahci::{AHCI, BLOCK_SIZE};
use bitflags::*;
use log::*;
use rcore_fs::dev::BlockDevice;
use volatile::Volatile;
use rcore_memory::paging::PageTable;
use rcore_memory::{PhysAddr, VirtAddr, PAGE_SIZE};
use crate::drivers::provider::Provider;
use crate::drivers::BlockDriver; use crate::drivers::BlockDriver;
use crate::memory::active_table;
use crate::sync::SpinNoIrqLock as Mutex; use crate::sync::SpinNoIrqLock as Mutex;
use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS};
pub struct AHCI { pub struct AHCIDriver(Mutex<AHCI<Provider>>);
header: usize,
size: usize,
received_fis: &'static mut AHCIReceivedFIS,
cmd_list: &'static mut [AHCICommandHeader],
cmd_table: &'static mut AHCICommandTable,
data: &'static mut [u8],
port: &'static mut AHCIPort,
}
pub struct AHCIDriver(Mutex<AHCI>);
/// AHCI Generic Host Control (3.1)
#[repr(C)]
pub struct AHCIGHC {
/// Host capability
capability: Volatile<AHCICap>,
/// Global host control
global_host_control: Volatile<u32>,
/// Interrupt status
interrupt_status: Volatile<u32>,
/// Port implemented
port_implemented: Volatile<u32>,
/// Version
version: Volatile<u32>,
/// Command completion coalescing control
ccc_control: Volatile<u32>,
/// Command completion coalescing ports
ccc_ports: Volatile<u32>,
/// Enclosure management location
em_location: Volatile<u32>,
/// Enclosure management control
em_control: Volatile<u32>,
/// Host capabilities extended
capabilities2: Volatile<u32>,
/// BIOS/OS handoff control and status
bios_os_handoff_control: Volatile<u32>,
}
bitflags! {
struct AHCICap : u32 {
const S64A = 1 << 31;
const SNCQ = 1 << 30;
const SSNTF = 1 << 29;
const SMPS = 1 << 28;
const SSS = 1 << 27;
const SALP = 1 << 26;
const SAL = 1 << 25;
const SCLO = 1 << 24;
const ISS_GEN_1 = 1 << 20;
const ISS_GEN_2 = 2 << 20;
const ISS_GEN_3 = 3 << 20;
const SAM = 1 << 18;
const SPM = 1 << 17;
const FBSS = 1 << 16;
const PMD = 1 << 15;
const SSC = 1 << 14;
const PSC = 1 << 13;
const CCCS = 1 << 7;
const EMS = 1 << 6;
const SXS = 1 << 5;
// number of ports - 1
const NUM_MASK = 0b11111;
}
}
impl AHCIGHC {
fn enable(&mut self) {
self.global_host_control.update(|v| {
v.set_bit(13, true);
});
}
fn num_ports(&self) -> usize {
(self.capability.read() & AHCICap::NUM_MASK).bits() as usize + 1
}
fn has_port(&self, port_num: usize) -> bool {
self.port_implemented.read().get_bit(port_num)
}
}
/// AHCI Port Registers (3.3) (one set per port)
#[repr(C)]
pub struct AHCIPort {
command_list_base_address: Volatile<u64>,
fis_base_address: Volatile<u64>,
interrupt_status: Volatile<u32>,
interrupt_enable: Volatile<u32>,
command: Volatile<u32>,
reserved: Volatile<u32>,
task_file_data: Volatile<u32>,
signature: Volatile<u32>,
sata_status: Volatile<u32>,
sata_control: Volatile<u32>,
sata_error: Volatile<u32>,
sata_active: Volatile<u32>,
command_issue: Volatile<u32>,
sata_notification: Volatile<u32>,
fis_based_switch_control: Volatile<u32>,
}
impl AHCIPort {
fn spin_on_slot(&mut self, slot: usize) {
loop {
let ci = self.command_issue.read();
if !ci.get_bit(slot) {
break;
}
spin_loop_hint();
}
}
fn issue_command(&mut self, slot: usize) {
assert!(slot < 32);
self.command_issue.write(1 << (slot as u32));
}
}
/// AHCI Received FIS Structure (4.2.1)
#[repr(C)]
pub struct AHCIReceivedFIS {
dma: [u8; 0x20],
pio: [u8; 0x20],
d2h: [u8; 0x18],
sdbfis: [u8; 0x8],
ufis: [u8; 0x40],
reserved: [u8; 0x60],
}
/// # AHCI Command List Structure (4.2.2)
///
/// Host sends commands to the device through Command List.
///
/// Command List consists of 1 to 32 command headers, each one is called a slot.
///
/// Each command header describes an ATA or ATAPI command, including a
/// Command FIS, an ATAPI command buffer and a bunch of Physical Region
/// Descriptor Tables specifying the data payload address and size.
///
/// https://wiki.osdev.org/images/e/e8/Command_list.jpg
#[repr(C)]
pub struct AHCICommandHeader {
///
flags: CommandHeaderFlags,
/// Physical region descriptor table length in entries
prdt_length: u16,
/// Physical region descriptor byte count transferred
prd_byte_count: u32,
/// Command table descriptor base address
command_table_base_address: u64,
/// Reserved
reserved: [u32; 4],
}
bitflags! {
pub struct CommandHeaderFlags: u16 {
/// Command FIS length in DWORDS, 2 ~ 16
const CFL_MASK = 0b11111;
/// ATAPI
const ATAPI = 1 << 5;
/// Write, 1: H2D, 0: D2H
const WRITE = 1 << 6;
/// Prefetchable
const PREFETCHABLE = 1 << 7;
/// Reset
const RESET = 1 << 8;
/// BIST
const BIST = 1 << 9;
/// Clear busy upon R_OK
const CLEAR = 1 << 10;
/// Port multiplier port
const PORT_MULTIPLIER_PORT_MASK = 0b1111 << 12;
}
}
/// AHCI Command Table (4.2.3)
#[repr(C)]
pub struct AHCICommandTable {
/// Command FIS
cfis: SATAFISRegH2D,
/// ATAPI command, 12 or 16 bytes
acmd: [u8; 16],
/// Reserved
reserved: [u8; 48],
/// Physical region descriptor table entries, 0 ~ 65535
prdt: [AHCIPrdtEntry; 1],
}
/// Physical region descriptor table entry
#[repr(C)]
pub struct AHCIPrdtEntry {
/// Data base address
data_base_address: u64,
/// Reserved
reserved: u32,
/// Bit 21-0: Byte count, 4M max
/// Bit 31: Interrupt on completion
dbc_i: u32,
}
const FIS_REG_H2D: u8 = 0x27;
const CMD_READ_DMA_EXT: u8 = 0x25;
const CMD_WRITE_DMA_EXT: u8 = 0x35;
const CMD_IDENTIFY_DEVICE: u8 = 0xec;
/// SATA Register FIS - Host to Device
///
/// https://wiki.osdev.org/AHCI Figure 5-2
#[repr(C)]
pub struct SATAFISRegH2D {
fis_type: u8,
cflags: u8,
command: u8,
feature_lo: u8,
lba_0: u8, // LBA 7:0
lba_1: u8, // LBA 15:8
lba_2: u8, // LBA 23:16
dev_head: u8,
lba_3: u8, // LBA 31:24
lba_4: u8, // LBA 39:32
lba_5: u8, // LBA 47:40
feature_hi: u8,
sector_count: u16,
reserved: u8,
control: u8,
_padding: [u8; 48],
}
impl SATAFISRegH2D {
fn set_lba(&mut self, lba: u64) {
self.lba_0 = (lba >> 0) as u8;
self.lba_1 = (lba >> 8) as u8;
self.lba_2 = (lba >> 16) as u8;
self.lba_3 = (lba >> 24) as u8;
self.lba_4 = (lba >> 32) as u8;
self.lba_5 = (lba >> 40) as u8;
}
}
/// IDENTIFY DEVICE data
///
/// ATA8-ACS Table 29
#[repr(C)]
pub struct ATAIdentifyPacket {
_1: [u16; 10],
serial: [u8; 20], // words 10-19
_2: [u16; 3],
firmware: [u8; 8], // words 23-26
model: [u8; 40], // words 27-46
_3: [u16; 13],
lba_sectors: u32, // words 60-61
_4: [u16; 38],
lba48_sectors: u64, // words 100-103
}
impl AHCI {
fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> usize {
self.cmd_list[0].flags = CommandHeaderFlags::empty();
let fis = &mut self.cmd_table.cfis;
// Register FIS from HBA to device
fis.fis_type = FIS_REG_H2D;
fis.cflags = 1 << 7;
// 7.25 READ DMA EXT - 25h, DMA
fis.command = CMD_READ_DMA_EXT;
fis.sector_count = 1;
fis.dev_head = 0x40; // LBA
fis.control = 0x80; // LBA48
fis.set_lba(block_id as u64);
self.port.issue_command(0);
self.port.spin_on_slot(0);
let len = buf.len().min(BLOCK_SIZE);
buf[..len].clone_from_slice(&self.data[0..len]);
len
}
fn write_block(&mut self, block_id: usize, buf: &[u8]) -> usize {
self.cmd_list[0].flags = CommandHeaderFlags::WRITE; // device write
let len = buf.len().min(BLOCK_SIZE);
self.data[0..len].clone_from_slice(&buf[..len]);
let fis = &mut self.cmd_table.cfis;
// Register FIS from HBA to device
fis.fis_type = FIS_REG_H2D;
fis.cflags = 1 << 7;
// ATA8-ACS
// 7.63 WRITE DMA EXT - 35h, DMA
fis.command = CMD_WRITE_DMA_EXT;
fis.sector_count = 1;
fis.dev_head = 0x40; // LBA
fis.control = 0x80; // LBA48
fis.set_lba(block_id as u64);
self.port.issue_command(0);
self.port.spin_on_slot(0);
len
}
}
impl Driver for AHCIDriver { impl Driver for AHCIDriver {
fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool { fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool {
@ -361,137 +44,12 @@ impl Driver for AHCIDriver {
} }
} }
const BLOCK_SIZE: usize = 512; pub fn init(_irq: Option<u32>, header: usize, size: usize) -> Arc<AHCIDriver> {
let ahci = AHCI::new(header, size);
fn from_ata_string(data: &[u8]) -> String { let driver = Arc::new(AHCIDriver(Mutex::new(ahci)));
let mut swapped_data = Vec::new(); DRIVERS.write().push(driver.clone());
assert_eq!(data.len() % 2, 0); BLK_DRIVERS
for i in (0..data.len()).step_by(2) { .write()
swapped_data.push(data[i + 1]); .push(Arc::new(BlockDriver(driver.clone())));
swapped_data.push(data[i]); driver
}
return String::from_utf8(swapped_data).unwrap();
}
/// Allocate consequent physical frames for DMA
fn alloc_dma(page_num: usize) -> (VirtAddr, PhysAddr) {
let layout = Layout::from_size_align(PAGE_SIZE * page_num, PAGE_SIZE).unwrap();
let vaddr = unsafe { alloc_zeroed(layout) } as usize;
let paddr = active_table().get_entry(vaddr).unwrap().target();
(vaddr, paddr)
}
pub fn ahci_init(irq: Option<u32>, header: usize, size: usize) -> Arc<AHCIDriver> {
let ghc = unsafe { &mut *(header as *mut AHCIGHC) };
ghc.enable();
for port_num in 0..ghc.num_ports() {
if ghc.has_port(port_num) {
let addr = header + 0x100 + 0x80 * port_num;
let port = unsafe { &mut *(addr as *mut AHCIPort) };
// SSTS IPM Active
if port.sata_status.read().get_bits(8..12) != 1 {
continue;
}
// SSTS DET Present
if port.sata_status.read().get_bits(0..4) != 3 {
continue;
}
debug!("probing port {}", port_num);
// Disable Port First
port.command.update(|c| {
c.set_bit(4, false);
c.set_bit(0, false);
});
let (rfis_va, rfis_pa) = alloc_dma(1);
let (cmd_list_va, cmd_list_pa) = alloc_dma(1);
let (cmd_table_va, cmd_table_pa) = alloc_dma(1);
let (data_va, data_pa) = alloc_dma(1);
let received_fis = unsafe { &mut *(rfis_va as *mut AHCIReceivedFIS) };
let cmd_list = unsafe {
slice::from_raw_parts_mut(
cmd_list_va as *mut AHCICommandHeader,
PAGE_SIZE / size_of::<AHCICommandHeader>(),
)
};
let cmd_table = unsafe { &mut *(cmd_table_va as *mut AHCICommandTable) };
let identify_data = unsafe { &*(data_va as *mut ATAIdentifyPacket) };
cmd_table.prdt[0].data_base_address = data_pa as u64;
cmd_table.prdt[0].dbc_i = (BLOCK_SIZE - 1) as u32;
cmd_list[0].command_table_base_address = cmd_table_pa as u64;
cmd_list[0].prdt_length = 1;
cmd_list[0].prd_byte_count = 0;
port.command_list_base_address.write(cmd_list_pa as u64);
port.fis_base_address.write(rfis_pa as u64);
// clear status and errors
port.command_issue.write(0);
port.sata_active.write(0);
port.sata_error.write(0);
// enable port
port.command.update(|c| {
*c |= 1 << 0 | 1 << 1 | 1 << 2 | 1 << 4 | 1 << 28;
});
let stat = port.sata_status.read();
if stat == 0 {
warn!("port is not connected to external drive?");
}
let fis = &mut cmd_table.cfis;
// Register FIS from HBA to device
fis.fis_type = FIS_REG_H2D;
fis.cflags = 1 << 7;
// 7.15 IDENTIFY DEVICE - ECh, PIO Data-In
fis.command = CMD_IDENTIFY_DEVICE;
fis.sector_count = 1;
port.issue_command(0);
port.spin_on_slot(0);
unsafe {
debug!(
"Found ATA Device serial {} firmware {} model {} sectors 24bit={} 48bit={}",
from_ata_string(&identify_data.serial).trim_end(),
from_ata_string(&identify_data.firmware).trim_end(),
from_ata_string(&identify_data.model).trim_end(),
identify_data.lba_sectors,
identify_data.lba48_sectors,
);
}
let data = unsafe { slice::from_raw_parts_mut(data_va as *mut u8, BLOCK_SIZE) };
let driver = AHCIDriver(Mutex::new(AHCI {
header,
size,
received_fis,
cmd_list,
cmd_table,
data,
port,
}));
let driver = Arc::new(driver);
DRIVERS.write().push(driver.clone());
BLK_DRIVERS
.write()
.push(Arc::new(BlockDriver(driver.clone())));
return driver;
}
}
unimplemented!();
} }

@ -149,7 +149,7 @@ pub fn init_driver(dev: &PCIDevice) {
active_table().map(vaddr, addr as usize); active_table().map(vaddr, addr as usize);
PCI_DRIVERS PCI_DRIVERS
.lock() .lock()
.insert(dev.loc, ahci::ahci_init(irq, vaddr, len as usize)); .insert(dev.loc, ahci::init(irq, vaddr, len as usize));
} }
} }
_ => {} _ => {}

@ -26,7 +26,7 @@ use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS,
#[derive(Clone)] #[derive(Clone)]
struct IXGBEDriver { struct IXGBEDriver {
inner: ixgbe::IXGBEDriver, inner: Arc<Mutex<ixgbe::IXGBE<Provider>>>,
header: usize, header: usize,
size: usize, size: usize,
mtu: usize, mtu: usize,
@ -49,7 +49,7 @@ impl Driver for IXGBEInterface {
let handled = { let handled = {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
self.driver.inner.try_handle_interrupt() self.driver.inner.lock().try_handle_interrupt()
}; };
if handled { if handled {
@ -102,7 +102,7 @@ impl Driver for IXGBEInterface {
} }
fn send(&self, data: &[u8]) -> Option<usize> { fn send(&self, data: &[u8]) -> Option<usize> {
self.driver.inner.send(&data); self.driver.inner.lock().send(&data);
Some(data.len()) Some(data.len())
} }
@ -121,8 +121,8 @@ impl<'a> phy::Device<'a> for IXGBEDriver {
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
if self.inner.can_send() { if self.inner.lock().can_send() {
if let Some(data) = self.inner.recv() { if let Some(data) = self.inner.lock().recv() {
Some((IXGBERxToken(data), IXGBETxToken(self.clone()))) Some((IXGBERxToken(data), IXGBETxToken(self.clone())))
} else { } else {
None None
@ -134,7 +134,7 @@ impl<'a> phy::Device<'a> for IXGBEDriver {
fn transmit(&'a mut self) -> Option<Self::TxToken> { fn transmit(&'a mut self) -> Option<Self::TxToken> {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
if self.inner.can_send() { if self.inner.lock().can_send() {
Some(IXGBETxToken(self.clone())) Some(IXGBETxToken(self.clone()))
} else { } else {
None None
@ -168,10 +168,10 @@ impl phy::TxToken for IXGBETxToken {
F: FnOnce(&mut [u8]) -> Result<R>, F: FnOnce(&mut [u8]) -> Result<R>,
{ {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()]; let mut buffer = [0u8; ixgbe::IXGBE::<Provider>::get_mtu()];
let result = f(&mut buffer[..len]); let result = f(&mut buffer[..len]);
if result.is_ok() { if result.is_ok() {
(self.0).inner.send(&buffer[..len]); self.0.inner.lock().send(&buffer[..len]);
} }
result result
} }
@ -185,13 +185,13 @@ pub fn ixgbe_init(
index: usize, index: usize,
) -> Arc<IXGBEInterface> { ) -> Arc<IXGBEInterface> {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), header, size); let mut ixgbe = ixgbe::IXGBE::new(header, size);
ixgbe.enable_irq(); ixgbe.enable_irq();
let ethernet_addr = EthernetAddress::from_bytes(&ixgbe.get_mac().as_bytes()); let ethernet_addr = EthernetAddress::from_bytes(&ixgbe.get_mac().as_bytes());
let net_driver = IXGBEDriver { let net_driver = IXGBEDriver {
inner: ixgbe, inner: Arc::new(Mutex::new(ixgbe)),
header, header,
size, size,
mtu: 1500, mtu: 1500,

@ -1,36 +1,23 @@
use crate::memory::active_table; use alloc::alloc::{alloc_zeroed, dealloc, Layout};
use alloc::boxed::Box;
use alloc::vec::Vec;
use isomorphic_drivers::provider; use isomorphic_drivers::provider;
use rcore_memory::paging::PageTable; use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE; use rcore_memory::PAGE_SIZE;
#[derive(Copy, Clone)] use crate::memory::active_table;
pub struct Provider;
impl Provider { pub struct Provider;
pub fn new() -> Box<Provider> {
Box::new(Provider {})
}
}
impl provider::Provider for Provider { impl provider::Provider for Provider {
/// Get page size fn alloc_dma(size: usize) -> (usize, usize) {
fn get_page_size(&self) -> usize { let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
PAGE_SIZE let vaddr = unsafe { alloc_zeroed(layout) } as usize;
} let paddr = active_table().get_entry(vaddr).unwrap().target();
(vaddr, paddr)
// Translate virtual address to physical address
fn translate_va(&self, va: usize) -> usize {
active_table().get_entry(va).unwrap().target()
} }
// Bulk translate virtual addresses to physical addresses for performance fn dealloc_dma(vaddr: usize, size: usize) {
fn translate_vas(&self, vas: &[usize]) -> Vec<usize> { let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
let mut result = Vec::new(); unsafe { dealloc(vaddr as *mut u8, layout) }
for va in vas.iter() {
result.push(active_table().get_entry(*va).unwrap().target());
}
result
} }
} }

Loading…
Cancel
Save