From 9831cae13c6de408514ce71b60b62bda466f578b Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 29 Mar 2019 15:19:40 +0800 Subject: [PATCH 01/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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 4e3b2fb80f6cbbfd0c5eae1293b754faf9b31997 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Tue, 2 Apr 2019 16:52:36 +0800 Subject: [PATCH 14/23] Add support for 16550 serial controller Signed-off-by: Harry Chen --- kernel/src/arch/mipsel/io.rs | 76 +++++++++++++++++++++++++++++------ kernel/src/arch/mipsel/mod.rs | 2 + 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/kernel/src/arch/mipsel/io.rs b/kernel/src/arch/mipsel/io.rs index ca99ad3..e14c4ec 100644 --- a/kernel/src/arch/mipsel/io.rs +++ b/kernel/src/arch/mipsel/io.rs @@ -1,6 +1,7 @@ use core::fmt::{Write, Result, Arguments}; +use core::ptr::{read_volatile, write_volatile}; -struct SerialPort; +struct SerialPort {}; impl Write for SerialPort { fn write_str(&mut self, s: &str) -> Result { @@ -17,26 +18,40 @@ impl Write for SerialPort { } } +fn write(addr: usize, content: T) { + let cell = (addr) as *mut T; + write_volatile(cell, content); +} + +fn read(addr: usize) -> T { + let cell = (addr) as *const T; + read_volatile(cell); +} + +/// non-blocking version of putchar() fn putchar(c: u8) { - // TODO: output to uart + write(COM1 + COM_TX, c); } +/// blocking version of getchar() pub fn getchar() -> char { - // TODO: get char from uart - let c = 0 as u8; - + loop { + if (read::(COM1 + COM_LSR) & COM_LSR_DATA) == 0 { + break; + } + } + let c = read::(COM1 + COM_RX); match c { 255 => '\0', // null c => c as char, } } +/// non-blocking version of getchar() pub fn getchar_option() -> Option { - // TODO: get char from uart - let c = 0 as u8; - match c { - -1 => None, - c => Some(c as u8 as char), + match read::(COM1 + COM_LSR) & COM_LSR_DATA { + 0 => None, + else => Some(read::(COM1 + COM_RX) as u8 as char), } } @@ -44,5 +59,42 @@ pub fn putfmt(fmt: Arguments) { SerialPort.write_fmt(fmt).unwrap(); } -const TXDATA: *mut u32 = 0x38000000 as *mut u32; -const RXDATA: *mut u32 = 0x38000004 as *mut u32; +pub fn init(serial_base_addr: usize) { + COM1 = serial_base_addr; + // Turn off the FIFO + write(COM1 + COM_FCR, 0 as u8); + // Set speed; requires DLAB latch + write(COM1 + COM_LCR, COM_LCR_DLAB); + write(COM1 + COM_DLL, (115200 / 9600) as u8); + write(COM1 + COM_DLM, 0 as u8); + + // 8 data bits, 1 stop bit, parity off; turn off DLAB latch + write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); + + // No modem controls + write(COM1 + COM_MCR, 0 as u8); + // Enable rcv interrupts + write(COM1 + COM_IER, COM_IER_RDI); +} + +static mut COM1: usize = 0; + +const COM_RX :usize = 0; // In: Receive buffer (DLAB=0) +const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0) +const COM_DLL :usize = 0; // Out: Divisor Latch Low (DLAB=1) +const COM_DLM :usize = 1; // Out: Divisor Latch High (DLAB=1) +const COM_IER :usize = 1; // Out: Interrupt Enable Register +const COM_IER_RDI :u8 = 0x01; // Enable receiver data interrupt +const COM_IIR :usize = 2; // In: Interrupt ID Register +const COM_FCR :usize = 2; // Out: FIFO Control Register +const COM_LCR :usize = 3; // Out: Line Control Register +const COM_LCR_DLAB :u8 = 0x80; // Divisor latch access bit +const COM_LCR_WLEN8 :u8 = 0x03; // Wordlength: 8 bits +const COM_MCR :usize = 4; // Out: Modem Control Register +const COM_MCR_RTS :u8 = 0x02; // RTS complement +const COM_MCR_DTR :u8 = 0x01; // DTR complement +const COM_MCR_OUT2 :u8 = 0x08; // Out2 complement +const COM_LSR :usize = 5; // In: Line Status Register +const COM_LSR_DATA :u8 = 0x01; // Data available +const COM_LSR_TXRDY :u8 = 0x20; // Transmit buffer avail +const COM_LSR_TSRE :u8 = 0x40; // Transmitter off diff --git a/kernel/src/arch/mipsel/mod.rs b/kernel/src/arch/mipsel/mod.rs index bb3d87f..9681b06 100644 --- a/kernel/src/arch/mipsel/mod.rs +++ b/kernel/src/arch/mipsel/mod.rs @@ -38,6 +38,8 @@ pub extern fn rust_main() -> ! { unsafe { memory::clear_bss(); } + crate::io::init(); + println!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start); crate::logging::init(); From 85245c4e21c3eac39878dff1a67742ecc50c0373 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Wed, 3 Apr 2019 08:46:22 +0800 Subject: [PATCH 15/23] Finish serial initialization Signed-off-by: Harry Chen --- kernel/src/arch/mipsel/interrupt.rs | 4 ---- kernel/src/arch/mipsel/io.rs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index f6bea8a..b6957bf 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -74,9 +74,6 @@ pub extern fn rust_trap(tf: &mut TrapFrame) { fn external() { // TODO - #[cfg(feature = "board_u540")] - unsafe { super::board::handle_external_interrupt(); } - // true means handled, false otherwise let handlers = [try_process_serial, try_process_drivers]; for handler in handlers.iter() { @@ -87,7 +84,6 @@ fn external() { } fn try_process_serial() -> bool { - // TODO match super::io::getchar_option() { Some(ch) => { crate::trap::serial(ch); diff --git a/kernel/src/arch/mipsel/io.rs b/kernel/src/arch/mipsel/io.rs index e14c4ec..50c224d 100644 --- a/kernel/src/arch/mipsel/io.rs +++ b/kernel/src/arch/mipsel/io.rs @@ -59,8 +59,7 @@ pub fn putfmt(fmt: Arguments) { SerialPort.write_fmt(fmt).unwrap(); } -pub fn init(serial_base_addr: usize) { - COM1 = serial_base_addr; +pub fn init() { // Turn off the FIFO write(COM1 + COM_FCR, 0 as u8); // Set speed; requires DLAB latch @@ -77,7 +76,8 @@ pub fn init(serial_base_addr: usize) { write(COM1 + COM_IER, COM_IER_RDI); } -static mut COM1: usize = 0; +#[cfg(feature = "board_malta")] +const COM1 :usize = 0xbf000900; // 16550 Base Address const COM_RX :usize = 0; // In: Receive buffer (DLAB=0) const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0) From 8dff9f1b1444ac3df2e428d5fc7eb7e8c9a0387c Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Wed, 3 Apr 2019 12:07:58 +0800 Subject: [PATCH 16/23] Re-orgnize drivers for mipsel, extract FBConsole driver to common directory Signed-off-by: Harry Chen --- kernel/src/arch/aarch64/driver/mod.rs | 1 + kernel/src/arch/mipsel/board/malta/fb.rs | 7 ++ kernel/src/arch/mipsel/board/malta/mod.rs | 19 +++ kernel/src/arch/mipsel/board/malta/serial.rs | 114 ++++++++++++++++++ kernel/src/arch/mipsel/board/thinpad/mod.rs | 20 +++ kernel/src/arch/mipsel/driver/mod.rs | 16 +++ kernel/src/arch/mipsel/io.rs | 108 +++-------------- kernel/src/arch/mipsel/mod.rs | 15 ++- .../driver => drivers}/console/color.rs | 0 .../console/fonts/font8x16.rs | 0 .../driver => drivers}/console/fonts/mod.rs | 0 .../aarch64/driver => drivers}/console/mod.rs | 0 12 files changed, 209 insertions(+), 91 deletions(-) create mode 100644 kernel/src/arch/mipsel/board/malta/fb.rs create mode 100644 kernel/src/arch/mipsel/board/malta/mod.rs create mode 100644 kernel/src/arch/mipsel/board/malta/serial.rs create mode 100644 kernel/src/arch/mipsel/board/thinpad/mod.rs create mode 100644 kernel/src/arch/mipsel/driver/mod.rs rename kernel/src/{arch/aarch64/driver => drivers}/console/color.rs (100%) rename kernel/src/{arch/aarch64/driver => drivers}/console/fonts/font8x16.rs (100%) rename kernel/src/{arch/aarch64/driver => drivers}/console/fonts/mod.rs (100%) rename kernel/src/{arch/aarch64/driver => drivers}/console/mod.rs (100%) diff --git a/kernel/src/arch/aarch64/driver/mod.rs b/kernel/src/arch/aarch64/driver/mod.rs index 9c29662..a100c2b 100644 --- a/kernel/src/arch/aarch64/driver/mod.rs +++ b/kernel/src/arch/aarch64/driver/mod.rs @@ -5,6 +5,7 @@ use once::*; pub use self::board::fb; pub use self::board::serial; +#[path = "../../../drivers/console/mod.rs"] pub mod console; /// Initialize ARM64 common drivers diff --git a/kernel/src/arch/mipsel/board/malta/fb.rs b/kernel/src/arch/mipsel/board/malta/fb.rs new file mode 100644 index 0000000..89c4321 --- /dev/null +++ b/kernel/src/arch/mipsel/board/malta/fb.rs @@ -0,0 +1,7 @@ +lazy_static! { + pub static ref FRAME_BUFFER: Mutex> = Mutex::new(None); +} + +pub struct FramebufferInfo {} + +pub enum ColorDepth {} \ No newline at end of file diff --git a/kernel/src/arch/mipsel/board/malta/mod.rs b/kernel/src/arch/mipsel/board/malta/mod.rs new file mode 100644 index 0000000..ae61c69 --- /dev/null +++ b/kernel/src/arch/mipsel/board/malta/mod.rs @@ -0,0 +1,19 @@ +use once::*; + +pub mod serial; +pub mod fb; +#[path = "../../../../drivers/console/mod.rs"] +pub mod console; + +/// Initialize serial port first +pub fn init_serial_early() { + assert_has_not_been_called!("board::init must be called only once"); + serial::init(); + println!("Hello QEMU Malta!"); +} + +/// Initialize other board drivers +pub fn init_driver() { + // TODO: add possibly more drivers + // timer::init(); +} \ No newline at end of file diff --git a/kernel/src/arch/mipsel/board/malta/serial.rs b/kernel/src/arch/mipsel/board/malta/serial.rs new file mode 100644 index 0000000..4a20383 --- /dev/null +++ b/kernel/src/arch/mipsel/board/malta/serial.rs @@ -0,0 +1,114 @@ +use core::fmt::{Write, Result, Arguments}; +use core::ptr::{read_volatile, write_volatile}; + +struct SerialPort {}; + +impl SerialPort { + fn new() -> SerialPort { + SerialPort { } + } +} + +impl Write for SerialPort { + fn write_str(&mut self, s: &str) -> Result { + for c in s.bytes() { + if c == 127 { + putchar(8); + putchar(b' '); + putchar(8); + } else { + putchar(c); + } + } + Ok(()) + } +} + +fn write(addr: usize, content: T) { + let cell = (addr) as *mut T; + write_volatile(cell, content); +} + +fn read(addr: usize) -> T { + let cell = (addr) as *const T; + read_volatile(cell); +} + +/// non-blocking version of putchar() +fn putchar(c: u8) { + write(COM1 + COM_TX, c); +} + +/// blocking version of getchar() +pub fn getchar() -> char { + loop { + if (read::(COM1 + COM_LSR) & COM_LSR_DATA) == 0 { + break; + } + } + let c = read::(COM1 + COM_RX); + match c { + 255 => '\0', // null + c => c as char, + } +} + +/// non-blocking version of getchar() +pub fn getchar_option() -> Option { + match read::(COM1 + COM_LSR) & COM_LSR_DATA { + 0 => None, + else => Some(read::(COM1 + COM_RX) as u8 as char), + } +} + +pub fn putfmt(fmt: Arguments) { + SerialPort.write_fmt(fmt).unwrap(); +} + +pub fn init() { + // Turn off the FIFO + write(COM1 + COM_FCR, 0 as u8); + // Set speed; requires DLAB latch + write(COM1 + COM_LCR, COM_LCR_DLAB); + write(COM1 + COM_DLL, (115200 / 9600) as u8); + write(COM1 + COM_DLM, 0 as u8); + + // 8 data bits, 1 stop bit, parity off; turn off DLAB latch + write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); + + // No modem controls + write(COM1 + COM_MCR, 0 as u8); + // Enable rcv interrupts + write(COM1 + COM_IER, COM_IER_RDI); +} + +const COM1 :usize = 0xbf000900; // 16550 Base Address + +const COM_RX :usize = 0; // In: Receive buffer (DLAB=0) +const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0) +const COM_DLL :usize = 0; // Out: Divisor Latch Low (DLAB=1) +const COM_DLM :usize = 1; // Out: Divisor Latch High (DLAB=1) +const COM_IER :usize = 1; // Out: Interrupt Enable Register +const COM_IER_RDI :u8 = 0x01; // Enable receiver data interrupt +const COM_IIR :usize = 2; // In: Interrupt ID Register +const COM_FCR :usize = 2; // Out: FIFO Control Register +const COM_LCR :usize = 3; // Out: Line Control Register +const COM_LCR_DLAB :u8 = 0x80; // Divisor latch access bit +const COM_LCR_WLEN8 :u8 = 0x03; // Wordlength: 8 bits +const COM_MCR :usize = 4; // Out: Modem Control Register +const COM_MCR_RTS :u8 = 0x02; // RTS complement +const COM_MCR_DTR :u8 = 0x01; // DTR complement +const COM_MCR_OUT2 :u8 = 0x08; // Out2 complement +const COM_LSR :usize = 5; // In: Line Status Register +const COM_LSR_DATA :u8 = 0x01; // Data available +const COM_LSR_TXRDY :u8 = 0x20; // Transmit buffer avail +const COM_LSR_TSRE :u8 = 0x40; // Transmitter off + + +lazy_static! { + pub static ref SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); +} + +pub fn init() { + SERIAL_PORT.lock().init(); +} \ No newline at end of file diff --git a/kernel/src/arch/mipsel/board/thinpad/mod.rs b/kernel/src/arch/mipsel/board/thinpad/mod.rs new file mode 100644 index 0000000..1277ed7 --- /dev/null +++ b/kernel/src/arch/mipsel/board/thinpad/mod.rs @@ -0,0 +1,20 @@ +use once::*; + +pub mod serial; +pub mod fb; +#[path = "../../../../drivers/console/mod.rs"] +pub mod console; + +/// Initialize serial port first +pub fn init_serial_early() { + assert_has_not_been_called!("board::init must be called only once"); + serial::init(); + println!("Hello ThinPad!"); +} + +/// Initialize other board drivers +pub fn init_driver() { + // TODO: add possibly more drivers + // timer::init(); + console::init(); +} \ No newline at end of file diff --git a/kernel/src/arch/mipsel/driver/mod.rs b/kernel/src/arch/mipsel/driver/mod.rs new file mode 100644 index 0000000..67c4009 --- /dev/null +++ b/kernel/src/arch/mipsel/driver/mod.rs @@ -0,0 +1,16 @@ +//! mipsel drivers + +use super::board; +use once::*; + +pub use self::board::serial; +pub use self::board::fb; +#[path = "../../../drivers/console/mod.rs"] +pub mod console; + +/// Initialize common drivers +pub fn init() { + assert_has_not_been_called!("driver::init must be called only once"); + board::init_driver(); + console::init(); +} diff --git a/kernel/src/arch/mipsel/io.rs b/kernel/src/arch/mipsel/io.rs index 50c224d..b184a57 100644 --- a/kernel/src/arch/mipsel/io.rs +++ b/kernel/src/arch/mipsel/io.rs @@ -1,100 +1,30 @@ -use core::fmt::{Write, Result, Arguments}; -use core::ptr::{read_volatile, write_volatile}; +//! Input/output for mipsel. -struct SerialPort {}; +use super::driver::console::CONSOLE; +use super::driver::serial::*; +use core::fmt::{Arguments, Write}; -impl Write for SerialPort { - fn write_str(&mut self, s: &str) -> Result { - for c in s.bytes() { - if c == 127 { - putchar(8); - putchar(b' '); - putchar(8); - } else { - putchar(c); - } - } - Ok(()) - } -} - -fn write(addr: usize, content: T) { - let cell = (addr) as *mut T; - write_volatile(cell, content); -} - -fn read(addr: usize) -> T { - let cell = (addr) as *const T; - read_volatile(cell); -} - -/// non-blocking version of putchar() -fn putchar(c: u8) { - write(COM1 + COM_TX, c); -} - -/// blocking version of getchar() pub fn getchar() -> char { - loop { - if (read::(COM1 + COM_LSR) & COM_LSR_DATA) == 0 { - break; - } - } - let c = read::(COM1 + COM_RX); - match c { - 255 => '\0', // null - c => c as char, - } + unsafe { SERIAL_PORT.force_unlock() } + SERIAL_PORT.lock().getchar() } -/// non-blocking version of getchar() -pub fn getchar_option() -> Option { - match read::(COM1 + COM_LSR) & COM_LSR_DATA { - 0 => None, - else => Some(read::(COM1 + COM_RX) as u8 as char), - } +pub fn getchar_option() -> Option { + unsafe { SERIAL_PORT.force_unlock() } + SERIAL_PORT.lock().getchar_option() } pub fn putfmt(fmt: Arguments) { - SerialPort.write_fmt(fmt).unwrap(); -} - -pub fn init() { - // Turn off the FIFO - write(COM1 + COM_FCR, 0 as u8); - // Set speed; requires DLAB latch - write(COM1 + COM_LCR, COM_LCR_DLAB); - write(COM1 + COM_DLL, (115200 / 9600) as u8); - write(COM1 + COM_DLM, 0 as u8); + unsafe { SERIAL_PORT.force_unlock() } + SERIAL_PORT.lock().write_fmt(fmt).unwrap(); - // 8 data bits, 1 stop bit, parity off; turn off DLAB latch - write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); - - // No modem controls - write(COM1 + COM_MCR, 0 as u8); - // Enable rcv interrupts - write(COM1 + COM_IER, COM_IER_RDI); + unsafe { CONSOLE.force_unlock() } + if let Some(console) = CONSOLE.lock().as_mut() { + console.write_fmt(fmt).unwrap(); + } } -#[cfg(feature = "board_malta")] -const COM1 :usize = 0xbf000900; // 16550 Base Address - -const COM_RX :usize = 0; // In: Receive buffer (DLAB=0) -const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0) -const COM_DLL :usize = 0; // Out: Divisor Latch Low (DLAB=1) -const COM_DLM :usize = 1; // Out: Divisor Latch High (DLAB=1) -const COM_IER :usize = 1; // Out: Interrupt Enable Register -const COM_IER_RDI :u8 = 0x01; // Enable receiver data interrupt -const COM_IIR :usize = 2; // In: Interrupt ID Register -const COM_FCR :usize = 2; // Out: FIFO Control Register -const COM_LCR :usize = 3; // Out: Line Control Register -const COM_LCR_DLAB :u8 = 0x80; // Divisor latch access bit -const COM_LCR_WLEN8 :u8 = 0x03; // Wordlength: 8 bits -const COM_MCR :usize = 4; // Out: Modem Control Register -const COM_MCR_RTS :u8 = 0x02; // RTS complement -const COM_MCR_DTR :u8 = 0x01; // DTR complement -const COM_MCR_OUT2 :u8 = 0x08; // Out2 complement -const COM_LSR :usize = 5; // In: Line Status Register -const COM_LSR_DATA :u8 = 0x01; // Data available -const COM_LSR_TXRDY :u8 = 0x20; // Transmit buffer avail -const COM_LSR_TSRE :u8 = 0x40; // Transmitter off +pub fn putchar(c: u8) { + unsafe { SERIAL_PORT.force_unlock() } + SERIAL_PORT.lock().putchar(c); +} diff --git a/kernel/src/arch/mipsel/mod.rs b/kernel/src/arch/mipsel/mod.rs index 9681b06..ca51a72 100644 --- a/kernel/src/arch/mipsel/mod.rs +++ b/kernel/src/arch/mipsel/mod.rs @@ -8,11 +8,20 @@ pub mod consts; pub mod cpu; pub mod syscall; pub mod rand; +pub mod driver; use log::*; use mips::registers; use mips::instructions; +#[cfg(feature = "board_malta")] +#[path = "board/malta/mod.rs"] +pub mod board; + +#[cfg(feature = "board_thinpad")] +#[path = "board/thinpad/mod.rs"] +pub mod board; + extern "C" { fn _dtb_start(); fn _dtb_end(); @@ -38,14 +47,16 @@ pub extern fn rust_main() -> ! { unsafe { memory::clear_bss(); } - crate::io::init(); + board::init_serial_early(); + driver::init(); println!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start); - crate::logging::init(); interrupt::init(); memory::init(); timer::init(); + + crate::logging::init(); crate::drivers::init(dtb_start); crate::process::init(); diff --git a/kernel/src/arch/aarch64/driver/console/color.rs b/kernel/src/drivers/console/color.rs similarity index 100% rename from kernel/src/arch/aarch64/driver/console/color.rs rename to kernel/src/drivers/console/color.rs diff --git a/kernel/src/arch/aarch64/driver/console/fonts/font8x16.rs b/kernel/src/drivers/console/fonts/font8x16.rs similarity index 100% rename from kernel/src/arch/aarch64/driver/console/fonts/font8x16.rs rename to kernel/src/drivers/console/fonts/font8x16.rs diff --git a/kernel/src/arch/aarch64/driver/console/fonts/mod.rs b/kernel/src/drivers/console/fonts/mod.rs similarity index 100% rename from kernel/src/arch/aarch64/driver/console/fonts/mod.rs rename to kernel/src/drivers/console/fonts/mod.rs diff --git a/kernel/src/arch/aarch64/driver/console/mod.rs b/kernel/src/drivers/console/mod.rs similarity index 100% rename from kernel/src/arch/aarch64/driver/console/mod.rs rename to kernel/src/drivers/console/mod.rs From 015cc72aa42d223111436b579d14e8b823437205 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Wed, 3 Apr 2019 13:53:34 +0800 Subject: [PATCH 17/23] Fix malta drivers Signed-off-by: Harry Chen --- kernel/Cargo.toml | 6 +- kernel/Makefile | 4 +- kernel/src/arch/mipsel/board/malta/fb.rs | 2 + kernel/src/arch/mipsel/board/malta/mod.rs | 2 +- kernel/src/arch/mipsel/board/malta/serial.rs | 115 ++++++++++--------- 5 files changed, 70 insertions(+), 59 deletions(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 6f32b9d..936a813 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -13,7 +13,9 @@ authors = [ "chenqiuhao ", "maoyuchaxue ", "Jiajie Chen ", - "chyyuu " + "chyyuu ", + "Shengqi Chen ", + "Yuhao Zhou " ] [features] @@ -26,6 +28,8 @@ board_raspi3 = ["bcm2837", "link_user"] raspi3_use_generic_timer = ["bcm2837/use_generic_timer"] # for mipsel qemu malta machine board_malta = [] +# for thinpad +board_thinpad = [] # Hard link user program link_user = [] # Run cmdline instead of user shell, useful for automatic testing diff --git a/kernel/Makefile b/kernel/Makefile index 07b74ce..19d0c88 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -113,11 +113,13 @@ qemu_opts += \ -kernel $(kernel_img) else ifeq ($(arch), mipsel) +ifeq ($(board), malta) qemu_opts += \ -machine $(board) \ - -serial null -serial null -serial mon:stdio \ + -serial none -serial none -serial mon:stdio \ -kernel $(kernel_img) endif +endif ifdef d qemu_opts += -d $(d) diff --git a/kernel/src/arch/mipsel/board/malta/fb.rs b/kernel/src/arch/mipsel/board/malta/fb.rs index 89c4321..7023e5e 100644 --- a/kernel/src/arch/mipsel/board/malta/fb.rs +++ b/kernel/src/arch/mipsel/board/malta/fb.rs @@ -2,6 +2,8 @@ lazy_static! { pub static ref FRAME_BUFFER: Mutex> = Mutex::new(None); } +pub struct Framebuffer {} + pub struct FramebufferInfo {} pub enum ColorDepth {} \ No newline at end of file diff --git a/kernel/src/arch/mipsel/board/malta/mod.rs b/kernel/src/arch/mipsel/board/malta/mod.rs index ae61c69..0a3f750 100644 --- a/kernel/src/arch/mipsel/board/malta/mod.rs +++ b/kernel/src/arch/mipsel/board/malta/mod.rs @@ -8,7 +8,7 @@ pub mod console; /// Initialize serial port first pub fn init_serial_early() { assert_has_not_been_called!("board::init must be called only once"); - serial::init(); + serial::init(0xbf000900); println!("Hello QEMU Malta!"); } diff --git a/kernel/src/arch/mipsel/board/malta/serial.rs b/kernel/src/arch/mipsel/board/malta/serial.rs index 4a20383..2ee0a4e 100644 --- a/kernel/src/arch/mipsel/board/malta/serial.rs +++ b/kernel/src/arch/mipsel/board/malta/serial.rs @@ -1,23 +1,75 @@ use core::fmt::{Write, Result, Arguments}; use core::ptr::{read_volatile, write_volatile}; -struct SerialPort {}; +struct SerialPort { + base: usize +} impl SerialPort { fn new() -> SerialPort { SerialPort { } } + + pub fn init(&mut self, base: usize) { + self.base = base; + // Turn off the FIFO + write(self.base + COM_FCR, 0 as u8); + // Set speed; requires DLAB latch + write(self.base + COM_LCR, COM_LCR_DLAB); + write(self.base + COM_DLL, (115200 / 9600) as u8); + write(self.base + COM_DLM, 0 as u8); + + // 8 data bits, 1 stop bit, parity off; turn off DLAB latch + write(self.base + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); + + // No modem controls + write(self.base + COM_MCR, 0 as u8); + // Enable rcv interrupts + write(self.base + COM_IER, COM_IER_RDI); + } + + /// non-blocking version of putchar() + fn putchar(&mut self, c: u8) { + write(self.base + COM_TX, c); + } + + /// blocking version of getchar() + pub fn getchar(&mut self) -> char { + loop { + if (read::(self.base + COM_LSR) & COM_LSR_DATA) == 0 { + break; + } + } + let c = read::(self.base + COM_RX); + match c { + 255 => '\0', // null + c => c as char, + } + } + + /// non-blocking version of getchar() + pub fn getchar_option(&mut self) -> Option { + match read::(self.base + COM_LSR) & COM_LSR_DATA { + 0 => None, + _ => Some(read::(self.base + COM_RX) as u8 as char), + } + } + + pub fn putfmt(&mut self, fmt: Arguments) { + self.write_fmt(fmt).unwrap(); + } + } impl Write for SerialPort { fn write_str(&mut self, s: &str) -> Result { for c in s.bytes() { if c == 127 { - putchar(8); - putchar(b' '); - putchar(8); + self.putchar(8); + self.putchar(b' '); + self.putchar(8); } else { - putchar(c); + self.putchar(c); } } Ok(()) @@ -34,55 +86,6 @@ fn read(addr: usize) -> T { read_volatile(cell); } -/// non-blocking version of putchar() -fn putchar(c: u8) { - write(COM1 + COM_TX, c); -} - -/// blocking version of getchar() -pub fn getchar() -> char { - loop { - if (read::(COM1 + COM_LSR) & COM_LSR_DATA) == 0 { - break; - } - } - let c = read::(COM1 + COM_RX); - match c { - 255 => '\0', // null - c => c as char, - } -} - -/// non-blocking version of getchar() -pub fn getchar_option() -> Option { - match read::(COM1 + COM_LSR) & COM_LSR_DATA { - 0 => None, - else => Some(read::(COM1 + COM_RX) as u8 as char), - } -} - -pub fn putfmt(fmt: Arguments) { - SerialPort.write_fmt(fmt).unwrap(); -} - -pub fn init() { - // Turn off the FIFO - write(COM1 + COM_FCR, 0 as u8); - // Set speed; requires DLAB latch - write(COM1 + COM_LCR, COM_LCR_DLAB); - write(COM1 + COM_DLL, (115200 / 9600) as u8); - write(COM1 + COM_DLM, 0 as u8); - - // 8 data bits, 1 stop bit, parity off; turn off DLAB latch - write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); - - // No modem controls - write(COM1 + COM_MCR, 0 as u8); - // Enable rcv interrupts - write(COM1 + COM_IER, COM_IER_RDI); -} - -const COM1 :usize = 0xbf000900; // 16550 Base Address const COM_RX :usize = 0; // In: Receive buffer (DLAB=0) const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0) @@ -109,6 +112,6 @@ lazy_static! { pub static ref SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); } -pub fn init() { - SERIAL_PORT.lock().init(); +pub fn init(base: usize) { + SERIAL_PORT.lock().init(base); } \ No newline at end of file From 6245d86a276104bc569e874976f62ffcb91da932 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Wed, 3 Apr 2019 15:52:34 +0800 Subject: [PATCH 18/23] Move dts to board dir, fix some import error Signed-off-by: Harry Chen --- kernel/Makefile | 16 +++++++++------- .../dts/malta.dts => board/malta/device.dts} | 0 kernel/src/arch/mipsel/board/malta/fb.rs | 4 ++++ kernel/src/arch/mipsel/board/malta/serial.rs | 7 ++++++- kernel/src/arch/mipsel/interrupt.rs | 4 ++-- kernel/src/arch/mipsel/io.rs | 2 +- kernel/src/arch/mipsel/mod.rs | 2 +- 7 files changed, 23 insertions(+), 12 deletions(-) rename kernel/src/arch/mipsel/{boot/dts/malta.dts => board/malta/device.dts} (100%) diff --git a/kernel/Makefile b/kernel/Makefile index 19d0c88..2ab9b70 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -49,20 +49,22 @@ user_dir := ../user ### export environments ### -export ARCH = $(arch) -export BOARD = $(board) -export SMP = $(smp) -export DTB = $(dtb) export SFSIMG = $(user_dir)/build/$(arch).qcow2 ifeq ($(arch), aarch64) board := raspi3 export SFSIMG = $(user_dir)/build/$(arch).img -else ifeq ($(arch), mipsel) -board := malta endif -dtb := src/arch/$(arch)/boot/dts/$(board).dtb +# currently only mipsel architecture needs DTB linked to the kernel +ifeq ($(arch), mipsel) +dtb := src/arch/$(arch)/board/$(board)/device.dtb +endif + +export ARCH = $(arch) +export BOARD = $(board) +export SMP = $(smp) +export DTB = $(dtb) ### qemu options ### diff --git a/kernel/src/arch/mipsel/boot/dts/malta.dts b/kernel/src/arch/mipsel/board/malta/device.dts similarity index 100% rename from kernel/src/arch/mipsel/boot/dts/malta.dts rename to kernel/src/arch/mipsel/board/malta/device.dts diff --git a/kernel/src/arch/mipsel/board/malta/fb.rs b/kernel/src/arch/mipsel/board/malta/fb.rs index 7023e5e..f466bfa 100644 --- a/kernel/src/arch/mipsel/board/malta/fb.rs +++ b/kernel/src/arch/mipsel/board/malta/fb.rs @@ -1,3 +1,7 @@ +//! stub frame buffer driver for malta board + +use spin::Mutex; + lazy_static! { pub static ref FRAME_BUFFER: Mutex> = Mutex::new(None); } diff --git a/kernel/src/arch/mipsel/board/malta/serial.rs b/kernel/src/arch/mipsel/board/malta/serial.rs index 2ee0a4e..b9b7fe0 100644 --- a/kernel/src/arch/mipsel/board/malta/serial.rs +++ b/kernel/src/arch/mipsel/board/malta/serial.rs @@ -1,5 +1,8 @@ +//! 16550 serial adapter driver for malta board + use core::fmt::{Write, Result, Arguments}; use core::ptr::{read_volatile, write_volatile}; +use spin::Mutex; struct SerialPort { base: usize @@ -7,7 +10,9 @@ struct SerialPort { impl SerialPort { fn new() -> SerialPort { - SerialPort { } + SerialPort { + base: 0 + } } pub fn init(&mut self, base: usize) { diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index b6957bf..f78657a 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -1,5 +1,5 @@ -use mips::interrupts::*; -use mips::registers::*; +use mips::interrupts; +use mips::registers::cp0; use crate::drivers::DRIVERS; pub use self::context::*; use log::*; diff --git a/kernel/src/arch/mipsel/io.rs b/kernel/src/arch/mipsel/io.rs index b184a57..2012a62 100644 --- a/kernel/src/arch/mipsel/io.rs +++ b/kernel/src/arch/mipsel/io.rs @@ -9,7 +9,7 @@ pub fn getchar() -> char { SERIAL_PORT.lock().getchar() } -pub fn getchar_option() -> Option { +pub fn getchar_option() -> Option { unsafe { SERIAL_PORT.force_unlock() } SERIAL_PORT.lock().getchar_option() } diff --git a/kernel/src/arch/mipsel/mod.rs b/kernel/src/arch/mipsel/mod.rs index ca51a72..e8c3fe0 100644 --- a/kernel/src/arch/mipsel/mod.rs +++ b/kernel/src/arch/mipsel/mod.rs @@ -11,7 +11,7 @@ pub mod rand; pub mod driver; use log::*; -use mips::registers; +use mips::registers::cp0; use mips::instructions; #[cfg(feature = "board_malta")] From f394f0fccb4153901caf0c09ea8da541326e86a6 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Wed, 3 Apr 2019 16:50:45 +0800 Subject: [PATCH 19/23] Add DTS for thinpad Signed-off-by: Harry Chen --- .../src/arch/mipsel/board/thinpad/device.dts | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 kernel/src/arch/mipsel/board/thinpad/device.dts diff --git a/kernel/src/arch/mipsel/board/thinpad/device.dts b/kernel/src/arch/mipsel/board/thinpad/device.dts new file mode 100644 index 0000000..5a771c9 --- /dev/null +++ b/kernel/src/arch/mipsel/board/thinpad/device.dts @@ -0,0 +1,85 @@ +/dts-v1/; + + +/ { + model = "thinpad trivialmips"; + compatible = "tsinghua,thinpad"; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + stdio = &uart; + bootargs = ""; + }; + + aliases { }; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + interrupt-controller; + #interrupt-cells = <1>; + }; + + memory: memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x00800000>; + }; + + bus: trivial_bus@a0000000 { + compatible = "thinpad,bus"; + reg = <0xa0000000 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + flash: flash@a1000000 { + compatible = "cfi-flash"; + reg = <0xa1000000 0x00800000>; + }; + + framebuffer: framebuffer@a2000000 { + compatible = "thinpad,framebuffer"; + reg = <0xa2000000 0x75300 + 0xa2075300 0x4>; + }; + + uart: serial@a3000000 { + compatible = "thinpad,uart"; + reg = <0xa3000000 0x1 + 0xa3000004 0x1>; + clock-frequency = <115200>; + interrupt-parent = <&cpu_intc>; + interrupts = <1>; + }; + + timer: gpio@a4000000 { + compatible = "thinpad,timer"; + reg = <0xa400000 0x8>; + }; + + eth: ethernet@a5000000 { + compatible = "davicom,dm9000"; + reg = <0xa5000000 0x2 + 0xa5000004 0x2>; + interrupt-parent = <&cpu_intc>; + interrupts = <2>; + davicom,no-eeprom; + mac-address = [00 0a 2d 98 01 29]; + }; + + gpio: gpio@a6000000 { + compatible = "thinpad,gpio"; + reg = <0xa6000000 0x2 + 0xa6000004 0x2 + 0xa6000008 0x2>; + reg-io-width = <2>; + }; + + usb: usb@a7000000 { + compatible = "cypress,sl811"; + reg = <0xa7000000 0x1 + 0xa7000004 0x1>; + }; + }; + +}; From 0acb65ff747a35e34923d8dfcc01b456e173dce9 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Wed, 3 Apr 2019 16:58:52 +0800 Subject: [PATCH 20/23] Add driver for thinpad Signed-off-by: Harry Chen --- kernel/src/arch/mipsel/board/thinpad/fb.rs | 232 ++++++++++++++++++ kernel/src/arch/mipsel/board/thinpad/mod.rs | 3 +- .../src/arch/mipsel/board/thinpad/serial.rs | 94 +++++++ 3 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 kernel/src/arch/mipsel/board/thinpad/fb.rs create mode 100644 kernel/src/arch/mipsel/board/thinpad/serial.rs diff --git a/kernel/src/arch/mipsel/board/thinpad/fb.rs b/kernel/src/arch/mipsel/board/thinpad/fb.rs new file mode 100644 index 0000000..ff3b31f --- /dev/null +++ b/kernel/src/arch/mipsel/board/thinpad/fb.rs @@ -0,0 +1,232 @@ +//! Framebuffer + +use super::mailbox; +use alloc::string::String; +use core::fmt; +use lazy_static::lazy_static; +use log::*; +use once::*; +use spin::Mutex; + +/// Framebuffer information +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct FramebufferInfo { + /// visible width + pub xres: u32, + /// visible height + pub yres: u32, + /// virtual width + pub xres_virtual: u32, + /// virtual height + pub yres_virtual: u32, + /// virtual offset x + pub xoffset: u32, + /// virtual offset y + pub yoffset: u32, + + /// bits per pixel + pub depth: u32, + /// bytes per line + pub pitch: u32, + + /// bus address, starts from 0xC0000000/0x40000000 + /// (see https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes) + pub bus_addr: u32, + /// screen buffer size + pub screen_size: u32, +} + +#[repr(u32)] +#[derive(Debug, Clone, Copy)] +pub enum ColorDepth { + ColorDepth16 = 16, + ColorDepth32 = 32, +} +use self::ColorDepth::*; + +#[repr(C)] +union ColorBuffer { + base_addr: usize, + buf16: &'static mut [u16], + buf32: &'static mut [u32], +} + +impl ColorBuffer { + fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer { + unsafe { + match color_depth { + ColorDepth16 => ColorBuffer { + buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2), + }, + ColorDepth32 => ColorBuffer { + buf32: core::slice::from_raw_parts_mut(base_addr as *mut u32, size / 4), + }, + } + } + } + + #[inline] + fn read16(&self, index: u32) -> u16 { + unsafe { self.buf16[index as usize] } + } + + #[inline] + fn read32(&self, index: u32) -> u32 { + unsafe { self.buf32[index as usize] } + } + + #[inline] + fn write16(&mut self, index: u32, pixel: u16) { + unsafe { self.buf16[index as usize] = pixel } + } + + #[inline] + fn write32(&mut self, index: u32, pixel: u32) { + unsafe { self.buf32[index as usize] = pixel } + } +} + +/// Frambuffer structure +pub struct Framebuffer { + pub fb_info: FramebufferInfo, + pub color_depth: ColorDepth, + buf: ColorBuffer, +} + +impl fmt::Debug for Framebuffer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("Framebuffer"); + f.field("fb_info", &self.fb_info); + f.field("color_depth", &self.color_depth); + f.field("base_addr", unsafe { &self.buf.base_addr }); + f.finish() + } +} + +impl Framebuffer { + fn new(width: u32, height: u32, depth: u32) -> Result { + assert_has_not_been_called!("Framebuffer::new must be called only once"); + + let (width, height) = if width == 0 || height == 0 { + mailbox::framebuffer_get_physical_size()? + } else { + (width, height) + }; + let depth = if depth == 0 { + mailbox::framebuffer_get_depth()? + } else { + depth + }; + + let info = mailbox::framebuffer_alloc(width, height, depth)?; + let color_depth = match info.depth { + 16 => ColorDepth16, + 32 => ColorDepth32, + _ => Err(format!("unsupported color depth {}", info.depth))?, + }; + + if info.bus_addr == 0 || info.screen_size == 0 { + Err(format!("mailbox call returned an invalid address/size"))?; + } + if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 { + Err(format!( + "mailbox call returned an invalid pitch value {}", + info.pitch + ))?; + } + + use crate::arch::memory; + let paddr = info.bus_addr & !0xC0000000; + let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb"); + if vaddr == 0 { + Err(format!( + "cannot remap memory range [{:#x?}..{:#x?}]", + paddr, + paddr + info.screen_size + ))?; + } + Ok(Framebuffer { + buf: ColorBuffer::new(color_depth, vaddr, info.screen_size as usize), + color_depth, + fb_info: info, + }) + } + + #[inline] + pub fn base_addr(&self) -> usize { + unsafe { self.buf.base_addr } + } + + /// Read pixel at `(x, y)`. + #[inline] + pub fn read(&self, x: u32, y: u32) -> u32 { + match self.color_depth { + ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32, + ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x), + } + } + + /// Write pixel at `(x, y)`. + #[inline] + pub fn write(&mut self, x: u32, y: u32, pixel: u32) { + match self.color_depth { + ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16), + ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel), + } + } + + /// Copy buffer `[src_off .. src_off + size]` to `[dst_off .. dst_off + size]`. + /// `dst_off`, `src_off` and `size` must be aligned with `usize`. + pub fn copy(&mut self, dst_off: usize, src_off: usize, size: usize) { + const USIZE: usize = core::mem::size_of::(); + let mut dst = self.base_addr() + dst_off; + let mut src = self.base_addr() + src_off; + let src_end = src + size; + while src < src_end { + unsafe { *(dst as *mut usize) = *(src as *mut usize) } + dst += USIZE; + src += USIZE; + } + } + + /// Fill buffer `[offset .. offset + size]` with `pixel`. + /// `offset` and `size` must be aligned with `usize`. + pub fn fill(&mut self, offset: usize, size: usize, pixel: u32) { + const USIZE: usize = core::mem::size_of::(); + let mut value: usize = 0; + let repeat = USIZE * 8 / self.fb_info.depth as usize; + let mask = ((1u64 << self.fb_info.depth) - 1) as usize; + for _i in 0..repeat { + value <<= self.fb_info.depth; + value += pixel as usize & mask; + } + + let mut start = self.base_addr() + offset; + let end = start + size; + while start < end { + unsafe { *(start as *mut usize) = value } + start += USIZE; + } + } + + /// Fill the entire buffer with `0`. + pub fn clear(&mut self) { + self.fill(0, self.fb_info.screen_size as usize, 0); + } +} + +lazy_static! { + pub static ref FRAME_BUFFER: Mutex> = Mutex::new(None); +} + +/// Initialize framebuffer +pub fn init() { + match Framebuffer::new(0, 0, 0) { + Ok(fb) => { + info!("framebuffer: init end\n{:#x?}", fb); + *FRAME_BUFFER.lock() = Some(fb); + } + Err(err) => warn!("framebuffer init failed: {}", err), + } +} diff --git a/kernel/src/arch/mipsel/board/thinpad/mod.rs b/kernel/src/arch/mipsel/board/thinpad/mod.rs index 1277ed7..dbfbb84 100644 --- a/kernel/src/arch/mipsel/board/thinpad/mod.rs +++ b/kernel/src/arch/mipsel/board/thinpad/mod.rs @@ -8,7 +8,7 @@ pub mod console; /// Initialize serial port first pub fn init_serial_early() { assert_has_not_been_called!("board::init must be called only once"); - serial::init(); + serial::init(0xa3000000); println!("Hello ThinPad!"); } @@ -16,5 +16,4 @@ pub fn init_serial_early() { pub fn init_driver() { // TODO: add possibly more drivers // timer::init(); - console::init(); } \ No newline at end of file diff --git a/kernel/src/arch/mipsel/board/thinpad/serial.rs b/kernel/src/arch/mipsel/board/thinpad/serial.rs new file mode 100644 index 0000000..3c59a0d --- /dev/null +++ b/kernel/src/arch/mipsel/board/thinpad/serial.rs @@ -0,0 +1,94 @@ +//! naive serial adapter driver for thinpad + +use core::fmt::{Write, Result, Arguments}; +use core::ptr::{read_volatile, write_volatile}; +use spin::Mutex; + +struct SerialPort { + base: usize +} + +const UART_STATUS: usize = 0; +const UART_DATA: usize = 0; + +const UART_STATUS_CTS: u8 = 0x1; // clear to send signal +const UART_STATUS_DR: u8 = 0x2; // data ready signal + + +impl SerialPort { + fn new() -> SerialPort { + SerialPort { + base: 0 + } + } + + pub fn init(&mut self, base: usize) { + self.base = base; + } + + /// non-blocking version of putchar() + fn putchar(&mut self, c: u8) { + write(self.base + UART_DATA, c); + } + + /// blocking version of getchar() + pub fn getchar(&mut self) -> char { + loop { + if (read::(self.base + UART_STATUS) & UART_STATUS_DR) == 0 { + break; + } + } + let c = read::(self.base + UART_DATA); + match c { + 255 => '\0', // null + c => c as char, + } + } + + /// non-blocking version of getchar() + pub fn getchar_option(&mut self) -> Option { + match read::(self.base + UART_STATUS) & UART_STATUS_DR { + 0 => None, + _ => Some(read::(self.base + UART_DATA) as u8 as char), + } + } + + pub fn putfmt(&mut self, fmt: Arguments) { + self.write_fmt(fmt).unwrap(); + } + +} + +impl Write for SerialPort { + fn write_str(&mut self, s: &str) -> Result { + for c in s.bytes() { + if c == 127 { + self.putchar(8); + self.putchar(b' '); + self.putchar(8); + } else { + self.putchar(c); + } + } + Ok(()) + } +} + +fn write(addr: usize, content: T) { + let cell = (addr) as *mut T; + write_volatile(cell, content); +} + +fn read(addr: usize) -> T { + let cell = (addr) as *const T; + read_volatile(cell); +} + + +lazy_static! { + pub static ref SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); +} + +pub fn init(base: usize) { + SERIAL_PORT.lock().init(base); +} From 8bc00324c8aaa2d631f45f543f9bb8ad8ac03bcb Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Thu, 4 Apr 2019 00:10:18 +0800 Subject: [PATCH 21/23] Extract common framebuffer driver from aarch64 Signed-off-by: Harry Chen --- kernel/build.rs | 2 +- kernel/src/arch/aarch64/board/raspi3/mod.rs | 45 ++++ kernel/src/arch/mipsel/board/thinpad/fb.rs | 232 ------------------ kernel/src/arch/mipsel/board/thinpad/mod.rs | 17 ++ kernel/src/drivers/console/color.rs | 14 ++ kernel/src/drivers/console/mod.rs | 4 + .../board/raspi3 => drivers/gpu}/fb.rs | 78 +++--- 7 files changed, 117 insertions(+), 275 deletions(-) delete mode 100644 kernel/src/arch/mipsel/board/thinpad/fb.rs rename kernel/src/{arch/aarch64/board/raspi3 => drivers/gpu}/fb.rs (78%) diff --git a/kernel/build.rs b/kernel/build.rs index 3a0945f..3efcadb 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -53,7 +53,7 @@ fn gen_vector_asm() -> Result<()> { } -fn gen_dtb_asm(arch: &String, board: &String) -> Result<()> { +fn gen_dtb_asm(arch: &String, _board: &String) -> Result<()> { let dtb = std::env::var("DTB").unwrap(); if !Path::new(&dtb).is_file() { diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index 713c725..9b2a66b 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -2,13 +2,18 @@ use bcm2837::atags::Atags; use once::*; +use alloc::string::String; + +#[path = "../../../../drivers/gpu/fb.rs"] pub mod fb; pub mod irq; pub mod mailbox; pub mod serial; pub mod timer; +use fb::FramebufferInfo; + pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE; pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000; @@ -41,3 +46,43 @@ pub fn probe_memory() -> Option<(usize, usize)> { } None } + +pub fn probe_fb_info(width: u32, height: u32, depth: u32) -> Result<(FramebufferInfo, usize), String> { + + let (width, height) = if width == 0 || height == 0 { + mailbox::framebuffer_get_physical_size()? + } else { + (width, height) + }; + + let depth = if depth == 0 { + mailbox::framebuffer_get_depth()? + } else { + depth + }; + + let info = mailbox::framebuffer_alloc(width, height, depth)?; + + if info.bus_addr == 0 || info.screen_size == 0 { + Err(format!("mailbox call returned an invalid address/size"))?; + } + if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 { + Err(format!( + "mailbox call returned an invalid pitch value {}", + info.pitch + ))?; + } + + use crate::arch::memory; + let paddr = info.bus_addr & !0xC0000000; + let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb"); + if vaddr == 0 { + Err(format!( + "cannot remap memory range [{:#x?}..{:#x?}]", + paddr, + paddr + info.screen_size + ))?; + } + + Ok((info, vaddr)) +} \ No newline at end of file diff --git a/kernel/src/arch/mipsel/board/thinpad/fb.rs b/kernel/src/arch/mipsel/board/thinpad/fb.rs deleted file mode 100644 index ff3b31f..0000000 --- a/kernel/src/arch/mipsel/board/thinpad/fb.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! Framebuffer - -use super::mailbox; -use alloc::string::String; -use core::fmt; -use lazy_static::lazy_static; -use log::*; -use once::*; -use spin::Mutex; - -/// Framebuffer information -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct FramebufferInfo { - /// visible width - pub xres: u32, - /// visible height - pub yres: u32, - /// virtual width - pub xres_virtual: u32, - /// virtual height - pub yres_virtual: u32, - /// virtual offset x - pub xoffset: u32, - /// virtual offset y - pub yoffset: u32, - - /// bits per pixel - pub depth: u32, - /// bytes per line - pub pitch: u32, - - /// bus address, starts from 0xC0000000/0x40000000 - /// (see https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes) - pub bus_addr: u32, - /// screen buffer size - pub screen_size: u32, -} - -#[repr(u32)] -#[derive(Debug, Clone, Copy)] -pub enum ColorDepth { - ColorDepth16 = 16, - ColorDepth32 = 32, -} -use self::ColorDepth::*; - -#[repr(C)] -union ColorBuffer { - base_addr: usize, - buf16: &'static mut [u16], - buf32: &'static mut [u32], -} - -impl ColorBuffer { - fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer { - unsafe { - match color_depth { - ColorDepth16 => ColorBuffer { - buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2), - }, - ColorDepth32 => ColorBuffer { - buf32: core::slice::from_raw_parts_mut(base_addr as *mut u32, size / 4), - }, - } - } - } - - #[inline] - fn read16(&self, index: u32) -> u16 { - unsafe { self.buf16[index as usize] } - } - - #[inline] - fn read32(&self, index: u32) -> u32 { - unsafe { self.buf32[index as usize] } - } - - #[inline] - fn write16(&mut self, index: u32, pixel: u16) { - unsafe { self.buf16[index as usize] = pixel } - } - - #[inline] - fn write32(&mut self, index: u32, pixel: u32) { - unsafe { self.buf32[index as usize] = pixel } - } -} - -/// Frambuffer structure -pub struct Framebuffer { - pub fb_info: FramebufferInfo, - pub color_depth: ColorDepth, - buf: ColorBuffer, -} - -impl fmt::Debug for Framebuffer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = f.debug_struct("Framebuffer"); - f.field("fb_info", &self.fb_info); - f.field("color_depth", &self.color_depth); - f.field("base_addr", unsafe { &self.buf.base_addr }); - f.finish() - } -} - -impl Framebuffer { - fn new(width: u32, height: u32, depth: u32) -> Result { - assert_has_not_been_called!("Framebuffer::new must be called only once"); - - let (width, height) = if width == 0 || height == 0 { - mailbox::framebuffer_get_physical_size()? - } else { - (width, height) - }; - let depth = if depth == 0 { - mailbox::framebuffer_get_depth()? - } else { - depth - }; - - let info = mailbox::framebuffer_alloc(width, height, depth)?; - let color_depth = match info.depth { - 16 => ColorDepth16, - 32 => ColorDepth32, - _ => Err(format!("unsupported color depth {}", info.depth))?, - }; - - if info.bus_addr == 0 || info.screen_size == 0 { - Err(format!("mailbox call returned an invalid address/size"))?; - } - if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 { - Err(format!( - "mailbox call returned an invalid pitch value {}", - info.pitch - ))?; - } - - use crate::arch::memory; - let paddr = info.bus_addr & !0xC0000000; - let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb"); - if vaddr == 0 { - Err(format!( - "cannot remap memory range [{:#x?}..{:#x?}]", - paddr, - paddr + info.screen_size - ))?; - } - Ok(Framebuffer { - buf: ColorBuffer::new(color_depth, vaddr, info.screen_size as usize), - color_depth, - fb_info: info, - }) - } - - #[inline] - pub fn base_addr(&self) -> usize { - unsafe { self.buf.base_addr } - } - - /// Read pixel at `(x, y)`. - #[inline] - pub fn read(&self, x: u32, y: u32) -> u32 { - match self.color_depth { - ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32, - ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x), - } - } - - /// Write pixel at `(x, y)`. - #[inline] - pub fn write(&mut self, x: u32, y: u32, pixel: u32) { - match self.color_depth { - ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16), - ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel), - } - } - - /// Copy buffer `[src_off .. src_off + size]` to `[dst_off .. dst_off + size]`. - /// `dst_off`, `src_off` and `size` must be aligned with `usize`. - pub fn copy(&mut self, dst_off: usize, src_off: usize, size: usize) { - const USIZE: usize = core::mem::size_of::(); - let mut dst = self.base_addr() + dst_off; - let mut src = self.base_addr() + src_off; - let src_end = src + size; - while src < src_end { - unsafe { *(dst as *mut usize) = *(src as *mut usize) } - dst += USIZE; - src += USIZE; - } - } - - /// Fill buffer `[offset .. offset + size]` with `pixel`. - /// `offset` and `size` must be aligned with `usize`. - pub fn fill(&mut self, offset: usize, size: usize, pixel: u32) { - const USIZE: usize = core::mem::size_of::(); - let mut value: usize = 0; - let repeat = USIZE * 8 / self.fb_info.depth as usize; - let mask = ((1u64 << self.fb_info.depth) - 1) as usize; - for _i in 0..repeat { - value <<= self.fb_info.depth; - value += pixel as usize & mask; - } - - let mut start = self.base_addr() + offset; - let end = start + size; - while start < end { - unsafe { *(start as *mut usize) = value } - start += USIZE; - } - } - - /// Fill the entire buffer with `0`. - pub fn clear(&mut self) { - self.fill(0, self.fb_info.screen_size as usize, 0); - } -} - -lazy_static! { - pub static ref FRAME_BUFFER: Mutex> = Mutex::new(None); -} - -/// Initialize framebuffer -pub fn init() { - match Framebuffer::new(0, 0, 0) { - Ok(fb) => { - info!("framebuffer: init end\n{:#x?}", fb); - *FRAME_BUFFER.lock() = Some(fb); - } - Err(err) => warn!("framebuffer init failed: {}", err), - } -} diff --git a/kernel/src/arch/mipsel/board/thinpad/mod.rs b/kernel/src/arch/mipsel/board/thinpad/mod.rs index dbfbb84..6c480f4 100644 --- a/kernel/src/arch/mipsel/board/thinpad/mod.rs +++ b/kernel/src/arch/mipsel/board/thinpad/mod.rs @@ -1,6 +1,7 @@ use once::*; pub mod serial; +#[path = "../../../../drivers/gpu/fb.rs"] pub mod fb; #[path = "../../../../drivers/console/mod.rs"] pub mod console; @@ -16,4 +17,20 @@ pub fn init_serial_early() { pub fn init_driver() { // TODO: add possibly more drivers // timer::init(); +} + +pub fn probe_fb_info(width: u32, height: u32, depth: u32) -> Result<(FramebufferInfo, u32), String> { + let fb_info = FramebufferInfo { + xres: 800, + yres: 600, + xres_virtual: 800, + yres_virtual: 600, + xoffset: 0, + yoffset: 0, + depth: 8, + pitch: 800, + bus_addr: 0xa2000000, + screen_size: 800 * 600, + } + Ok((fb_info, 0xa2000000)) } \ No newline at end of file diff --git a/kernel/src/drivers/console/color.rs b/kernel/src/drivers/console/color.rs index 419df50..1936fb8 100644 --- a/kernel/src/drivers/console/color.rs +++ b/kernel/src/drivers/console/color.rs @@ -3,6 +3,9 @@ use crate::util::color::ConsoleColor; pub trait FramebufferColor { + /// pack as 8-bit integer + fn pack8(&self) -> u8; + /// pack as 16-bit integer fn pack16(&self) -> u16; @@ -42,6 +45,12 @@ impl From for RgbColor { } impl FramebufferColor for RgbColor { + #[inline] + fn pack8(&self) -> u8 { + // RGB332 + ((self.0 >> 5) << 5) | ((self.1 >> 5) << 2) | (self.2 >> 6) + } + #[inline] fn pack16(&self) -> u16 { // BGR565 @@ -58,6 +67,11 @@ impl FramebufferColor for RgbColor { } impl FramebufferColor for ConsoleColor { + #[inline] + fn pack8(&self) -> u8 { + RgbColor::from(*self).pack8() + } + #[inline] fn pack16(&self) -> u16 { RgbColor::from(*self).pack16() diff --git a/kernel/src/drivers/console/mod.rs b/kernel/src/drivers/console/mod.rs index b16ae13..29d56be 100644 --- a/kernel/src/drivers/console/mod.rs +++ b/kernel/src/drivers/console/mod.rs @@ -63,6 +63,10 @@ impl ConsoleBuffer { let off_y = row * F::HEIGHT; if let Some(fb) = FRAME_BUFFER.lock().as_mut() { let (mut foreground, mut background) = match fb.color_depth { + ColorDepth8 => ( + ch.attr.foreground.pack8() as u32, + ch.attr.background.pack8() as u32, + ), ColorDepth16 => ( ch.attr.foreground.pack16() as u32, ch.attr.background.pack16() as u32, diff --git a/kernel/src/arch/aarch64/board/raspi3/fb.rs b/kernel/src/drivers/gpu/fb.rs similarity index 78% rename from kernel/src/arch/aarch64/board/raspi3/fb.rs rename to kernel/src/drivers/gpu/fb.rs index ff3b31f..d5f7021 100644 --- a/kernel/src/arch/aarch64/board/raspi3/fb.rs +++ b/kernel/src/drivers/gpu/fb.rs @@ -1,6 +1,5 @@ //! Framebuffer -use super::mailbox; use alloc::string::String; use core::fmt; use lazy_static::lazy_static; @@ -40,6 +39,7 @@ pub struct FramebufferInfo { #[repr(u32)] #[derive(Debug, Clone, Copy)] pub enum ColorDepth { + ColorDepth8 = 8, ColorDepth16 = 16, ColorDepth32 = 32, } @@ -48,6 +48,7 @@ use self::ColorDepth::*; #[repr(C)] union ColorBuffer { base_addr: usize, + buf8: &'static mut [u8], buf16: &'static mut [u16], buf32: &'static mut [u32], } @@ -56,6 +57,9 @@ impl ColorBuffer { fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer { unsafe { match color_depth { + ColorDepth8 => ColorBuffer { + buf8: core::slice::from_raw_parts_mut(base_addr as *mut u8, size), + }, ColorDepth16 => ColorBuffer { buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2), }, @@ -66,6 +70,11 @@ impl ColorBuffer { } } + #[inline] + fn read8(&self, index: u32) -> u8 { + unsafe { self.buf8[index as usize] } + } + #[inline] fn read16(&self, index: u32) -> u16 { unsafe { self.buf16[index as usize] } @@ -76,6 +85,11 @@ impl ColorBuffer { unsafe { self.buf32[index as usize] } } + #[inline] + fn write8(&mut self, index: u32, pixel: u8) { + unsafe { self.buf8[index as usize] = pixel } + } + #[inline] fn write16(&mut self, index: u32, pixel: u16) { unsafe { self.buf16[index as usize] = pixel } @@ -108,49 +122,27 @@ impl Framebuffer { fn new(width: u32, height: u32, depth: u32) -> Result { assert_has_not_been_called!("Framebuffer::new must be called only once"); - let (width, height) = if width == 0 || height == 0 { - mailbox::framebuffer_get_physical_size()? - } else { - (width, height) - }; - let depth = if depth == 0 { - mailbox::framebuffer_get_depth()? - } else { - depth - }; - - let info = mailbox::framebuffer_alloc(width, height, depth)?; - let color_depth = match info.depth { - 16 => ColorDepth16, - 32 => ColorDepth32, - _ => Err(format!("unsupported color depth {}", info.depth))?, - }; - - if info.bus_addr == 0 || info.screen_size == 0 { - Err(format!("mailbox call returned an invalid address/size"))?; - } - if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 { - Err(format!( - "mailbox call returned an invalid pitch value {}", - info.pitch - ))?; + let probed_info = super::probe_fb_info(width, height, depth); + + match probed_info { + Ok((info, addr)) => { + let color_depth = match info.depth { + 8 => ColorDepth8, + 16 => ColorDepth16, + 32 => ColorDepth32, + _ => Err(format!("unsupported color depth {}", info.depth))?, + }; + Ok(Framebuffer { + buf: ColorBuffer::new(color_depth, addr, info.screen_size as usize), + color_depth, + fb_info: info, + }) + }, + Err(e) => { + Err(e)? + }, } - use crate::arch::memory; - let paddr = info.bus_addr & !0xC0000000; - let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb"); - if vaddr == 0 { - Err(format!( - "cannot remap memory range [{:#x?}..{:#x?}]", - paddr, - paddr + info.screen_size - ))?; - } - Ok(Framebuffer { - buf: ColorBuffer::new(color_depth, vaddr, info.screen_size as usize), - color_depth, - fb_info: info, - }) } #[inline] @@ -162,6 +154,7 @@ impl Framebuffer { #[inline] pub fn read(&self, x: u32, y: u32) -> u32 { match self.color_depth { + ColorDepth8 => self.buf.read8(y * self.fb_info.xres + x) as u32, ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32, ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x), } @@ -171,6 +164,7 @@ impl Framebuffer { #[inline] pub fn write(&mut self, x: u32, y: u32, pixel: u32) { match self.color_depth { + ColorDepth8 => self.buf.write8(y * self.fb_info.xres + x, pixel as u8), ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16), ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel), } From c99b7a1aed4e77e0c9eb53fc7d238b93bb8c4a42 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 00:16:27 +0800 Subject: [PATCH 22/23] 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 From 78b7c7b893b78f933d3c8fd784f4c715695bdd52 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Thu, 4 Apr 2019 21:55:59 +0800 Subject: [PATCH 23/23] Fix syscall handling for mipsel, update user programs repo Signed-off-by: Harry Chen --- kernel/src/arch/mipsel/interrupt.rs | 5 ++--- user | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index f78657a..909c7c1 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -115,10 +115,9 @@ fn timer() { } fn syscall(tf: &mut TrapFrame) { - // TODO tf.sepc += 4; // Must before syscall, because of fork. - let ret = crate::syscall::syscall(tf.x[17], [tf.x[10], tf.x[11], tf.x[12], tf.x[13], tf.x[14], tf.x[15]], tf); - tf.x[10] = ret as usize; + let ret = crate::syscall::syscall(tf.t0, [tf.x0, tf.x1, tf.x2, tf.x3, tf.s0, tf.s1], tf); + tf.v0 = ret as usize; } fn page_fault(tf: &mut TrapFrame) { diff --git a/user b/user index b1e7a2d..97bae0c 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit b1e7a2d07e81ce5035a1cc25b0ade9367aee1a94 +Subproject commit 97bae0c39a7aeaab07654d99c3ba3bcb4d01658c