diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 0c0b6e9..901f2c7 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -192,8 +192,9 @@ dependencies = [ [[package]] name = "isomorphic_drivers" 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 = [ + "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)", "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)", diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index 842259c..189c6e4 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -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 -use alloc::alloc::{alloc_zeroed, Layout}; -use alloc::boxed::Box; use alloc::string::String; 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 bitflags::*; -use log::*; -use rcore_fs::dev::BlockDevice; -use volatile::Volatile; - -use rcore_memory::paging::PageTable; -use rcore_memory::{PhysAddr, VirtAddr, PAGE_SIZE}; +use isomorphic_drivers::block::ahci::{AHCI, BLOCK_SIZE}; +use crate::drivers::provider::Provider; use crate::drivers::BlockDriver; -use crate::memory::active_table; use crate::sync::SpinNoIrqLock as Mutex; use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; -pub struct AHCI { - 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 Generic Host Control (3.1) -#[repr(C)] -pub struct AHCIGHC { - /// Host capability - capability: Volatile, - /// Global host control - global_host_control: Volatile, - /// Interrupt status - interrupt_status: Volatile, - /// Port implemented - port_implemented: Volatile, - /// Version - version: Volatile, - /// Command completion coalescing control - ccc_control: Volatile, - /// Command completion coalescing ports - ccc_ports: Volatile, - /// Enclosure management location - em_location: Volatile, - /// Enclosure management control - em_control: Volatile, - /// Host capabilities extended - capabilities2: Volatile, - /// BIOS/OS handoff control and status - bios_os_handoff_control: Volatile, -} - -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, - fis_base_address: Volatile, - interrupt_status: Volatile, - interrupt_enable: Volatile, - command: Volatile, - reserved: Volatile, - task_file_data: Volatile, - signature: Volatile, - sata_status: Volatile, - sata_control: Volatile, - sata_error: Volatile, - sata_active: Volatile, - command_issue: Volatile, - sata_notification: Volatile, - fis_based_switch_control: Volatile, -} - -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 - } -} +pub struct AHCIDriver(Mutex>); impl Driver for AHCIDriver { fn try_handle_interrupt(&self, _irq: Option) -> bool { @@ -361,137 +44,12 @@ impl Driver for AHCIDriver { } } -const BLOCK_SIZE: usize = 512; - -fn from_ata_string(data: &[u8]) -> String { - let mut swapped_data = Vec::new(); - assert_eq!(data.len() % 2, 0); - for i in (0..data.len()).step_by(2) { - swapped_data.push(data[i + 1]); - swapped_data.push(data[i]); - } - 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, header: usize, size: usize) -> Arc { - 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::(), - ) - }; - 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!(); +pub fn init(_irq: Option, header: usize, size: usize) -> Arc { + let ahci = AHCI::new(header, size); + let driver = Arc::new(AHCIDriver(Mutex::new(ahci))); + DRIVERS.write().push(driver.clone()); + BLK_DRIVERS + .write() + .push(Arc::new(BlockDriver(driver.clone()))); + driver } diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 2c14ea1..325c37b 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -149,7 +149,7 @@ pub fn init_driver(dev: &PCIDevice) { active_table().map(vaddr, addr as usize); PCI_DRIVERS .lock() - .insert(dev.loc, ahci::ahci_init(irq, vaddr, len as usize)); + .insert(dev.loc, ahci::init(irq, vaddr, len as usize)); } } _ => {} diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 4ee4475..72fd7c9 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -26,7 +26,7 @@ use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS, #[derive(Clone)] struct IXGBEDriver { - inner: ixgbe::IXGBEDriver, + inner: Arc>>, header: usize, size: usize, mtu: usize, @@ -49,7 +49,7 @@ impl Driver for IXGBEInterface { let handled = { let _ = FlagsGuard::no_irq_region(); - self.driver.inner.try_handle_interrupt() + self.driver.inner.lock().try_handle_interrupt() }; if handled { @@ -102,7 +102,7 @@ impl Driver for IXGBEInterface { } fn send(&self, data: &[u8]) -> Option { - self.driver.inner.send(&data); + self.driver.inner.lock().send(&data); Some(data.len()) } @@ -121,8 +121,8 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { let _ = FlagsGuard::no_irq_region(); - if self.inner.can_send() { - if let Some(data) = self.inner.recv() { + if self.inner.lock().can_send() { + if let Some(data) = self.inner.lock().recv() { Some((IXGBERxToken(data), IXGBETxToken(self.clone()))) } else { None @@ -134,7 +134,7 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn transmit(&'a mut self) -> Option { let _ = FlagsGuard::no_irq_region(); - if self.inner.can_send() { + if self.inner.lock().can_send() { Some(IXGBETxToken(self.clone())) } else { None @@ -168,10 +168,10 @@ impl phy::TxToken for IXGBETxToken { F: FnOnce(&mut [u8]) -> Result, { let _ = FlagsGuard::no_irq_region(); - let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()]; + let mut buffer = [0u8; ixgbe::IXGBE::::get_mtu()]; let result = f(&mut buffer[..len]); if result.is_ok() { - (self.0).inner.send(&buffer[..len]); + self.0.inner.lock().send(&buffer[..len]); } result } @@ -185,13 +185,13 @@ pub fn ixgbe_init( index: usize, ) -> Arc { 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(); let ethernet_addr = EthernetAddress::from_bytes(&ixgbe.get_mac().as_bytes()); let net_driver = IXGBEDriver { - inner: ixgbe, + inner: Arc::new(Mutex::new(ixgbe)), header, size, mtu: 1500, diff --git a/kernel/src/drivers/provider.rs b/kernel/src/drivers/provider.rs index 6857ae5..1a75efb 100644 --- a/kernel/src/drivers/provider.rs +++ b/kernel/src/drivers/provider.rs @@ -1,36 +1,23 @@ -use crate::memory::active_table; -use alloc::boxed::Box; -use alloc::vec::Vec; +use alloc::alloc::{alloc_zeroed, dealloc, Layout}; + use isomorphic_drivers::provider; use rcore_memory::paging::PageTable; use rcore_memory::PAGE_SIZE; -#[derive(Copy, Clone)] -pub struct Provider; +use crate::memory::active_table; -impl Provider { - pub fn new() -> Box { - Box::new(Provider {}) - } -} +pub struct Provider; impl provider::Provider for Provider { - /// Get page size - fn get_page_size(&self) -> usize { - PAGE_SIZE - } - - // Translate virtual address to physical address - fn translate_va(&self, va: usize) -> usize { - active_table().get_entry(va).unwrap().target() + fn alloc_dma(size: usize) -> (usize, usize) { + let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap(); + let vaddr = unsafe { alloc_zeroed(layout) } as usize; + let paddr = active_table().get_entry(vaddr).unwrap().target(); + (vaddr, paddr) } - // Bulk translate virtual addresses to physical addresses for performance - fn translate_vas(&self, vas: &[usize]) -> Vec { - let mut result = Vec::new(); - for va in vas.iter() { - result.push(active_table().get_entry(*va).unwrap().target()); - } - result + fn dealloc_dma(vaddr: usize, size: usize) { + let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap(); + unsafe { dealloc(vaddr as *mut u8, layout) } } }