diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index fbfd318..942a0a9 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" @@ -252,6 +252,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" @@ -317,6 +325,7 @@ dependencies = [ "mips 0.1.0 (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)", @@ -618,6 +627,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 936a813..4e7758c 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -50,6 +50,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/Makefile b/kernel/Makefile index 2ab9b70..07d5259 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) @@ -76,7 +78,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 @@ -85,10 +89,15 @@ 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 +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 += \ 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..842259c --- /dev/null +++ b/kernel/src/drivers/block/ahci.rs @@ -0,0 +1,497 @@ +//! 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, 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 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 + } +} + +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; + } + let mut driver = self.0.lock(); + driver.write_block(block_id, buf); + true + } +} + +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!(); +} diff --git a/kernel/src/drivers/block/mod.rs b/kernel/src/drivers/block/mod.rs index bbcee0a..fb9a39e 100644 --- a/kernel/src/drivers/block/mod.rs +++ b/kernel/src/drivers/block/mod.rs @@ -1 +1,2 @@ +pub mod ahci; pub mod virtio_blk; diff --git a/kernel/src/drivers/block/virtio_blk.rs b/kernel/src/drivers/block/virtio_blk.rs index 5fff2d7..b6cc9cb 100644 --- a/kernel/src/drivers/block/virtio_blk.rs +++ b/kernel/src/drivers/block/virtio_blk.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; use core::cmp::min; @@ -14,6 +15,7 @@ use volatile::Volatile; use rcore_fs::dev::BlockDevice; +use crate::drivers::BlockDriver; use crate::memory::active_table; use crate::sync::SpinNoIrqLock as Mutex; @@ -125,11 +127,8 @@ impl Driver for VirtIOBlkDriver { fn get_id(&self) -> 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/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index e46c7d0..6a143c8 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -1,309 +1,159 @@ +use crate::consts::KERNEL_OFFSET; +use crate::drivers::block::*; use crate::drivers::net::*; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; +use crate::memory::active_table; use alloc::collections::BTreeMap; use alloc::string::String; use alloc::sync::Arc; use core::cmp::Ordering; +use pci::*; +use rcore_memory::{paging::PageTable, PAGE_SIZE}; 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_COMMAND: u16 = 0x04; +const PCI_CAP_PTR: u16 = 0x34; +const PCI_INTERRUPT_LINE: u16 = 0x3c; +const PCI_INTERRUPT_PIN: u16 = 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_MSI_CTRL_CAP: u16 = 0x00; +const PCI_MSI_ADDR: u16 = 0x04; +const PCI_MSI_UPPER_ADDR: u16 = 0x08; +const PCI_MSI_DATA: u16 = 0x0C; -const PCI_CAP_ID_MSI: u32 = 0x05; +const PCI_CAP_ID_MSI: u8 = 0x05; -const PCI_ADDR_PORT: u16 = 0xcf8; -const PCI_DATA_PORT: u16 = 0xcfc; +struct PortOpsImpl; -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 PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + Port::new(port).read() } -} - -impl PartialOrd for PciTag { - fn partial_cmp(&self, other: &PciTag) -> Option { - Some(self.cmp(other)) + unsafe fn read16(&self, port: u16) -> u16 { + Port::new(port).read() } -} - -impl Eq for PciTag {} - -impl PartialEq for PciTag { - fn eq(&self, other: &PciTag) -> bool { - self.0 == other.0 + unsafe fn read32(&self, port: u16) -> u32 { + Port::new(port).read() } -} - -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) + unsafe fn write8(&self, port: u16, val: u8) { + Port::new(port).write(val); } - - pub fn bus(&self) -> u32 { - (self.0 >> 16) & 0xFF + unsafe fn write16(&self, port: u16, val: u16) { + Port::new(port).write(val); } - - pub fn dev(&self) -> u32 { - (self.0 >> 11) & 0x1F + unsafe fn write32(&self, port: u16, val: u32) { + Port::new(port).write(val); } +} - pub fn func(&self) -> u32 { - (self.0 >> 8) & 0x7 - } - - // 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; - } - - 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); - } - - // 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 <= 4); - 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)); - } - - // 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)); - } - } - - /// 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) { + 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 // 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(); + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + 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(addr, len); + e1000::e1000_init(name, irq, vaddr, 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() }; + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + 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; + } + PCI_DRIVERS + .lock() + .insert(dev.loc, ixgbe::ixgbe_init(name, irq, vaddr, len as usize)); + } + } + (0x8086, 0x2922) => { + // 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] { + let irq = unsafe { enable(dev.loc) }; + assert!(len as usize <= PAGE_SIZE); + let vaddr = KERNEL_OFFSET + addr as usize; + active_table().map(vaddr, addr as usize); PCI_DRIVERS .lock() - .insert(tag, ixgbe::ixgbe_init(name, irq, addr, len)); + .insert(dev.loc, ahci::ahci_init(irq, vaddr, 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() @@ -318,51 +168,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/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 b030cdc..0356a48 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -1,12 +1,13 @@ -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}; 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 +65,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/e1000.rs b/kernel/src/drivers/net/e1000.rs index 743070b..fb32d8f 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}; @@ -72,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) @@ -101,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) { @@ -114,7 +114,7 @@ impl Driver for E1000Interface { } } - return irq; + return data; } fn device_type(&self) -> DeviceType { @@ -130,7 +130,7 @@ impl Driver for E1000Interface { } fn get_ifname(&self) -> String { - format!("e1000") + self.name.clone() } fn ipv4_address(&self) -> Option { @@ -184,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) }; @@ -237,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) }; @@ -353,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); @@ -386,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: {:#?}", @@ -501,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); diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 284f457..7e289f7 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; @@ -20,7 +21,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}; @@ -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(); 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; 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")] 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); 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 69febc9..b1e7a2d 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 69febc9fcc64df60329687b4f24b9b5309c99adf +Subproject commit b1e7a2d07e81ce5035a1cc25b0ade9367aee1a94