From 9831cae13c6de408514ce71b60b62bda466f578b Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 29 Mar 2019 15:19:40 +0800 Subject: [PATCH 01/14] Fix travis CI for riscv32 --- kernel/Cargo.lock | 4 ++-- user | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 1d22c8d..e945a93 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -328,12 +328,12 @@ dependencies = [ [[package]] name = "rcore-fs" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-fs#f8d7b06727b0a66091419b2dd6a15f620a7152af" +source = "git+https://github.com/rcore-os/rcore-fs#c611248f800e946acf44d64b218aeb8fc6751640" [[package]] name = "rcore-fs-sfs" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-fs#f8d7b06727b0a66091419b2dd6a15f620a7152af" +source = "git+https://github.com/rcore-os/rcore-fs#c611248f800e946acf44d64b218aeb8fc6751640" dependencies = [ "bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/user b/user index 69febc9..8af7200 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 69febc9fcc64df60329687b4f24b9b5309c99adf +Subproject commit 8af72001d15af969c2e7c4feec43d8f9efe9331e From cbba658e22fc15865bbd9e47b36e32ac85f14fe0 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 30 Mar 2019 00:06:27 +0800 Subject: [PATCH 02/14] Implement ATA IDENTIFY DEVICE via AHCI interface --- kernel/src/arch/x86_64/memory.rs | 10 +- kernel/src/drivers/block/ahci.rs | 367 +++++++++++++++++++++++++++++++ kernel/src/syscall/misc.rs | 4 +- user | 2 +- 4 files changed, 374 insertions(+), 9 deletions(-) create mode 100644 kernel/src/drivers/block/ahci.rs diff --git a/kernel/src/arch/x86_64/memory.rs b/kernel/src/arch/x86_64/memory.rs index b2570a9..325b0b8 100644 --- a/kernel/src/arch/x86_64/memory.rs +++ b/kernel/src/arch/x86_64/memory.rs @@ -2,13 +2,13 @@ use crate::consts::KERNEL_OFFSET; use bit_allocator::BitAlloc; // Depends on kernel use super::{BootInfo, MemoryRegionType}; -use crate::memory::{active_table, init_heap, FRAME_ALLOCATOR, alloc_frame}; +use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR}; use crate::HEAP_ALLOCATOR; -use rcore_memory::PAGE_SIZE; use alloc::vec::Vec; use log::*; use once::*; use rcore_memory::paging::*; +use rcore_memory::PAGE_SIZE; pub fn init(boot_info: &BootInfo) { assert_has_not_been_called!("memory::init must be called only once"); @@ -60,14 +60,12 @@ fn enlarge_heap() { addrs.push((va, PAGE_SIZE)); } for (addr, len) in addrs.into_iter() { - for va in (addr..(addr+len)).step_by(PAGE_SIZE) { + for va in (addr..(addr + len)).step_by(PAGE_SIZE) { page_table.map(va, va - va_offset).update(); } info!("Adding {:#X} {:#X} to heap", addr, len); unsafe { - HEAP_ALLOCATOR - .lock() - .init(addr, len); + HEAP_ALLOCATOR.lock().init(addr, len); } } } diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs new file mode 100644 index 0000000..a84e577 --- /dev/null +++ b/kernel/src/drivers/block/ahci.rs @@ -0,0 +1,367 @@ +//! Driver for AHCI +//! +//! 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, GlobalAlloc, Layout}; +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::cmp::min; +use core::mem::{size_of, zeroed}; +use core::slice; +use core::str; + +use crate::sync::FlagsGuard; +use bitflags::*; +use device_tree::util::SliceRead; +use device_tree::Node; +use log::*; +use rcore_memory::paging::PageTable; +use rcore_memory::PAGE_SIZE; +use volatile::Volatile; + +use rcore_fs::dev::BlockDevice; + +use crate::memory::active_table; +use crate::sync::SpinNoIrqLock as Mutex; + +use super::super::bus::virtio_mmio::*; +use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; + +pub struct AHCI { + header: usize, + size: usize, + rfis: usize, + cmd_list: usize, + cmd_table: usize, + data: usize, +} + +pub struct AHCIDriver(Mutex); + +// 3.1 Generic Host Control +#[repr(C)] +pub struct AHCIGHC { + cap: Volatile, + ghc: Volatile, + is: Volatile, + pi: Volatile, + vs: Volatile, + ccc_ctl: Volatile, + ccc_ports: Volatile, + em_loc: Volatile, + em_ctl: Volatile, + cap2: Volatile, + bohc: 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 NP_1 = 1 << 0; + const NP_2 = 1 << 1; + const NP_4 = 1 << 2; + const NP_8 = 1 << 3; + const NP_16 = 1 << 4; + } +} + +// 3.3 Port Registers (one set per port) +#[repr(C)] +pub struct AHCIPort { + clb: Volatile, + clbu: Volatile, + fb: Volatile, + fbu: Volatile, + is: Volatile, + ie: Volatile, + cmd: Volatile, + reserved: Volatile, + tfd: Volatile, + sig: Volatile, + ssts: Volatile, + sctl: Volatile, + serr: Volatile, + sact: Volatile, + ci: Volatile, + sntf: Volatile, + fbs: Volatile, + devslp: Volatile, +} + +// 4.2.1 Received FIS Structure +#[repr(C)] +pub struct AHCIRFIS { + dma: [u8; 0x20], + pio: [u8; 0x20], + d2h: [u8; 0x18], + sdbfis: [u8; 0x8], + ufis: [u8; 0x40], + reserved: [u8; 0x60], +} + +// 4.2.2 Command List Structure +#[repr(C)] +pub struct AHCICommandHeader { + pwa_cfl: u8, + pmp_cbr: u8, + prdtl: u16, + prdbc: u32, + ctba0: u32, + ctba_u0: u32, + reservec: [u32; 4], +} + +// 4.2.3 Command Table +#[repr(C)] +pub struct AHCICommandTable { + cfis: [u8; 64], + acmd: [u8; 16], + reserved: [u8; 48], + prdt: [AHCIPRD; 1], +} + +// 4.2.3 Command Table +#[repr(C)] +pub struct AHCIPRD { + dba: u32, + dbau: u32, + reserved: u32, + dbc_i: u32, +} + +// https://wiki.osdev.org/AHCI +#[repr(C)] +#[derive(Default)] +pub struct AHCIFISRegH2D { + fis_type: u8, + cflags: u8, + command: u8, + feature_lo: u8, + lba_0: u8, + lba_1: u8, + lba_2: u8, + device: u8, + lba_3: u8, + lba_4: u8, + lba_5: u8, + feature_hi: u8, + count_lo: u8, + count_hi: u8, + icc: u8, + control: u8, + sector_count_lo: u8, + sector_count_hi: u8, +} + +// Table 29 IDENTIFY DEVICE data +#[repr(C)] +pub struct AHCIIdentifyPacket { + _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; 16], + lba_sectors: u32, // words 60-61 +} + +impl Driver for AHCIDriver { + fn try_handle_interrupt(&self, _irq: Option) -> bool { + let driver = self.0.lock(); + + // ensure header page is mapped + active_table().map_if_not_exists(driver.header as usize, driver.header as usize); + unimplemented!(); + return false; + } + + fn device_type(&self) -> DeviceType { + DeviceType::Block + } + + fn get_id(&self) -> String { + format!("ahci") + } +} + +const BLOCK_SIZE: usize = 512; +impl BlockDevice for AHCIDriver { + const BLOCK_SIZE_LOG2: u8 = 9; // 512 + fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool { + let mut driver = self.0.lock(); + // ensure header page is mapped + active_table().map_if_not_exists(driver.header as usize, driver.header as usize); + unimplemented!() + } + + fn write_at(&self, block_id: usize, buf: &[u8]) -> bool { + let mut driver = self.0.lock(); + // ensure header page is mapped + active_table().map_if_not_exists(driver.header as usize, driver.header as usize); + unimplemented!() + } +} + +fn from_ata_string(data: &[u8]) -> String { + let mut swapped_data = Vec::new(); + assert!(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(); +} + +pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc { + let _ = FlagsGuard::no_irq_region(); + if let None = active_table().get_entry(header) { + let mut current_addr = header; + while current_addr < header + size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + } + let ghc = unsafe { &mut *(header as *mut AHCIGHC) }; + debug!("header {:?}", ghc.cap); + + // AHCI Enable + ghc.ghc.write(ghc.ghc.read() | (1 << 13)); + + let num_ports = (ghc.cap.read().bits() & 0x1f) as usize + 1; + + for port_num in 0..num_ports { + if (ghc.pi.read() | (1 << port_num)) != 0 { + let addr = header + 0x100 + 0x80 * port_num; + let port = unsafe { &mut *(addr as *mut AHCIPort) }; + + // SSTS IPM Active + if (port.ssts.read() >> 8) & 0xF != 1 { + continue; + } + + // SSTS DET Present + if port.ssts.read() & 0xF != 3 { + continue; + } + + debug!("probing port {}", port_num); + // Disable Port First + port.cmd.write(port.cmd.read() & !(1 << 4 | 1 << 0)); + + let rfis_va = + unsafe { alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) } + as usize; + let rfis_pa = active_table().get_entry(rfis_va).unwrap().target(); + + let cmd_list_va = + unsafe { alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) } + as usize; + let cmd_list_pa = active_table().get_entry(cmd_list_va).unwrap().target(); + + let cmd_table_va = + unsafe { alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) } + as usize; + let cmd_table_pa = active_table().get_entry(cmd_table_va).unwrap().target(); + + let data_va = + unsafe { alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) } + as usize; + let data_pa = active_table().get_entry(data_va).unwrap().target(); + + let cmd_headers = 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) }; + + cmd_table.prdt[0].dba = data_pa as u32; + cmd_table.prdt[0].dbau = (data_pa >> 32) as u32; + cmd_table.prdt[0].dbc_i = (BLOCK_SIZE - 1) as u32; + + cmd_headers[0].ctba0 = cmd_table_pa as u32; + cmd_headers[0].ctba_u0 = (cmd_table_pa >> 32) as u32; + cmd_headers[0].prdtl = 1; + cmd_headers[0].prdbc = 0; + + port.clb.write(cmd_list_pa as u32); + port.clbu.write((cmd_list_pa >> 32) as u32); + + port.fb.write(rfis_pa as u32); + port.fbu.write((rfis_pa >> 32) as u32); + + // clear status and errors + port.ci.write(0); + port.sact.write(0); + port.serr.write(0); + + // enable port + port.cmd + .write(port.cmd.read() | 1 << 0 | 1 << 1 | 1 << 2 | 1 << 4 | 1 << 28); + + let stat = port.ssts.read(); + if stat == 0 { + warn!("port is not connected to external drive?"); + } + + let fis = unsafe { &mut *(cmd_table.cfis.as_ptr() as *mut AHCIFISRegH2D) }; + // Register FIS from host to device + fis.fis_type = 0x27; + fis.cflags = 1 << 7; + + // 7.15 IDENTIFY DEVICE - ECh, PIO Data-In + fis.command = 0xec; // ide identify + fis.sector_count_lo = 1; + + debug!("issued identify command"); + port.ci.write(1 << 0); + + loop { + let stat = port.tfd.read(); + let ci = port.ci.read(); + if stat & 0x80 == 0 || (ci & (1 << 0)) == 0 { + break; + } + } + + let identify_data = unsafe { &*(data_va as *mut AHCIIdentifyPacket) }; + + unsafe { + debug!( + "{:?} {:?} {:?} {}", + from_ata_string(&identify_data.serial), + from_ata_string(&identify_data.firmware), + from_ata_string(&identify_data.model), + identify_data.lba_sectors + ); + } + + break; + } + } + + unimplemented!(); +} diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index fc6779f..ac3ff39 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -1,8 +1,8 @@ use super::*; use crate::arch::cpu; +use crate::consts::USER_STACK_SIZE; use core::mem::size_of; use core::sync::atomic::{AtomicI32, Ordering}; -use crate::consts::USER_STACK_SIZE; pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult { const ARCH_SET_FS: i32 = 0x1002; @@ -177,7 +177,7 @@ pub fn sys_prlimit64( } } Ok(0) - }, + } RLIMIT_RSS | RLIMIT_AS => { if !old_limit.is_null() { proc.vm.check_write_ptr(old_limit)?; diff --git a/user b/user index 8af7200..ec476c3 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 8af72001d15af969c2e7c4feec43d8f9efe9331e +Subproject commit ec476c3acb600c6d437454e74fb3e0eb6c452de4 From 2da17d7fcd549f94282172610ac8296219c24677 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 30 Mar 2019 10:03:08 +0800 Subject: [PATCH 03/14] Replace IDE with AHCI driver --- kernel/Makefile | 4 +- kernel/src/drivers/block/ahci.rs | 230 ++++++++++++++++++++----- kernel/src/drivers/block/virtio_blk.rs | 11 +- kernel/src/drivers/mod.rs | 26 ++- kernel/src/drivers/net/ixgbe.rs | 1 - kernel/src/fs/mod.rs | 8 +- 6 files changed, 221 insertions(+), 59 deletions(-) diff --git a/kernel/Makefile b/kernel/Makefile index f1c3281..8a3bbf9 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -66,7 +66,9 @@ qemu_net_opts := \ ifeq ($(arch), x86_64) qemu_opts += \ -drive format=raw,file=$(bootimage) \ - -drive format=qcow2,file=$(SFSIMG),media=disk,cache=writeback \ + -drive format=qcow2,file=$(SFSIMG),media=disk,cache=writeback,id=sfsimg,if=none \ + -device ahci,id=ahci0 \ + -device ide-drive,drive=sfsimg,bus=ahci0.0 \ -serial mon:stdio \ -m 4G \ -device isa-debug-exit diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index a84e577..74ba464 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -2,19 +2,17 @@ //! //! 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, GlobalAlloc, Layout}; +use alloc::alloc::{alloc_zeroed, Layout}; +use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; use core::cmp::min; -use core::mem::{size_of, zeroed}; +use core::mem::size_of; use core::slice; -use core::str; use crate::sync::FlagsGuard; use bitflags::*; -use device_tree::util::SliceRead; -use device_tree::Node; use log::*; use rcore_memory::paging::PageTable; use rcore_memory::PAGE_SIZE; @@ -22,10 +20,10 @@ use volatile::Volatile; use rcore_fs::dev::BlockDevice; +use crate::drivers::BlockDriver; use crate::memory::active_table; use crate::sync::SpinNoIrqLock as Mutex; -use super::super::bus::virtio_mmio::*; use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; pub struct AHCI { @@ -35,10 +33,12 @@ pub struct AHCI { cmd_list: usize, cmd_table: usize, data: usize, + port_addr: usize, } pub struct AHCIDriver(Mutex); +// AHCI // 3.1 Generic Host Control #[repr(C)] pub struct AHCIGHC { @@ -86,6 +86,7 @@ bitflags! { } } +// AHCI // 3.3 Port Registers (one set per port) #[repr(C)] pub struct AHCIPort { @@ -109,6 +110,7 @@ pub struct AHCIPort { devslp: Volatile, } +// AHCi // 4.2.1 Received FIS Structure #[repr(C)] pub struct AHCIRFIS { @@ -120,6 +122,7 @@ pub struct AHCIRFIS { reserved: [u8; 0x60], } +// AHCI // 4.2.2 Command List Structure #[repr(C)] pub struct AHCICommandHeader { @@ -132,6 +135,7 @@ pub struct AHCICommandHeader { reservec: [u32; 4], } +// AHCI // 4.2.3 Command Table #[repr(C)] pub struct AHCICommandTable { @@ -150,40 +154,49 @@ pub struct AHCIPRD { 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; + // https://wiki.osdev.org/AHCI +// SATA +// Figure 5-2: Register FIS - Host to Device #[repr(C)] #[derive(Default)] -pub struct AHCIFISRegH2D { +pub struct SATAFISRegH2D { fis_type: u8, cflags: u8, command: u8, feature_lo: u8, - lba_0: u8, - lba_1: u8, - lba_2: u8, - device: u8, - lba_3: u8, - lba_4: u8, - lba_5: 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, - count_lo: u8, - count_hi: u8, - icc: u8, - control: u8, sector_count_lo: u8, sector_count_hi: u8, + reserved: u8, + control: u8, } +// ATA8-ACS // Table 29 IDENTIFY DEVICE data #[repr(C)] -pub struct AHCIIdentifyPacket { +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; 16], + _3: [u16; 13], lba_sectors: u32, // words 60-61 + _4: [u16; 38], + lba48_sectors: u64, // words 100-103 } impl Driver for AHCIDriver { @@ -191,8 +204,15 @@ impl Driver for AHCIDriver { let driver = self.0.lock(); // ensure header page is mapped - active_table().map_if_not_exists(driver.header as usize, driver.header as usize); - unimplemented!(); + let header = driver.header as usize; + let size = driver.size as usize; + if let None = active_table().get_entry(header) { + let mut current_addr = header; + while current_addr < header + size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + } return false; } @@ -203,26 +223,130 @@ impl Driver for AHCIDriver { fn get_id(&self) -> String { format!("ahci") } -} -const BLOCK_SIZE: usize = 512; -impl BlockDevice for AHCIDriver { - const BLOCK_SIZE_LOG2: u8 = 9; // 512 - fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool { + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { let mut driver = self.0.lock(); // ensure header page is mapped - active_table().map_if_not_exists(driver.header as usize, driver.header as usize); - unimplemented!() + let header = driver.header as usize; + let size = driver.size as usize; + if let None = active_table().get_entry(header) { + let mut current_addr = header; + while current_addr < header + size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + } + let port = unsafe { &mut *(driver.port_addr as *mut AHCIPort) }; + let cmd_headers = unsafe { + slice::from_raw_parts_mut( + driver.cmd_list as *mut AHCICommandHeader, + PAGE_SIZE / size_of::(), + ) + }; + cmd_headers[0].prdbc = 0; + cmd_headers[0].pwa_cfl = 0; + + let cmd_table = unsafe { &mut *(driver.cmd_table as *mut AHCICommandTable) }; + let len = min(BLOCK_SIZE, buf.len()); + let data = unsafe { slice::from_raw_parts(driver.data as *const u8, len) }; + + let fis = unsafe { &mut *(cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; + // 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_lo = 1; + fis.sector_count_hi = 0; + fis.dev_head = 0x40; // LBA + fis.control = 0x80; // LBA48 + + let block_id = block_id as u64; // avoid problems on riscv32 + fis.lba_0 = block_id as u8; + fis.lba_1 = (block_id >> 8) as u8; + fis.lba_2 = (block_id >> 16) as u8; + fis.lba_3 = (block_id >> 24) as u8; + fis.lba_4 = (block_id >> 32) as u8; + fis.lba_5 = (block_id >> 40) as u8; + + port.ci.write(1 << 0); + + loop { + let ci = port.ci.read(); + if (ci & (1 << 0)) == 0 { + break; + } + } + + (&mut buf[..len]).clone_from_slice(&data); + return true; } - fn write_at(&self, block_id: usize, buf: &[u8]) -> bool { + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { + if buf.len() < BLOCK_SIZE { + return false; + } let mut driver = self.0.lock(); // ensure header page is mapped - active_table().map_if_not_exists(driver.header as usize, driver.header as usize); - unimplemented!() + let header = driver.header as usize; + let size = driver.size as usize; + if let None = active_table().get_entry(header) { + let mut current_addr = header; + while current_addr < header + size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + } + let port = unsafe { &mut *(driver.port_addr as *mut AHCIPort) }; + let cmd_headers = unsafe { + slice::from_raw_parts_mut( + driver.cmd_list as *mut AHCICommandHeader, + PAGE_SIZE / size_of::(), + ) + }; + cmd_headers[0].prdbc = 0; + cmd_headers[0].pwa_cfl = 1 << 6; // devic write + + let cmd_table = unsafe { &mut *(driver.cmd_table as *mut AHCICommandTable) }; + let data = unsafe { slice::from_raw_parts_mut(driver.data as *mut u8, BLOCK_SIZE) }; + data.clone_from_slice(&buf[..BLOCK_SIZE]); + + let fis = unsafe { &mut *(cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; + // 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_lo = 1; + fis.sector_count_hi = 0; + fis.dev_head = 0x40; // LBA + fis.control = 0x80; // LBA48 + + let block_id = block_id as u64; // avoid problems on riscv32 + fis.lba_0 = block_id as u8; + fis.lba_1 = (block_id >> 8) as u8; + fis.lba_2 = (block_id >> 16) as u8; + fis.lba_3 = (block_id >> 24) as u8; + fis.lba_4 = (block_id >> 32) as u8; + fis.lba_5 = (block_id >> 40) as u8; + + port.ci.write(1 << 0); + + loop { + let ci = port.ci.read(); + if (ci & (1 << 0)) == 0 { + break; + } + } + return true; } } +const BLOCK_SIZE: usize = 512; + fn from_ata_string(data: &[u8]) -> String { let mut swapped_data = Vec::new(); assert!(data.len() % 2 == 0); @@ -327,39 +451,55 @@ pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc String { format!("virtio_block") } -} -impl BlockDevice for VirtIOBlkDriver { - const BLOCK_SIZE_LOG2: u8 = 9; // 512 - fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool { + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { let mut driver = self.0.lock(); // ensure header page is mapped active_table().map_if_not_exists(driver.header as usize, driver.header as usize); @@ -157,7 +156,7 @@ impl BlockDevice for VirtIOBlkDriver { } } - fn write_at(&self, block_id: usize, buf: &[u8]) -> bool { + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { let mut driver = self.0.lock(); // ensure header page is mapped active_table().map_if_not_exists(driver.header as usize, driver.header as usize); @@ -226,5 +225,5 @@ pub fn virtio_blk_init(node: &Node) { let driver = Arc::new(driver); DRIVERS.write().push(driver.clone()); - BLK_DRIVERS.write().push(driver); + BLK_DRIVERS.write().push(Arc::new(BlockDriver(driver))); } diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index 9a1f3e0..1363330 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -5,8 +5,8 @@ use lazy_static::lazy_static; use smoltcp::wire::{EthernetAddress, Ipv4Address}; use spin::RwLock; -use self::block::virtio_blk::VirtIOBlkDriver; use crate::sync::Condvar; +use rcore_fs::dev::BlockDevice; #[allow(dead_code)] pub mod block; @@ -64,13 +64,35 @@ pub trait Driver: Send + Sync { fn poll(&self) { unimplemented!("not a net driver") } + + // block related drivers should implement these + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { + unimplemented!("not a block driver") + } + + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { + unimplemented!("not a block driver") + } } lazy_static! { // NOTE: RwLock only write when initializing drivers pub static ref DRIVERS: RwLock>> = RwLock::new(Vec::new()); pub static ref NET_DRIVERS: RwLock>> = RwLock::new(Vec::new()); - pub static ref BLK_DRIVERS: RwLock>> = RwLock::new(Vec::new()); + pub static ref BLK_DRIVERS: RwLock>> = RwLock::new(Vec::new()); +} + +pub struct BlockDriver(Arc); + +impl BlockDevice for BlockDriver { + const BLOCK_SIZE_LOG2: u8 = 9; // 512 + fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool { + self.0.read_block(block_id, buf) + } + + fn write_at(&self, block_id: usize, buf: &[u8]) -> bool { + self.0.write_block(block_id, buf) + } } lazy_static! { diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 284f457..fd96b7d 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -20,7 +20,6 @@ use crate::memory::active_table; use crate::net::SOCKETS; use crate::sync::FlagsGuard; use crate::sync::SpinNoIrqLock as Mutex; -use crate::sync::{MutexGuard, SpinNoIrq}; use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 488dcb2..9414c47 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -37,15 +37,15 @@ lazy_static! { pub static ref ROOT_INODE: Arc = { #[cfg(not(feature = "link_user"))] let device = { - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "x86_64"))] { crate::drivers::BLK_DRIVERS.read().iter() - .next().expect("VirtIOBlk not found") + .next().expect("Block device not found") .clone() } - #[cfg(target_arch = "x86_64")] + #[cfg(target_arch = "aarch64")] { - Arc::new(ide::IDE::new(1)) + unimplemented!() } }; #[cfg(feature = "link_user")] From 3dff84c6867b1ac2258ee1e0a3380440f5475e46 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 30 Mar 2019 10:14:46 +0800 Subject: [PATCH 04/14] Fix last commit for pci device probing --- kernel/src/drivers/block/mod.rs | 1 + kernel/src/drivers/bus/pci.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/kernel/src/drivers/block/mod.rs b/kernel/src/drivers/block/mod.rs index bbcee0a..c2f9aeb 100644 --- a/kernel/src/drivers/block/mod.rs +++ b/kernel/src/drivers/block/mod.rs @@ -1 +1,2 @@ pub mod virtio_blk; +pub mod ahci; \ No newline at end of file diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index e46c7d0..9985d0d 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -1,4 +1,5 @@ use crate::drivers::net::*; +use crate::drivers::block::*; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; use alloc::collections::BTreeMap; use alloc::string::String; @@ -129,7 +130,7 @@ impl PciTag { // linux/drivers/pci/probe.c pci_read_bases // return (addr, len) pub unsafe fn get_bar_mem(&self, bar_number: u32) -> Option<(usize, usize)> { - assert!(bar_number <= 4); + assert!(bar_number <= 6); let bar = PCI_BAR0 + 4 * bar_number; let mut base_lo = self.read(bar, 4); self.write(bar, 0xffffffff); @@ -298,6 +299,14 @@ pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) { .lock() .insert(tag, ixgbe::ixgbe_init(name, irq, addr, len)); } + } else if did == 0x2922 { + // 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] + if let Some((addr, len)) = unsafe { tag.get_bar_mem(5) } { + let irq = unsafe { tag.enable() }; + PCI_DRIVERS + .lock() + .insert(tag, ahci::ahci_init(irq, addr, len)); + } } } } From d9bdaf987571f506d56f3b50c4ccd6956cb8a4a0 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 30 Mar 2019 16:03:16 +0800 Subject: [PATCH 05/14] Fix AHCI not working on newer versions of QEMU --- kernel/src/drivers/block/ahci.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index 74ba464..d5f9982 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -359,15 +359,12 @@ fn from_ata_string(data: &[u8]) -> String { pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc { let _ = FlagsGuard::no_irq_region(); - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } + let mut current_addr = header; + while current_addr < header + size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; } let ghc = unsafe { &mut *(header as *mut AHCIGHC) }; - debug!("header {:?}", ghc.cap); // AHCI Enable ghc.ghc.write(ghc.ghc.read() | (1 << 13)); From 11c56091716b21cc04a1d30e9de03bf036c1e200 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 30 Mar 2019 23:43:20 +0800 Subject: [PATCH 06/14] refactor PCI mod using pci crate --- kernel/Cargo.lock | 10 + kernel/Cargo.toml | 1 + kernel/src/drivers/bus/pci.rs | 435 ++++++++++------------------------ kernel/src/syscall/custom.rs | 4 +- 4 files changed, 139 insertions(+), 311 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index e945a93..d2dd79e 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -247,6 +247,14 @@ name = "pc-keyboard" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pci" +version = "0.0.1" +source = "git+https://github.com/rcore-os/pci-rs#30f2e83aa51dd313957f3fd6c3b233d3c905a4d0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pulldown-cmark" version = "0.0.3" @@ -311,6 +319,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", "rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", @@ -611,6 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce" +"checksum pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)" = "" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 63f4969..1665f77 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -44,6 +44,7 @@ volatile = "0.2" heapless = "0.4" console-traits = "0.3" buddy_system_allocator = "0.1" +pci = { git = "https://github.com/rcore-os/pci-rs" } device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" } lazy_static = { version = "1.3", features = ["spin_no_std"] } diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 9985d0d..c5d9661 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -1,318 +1,142 @@ -use crate::drivers::net::*; use crate::drivers::block::*; +use crate::drivers::net::*; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; use alloc::collections::BTreeMap; use alloc::string::String; use alloc::sync::Arc; use core::cmp::Ordering; +use pci::*; use spin::Mutex; use x86_64::instructions::port::Port; -const PCI_VENDOR: u32 = 0x00; -const PCI_DEVICE: u32 = 0x02; -const PCI_COMMAND: u32 = 0x04; -const PCI_STATUS: u32 = 0x06; -const PCI_SUBCLASS: u32 = 0x0a; -const PCI_CLASS: u32 = 0x0b; -const PCI_HEADER: u32 = 0x0e; -const PCI_BAR0: u32 = 0x10; // first -const PCI_BAR5: u32 = 0x24; // last -const PCI_CAP_PTR: u32 = 0x34; -const PCI_INTERRUPT_LINE: u32 = 0x3c; -const PCI_INTERRUPT_PIN: u32 = 0x3d; - -const PCI_MSI_CTRL_CAP: u32 = 0x00; -const PCI_MSI_ADDR: u32 = 0x04; -const PCI_MSI_UPPER_ADDR: u32 = 0x08; -const PCI_MSI_DATA: u32 = 0x0C; - -const PCI_CAP_ID_MSI: u32 = 0x05; - -const PCI_ADDR_PORT: u16 = 0xcf8; -const PCI_DATA_PORT: u16 = 0xcfc; - -const PCI_BASE_ADDRESS_SPACE: u32 = 0x01; -const PCI_BASE_ADDRESS_SPACE_IO: u32 = 0x01; -const PCI_BASE_ADDRESS_SPACE_MEMORY: u32 = 0x00; - -const PCI_BASE_ADDRESS_MEM_TYPE_MASK: u32 = 0x06; -const PCI_BASE_ADDRESS_MEM_TYPE_32: u32 = 0x00; -const PCI_BASE_ADDRESS_MEM_TYPE_1M: u32 = 0x02; -const PCI_BASE_ADDRESS_MEM_TYPE_64: u32 = 0x04; -const PCI_BASE_ADDRESS_MEM_PREFETCH: u32 = 0x08; -const PCI_BASE_ADDRESS_MEM_MASK: u32 = 0xfffffff0; - -#[derive(Copy, Clone)] -pub struct PciTag(u32); - -impl Ord for PciTag { - fn cmp(&self, other: &PciTag) -> Ordering { - self.0.cmp(&other.0) - } -} - -impl PartialOrd for PciTag { - fn partial_cmp(&self, other: &PciTag) -> Option { - Some(self.cmp(other)) - } -} +const PCI_COMMAND: u16 = 0x04; +const PCI_CAP_PTR: u16 = 0x34; +const PCI_INTERRUPT_LINE: u16 = 0x3c; +const PCI_INTERRUPT_PIN: u16 = 0x3d; -impl Eq for PciTag {} +const PCI_MSI_CTRL_CAP: u16 = 0x00; +const PCI_MSI_ADDR: u16 = 0x04; +const PCI_MSI_UPPER_ADDR: u16 = 0x08; +const PCI_MSI_DATA: u16 = 0x0C; -impl PartialEq for PciTag { - fn eq(&self, other: &PciTag) -> bool { - self.0 == other.0 - } -} - -impl PciTag { - pub fn new(bus: u32, dev: u32, func: u32) -> PciTag { - assert!(bus < 256); - assert!(dev < 32); - assert!(func < 8); - PciTag(bus << 16 | dev << 11 | func << 8) - } +const PCI_CAP_ID_MSI: u8 = 0x05; - pub fn bus(&self) -> u32 { - (self.0 >> 16) & 0xFF - } +struct PortOpsImpl; - pub fn dev(&self) -> u32 { - (self.0 >> 11) & 0x1F +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + Port::new(port).read() } - - pub fn func(&self) -> u32 { - (self.0 >> 8) & 0x7 + unsafe fn read16(&self, port: u16) -> u16 { + Port::new(port).read() } - - // biscuit/src/pci/pci.go Pci_read - pub unsafe fn read(&self, reg: u32, width: u32) -> u32 { - // spans in one reg - assert_eq!(reg / 4, (reg + width - 1) / 4); - - let enable = 1 << 31; - let rsh = reg % 4; - let r = reg - rsh; - let t = enable | self.0 | r; - - let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); - let mut pci_data: Port = Port::new(PCI_DATA_PORT); - - pci_addr.write(t); - let d = pci_data.read(); - pci_addr.write(0); - - let ret = d >> (rsh * 8); - let m = if width < 4 { - (1 << (8 * width)) - 1 - } else { - 0xffffffff - }; - - return ret & m; + unsafe fn read32(&self, port: u16) -> u32 { + Port::new(port).read() } - - pub unsafe fn write(&self, reg: u32, val: u32) { - assert_eq!(reg & 3, 0); - - let enable = 1 << 31; - let t = enable | self.0 | reg; - - let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); - let mut pci_data: Port = Port::new(PCI_DATA_PORT); - - pci_addr.write(t); - pci_data.write(val); - pci_addr.write(0); + unsafe fn write8(&self, port: u16, val: u8) { + Port::new(port).write(val); } - - // biscuit/src/pci/pci.go Pci_bar_mem - // linux/drivers/pci/probe.c pci_read_bases - // return (addr, len) - pub unsafe fn get_bar_mem(&self, bar_number: u32) -> Option<(usize, usize)> { - assert!(bar_number <= 6); - let bar = PCI_BAR0 + 4 * bar_number; - let mut base_lo = self.read(bar, 4); - self.write(bar, 0xffffffff); - let mut max_base_lo = self.read(bar, 4); - self.write(bar, base_lo); - - let mut base; - let mut max_base; - let mut address_mark; - - // memory instead of io - assert!(base_lo & PCI_BASE_ADDRESS_SPACE == PCI_BASE_ADDRESS_SPACE_MEMORY); - match base_lo & PCI_BASE_ADDRESS_MEM_TYPE_MASK { - PCI_BASE_ADDRESS_MEM_TYPE_32 => { - base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - address_mark = PCI_BASE_ADDRESS_MEM_MASK as usize; - } - PCI_BASE_ADDRESS_MEM_TYPE_64 => { - base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - - let base_hi = self.read(bar + 4, 4); - self.write(bar + 4, 0xffffffff); - let max_base_hi = self.read(bar + 4, 4); - self.write(bar + 4, base_hi); - base |= (base_hi as usize) << 32; - max_base |= (max_base_hi as usize) << 32; - address_mark = !0; - } - _ => unimplemented!("pci bar mem type"), - } - - if max_base == 0 { - return None; - } - - // linux/drivers/pci/probe.c pci_size - let mut size = max_base & address_mark; - if size == 0 { - return None; - } - size = (size & !(size - 1)) - 1; - - debug!( - "device memory address from {:#X} to {:#X}", - base, - base + size - ); - return Some((base as usize, size as usize)); + unsafe fn write16(&self, port: u16, val: u16) { + Port::new(port).write(val); } - - // returns a tuple of (vid, did, next) - pub fn probe(&self) -> Option<(u32, u32, bool)> { - unsafe { - // To lookup vendor and device, please see https://pci-ids.ucw.cz/read/PC/ - let v = self.read(PCI_VENDOR, 2); - if v == 0xffff { - return None; - } - let d = self.read(PCI_DEVICE, 2); - let mf = self.read(PCI_HEADER, 1); - - // To lookup class and subclass, please see https://pci-ids.ucw.cz/read/PD/ - let cl = self.read(PCI_CLASS, 1); - let scl = self.read(PCI_SUBCLASS, 1); - let line = self.read(PCI_INTERRUPT_LINE, 1); - let pin = self.read(PCI_INTERRUPT_PIN, 1); - info!( - "{:02x}:{:02x}.{}: {:#x} {:#x} ({} {}) irq {}:{}", - self.bus(), - self.dev(), - self.func(), - v, - d, - cl, - scl, - line, - pin - ); - - return Some((v, d, mf & 0x80 != 0)); - } + unsafe fn write32(&self, port: u16, val: u32) { + Port::new(port).write(val); } +} - /// Enable the pci tag and its interrupt - /// Return assigned MSI interrupt number when applicable - pub unsafe fn enable(&self) -> Option { - // 23 and lower are used - static mut MSI_IRQ: u32 = 23; - - let orig = self.read(PCI_COMMAND, 2); - // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable - self.write(PCI_COMMAND, orig | 0x40f); - - // find MSI cap - let mut msi_found = false; - let mut cap_ptr = self.read(PCI_CAP_PTR, 1); - let mut assigned_irq = None; - while cap_ptr > 0 { - let cap_id = self.read(cap_ptr, 1); - if cap_id == PCI_CAP_ID_MSI { - // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts - // 0 is (usually) the apic id of the bsp. - self.write(cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); - MSI_IRQ += 1; - let irq = MSI_IRQ; - assigned_irq = Some(irq); - // we offset all our irq numbers by 32 - self.write(cap_ptr + PCI_MSI_DATA, irq + 32); - - // enable MSI interrupt, assuming 64bit for now - let orig_ctrl = self.read(cap_ptr + PCI_MSI_CTRL_CAP, 4); - self.write(cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); - debug!( - "MSI control {:#b}, enabling MSI interrupts", - orig_ctrl >> 16 - ); - msi_found = true; - break; - } - debug!( - "PCI device has cap id {} at {:#X}", - self.read(cap_ptr, 1), - cap_ptr - ); - cap_ptr = self.read(cap_ptr + 1, 1); - } - - if !msi_found { - // Use PCI legacy interrupt instead - // IO Space | MEM Space | Bus Mastering | Special Cycles - self.write(PCI_COMMAND, orig | 0xf); - let line = self.read(PCI_INTERRUPT_LINE, 1); - let pin = self.read(PCI_INTERRUPT_PIN, 1); +/// Enable the pci device and its interrupt +/// Return assigned MSI interrupt number when applicable +unsafe fn enable(loc: Location) -> Option { + let ops = &PortOpsImpl; + let am = CSpaceAccessMethod::IO; + + // 23 and lower are used + static mut MSI_IRQ: u32 = 23; + + let orig = am.read16(ops, loc, PCI_COMMAND); + // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable + am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32); + + // find MSI cap + let mut msi_found = false; + let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16; + let mut assigned_irq = None; + while cap_ptr > 0 { + let cap_id = am.read8(ops, loc, cap_ptr); + if cap_id == PCI_CAP_ID_MSI { + // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts + // 0 is (usually) the apic id of the bsp. + am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); + MSI_IRQ += 1; + let irq = MSI_IRQ; + assigned_irq = Some(irq); + // we offset all our irq numbers by 32 + am.write32(ops, loc, cap_ptr + PCI_MSI_DATA, irq + 32); + + // enable MSI interrupt, assuming 64bit for now + let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); + am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); debug!( - "MSI not found, using PCI interrupt line {} pin {}", - line, pin + "MSI control {:#b}, enabling MSI interrupts", + orig_ctrl >> 16 ); + msi_found = true; + break; } + debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr); + cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16; + } - assigned_irq + if !msi_found { + // Use PCI legacy interrupt instead + // IO Space | MEM Space | Bus Mastering | Special Cycles + am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32); + debug!("MSI not found, using PCI interrupt"); } + + assigned_irq } -pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) { - if vid == 0x8086 { - if did == 0x100e || did == 0x100f || did == 0x10d3 { +pub fn init_driver(dev: &PCIDevice) { + match (dev.id.vendor_id, dev.id.device_id) { + (0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => { // 0x100e // 82540EM Gigabit Ethernet Controller // 0x100f // 82545EM Gigabit Ethernet Controller (Copper) // 0x10d3 // 82574L Gigabit Network Connection - if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { - unsafe { - tag.enable(); - } - e1000::e1000_init(addr, len); + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let _ = unsafe { enable(dev.loc) }; + e1000::e1000_init(addr as usize, len as usize); } - } else if did == 0x10fb { + } + (0x8086, 0x10fb) => { // 82599ES 10-Gigabit SFI/SFP+ Network Connection - if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { - let irq = unsafe { tag.enable() }; - PCI_DRIVERS - .lock() - .insert(tag, ixgbe::ixgbe_init(name, irq, addr, len)); + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); + let irq = unsafe { enable(dev.loc) }; + PCI_DRIVERS.lock().insert( + dev.loc, + ixgbe::ixgbe_init(name, irq, addr as usize, len as usize), + ); } - } else if did == 0x2922 { + } + (0x8086, 0x2922) => { // 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] - if let Some((addr, len)) = unsafe { tag.get_bar_mem(5) } { - let irq = unsafe { tag.enable() }; + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] { + let irq = unsafe { enable(dev.loc) }; PCI_DRIVERS .lock() - .insert(tag, ahci::ahci_init(irq, addr, len)); + .insert(dev.loc, ahci::ahci_init(irq, addr as usize, len as usize)); } } + _ => {} } } -pub fn detach_driver(tag: &PciTag) -> bool { - match PCI_DRIVERS.lock().remove(tag) { +pub fn detach_driver(loc: &Location) -> bool { + match PCI_DRIVERS.lock().remove(loc) { Some(driver) => { DRIVERS .write() @@ -327,51 +151,44 @@ pub fn detach_driver(tag: &PciTag) -> bool { } pub fn init() { - for bus in 0..256 { - for dev in 0..32 { - let tag = PciTag::new(bus, dev, 0); - if let Some((vid, did, next)) = tag.probe() { - let name = format!("enp{}s{}f0", bus, dev); - init_driver(name, vid, did, tag); - if next { - for func in 1..8 { - let tag = PciTag::new(bus, dev, func); - if let Some((vid, did, _)) = tag.probe() { - let name = format!("enp{}s{}f{}", bus, dev, func); - init_driver(name, vid, did, tag); - } - } - } - } - } + let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + info!( + "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}", + dev.loc.bus, + dev.loc.device, + dev.loc.function, + dev.id.vendor_id, + dev.id.device_id, + dev.id.class, + dev.id.subclass, + dev.pic_interrupt_line, + dev.interrupt_pin, + ); + init_driver(&dev); } } -pub fn find_device(vendor: u32, product: u32) -> Option { - for bus in 0..256 { - for dev in 0..32 { - let tag = PciTag::new(bus, dev, 0); - if let Some((vid, did, next)) = tag.probe() { - if vid == vendor && did == product { - return Some(tag); - } - if next { - for func in 1..8 { - let tag = PciTag::new(bus, dev, func); - if let Some((vid, did, _)) = tag.probe() { - if vid == vendor && did == product { - return Some(tag); - } - } - } - } - } +pub fn find_device(vendor: u16, product: u16) -> Option { + let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + if dev.id.vendor_id == vendor && dev.id.device_id == product { + return Some(dev.loc); } } None } +pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> { + unsafe { probe_function(&PortOpsImpl, loc, CSpaceAccessMethod::IO) } + .and_then(|dev| dev.bars[0]) + .map(|bar| match bar { + BAR::Memory(addr, len, _, _) => (addr as usize, len as usize), + _ => unimplemented!(), + }) +} + lazy_static! { - pub static ref PCI_DRIVERS: Arc>>> = - Arc::new(Mutex::new(BTreeMap::new())); + pub static ref PCI_DRIVERS: Mutex>> = + Mutex::new(BTreeMap::new()); } diff --git a/kernel/src/syscall/custom.rs b/kernel/src/syscall/custom.rs index 94ef99a..e21fa12 100644 --- a/kernel/src/syscall/custom.rs +++ b/kernel/src/syscall/custom.rs @@ -13,13 +13,13 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { vendor, product ); - let tag = pci::find_device(vendor as u32, product as u32).ok_or(SysError::ENOENT)?; + let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?; if pci::detach_driver(&tag) { info!("Kernel driver detached"); } // Get BAR0 memory - let (base, len) = unsafe { tag.get_bar_mem(0) }.ok_or(SysError::ENOENT)?; + let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?; let mut proc = process(); let virt_addr = proc.vm.find_free_area(0, len); From 8d92b7b98551efd555aaf4b4064e8b0161c27e20 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 31 Mar 2019 00:58:50 +0800 Subject: [PATCH 07/14] simplify AHCI mod stage 1 --- kernel/src/drivers/block/ahci.rs | 153 ++++++++++--------------------- kernel/src/drivers/block/mod.rs | 2 +- kernel/src/drivers/bus/pci.rs | 8 +- 3 files changed, 55 insertions(+), 108 deletions(-) diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index d5f9982..69a8f44 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -15,7 +15,7 @@ use crate::sync::FlagsGuard; use bitflags::*; use log::*; use rcore_memory::paging::PageTable; -use rcore_memory::PAGE_SIZE; +use rcore_memory::{PhysAddr, VirtAddr, PAGE_SIZE}; use volatile::Volatile; use rcore_fs::dev::BlockDevice; @@ -30,10 +30,10 @@ pub struct AHCI { header: usize, size: usize, rfis: usize, - cmd_list: usize, - cmd_table: usize, - data: usize, - port_addr: usize, + cmd_list: &'static mut [AHCICommandHeader], + cmd_table: &'static mut AHCICommandTable, + data: &'static mut [u8], + port: &'static mut AHCIPort, } pub struct AHCIDriver(Mutex); @@ -201,19 +201,7 @@ pub struct ATAIdentifyPacket { impl Driver for AHCIDriver { fn try_handle_interrupt(&self, _irq: Option) -> bool { - let driver = self.0.lock(); - - // ensure header page is mapped - let header = driver.header as usize; - let size = driver.size as usize; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - return false; + false } fn device_type(&self) -> DeviceType { @@ -226,31 +214,13 @@ impl Driver for AHCIDriver { fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { let mut driver = self.0.lock(); - // ensure header page is mapped - let header = driver.header as usize; - let size = driver.size as usize; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - let port = unsafe { &mut *(driver.port_addr as *mut AHCIPort) }; - let cmd_headers = unsafe { - slice::from_raw_parts_mut( - driver.cmd_list as *mut AHCICommandHeader, - PAGE_SIZE / size_of::(), - ) - }; - cmd_headers[0].prdbc = 0; - cmd_headers[0].pwa_cfl = 0; - - let cmd_table = unsafe { &mut *(driver.cmd_table as *mut AHCICommandTable) }; + + driver.cmd_list[0].prdbc = 0; + driver.cmd_list[0].pwa_cfl = 0; + let len = min(BLOCK_SIZE, buf.len()); - let data = unsafe { slice::from_raw_parts(driver.data as *const u8, len) }; - let fis = unsafe { &mut *(cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; + let fis = unsafe { &mut *(driver.cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; // Register FIS from HBA to device fis.fis_type = FIS_REG_H2D; fis.cflags = 1 << 7; @@ -270,16 +240,16 @@ impl Driver for AHCIDriver { fis.lba_4 = (block_id >> 32) as u8; fis.lba_5 = (block_id >> 40) as u8; - port.ci.write(1 << 0); + driver.port.ci.write(1 << 0); loop { - let ci = port.ci.read(); + let ci = driver.port.ci.read(); if (ci & (1 << 0)) == 0 { break; } } - (&mut buf[..len]).clone_from_slice(&data); + buf[..len].clone_from_slice(&driver.data[0..len]); return true; } @@ -288,31 +258,13 @@ impl Driver for AHCIDriver { return false; } let mut driver = self.0.lock(); - // ensure header page is mapped - let header = driver.header as usize; - let size = driver.size as usize; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - let port = unsafe { &mut *(driver.port_addr as *mut AHCIPort) }; - let cmd_headers = unsafe { - slice::from_raw_parts_mut( - driver.cmd_list as *mut AHCICommandHeader, - PAGE_SIZE / size_of::(), - ) - }; - cmd_headers[0].prdbc = 0; - cmd_headers[0].pwa_cfl = 1 << 6; // devic write - - let cmd_table = unsafe { &mut *(driver.cmd_table as *mut AHCICommandTable) }; - let data = unsafe { slice::from_raw_parts_mut(driver.data as *mut u8, BLOCK_SIZE) }; - data.clone_from_slice(&buf[..BLOCK_SIZE]); - - let fis = unsafe { &mut *(cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; + + driver.cmd_list[0].prdbc = 0; + driver.cmd_list[0].pwa_cfl = 1 << 6; // devic write + + driver.data[0..BLOCK_SIZE].clone_from_slice(&buf[..BLOCK_SIZE]); + + let fis = unsafe { &mut *(driver.cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; // Register FIS from HBA to device fis.fis_type = FIS_REG_H2D; fis.cflags = 1 << 7; @@ -333,10 +285,10 @@ impl Driver for AHCIDriver { fis.lba_4 = (block_id >> 32) as u8; fis.lba_5 = (block_id >> 40) as u8; - port.ci.write(1 << 0); + driver.port.ci.write(1 << 0); loop { - let ci = port.ci.read(); + let ci = driver.port.ci.read(); if (ci & (1 << 0)) == 0 { break; } @@ -349,7 +301,7 @@ const BLOCK_SIZE: usize = 512; fn from_ata_string(data: &[u8]) -> String { let mut swapped_data = Vec::new(); - assert!(data.len() % 2 == 0); + 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]); @@ -357,13 +309,15 @@ fn from_ata_string(data: &[u8]) -> String { 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 _ = FlagsGuard::no_irq_region(); - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } let ghc = unsafe { &mut *(header as *mut AHCIGHC) }; // AHCI Enable @@ -390,27 +344,12 @@ pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc(), @@ -423,10 +362,10 @@ pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc> 32) as u32; cmd_table.prdt[0].dbc_i = (BLOCK_SIZE - 1) as u32; - cmd_headers[0].ctba0 = cmd_table_pa as u32; - cmd_headers[0].ctba_u0 = (cmd_table_pa >> 32) as u32; - cmd_headers[0].prdtl = 1; - cmd_headers[0].prdbc = 0; + cmd_list[0].ctba0 = cmd_table_pa as u32; + cmd_list[0].ctba_u0 = (cmd_table_pa >> 32) as u32; + cmd_list[0].prdtl = 1; + cmd_list[0].prdbc = 0; port.clb.write(cmd_list_pa as u32); port.clbu.write((cmd_list_pa >> 32) as u32); @@ -480,14 +419,16 @@ pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc {} From 05d714ff27c08021e2ebef644421227e208bc39d Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 1 Apr 2019 16:15:58 +0800 Subject: [PATCH 08/14] improve AHCI mod stage 2 --- kernel/src/drivers/block/ahci.rs | 411 +++++++++++++++++-------------- 1 file changed, 232 insertions(+), 179 deletions(-) diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index 69a8f44..2d445f1 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -7,18 +7,18 @@ use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; -use core::cmp::min; use core::mem::size_of; use core::slice; +use core::sync::atomic::spin_loop_hint; -use crate::sync::FlagsGuard; +use bit_field::*; use bitflags::*; use log::*; -use rcore_memory::paging::PageTable; -use rcore_memory::{PhysAddr, VirtAddr, PAGE_SIZE}; +use rcore_fs::dev::BlockDevice; use volatile::Volatile; -use rcore_fs::dev::BlockDevice; +use rcore_memory::paging::PageTable; +use rcore_memory::{PhysAddr, VirtAddr, PAGE_SIZE}; use crate::drivers::BlockDriver; use crate::memory::active_table; @@ -29,7 +29,7 @@ use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; pub struct AHCI { header: usize, size: usize, - rfis: usize, + received_fis: &'static mut AHCIReceivedFIS, cmd_list: &'static mut [AHCICommandHeader], cmd_table: &'static mut AHCICommandTable, data: &'static mut [u8], @@ -38,21 +38,31 @@ pub struct AHCI { pub struct AHCIDriver(Mutex); -// AHCI -// 3.1 Generic Host Control +/// AHCI Generic Host Control (3.1) #[repr(C)] pub struct AHCIGHC { - cap: Volatile, - ghc: Volatile, - is: Volatile, - pi: Volatile, - vs: Volatile, - ccc_ctl: Volatile, + /// 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, - em_loc: Volatile, - em_ctl: Volatile, - cap2: Volatile, - bohc: 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! { @@ -78,42 +88,63 @@ bitflags! { const EMS = 1 << 6; const SXS = 1 << 5; // number of ports = 1 - const NP_1 = 1 << 0; - const NP_2 = 1 << 1; - const NP_4 = 1 << 2; - const NP_8 = 1 << 3; - const NP_16 = 1 << 4; + const NUM_MASK = 0b11111; } } -// AHCI -// 3.3 Port Registers (one set per port) +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 { - clb: Volatile, - clbu: Volatile, - fb: Volatile, - fbu: Volatile, - is: Volatile, - ie: Volatile, - cmd: Volatile, + command_list_base_address: Volatile, + fis_base_address: Volatile, + interrupt_status: Volatile, + interrupt_enable: Volatile, + command: Volatile, reserved: Volatile, - tfd: Volatile, - sig: Volatile, - ssts: Volatile, - sctl: Volatile, - serr: Volatile, - sact: Volatile, - ci: Volatile, - sntf: Volatile, - fbs: Volatile, - devslp: 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 -// 4.2.1 Received FIS Structure +/// AHCI Received FIS Structure (4.2.1) #[repr(C)] -pub struct AHCIRFIS { +pub struct AHCIReceivedFIS { dma: [u8; 0x20], pio: [u8; 0x20], d2h: [u8; 0x18], @@ -122,35 +153,74 @@ pub struct AHCIRFIS { reserved: [u8; 0x60], } -// AHCI -// 4.2.2 Command List Structure +/// # 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 { - pwa_cfl: u8, - pmp_cbr: u8, - prdtl: u16, - prdbc: u32, - ctba0: u32, - ctba_u0: u32, - reservec: [u32; 4], + /// + 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 -// 4.2.3 Command Table +/// AHCI Command Table (4.2.3) #[repr(C)] pub struct AHCICommandTable { - cfis: [u8; 64], + /// Command FIS + cfis: SATAFISRegH2D, + /// ATAPI command, 12 or 16 bytes acmd: [u8; 16], + /// Reserved reserved: [u8; 48], - prdt: [AHCIPRD; 1], + /// Physical region descriptor table entries, 0 ~ 65535 + prdt: [AHCIPrdtEntry; 1], } -// 4.2.3 Command Table +/// Physical region descriptor table entry #[repr(C)] -pub struct AHCIPRD { - dba: u32, - dbau: u32, +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, } @@ -160,32 +230,47 @@ const CMD_READ_DMA_EXT: u8 = 0x25; const CMD_WRITE_DMA_EXT: u8 = 0x35; const CMD_IDENTIFY_DEVICE: u8 = 0xec; -// https://wiki.osdev.org/AHCI -// SATA -// Figure 5-2: Register FIS - Host to Device +/// SATA Register FIS - Host to Device +/// +/// https://wiki.osdev.org/AHCI Figure 5-2 #[repr(C)] -#[derive(Default)] 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_lo: u8, - sector_count_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; + } } -// ATA8-ACS -// Table 29 IDENTIFY DEVICE data +/// IDENTIFY DEVICE data +/// +/// ATA8-ACS Table 29 #[repr(C)] pub struct ATAIdentifyPacket { _1: [u16; 10], @@ -199,101 +284,80 @@ pub struct ATAIdentifyPacket { lba48_sectors: u64, // words 100-103 } -impl Driver for AHCIDriver { - fn try_handle_interrupt(&self, _irq: Option) -> bool { - false - } - - fn device_type(&self) -> DeviceType { - DeviceType::Block - } - - fn get_id(&self) -> String { - format!("ahci") - } - - fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { - let mut driver = self.0.lock(); - - driver.cmd_list[0].prdbc = 0; - driver.cmd_list[0].pwa_cfl = 0; - - let len = min(BLOCK_SIZE, buf.len()); +impl AHCI { + fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> usize { + self.cmd_list[0].flags = CommandHeaderFlags::empty(); - let fis = unsafe { &mut *(driver.cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; + 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_lo = 1; - fis.sector_count_hi = 0; + fis.sector_count = 1; fis.dev_head = 0x40; // LBA fis.control = 0x80; // LBA48 + fis.set_lba(block_id as u64); - let block_id = block_id as u64; // avoid problems on riscv32 - fis.lba_0 = block_id as u8; - fis.lba_1 = (block_id >> 8) as u8; - fis.lba_2 = (block_id >> 16) as u8; - fis.lba_3 = (block_id >> 24) as u8; - fis.lba_4 = (block_id >> 32) as u8; - fis.lba_5 = (block_id >> 40) as u8; + self.port.issue_command(0); + self.port.spin_on_slot(0); - driver.port.ci.write(1 << 0); - - loop { - let ci = driver.port.ci.read(); - if (ci & (1 << 0)) == 0 { - break; - } - } - - buf[..len].clone_from_slice(&driver.data[0..len]); - return true; + let len = buf.len().min(BLOCK_SIZE); + buf[..len].clone_from_slice(&self.data[0..len]); + len } - fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { - if buf.len() < BLOCK_SIZE { - return false; - } - let mut driver = self.0.lock(); - - driver.cmd_list[0].prdbc = 0; - driver.cmd_list[0].pwa_cfl = 1 << 6; // devic write + fn write_block(&mut self, block_id: usize, buf: &[u8]) -> usize { + self.cmd_list[0].flags = CommandHeaderFlags::WRITE; // device write - driver.data[0..BLOCK_SIZE].clone_from_slice(&buf[..BLOCK_SIZE]); + let len = buf.len().min(BLOCK_SIZE); + self.data[0..len].clone_from_slice(&buf[..len]); - let fis = unsafe { &mut *(driver.cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; + 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_lo = 1; - fis.sector_count_hi = 0; + fis.sector_count = 1; fis.dev_head = 0x40; // LBA fis.control = 0x80; // LBA48 + fis.set_lba(block_id as u64); - let block_id = block_id as u64; // avoid problems on riscv32 - fis.lba_0 = block_id as u8; - fis.lba_1 = (block_id >> 8) as u8; - fis.lba_2 = (block_id >> 16) as u8; - fis.lba_3 = (block_id >> 24) as u8; - fis.lba_4 = (block_id >> 32) as u8; - fis.lba_5 = (block_id >> 40) as u8; + self.port.issue_command(0); + self.port.spin_on_slot(0); - driver.port.ci.write(1 << 0); + len + } +} - loop { - let ci = driver.port.ci.read(); - if (ci & (1 << 0)) == 0 { - break; - } +impl Driver for AHCIDriver { + fn try_handle_interrupt(&self, _irq: Option) -> bool { + false + } + + fn device_type(&self) -> DeviceType { + DeviceType::Block + } + + fn get_id(&self) -> String { + format!("ahci") + } + + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { + let mut driver = self.0.lock(); + driver.read_block(block_id, buf); + true + } + + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { + if buf.len() < BLOCK_SIZE { + return false; } - return true; + let mut driver = self.0.lock(); + driver.write_block(block_id, buf); + true } } @@ -320,93 +384,82 @@ fn alloc_dma(page_num: usize) -> (VirtAddr, PhysAddr) { pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc { let ghc = unsafe { &mut *(header as *mut AHCIGHC) }; - // AHCI Enable - ghc.ghc.write(ghc.ghc.read() | (1 << 13)); + ghc.enable(); - let num_ports = (ghc.cap.read().bits() & 0x1f) as usize + 1; - - for port_num in 0..num_ports { - if (ghc.pi.read() | (1 << port_num)) != 0 { + 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.ssts.read() >> 8) & 0xF != 1 { + if port.sata_status.read().get_bits(8..12) != 1 { continue; } // SSTS DET Present - if port.ssts.read() & 0xF != 3 { + if port.sata_status.read().get_bits(0..4) != 3 { continue; } debug!("probing port {}", port_num); // Disable Port First - port.cmd.write(port.cmd.read() & !(1 << 4 | 1 << 0)); + 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].dba = data_pa as u32; - cmd_table.prdt[0].dbau = (data_pa >> 32) as u32; + 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].ctba0 = cmd_table_pa as u32; - cmd_list[0].ctba_u0 = (cmd_table_pa >> 32) as u32; - cmd_list[0].prdtl = 1; - cmd_list[0].prdbc = 0; + 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.clb.write(cmd_list_pa as u32); - port.clbu.write((cmd_list_pa >> 32) as u32); - - port.fb.write(rfis_pa as u32); - port.fbu.write((rfis_pa >> 32) as u32); + 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.ci.write(0); - port.sact.write(0); - port.serr.write(0); + port.command_issue.write(0); + port.sata_active.write(0); + port.sata_error.write(0); // enable port - port.cmd - .write(port.cmd.read() | 1 << 0 | 1 << 1 | 1 << 2 | 1 << 4 | 1 << 28); + port.command.update(|c| { + *c |= 1 << 0 | 1 << 1 | 1 << 2 | 1 << 4 | 1 << 28; + }); - let stat = port.ssts.read(); + let stat = port.sata_status.read(); if stat == 0 { warn!("port is not connected to external drive?"); } - let fis = unsafe { &mut *(cmd_table.cfis.as_ptr() as *mut SATAFISRegH2D) }; + 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_lo = 1; + fis.sector_count = 1; debug!("issued identify command"); - port.ci.write(1 << 0); - - loop { - let ci = port.ci.read(); - if (ci & (1 << 0)) == 0 { - break; - } - } - - let identify_data = unsafe { &*(data_va as *mut ATAIdentifyPacket) }; + port.issue_command(0); + port.spin_on_slot(0); unsafe { debug!( @@ -424,7 +477,7 @@ pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc Date: Tue, 2 Apr 2019 08:12:26 +0800 Subject: [PATCH 09/14] Fix comment in AHCI --- kernel/src/drivers/block/ahci.rs | 2 +- user | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index 2d445f1..d05658c 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -87,7 +87,7 @@ bitflags! { const CCCS = 1 << 7; const EMS = 1 << 6; const SXS = 1 << 5; - // number of ports = 1 + // number of ports - 1 const NUM_MASK = 0b11111; } } diff --git a/user b/user index ec476c3..b1e7a2d 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit ec476c3acb600c6d437454e74fb3e0eb6c452de4 +Subproject commit b1e7a2d07e81ce5035a1cc25b0ade9367aee1a94 From ca45848028da8103882a206b43b0de90077502ce Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 2 Apr 2019 08:27:02 +0800 Subject: [PATCH 10/14] Add extra_nic option --- kernel/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/Makefile b/kernel/Makefile index 8a3bbf9..0d3a6d8 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -27,6 +27,7 @@ # | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ # pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device # init = /bin/ls Only available on riscv64, run specified program instead of user shell +# extra_nic = on | off Only available on x86_64, add an additional e1000 nic arch ?= riscv64 board ?= none @@ -36,6 +37,7 @@ graphic ?= off smp ?= 4 pci_passthru ?= init ?= +extra_nic ?= off target := $(arch) build_path := target/$(target)/$(mode) @@ -81,6 +83,11 @@ qemu_opts += \ qemu_net_opts += \ -device vfio-pci,host=$(pci_passthru) endif +ifeq ($(extra_nic), on) +qemu_net_opts += \ + -netdev type=tap,id=net1,script=no,downscript=no \ + -device e1000e,netdev=net1 +endif else ifeq ($(arch), riscv32) qemu_opts += \ From 66af7473ebc05313f27928225937647f7cb3aac9 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 2 Apr 2019 08:52:13 +0800 Subject: [PATCH 11/14] Do not use alloc::prelude --- kernel/Cargo.lock | 4 ++-- kernel/src/drivers/input/virtio_input.rs | 4 +++- kernel/src/drivers/mod.rs | 3 ++- kernel/src/drivers/net/e1000.rs | 3 ++- kernel/src/drivers/net/ixgbe.rs | 3 ++- kernel/src/drivers/net/virtio_net.rs | 3 ++- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index d2dd79e..603faef 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -125,12 +125,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "deque" version = "0.3.2" -source = "git+https://github.com/rcore-os/deque.git?branch=no_std#907d03935b9badde1902d9c84d138872f34c6763" +source = "git+https://github.com/rcore-os/deque.git?branch=no_std#b13a836dd69ae82cc0b8d711c2990b9baf5170d1" [[package]] name = "device_tree" version = "1.0.3" -source = "git+https://github.com/rcore-os/device_tree-rs#0e887395ab92e99f68117b17d85b0b417bfd1b45" +source = "git+https://github.com/rcore-os/device_tree-rs#7945459093f49a39996291283b8894753c8a638d" [[package]] name = "fixedvec" diff --git a/kernel/src/drivers/input/virtio_input.rs b/kernel/src/drivers/input/virtio_input.rs index 4f2d6a7..9ff1587 100644 --- a/kernel/src/drivers/input/virtio_input.rs +++ b/kernel/src/drivers/input/virtio_input.rs @@ -1,6 +1,8 @@ -use alloc::prelude::*; +use alloc::boxed::Box; +use alloc::string::String; use alloc::sync::Arc; use alloc::vec; +use alloc::vec::Vec; use core::fmt; use core::mem::size_of; use core::mem::transmute_copy; diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index 1363330..61e64bb 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -1,5 +1,6 @@ -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use lazy_static::lazy_static; use smoltcp::wire::{EthernetAddress, Ipv4Address}; diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 743070b..0917268 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -3,8 +3,9 @@ use alloc::alloc::{GlobalAlloc, Layout}; use alloc::format; -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use core::mem::size_of; use core::slice; use core::sync::atomic::{fence, Ordering}; diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index fd96b7d..556739b 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -1,8 +1,9 @@ //! Intel 10Gb Network Adapter 82599 i.e. ixgbe network driver //! Datasheet: https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82599-10-gbe-controller-datasheet.pdf -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use alloc::collections::BTreeMap; use isomorphic_drivers::net::ethernet::intel::ixgbe; diff --git a/kernel/src/drivers/net/virtio_net.rs b/kernel/src/drivers/net/virtio_net.rs index 397bd5d..d149ec3 100644 --- a/kernel/src/drivers/net/virtio_net.rs +++ b/kernel/src/drivers/net/virtio_net.rs @@ -1,7 +1,8 @@ use alloc::alloc::{GlobalAlloc, Layout}; use alloc::format; -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use core::mem::size_of; use core::slice; From ee66451873bb325f904fcf43288c020d5baff6f9 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 2 Apr 2019 10:24:18 +0800 Subject: [PATCH 12/14] Map e1000 to kernel space addr as well and rename its iface --- kernel/src/drivers/block/ahci.rs | 1 - kernel/src/drivers/bus/pci.rs | 12 ++++++-- kernel/src/drivers/net/e1000.rs | 53 ++++++++++---------------------- 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index d05658c..842259c 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -457,7 +457,6 @@ pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc Option { } pub fn init_driver(dev: &PCIDevice) { + let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); match (dev.id.vendor_id, dev.id.device_id) { (0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => { // 0x100e @@ -110,14 +111,19 @@ pub fn init_driver(dev: &PCIDevice) { // 0x10d3 // 82574L Gigabit Network Connection if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { - let _ = unsafe { enable(dev.loc) }; - e1000::e1000_init(addr as usize, len as usize); + let irq = unsafe { enable(dev.loc) }; + let vaddr = KERNEL_OFFSET + addr as usize; + let mut current_addr = addr as usize; + while current_addr < addr as usize + len as usize { + active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + e1000::e1000_init(name, irq, vaddr, len as usize); } } (0x8086, 0x10fb) => { // 82599ES 10-Gigabit SFI/SFP+ Network Connection if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { - let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); let irq = unsafe { enable(dev.loc) }; PCI_DRIVERS.lock().insert( dev.loc, diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 0917268..fb32d8f 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -73,20 +73,19 @@ const E1000_RAH: usize = 0x5404 / 4; pub struct E1000Interface { iface: Mutex>, driver: E1000Driver, + name: String, + irq: Option, } impl Driver for E1000Interface { - fn try_handle_interrupt(&self, _irq: Option) -> bool { - let irq = { - let driver = self.driver.0.lock(); + fn try_handle_interrupt(&self, irq: Option) -> bool { + if irq.is_some() && self.irq.is_some() && irq != self.irq { + // not ours, skip it + return false; + } - if let None = active_table().get_entry(driver.header) { - let mut current_addr = driver.header; - while current_addr < driver.header + driver.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } + let data = { + let driver = self.driver.0.lock(); let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) @@ -102,7 +101,7 @@ impl Driver for E1000Interface { } }; - if irq { + if data { let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64); let mut sockets = SOCKETS.lock(); match self.iface.lock().poll(&mut sockets, timestamp) { @@ -115,7 +114,7 @@ impl Driver for E1000Interface { } } - return irq; + return data; } fn device_type(&self) -> DeviceType { @@ -131,7 +130,7 @@ impl Driver for E1000Interface { } fn get_ifname(&self) -> String { - format!("e1000") + self.name.clone() } fn ipv4_address(&self) -> Option { @@ -185,14 +184,6 @@ impl<'a> phy::Device<'a> for E1000Driver { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { let driver = self.0.lock(); - if let None = active_table().get_entry(driver.header) { - let mut current_addr = driver.header; - while current_addr < driver.header + driver.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) }; @@ -238,14 +229,6 @@ impl<'a> phy::Device<'a> for E1000Driver { fn transmit(&'a mut self) -> Option { let driver = self.0.lock(); - if let None = active_table().get_entry(driver.header) { - let mut current_addr = driver.header; - while current_addr < driver.header + driver.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) }; @@ -354,8 +337,8 @@ bitflags! { } // JudgeDuck-OS/kern/e1000.c -pub fn e1000_init(header: usize, size: usize) { - info!("Probing e1000"); +pub fn e1000_init(name: String, irq: Option, header: usize, size: usize) { + info!("Probing e1000 {}", name); assert_eq!(size_of::(), 16); assert_eq!(size_of::(), 16); @@ -387,12 +370,6 @@ pub fn e1000_init(header: usize, size: usize) { first_trans: true, }; - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - let e1000 = unsafe { slice::from_raw_parts_mut(header as *mut Volatile, size / 4) }; debug!( "status before setup: {:#?}", @@ -502,6 +479,8 @@ pub fn e1000_init(header: usize, size: usize) { let e1000_iface = E1000Interface { iface: Mutex::new(iface), driver: net_driver.clone(), + name, + irq, }; let driver = Arc::new(e1000_iface); From b4bd960a7475e97598c6116ecc51a9acc185fedc Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 2 Apr 2019 10:50:33 +0800 Subject: [PATCH 13/14] Map ixgbe to kernel space as well --- kernel/src/drivers/bus/pci.rs | 13 +++++--- kernel/src/drivers/net/ixgbe.rs | 59 --------------------------------- 2 files changed, 9 insertions(+), 63 deletions(-) diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index bf4d163..6a143c8 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -125,10 +125,15 @@ pub fn init_driver(dev: &PCIDevice) { // 82599ES 10-Gigabit SFI/SFP+ Network Connection if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { let irq = unsafe { enable(dev.loc) }; - PCI_DRIVERS.lock().insert( - dev.loc, - ixgbe::ixgbe_init(name, irq, addr as usize, len as usize), - ); + let vaddr = KERNEL_OFFSET + addr as usize; + let mut current_addr = addr as usize; + while current_addr < addr as usize + len as usize { + active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + PCI_DRIVERS + .lock() + .insert(dev.loc, ixgbe::ixgbe_init(name, irq, vaddr, len as usize)); } } (0x8086, 0x2922) => { diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 556739b..7e289f7 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -32,21 +32,6 @@ struct IXGBEDriver { mtu: usize, } -impl Drop for IXGBEDriver { - fn drop(&mut self) { - let _ = FlagsGuard::no_irq_region(); - let header = self.header; - let size = self.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - } -} - pub struct IXGBEInterface { iface: Mutex>, driver: IXGBEDriver, @@ -64,16 +49,6 @@ impl Driver for IXGBEInterface { let handled = { let _ = FlagsGuard::no_irq_region(); - let header = self.driver.header; - let size = self.driver.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - self.driver.inner.try_handle_interrupt() }; @@ -135,15 +110,6 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { let _ = FlagsGuard::no_irq_region(); - let header = self.header; - let size = self.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } if self.inner.can_send() { if let Some(data) = self.inner.recv() { Some((IXGBERxToken(data), IXGBETxToken(self.clone()))) @@ -157,15 +123,6 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn transmit(&'a mut self) -> Option { let _ = FlagsGuard::no_irq_region(); - let header = self.header; - let size = self.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } if self.inner.can_send() { Some(IXGBETxToken(self.clone())) } else { @@ -200,15 +157,6 @@ impl phy::TxToken for IXGBETxToken { F: FnOnce(&mut [u8]) -> Result, { let _ = FlagsGuard::no_irq_region(); - let header = self.0.header; - let size = self.0.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()]; let result = f(&mut buffer[..len]); if result.is_ok() { @@ -225,13 +173,6 @@ pub fn ixgbe_init( size: usize, ) -> Arc { let _ = FlagsGuard::no_irq_region(); - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), header, size); ixgbe.enable_irq(); From c99b7a1aed4e77e0c9eb53fc7d238b93bb8c4a42 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 00:16:27 +0800 Subject: [PATCH 14/14] Remove -machine ubuntu for newer version of QEMU --- kernel/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/Makefile b/kernel/Makefile index 0d3a6d8..e4bec12 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -79,7 +79,7 @@ qemu_net_opts += \ -device e1000e,netdev=net0 else qemu_opts += \ - -machine ubuntu,accel=kvm + -machine accel=kvm qemu_net_opts += \ -device vfio-pci,host=$(pci_passthru) endif