diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index fbfd318..942a0a9 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -125,12 +125,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "deque" version = "0.3.2" -source = "git+https://github.com/rcore-os/deque.git?branch=no_std#907d03935b9badde1902d9c84d138872f34c6763" +source = "git+https://github.com/rcore-os/deque.git?branch=no_std#b13a836dd69ae82cc0b8d711c2990b9baf5170d1" [[package]] name = "device_tree" version = "1.0.3" -source = "git+https://github.com/rcore-os/device_tree-rs#0e887395ab92e99f68117b17d85b0b417bfd1b45" +source = "git+https://github.com/rcore-os/device_tree-rs#7945459093f49a39996291283b8894753c8a638d" [[package]] name = "fixedvec" @@ -252,6 +252,14 @@ name = "pc-keyboard" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pci" +version = "0.0.1" +source = "git+https://github.com/rcore-os/pci-rs#30f2e83aa51dd313957f3fd6c3b233d3c905a4d0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pulldown-cmark" version = "0.0.3" @@ -317,6 +325,7 @@ dependencies = [ "mips 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", "rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", @@ -618,6 +627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce" +"checksum pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)" = "" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 6f32b9d..4e7758c 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 @@ -46,6 +50,7 @@ volatile = "0.2" heapless = "0.4" console-traits = "0.3" buddy_system_allocator = "0.1" +pci = { git = "https://github.com/rcore-os/pci-rs" } device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" } lazy_static = { version = "1.3", features = ["spin_no_std"] } diff --git a/kernel/Makefile b/kernel/Makefile index 07b74ce..07d5259 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -27,6 +27,7 @@ # | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ # pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device # init = /bin/ls Only available on riscv64, run specified program instead of user shell +# extra_nic = on | off Only available on x86_64, add an additional e1000 nic arch ?= riscv64 board ?= none @@ -36,6 +37,7 @@ graphic ?= off smp ?= 4 pci_passthru ?= init ?= +extra_nic ?= off target := $(arch) build_path := target/$(target)/$(mode) @@ -49,20 +51,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 ### @@ -74,7 +78,9 @@ qemu_net_opts := \ ifeq ($(arch), x86_64) qemu_opts += \ -drive format=raw,file=$(bootimage) \ - -drive format=qcow2,file=$(SFSIMG),media=disk,cache=writeback \ + -drive format=qcow2,file=$(SFSIMG),media=disk,cache=writeback,id=sfsimg,if=none \ + -device ahci,id=ahci0 \ + -device ide-drive,drive=sfsimg,bus=ahci0.0 \ -serial mon:stdio \ -m 4G \ -device isa-debug-exit @@ -83,10 +89,15 @@ qemu_net_opts += \ -device e1000e,netdev=net0 else qemu_opts += \ - -machine ubuntu,accel=kvm + -machine accel=kvm qemu_net_opts += \ -device vfio-pci,host=$(pci_passthru) endif +ifeq ($(extra_nic), on) +qemu_net_opts += \ + -netdev type=tap,id=net1,script=no,downscript=no \ + -device e1000e,netdev=net1 +endif else ifeq ($(arch), riscv32) qemu_opts += \ @@ -113,11 +124,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/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/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/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 new file mode 100644 index 0000000..f466bfa --- /dev/null +++ b/kernel/src/arch/mipsel/board/malta/fb.rs @@ -0,0 +1,13 @@ +//! stub frame buffer driver for malta board + +use spin::Mutex; + +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 new file mode 100644 index 0000000..0a3f750 --- /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(0xbf000900); + 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..b9b7fe0 --- /dev/null +++ b/kernel/src/arch/mipsel/board/malta/serial.rs @@ -0,0 +1,122 @@ +//! 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 +} + +impl SerialPort { + fn new() -> SerialPort { + SerialPort { + base: 0 + } + } + + 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 { + 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); +} + + +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(base: usize) { + SERIAL_PORT.lock().init(base); +} \ No newline at end of file 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>; + }; + }; + +}; 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..6c480f4 --- /dev/null +++ b/kernel/src/arch/mipsel/board/thinpad/mod.rs @@ -0,0 +1,36 @@ +use once::*; + +pub mod serial; +#[path = "../../../../drivers/gpu/fb.rs"] +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(0xa3000000); + println!("Hello ThinPad!"); +} + +/// Initialize other board drivers +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/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); +} 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/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index 2d356b0..909c7c1 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); @@ -119,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/kernel/src/arch/mipsel/io.rs b/kernel/src/arch/mipsel/io.rs index ca99ad3..2012a62 100644 --- a/kernel/src/arch/mipsel/io.rs +++ b/kernel/src/arch/mipsel/io.rs @@ -1,48 +1,30 @@ -use core::fmt::{Write, Result, Arguments}; +//! Input/output for mipsel. -struct 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 putchar(c: u8) { - // TODO: output to uart -} +use super::driver::console::CONSOLE; +use super::driver::serial::*; +use core::fmt::{Arguments, Write}; pub fn getchar() -> char { - // TODO: get char from uart - let c = 0 as u8; - - match c { - 255 => '\0', // null - c => c as char, - } + unsafe { SERIAL_PORT.force_unlock() } + SERIAL_PORT.lock().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), - } + unsafe { SERIAL_PORT.force_unlock() } + SERIAL_PORT.lock().getchar_option() } pub fn putfmt(fmt: Arguments) { - SerialPort.write_fmt(fmt).unwrap(); + unsafe { SERIAL_PORT.force_unlock() } + SERIAL_PORT.lock().write_fmt(fmt).unwrap(); + + unsafe { CONSOLE.force_unlock() } + if let Some(console) = CONSOLE.lock().as_mut() { + console.write_fmt(fmt).unwrap(); + } } -const TXDATA: *mut u32 = 0x38000000 as *mut u32; -const RXDATA: *mut u32 = 0x38000004 as *mut u32; +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 f2f5dd2..e8c3fe0 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::cp0; 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,12 +47,16 @@ pub extern fn rust_main() -> ! { unsafe { memory::clear_bss(); } + 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/x86_64/memory.rs b/kernel/src/arch/x86_64/memory.rs index b2570a9..325b0b8 100644 --- a/kernel/src/arch/x86_64/memory.rs +++ b/kernel/src/arch/x86_64/memory.rs @@ -2,13 +2,13 @@ use crate::consts::KERNEL_OFFSET; use bit_allocator::BitAlloc; // Depends on kernel use super::{BootInfo, MemoryRegionType}; -use crate::memory::{active_table, init_heap, FRAME_ALLOCATOR, alloc_frame}; +use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR}; use crate::HEAP_ALLOCATOR; -use rcore_memory::PAGE_SIZE; use alloc::vec::Vec; use log::*; use once::*; use rcore_memory::paging::*; +use rcore_memory::PAGE_SIZE; pub fn init(boot_info: &BootInfo) { assert_has_not_been_called!("memory::init must be called only once"); @@ -60,14 +60,12 @@ fn enlarge_heap() { addrs.push((va, PAGE_SIZE)); } for (addr, len) in addrs.into_iter() { - for va in (addr..(addr+len)).step_by(PAGE_SIZE) { + for va in (addr..(addr + len)).step_by(PAGE_SIZE) { page_table.map(va, va - va_offset).update(); } info!("Adding {:#X} {:#X} to heap", addr, len); unsafe { - HEAP_ALLOCATOR - .lock() - .init(addr, len); + HEAP_ALLOCATOR.lock().init(addr, len); } } } diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs new file mode 100644 index 0000000..842259c --- /dev/null +++ b/kernel/src/drivers/block/ahci.rs @@ -0,0 +1,497 @@ +//! Driver for AHCI +//! +//! Spec: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1-3-1.pdf + +use alloc::alloc::{alloc_zeroed, Layout}; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::mem::size_of; +use core::slice; +use core::sync::atomic::spin_loop_hint; + +use bit_field::*; +use bitflags::*; +use log::*; +use rcore_fs::dev::BlockDevice; +use volatile::Volatile; + +use rcore_memory::paging::PageTable; +use rcore_memory::{PhysAddr, VirtAddr, PAGE_SIZE}; + +use crate::drivers::BlockDriver; +use crate::memory::active_table; +use crate::sync::SpinNoIrqLock as Mutex; + +use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; + +pub struct AHCI { + header: usize, + size: usize, + received_fis: &'static mut AHCIReceivedFIS, + cmd_list: &'static mut [AHCICommandHeader], + cmd_table: &'static mut AHCICommandTable, + data: &'static mut [u8], + port: &'static mut AHCIPort, +} + +pub struct AHCIDriver(Mutex); + +/// AHCI Generic Host Control (3.1) +#[repr(C)] +pub struct AHCIGHC { + /// Host capability + capability: Volatile, + /// Global host control + global_host_control: Volatile, + /// Interrupt status + interrupt_status: Volatile, + /// Port implemented + port_implemented: Volatile, + /// Version + version: Volatile, + /// Command completion coalescing control + ccc_control: Volatile, + /// Command completion coalescing ports + ccc_ports: Volatile, + /// Enclosure management location + em_location: Volatile, + /// Enclosure management control + em_control: Volatile, + /// Host capabilities extended + capabilities2: Volatile, + /// BIOS/OS handoff control and status + bios_os_handoff_control: Volatile, +} + +bitflags! { + struct AHCICap : u32 { + const S64A = 1 << 31; + const SNCQ = 1 << 30; + const SSNTF = 1 << 29; + const SMPS = 1 << 28; + const SSS = 1 << 27; + const SALP = 1 << 26; + const SAL = 1 << 25; + const SCLO = 1 << 24; + const ISS_GEN_1 = 1 << 20; + const ISS_GEN_2 = 2 << 20; + const ISS_GEN_3 = 3 << 20; + const SAM = 1 << 18; + const SPM = 1 << 17; + const FBSS = 1 << 16; + const PMD = 1 << 15; + const SSC = 1 << 14; + const PSC = 1 << 13; + const CCCS = 1 << 7; + const EMS = 1 << 6; + const SXS = 1 << 5; + // number of ports - 1 + const NUM_MASK = 0b11111; + } +} + +impl AHCIGHC { + fn enable(&mut self) { + self.global_host_control.update(|v| { + v.set_bit(13, true); + }); + } + fn num_ports(&self) -> usize { + (self.capability.read() & AHCICap::NUM_MASK).bits() as usize + 1 + } + fn has_port(&self, port_num: usize) -> bool { + self.port_implemented.read().get_bit(port_num) + } +} + +/// AHCI Port Registers (3.3) (one set per port) +#[repr(C)] +pub struct AHCIPort { + command_list_base_address: Volatile, + fis_base_address: Volatile, + interrupt_status: Volatile, + interrupt_enable: Volatile, + command: Volatile, + reserved: Volatile, + task_file_data: Volatile, + signature: Volatile, + sata_status: Volatile, + sata_control: Volatile, + sata_error: Volatile, + sata_active: Volatile, + command_issue: Volatile, + sata_notification: Volatile, + fis_based_switch_control: Volatile, +} + +impl AHCIPort { + fn spin_on_slot(&mut self, slot: usize) { + loop { + let ci = self.command_issue.read(); + if !ci.get_bit(slot) { + break; + } + spin_loop_hint(); + } + } + fn issue_command(&mut self, slot: usize) { + assert!(slot < 32); + self.command_issue.write(1 << (slot as u32)); + } +} + +/// AHCI Received FIS Structure (4.2.1) +#[repr(C)] +pub struct AHCIReceivedFIS { + dma: [u8; 0x20], + pio: [u8; 0x20], + d2h: [u8; 0x18], + sdbfis: [u8; 0x8], + ufis: [u8; 0x40], + reserved: [u8; 0x60], +} + +/// # AHCI Command List Structure (4.2.2) +/// +/// Host sends commands to the device through Command List. +/// +/// Command List consists of 1 to 32 command headers, each one is called a slot. +/// +/// Each command header describes an ATA or ATAPI command, including a +/// Command FIS, an ATAPI command buffer and a bunch of Physical Region +/// Descriptor Tables specifying the data payload address and size. +/// +/// https://wiki.osdev.org/images/e/e8/Command_list.jpg +#[repr(C)] +pub struct AHCICommandHeader { + /// + flags: CommandHeaderFlags, + /// Physical region descriptor table length in entries + prdt_length: u16, + /// Physical region descriptor byte count transferred + prd_byte_count: u32, + /// Command table descriptor base address + command_table_base_address: u64, + /// Reserved + reserved: [u32; 4], +} + +bitflags! { + pub struct CommandHeaderFlags: u16 { + /// Command FIS length in DWORDS, 2 ~ 16 + const CFL_MASK = 0b11111; + /// ATAPI + const ATAPI = 1 << 5; + /// Write, 1: H2D, 0: D2H + const WRITE = 1 << 6; + /// Prefetchable + const PREFETCHABLE = 1 << 7; + /// Reset + const RESET = 1 << 8; + /// BIST + const BIST = 1 << 9; + /// Clear busy upon R_OK + const CLEAR = 1 << 10; + /// Port multiplier port + const PORT_MULTIPLIER_PORT_MASK = 0b1111 << 12; + } +} + +/// AHCI Command Table (4.2.3) +#[repr(C)] +pub struct AHCICommandTable { + /// Command FIS + cfis: SATAFISRegH2D, + /// ATAPI command, 12 or 16 bytes + acmd: [u8; 16], + /// Reserved + reserved: [u8; 48], + /// Physical region descriptor table entries, 0 ~ 65535 + prdt: [AHCIPrdtEntry; 1], +} + +/// Physical region descriptor table entry +#[repr(C)] +pub struct AHCIPrdtEntry { + /// Data base address + data_base_address: u64, + /// Reserved + reserved: u32, + /// Bit 21-0: Byte count, 4M max + /// Bit 31: Interrupt on completion + dbc_i: u32, +} + +const FIS_REG_H2D: u8 = 0x27; + +const CMD_READ_DMA_EXT: u8 = 0x25; +const CMD_WRITE_DMA_EXT: u8 = 0x35; +const CMD_IDENTIFY_DEVICE: u8 = 0xec; + +/// SATA Register FIS - Host to Device +/// +/// https://wiki.osdev.org/AHCI Figure 5-2 +#[repr(C)] +pub struct SATAFISRegH2D { + fis_type: u8, + cflags: u8, + command: u8, + feature_lo: u8, + + lba_0: u8, // LBA 7:0 + lba_1: u8, // LBA 15:8 + lba_2: u8, // LBA 23:16 + dev_head: u8, + + lba_3: u8, // LBA 31:24 + lba_4: u8, // LBA 39:32 + lba_5: u8, // LBA 47:40 + feature_hi: u8, + + sector_count: u16, + reserved: u8, + control: u8, + + _padding: [u8; 48], +} + +impl SATAFISRegH2D { + fn set_lba(&mut self, lba: u64) { + self.lba_0 = (lba >> 0) as u8; + self.lba_1 = (lba >> 8) as u8; + self.lba_2 = (lba >> 16) as u8; + self.lba_3 = (lba >> 24) as u8; + self.lba_4 = (lba >> 32) as u8; + self.lba_5 = (lba >> 40) as u8; + } +} + +/// IDENTIFY DEVICE data +/// +/// ATA8-ACS Table 29 +#[repr(C)] +pub struct ATAIdentifyPacket { + _1: [u16; 10], + serial: [u8; 20], // words 10-19 + _2: [u16; 3], + firmware: [u8; 8], // words 23-26 + model: [u8; 40], // words 27-46 + _3: [u16; 13], + lba_sectors: u32, // words 60-61 + _4: [u16; 38], + lba48_sectors: u64, // words 100-103 +} + +impl AHCI { + fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> usize { + self.cmd_list[0].flags = CommandHeaderFlags::empty(); + + let fis = &mut self.cmd_table.cfis; + // Register FIS from HBA to device + fis.fis_type = FIS_REG_H2D; + fis.cflags = 1 << 7; + // 7.25 READ DMA EXT - 25h, DMA + fis.command = CMD_READ_DMA_EXT; + fis.sector_count = 1; + fis.dev_head = 0x40; // LBA + fis.control = 0x80; // LBA48 + fis.set_lba(block_id as u64); + + self.port.issue_command(0); + self.port.spin_on_slot(0); + + let len = buf.len().min(BLOCK_SIZE); + buf[..len].clone_from_slice(&self.data[0..len]); + len + } + + fn write_block(&mut self, block_id: usize, buf: &[u8]) -> usize { + self.cmd_list[0].flags = CommandHeaderFlags::WRITE; // device write + + let len = buf.len().min(BLOCK_SIZE); + self.data[0..len].clone_from_slice(&buf[..len]); + + let fis = &mut self.cmd_table.cfis; + // Register FIS from HBA to device + fis.fis_type = FIS_REG_H2D; + fis.cflags = 1 << 7; + // ATA8-ACS + // 7.63 WRITE DMA EXT - 35h, DMA + fis.command = CMD_WRITE_DMA_EXT; + fis.sector_count = 1; + fis.dev_head = 0x40; // LBA + fis.control = 0x80; // LBA48 + fis.set_lba(block_id as u64); + + self.port.issue_command(0); + self.port.spin_on_slot(0); + + len + } +} + +impl Driver for AHCIDriver { + fn try_handle_interrupt(&self, _irq: Option) -> bool { + false + } + + fn device_type(&self) -> DeviceType { + DeviceType::Block + } + + fn get_id(&self) -> String { + format!("ahci") + } + + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { + let mut driver = self.0.lock(); + driver.read_block(block_id, buf); + true + } + + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { + if buf.len() < BLOCK_SIZE { + return false; + } + let mut driver = self.0.lock(); + driver.write_block(block_id, buf); + true + } +} + +const BLOCK_SIZE: usize = 512; + +fn from_ata_string(data: &[u8]) -> String { + let mut swapped_data = Vec::new(); + assert_eq!(data.len() % 2, 0); + for i in (0..data.len()).step_by(2) { + swapped_data.push(data[i + 1]); + swapped_data.push(data[i]); + } + return String::from_utf8(swapped_data).unwrap(); +} + +/// Allocate consequent physical frames for DMA +fn alloc_dma(page_num: usize) -> (VirtAddr, PhysAddr) { + let layout = Layout::from_size_align(PAGE_SIZE * page_num, PAGE_SIZE).unwrap(); + let vaddr = unsafe { alloc_zeroed(layout) } as usize; + let paddr = active_table().get_entry(vaddr).unwrap().target(); + (vaddr, paddr) +} + +pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc { + let ghc = unsafe { &mut *(header as *mut AHCIGHC) }; + + ghc.enable(); + + for port_num in 0..ghc.num_ports() { + if ghc.has_port(port_num) { + let addr = header + 0x100 + 0x80 * port_num; + let port = unsafe { &mut *(addr as *mut AHCIPort) }; + + // SSTS IPM Active + if port.sata_status.read().get_bits(8..12) != 1 { + continue; + } + + // SSTS DET Present + if port.sata_status.read().get_bits(0..4) != 3 { + continue; + } + + debug!("probing port {}", port_num); + // Disable Port First + port.command.update(|c| { + c.set_bit(4, false); + c.set_bit(0, false); + }); + + let (rfis_va, rfis_pa) = alloc_dma(1); + let (cmd_list_va, cmd_list_pa) = alloc_dma(1); + let (cmd_table_va, cmd_table_pa) = alloc_dma(1); + let (data_va, data_pa) = alloc_dma(1); + + let received_fis = unsafe { &mut *(rfis_va as *mut AHCIReceivedFIS) }; + let cmd_list = unsafe { + slice::from_raw_parts_mut( + cmd_list_va as *mut AHCICommandHeader, + PAGE_SIZE / size_of::(), + ) + }; + let cmd_table = unsafe { &mut *(cmd_table_va as *mut AHCICommandTable) }; + let identify_data = unsafe { &*(data_va as *mut ATAIdentifyPacket) }; + + cmd_table.prdt[0].data_base_address = data_pa as u64; + cmd_table.prdt[0].dbc_i = (BLOCK_SIZE - 1) as u32; + + cmd_list[0].command_table_base_address = cmd_table_pa as u64; + cmd_list[0].prdt_length = 1; + cmd_list[0].prd_byte_count = 0; + + port.command_list_base_address.write(cmd_list_pa as u64); + port.fis_base_address.write(rfis_pa as u64); + + // clear status and errors + port.command_issue.write(0); + port.sata_active.write(0); + port.sata_error.write(0); + + // enable port + port.command.update(|c| { + *c |= 1 << 0 | 1 << 1 | 1 << 2 | 1 << 4 | 1 << 28; + }); + + let stat = port.sata_status.read(); + if stat == 0 { + warn!("port is not connected to external drive?"); + } + + let fis = &mut cmd_table.cfis; + // Register FIS from HBA to device + fis.fis_type = FIS_REG_H2D; + fis.cflags = 1 << 7; + + // 7.15 IDENTIFY DEVICE - ECh, PIO Data-In + fis.command = CMD_IDENTIFY_DEVICE; + fis.sector_count = 1; + + port.issue_command(0); + port.spin_on_slot(0); + + unsafe { + debug!( + "Found ATA Device serial {} firmware {} model {} sectors 24bit={} 48bit={}", + from_ata_string(&identify_data.serial).trim_end(), + from_ata_string(&identify_data.firmware).trim_end(), + from_ata_string(&identify_data.model).trim_end(), + identify_data.lba_sectors, + identify_data.lba48_sectors, + ); + } + + let data = unsafe { slice::from_raw_parts_mut(data_va as *mut u8, BLOCK_SIZE) }; + + let driver = AHCIDriver(Mutex::new(AHCI { + header, + size, + received_fis, + cmd_list, + cmd_table, + data, + port, + })); + + let driver = Arc::new(driver); + DRIVERS.write().push(driver.clone()); + BLK_DRIVERS + .write() + .push(Arc::new(BlockDriver(driver.clone()))); + + return driver; + } + } + + unimplemented!(); +} diff --git a/kernel/src/drivers/block/mod.rs b/kernel/src/drivers/block/mod.rs index bbcee0a..fb9a39e 100644 --- a/kernel/src/drivers/block/mod.rs +++ b/kernel/src/drivers/block/mod.rs @@ -1 +1,2 @@ +pub mod ahci; pub mod virtio_blk; diff --git a/kernel/src/drivers/block/virtio_blk.rs b/kernel/src/drivers/block/virtio_blk.rs index 5fff2d7..b6cc9cb 100644 --- a/kernel/src/drivers/block/virtio_blk.rs +++ b/kernel/src/drivers/block/virtio_blk.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; use core::cmp::min; @@ -14,6 +15,7 @@ use volatile::Volatile; use rcore_fs::dev::BlockDevice; +use crate::drivers::BlockDriver; use crate::memory::active_table; use crate::sync::SpinNoIrqLock as Mutex; @@ -125,11 +127,8 @@ impl Driver for VirtIOBlkDriver { fn get_id(&self) -> String { format!("virtio_block") } -} -impl BlockDevice for VirtIOBlkDriver { - const BLOCK_SIZE_LOG2: u8 = 9; // 512 - fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool { + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { let mut driver = self.0.lock(); // ensure header page is mapped active_table().map_if_not_exists(driver.header as usize, driver.header as usize); @@ -157,7 +156,7 @@ impl BlockDevice for VirtIOBlkDriver { } } - fn write_at(&self, block_id: usize, buf: &[u8]) -> bool { + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { let mut driver = self.0.lock(); // ensure header page is mapped active_table().map_if_not_exists(driver.header as usize, driver.header as usize); @@ -226,5 +225,5 @@ pub fn virtio_blk_init(node: &Node) { let driver = Arc::new(driver); DRIVERS.write().push(driver.clone()); - BLK_DRIVERS.write().push(driver); + BLK_DRIVERS.write().push(Arc::new(BlockDriver(driver))); } diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index e46c7d0..6a143c8 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -1,309 +1,159 @@ +use crate::consts::KERNEL_OFFSET; +use crate::drivers::block::*; use crate::drivers::net::*; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; +use crate::memory::active_table; use alloc::collections::BTreeMap; use alloc::string::String; use alloc::sync::Arc; use core::cmp::Ordering; +use pci::*; +use rcore_memory::{paging::PageTable, PAGE_SIZE}; use spin::Mutex; use x86_64::instructions::port::Port; -const PCI_VENDOR: u32 = 0x00; -const PCI_DEVICE: u32 = 0x02; -const PCI_COMMAND: u32 = 0x04; -const PCI_STATUS: u32 = 0x06; -const PCI_SUBCLASS: u32 = 0x0a; -const PCI_CLASS: u32 = 0x0b; -const PCI_HEADER: u32 = 0x0e; -const PCI_BAR0: u32 = 0x10; // first -const PCI_BAR5: u32 = 0x24; // last -const PCI_CAP_PTR: u32 = 0x34; -const PCI_INTERRUPT_LINE: u32 = 0x3c; -const PCI_INTERRUPT_PIN: u32 = 0x3d; +const PCI_COMMAND: u16 = 0x04; +const PCI_CAP_PTR: u16 = 0x34; +const PCI_INTERRUPT_LINE: u16 = 0x3c; +const PCI_INTERRUPT_PIN: u16 = 0x3d; -const PCI_MSI_CTRL_CAP: u32 = 0x00; -const PCI_MSI_ADDR: u32 = 0x04; -const PCI_MSI_UPPER_ADDR: u32 = 0x08; -const PCI_MSI_DATA: u32 = 0x0C; +const PCI_MSI_CTRL_CAP: u16 = 0x00; +const PCI_MSI_ADDR: u16 = 0x04; +const PCI_MSI_UPPER_ADDR: u16 = 0x08; +const PCI_MSI_DATA: u16 = 0x0C; -const PCI_CAP_ID_MSI: u32 = 0x05; +const PCI_CAP_ID_MSI: u8 = 0x05; -const PCI_ADDR_PORT: u16 = 0xcf8; -const PCI_DATA_PORT: u16 = 0xcfc; +struct PortOpsImpl; -const PCI_BASE_ADDRESS_SPACE: u32 = 0x01; -const PCI_BASE_ADDRESS_SPACE_IO: u32 = 0x01; -const PCI_BASE_ADDRESS_SPACE_MEMORY: u32 = 0x00; - -const PCI_BASE_ADDRESS_MEM_TYPE_MASK: u32 = 0x06; -const PCI_BASE_ADDRESS_MEM_TYPE_32: u32 = 0x00; -const PCI_BASE_ADDRESS_MEM_TYPE_1M: u32 = 0x02; -const PCI_BASE_ADDRESS_MEM_TYPE_64: u32 = 0x04; -const PCI_BASE_ADDRESS_MEM_PREFETCH: u32 = 0x08; -const PCI_BASE_ADDRESS_MEM_MASK: u32 = 0xfffffff0; - -#[derive(Copy, Clone)] -pub struct PciTag(u32); - -impl Ord for PciTag { - fn cmp(&self, other: &PciTag) -> Ordering { - self.0.cmp(&other.0) +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + Port::new(port).read() } -} - -impl PartialOrd for PciTag { - fn partial_cmp(&self, other: &PciTag) -> Option { - Some(self.cmp(other)) + unsafe fn read16(&self, port: u16) -> u16 { + Port::new(port).read() } -} - -impl Eq for PciTag {} - -impl PartialEq for PciTag { - fn eq(&self, other: &PciTag) -> bool { - self.0 == other.0 + unsafe fn read32(&self, port: u16) -> u32 { + Port::new(port).read() } -} - -impl PciTag { - pub fn new(bus: u32, dev: u32, func: u32) -> PciTag { - assert!(bus < 256); - assert!(dev < 32); - assert!(func < 8); - PciTag(bus << 16 | dev << 11 | func << 8) + unsafe fn write8(&self, port: u16, val: u8) { + Port::new(port).write(val); } - - pub fn bus(&self) -> u32 { - (self.0 >> 16) & 0xFF + unsafe fn write16(&self, port: u16, val: u16) { + Port::new(port).write(val); } - - pub fn dev(&self) -> u32 { - (self.0 >> 11) & 0x1F + unsafe fn write32(&self, port: u16, val: u32) { + Port::new(port).write(val); } +} - pub fn func(&self) -> u32 { - (self.0 >> 8) & 0x7 - } - - // biscuit/src/pci/pci.go Pci_read - pub unsafe fn read(&self, reg: u32, width: u32) -> u32 { - // spans in one reg - assert_eq!(reg / 4, (reg + width - 1) / 4); - - let enable = 1 << 31; - let rsh = reg % 4; - let r = reg - rsh; - let t = enable | self.0 | r; - - let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); - let mut pci_data: Port = Port::new(PCI_DATA_PORT); - - pci_addr.write(t); - let d = pci_data.read(); - pci_addr.write(0); - - let ret = d >> (rsh * 8); - let m = if width < 4 { - (1 << (8 * width)) - 1 - } else { - 0xffffffff - }; - - return ret & m; - } - - pub unsafe fn write(&self, reg: u32, val: u32) { - assert_eq!(reg & 3, 0); - - let enable = 1 << 31; - let t = enable | self.0 | reg; - - let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); - let mut pci_data: Port = Port::new(PCI_DATA_PORT); - - pci_addr.write(t); - pci_data.write(val); - pci_addr.write(0); - } - - // biscuit/src/pci/pci.go Pci_bar_mem - // linux/drivers/pci/probe.c pci_read_bases - // return (addr, len) - pub unsafe fn get_bar_mem(&self, bar_number: u32) -> Option<(usize, usize)> { - assert!(bar_number <= 4); - let bar = PCI_BAR0 + 4 * bar_number; - let mut base_lo = self.read(bar, 4); - self.write(bar, 0xffffffff); - let mut max_base_lo = self.read(bar, 4); - self.write(bar, base_lo); - - let mut base; - let mut max_base; - let mut address_mark; - - // memory instead of io - assert!(base_lo & PCI_BASE_ADDRESS_SPACE == PCI_BASE_ADDRESS_SPACE_MEMORY); - match base_lo & PCI_BASE_ADDRESS_MEM_TYPE_MASK { - PCI_BASE_ADDRESS_MEM_TYPE_32 => { - base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - address_mark = PCI_BASE_ADDRESS_MEM_MASK as usize; - } - PCI_BASE_ADDRESS_MEM_TYPE_64 => { - base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - - let base_hi = self.read(bar + 4, 4); - self.write(bar + 4, 0xffffffff); - let max_base_hi = self.read(bar + 4, 4); - self.write(bar + 4, base_hi); - base |= (base_hi as usize) << 32; - max_base |= (max_base_hi as usize) << 32; - address_mark = !0; - } - _ => unimplemented!("pci bar mem type"), - } - - if max_base == 0 { - return None; - } - - // linux/drivers/pci/probe.c pci_size - let mut size = max_base & address_mark; - if size == 0 { - return None; - } - size = (size & !(size - 1)) - 1; - - debug!( - "device memory address from {:#X} to {:#X}", - base, - base + size - ); - return Some((base as usize, size as usize)); - } - - // returns a tuple of (vid, did, next) - pub fn probe(&self) -> Option<(u32, u32, bool)> { - unsafe { - // To lookup vendor and device, please see https://pci-ids.ucw.cz/read/PC/ - let v = self.read(PCI_VENDOR, 2); - if v == 0xffff { - return None; - } - let d = self.read(PCI_DEVICE, 2); - let mf = self.read(PCI_HEADER, 1); - - // To lookup class and subclass, please see https://pci-ids.ucw.cz/read/PD/ - let cl = self.read(PCI_CLASS, 1); - let scl = self.read(PCI_SUBCLASS, 1); - let line = self.read(PCI_INTERRUPT_LINE, 1); - let pin = self.read(PCI_INTERRUPT_PIN, 1); - info!( - "{:02x}:{:02x}.{}: {:#x} {:#x} ({} {}) irq {}:{}", - self.bus(), - self.dev(), - self.func(), - v, - d, - cl, - scl, - line, - pin - ); - - return Some((v, d, mf & 0x80 != 0)); - } - } - - /// Enable the pci tag and its interrupt - /// Return assigned MSI interrupt number when applicable - pub unsafe fn enable(&self) -> Option { - // 23 and lower are used - static mut MSI_IRQ: u32 = 23; - - let orig = self.read(PCI_COMMAND, 2); - // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable - self.write(PCI_COMMAND, orig | 0x40f); - - // find MSI cap - let mut msi_found = false; - let mut cap_ptr = self.read(PCI_CAP_PTR, 1); - let mut assigned_irq = None; - while cap_ptr > 0 { - let cap_id = self.read(cap_ptr, 1); - if cap_id == PCI_CAP_ID_MSI { - // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts - // 0 is (usually) the apic id of the bsp. - self.write(cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); - MSI_IRQ += 1; - let irq = MSI_IRQ; - assigned_irq = Some(irq); - // we offset all our irq numbers by 32 - self.write(cap_ptr + PCI_MSI_DATA, irq + 32); - - // enable MSI interrupt, assuming 64bit for now - let orig_ctrl = self.read(cap_ptr + PCI_MSI_CTRL_CAP, 4); - self.write(cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); - debug!( - "MSI control {:#b}, enabling MSI interrupts", - orig_ctrl >> 16 - ); - msi_found = true; - break; - } - debug!( - "PCI device has cap id {} at {:#X}", - self.read(cap_ptr, 1), - cap_ptr - ); - cap_ptr = self.read(cap_ptr + 1, 1); - } - - if !msi_found { - // Use PCI legacy interrupt instead - // IO Space | MEM Space | Bus Mastering | Special Cycles - self.write(PCI_COMMAND, orig | 0xf); - let line = self.read(PCI_INTERRUPT_LINE, 1); - let pin = self.read(PCI_INTERRUPT_PIN, 1); +/// Enable the pci device and its interrupt +/// Return assigned MSI interrupt number when applicable +unsafe fn enable(loc: Location) -> Option { + let ops = &PortOpsImpl; + let am = CSpaceAccessMethod::IO; + + // 23 and lower are used + static mut MSI_IRQ: u32 = 23; + + let orig = am.read16(ops, loc, PCI_COMMAND); + // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable + am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32); + + // find MSI cap + let mut msi_found = false; + let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16; + let mut assigned_irq = None; + while cap_ptr > 0 { + let cap_id = am.read8(ops, loc, cap_ptr); + if cap_id == PCI_CAP_ID_MSI { + // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts + // 0 is (usually) the apic id of the bsp. + am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); + MSI_IRQ += 1; + let irq = MSI_IRQ; + assigned_irq = Some(irq); + // we offset all our irq numbers by 32 + am.write32(ops, loc, cap_ptr + PCI_MSI_DATA, irq + 32); + + // enable MSI interrupt, assuming 64bit for now + let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); + am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); debug!( - "MSI not found, using PCI interrupt line {} pin {}", - line, pin + "MSI control {:#b}, enabling MSI interrupts", + orig_ctrl >> 16 ); + msi_found = true; + break; } + debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr); + cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16; + } - assigned_irq + if !msi_found { + // Use PCI legacy interrupt instead + // IO Space | MEM Space | Bus Mastering | Special Cycles + am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32); + debug!("MSI not found, using PCI interrupt"); } + + assigned_irq } -pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) { - if vid == 0x8086 { - if did == 0x100e || did == 0x100f || did == 0x10d3 { +pub fn init_driver(dev: &PCIDevice) { + let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); + match (dev.id.vendor_id, dev.id.device_id) { + (0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => { // 0x100e // 82540EM Gigabit Ethernet Controller // 0x100f // 82545EM Gigabit Ethernet Controller (Copper) // 0x10d3 // 82574L Gigabit Network Connection - if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { - unsafe { - tag.enable(); + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let irq = unsafe { enable(dev.loc) }; + let vaddr = KERNEL_OFFSET + addr as usize; + let mut current_addr = addr as usize; + while current_addr < addr as usize + len as usize { + active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; } - e1000::e1000_init(addr, len); + e1000::e1000_init(name, irq, vaddr, len as usize); } - } else if did == 0x10fb { + } + (0x8086, 0x10fb) => { // 82599ES 10-Gigabit SFI/SFP+ Network Connection - if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { - let irq = unsafe { tag.enable() }; + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let irq = unsafe { enable(dev.loc) }; + let vaddr = KERNEL_OFFSET + addr as usize; + let mut current_addr = addr as usize; + while current_addr < addr as usize + len as usize { + active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + PCI_DRIVERS + .lock() + .insert(dev.loc, ixgbe::ixgbe_init(name, irq, vaddr, len as usize)); + } + } + (0x8086, 0x2922) => { + // 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] { + let irq = unsafe { enable(dev.loc) }; + assert!(len as usize <= PAGE_SIZE); + let vaddr = KERNEL_OFFSET + addr as usize; + active_table().map(vaddr, addr as usize); PCI_DRIVERS .lock() - .insert(tag, ixgbe::ixgbe_init(name, irq, addr, len)); + .insert(dev.loc, ahci::ahci_init(irq, vaddr, len as usize)); } } + _ => {} } } -pub fn detach_driver(tag: &PciTag) -> bool { - match PCI_DRIVERS.lock().remove(tag) { +pub fn detach_driver(loc: &Location) -> bool { + match PCI_DRIVERS.lock().remove(loc) { Some(driver) => { DRIVERS .write() @@ -318,51 +168,44 @@ pub fn detach_driver(tag: &PciTag) -> bool { } pub fn init() { - for bus in 0..256 { - for dev in 0..32 { - let tag = PciTag::new(bus, dev, 0); - if let Some((vid, did, next)) = tag.probe() { - let name = format!("enp{}s{}f0", bus, dev); - init_driver(name, vid, did, tag); - if next { - for func in 1..8 { - let tag = PciTag::new(bus, dev, func); - if let Some((vid, did, _)) = tag.probe() { - let name = format!("enp{}s{}f{}", bus, dev, func); - init_driver(name, vid, did, tag); - } - } - } - } - } + let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + info!( + "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}", + dev.loc.bus, + dev.loc.device, + dev.loc.function, + dev.id.vendor_id, + dev.id.device_id, + dev.id.class, + dev.id.subclass, + dev.pic_interrupt_line, + dev.interrupt_pin, + ); + init_driver(&dev); } } -pub fn find_device(vendor: u32, product: u32) -> Option { - for bus in 0..256 { - for dev in 0..32 { - let tag = PciTag::new(bus, dev, 0); - if let Some((vid, did, next)) = tag.probe() { - if vid == vendor && did == product { - return Some(tag); - } - if next { - for func in 1..8 { - let tag = PciTag::new(bus, dev, func); - if let Some((vid, did, _)) = tag.probe() { - if vid == vendor && did == product { - return Some(tag); - } - } - } - } - } +pub fn find_device(vendor: u16, product: u16) -> Option { + let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + if dev.id.vendor_id == vendor && dev.id.device_id == product { + return Some(dev.loc); } } None } +pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> { + unsafe { probe_function(&PortOpsImpl, loc, CSpaceAccessMethod::IO) } + .and_then(|dev| dev.bars[0]) + .map(|bar| match bar { + BAR::Memory(addr, len, _, _) => (addr as usize, len as usize), + _ => unimplemented!(), + }) +} + lazy_static! { - pub static ref PCI_DRIVERS: Arc>>> = - Arc::new(Mutex::new(BTreeMap::new())); + pub static ref PCI_DRIVERS: Mutex>> = + Mutex::new(BTreeMap::new()); } diff --git a/kernel/src/arch/aarch64/driver/console/color.rs b/kernel/src/drivers/console/color.rs similarity index 87% rename from kernel/src/arch/aarch64/driver/console/color.rs rename to kernel/src/drivers/console/color.rs index 419df50..1936fb8 100644 --- a/kernel/src/arch/aarch64/driver/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/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 97% rename from kernel/src/arch/aarch64/driver/console/mod.rs rename to kernel/src/drivers/console/mod.rs index b16ae13..29d56be 100644 --- a/kernel/src/arch/aarch64/driver/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), } diff --git a/kernel/src/drivers/input/virtio_input.rs b/kernel/src/drivers/input/virtio_input.rs index 4f2d6a7..9ff1587 100644 --- a/kernel/src/drivers/input/virtio_input.rs +++ b/kernel/src/drivers/input/virtio_input.rs @@ -1,6 +1,8 @@ -use alloc::prelude::*; +use alloc::boxed::Box; +use alloc::string::String; use alloc::sync::Arc; use alloc::vec; +use alloc::vec::Vec; use core::fmt; use core::mem::size_of; use core::mem::transmute_copy; diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index b030cdc..0356a48 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -1,12 +1,13 @@ -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use lazy_static::lazy_static; use smoltcp::wire::{EthernetAddress, Ipv4Address}; use spin::RwLock; -use self::block::virtio_blk::VirtIOBlkDriver; use crate::sync::Condvar; +use rcore_fs::dev::BlockDevice; #[allow(dead_code)] pub mod block; @@ -64,13 +65,35 @@ pub trait Driver: Send + Sync { fn poll(&self) { unimplemented!("not a net driver") } + + // block related drivers should implement these + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { + unimplemented!("not a block driver") + } + + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { + unimplemented!("not a block driver") + } } lazy_static! { // NOTE: RwLock only write when initializing drivers pub static ref DRIVERS: RwLock>> = RwLock::new(Vec::new()); pub static ref NET_DRIVERS: RwLock>> = RwLock::new(Vec::new()); - pub static ref BLK_DRIVERS: RwLock>> = RwLock::new(Vec::new()); + pub static ref BLK_DRIVERS: RwLock>> = RwLock::new(Vec::new()); +} + +pub struct BlockDriver(Arc); + +impl BlockDevice for BlockDriver { + const BLOCK_SIZE_LOG2: u8 = 9; // 512 + fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool { + self.0.read_block(block_id, buf) + } + + fn write_at(&self, block_id: usize, buf: &[u8]) -> bool { + self.0.write_block(block_id, buf) + } } lazy_static! { diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 743070b..fb32d8f 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -3,8 +3,9 @@ use alloc::alloc::{GlobalAlloc, Layout}; use alloc::format; -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use core::mem::size_of; use core::slice; use core::sync::atomic::{fence, Ordering}; @@ -72,20 +73,19 @@ const E1000_RAH: usize = 0x5404 / 4; pub struct E1000Interface { iface: Mutex>, driver: E1000Driver, + name: String, + irq: Option, } impl Driver for E1000Interface { - fn try_handle_interrupt(&self, _irq: Option) -> bool { - let irq = { - let driver = self.driver.0.lock(); + fn try_handle_interrupt(&self, irq: Option) -> bool { + if irq.is_some() && self.irq.is_some() && irq != self.irq { + // not ours, skip it + return false; + } - if let None = active_table().get_entry(driver.header) { - let mut current_addr = driver.header; - while current_addr < driver.header + driver.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } + let data = { + let driver = self.driver.0.lock(); let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) @@ -101,7 +101,7 @@ impl Driver for E1000Interface { } }; - if irq { + if data { let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64); let mut sockets = SOCKETS.lock(); match self.iface.lock().poll(&mut sockets, timestamp) { @@ -114,7 +114,7 @@ impl Driver for E1000Interface { } } - return irq; + return data; } fn device_type(&self) -> DeviceType { @@ -130,7 +130,7 @@ impl Driver for E1000Interface { } fn get_ifname(&self) -> String { - format!("e1000") + self.name.clone() } fn ipv4_address(&self) -> Option { @@ -184,14 +184,6 @@ impl<'a> phy::Device<'a> for E1000Driver { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { let driver = self.0.lock(); - if let None = active_table().get_entry(driver.header) { - let mut current_addr = driver.header; - while current_addr < driver.header + driver.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) }; @@ -237,14 +229,6 @@ impl<'a> phy::Device<'a> for E1000Driver { fn transmit(&'a mut self) -> Option { let driver = self.0.lock(); - if let None = active_table().get_entry(driver.header) { - let mut current_addr = driver.header; - while current_addr < driver.header + driver.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) }; @@ -353,8 +337,8 @@ bitflags! { } // JudgeDuck-OS/kern/e1000.c -pub fn e1000_init(header: usize, size: usize) { - info!("Probing e1000"); +pub fn e1000_init(name: String, irq: Option, header: usize, size: usize) { + info!("Probing e1000 {}", name); assert_eq!(size_of::(), 16); assert_eq!(size_of::(), 16); @@ -386,12 +370,6 @@ pub fn e1000_init(header: usize, size: usize) { first_trans: true, }; - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - let e1000 = unsafe { slice::from_raw_parts_mut(header as *mut Volatile, size / 4) }; debug!( "status before setup: {:#?}", @@ -501,6 +479,8 @@ pub fn e1000_init(header: usize, size: usize) { let e1000_iface = E1000Interface { iface: Mutex::new(iface), driver: net_driver.clone(), + name, + irq, }; let driver = Arc::new(e1000_iface); diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 284f457..7e289f7 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -1,8 +1,9 @@ //! Intel 10Gb Network Adapter 82599 i.e. ixgbe network driver //! Datasheet: https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82599-10-gbe-controller-datasheet.pdf -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use alloc::collections::BTreeMap; use isomorphic_drivers::net::ethernet::intel::ixgbe; @@ -20,7 +21,6 @@ use crate::memory::active_table; use crate::net::SOCKETS; use crate::sync::FlagsGuard; use crate::sync::SpinNoIrqLock as Mutex; -use crate::sync::{MutexGuard, SpinNoIrq}; use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; @@ -32,21 +32,6 @@ struct IXGBEDriver { mtu: usize, } -impl Drop for IXGBEDriver { - fn drop(&mut self) { - let _ = FlagsGuard::no_irq_region(); - let header = self.header; - let size = self.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - } -} - pub struct IXGBEInterface { iface: Mutex>, driver: IXGBEDriver, @@ -64,16 +49,6 @@ impl Driver for IXGBEInterface { let handled = { let _ = FlagsGuard::no_irq_region(); - let header = self.driver.header; - let size = self.driver.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - self.driver.inner.try_handle_interrupt() }; @@ -135,15 +110,6 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { let _ = FlagsGuard::no_irq_region(); - let header = self.header; - let size = self.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } if self.inner.can_send() { if let Some(data) = self.inner.recv() { Some((IXGBERxToken(data), IXGBETxToken(self.clone()))) @@ -157,15 +123,6 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn transmit(&'a mut self) -> Option { let _ = FlagsGuard::no_irq_region(); - let header = self.header; - let size = self.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } if self.inner.can_send() { Some(IXGBETxToken(self.clone())) } else { @@ -200,15 +157,6 @@ impl phy::TxToken for IXGBETxToken { F: FnOnce(&mut [u8]) -> Result, { let _ = FlagsGuard::no_irq_region(); - let header = self.0.header; - let size = self.0.size; - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()]; let result = f(&mut buffer[..len]); if result.is_ok() { @@ -225,13 +173,6 @@ pub fn ixgbe_init( size: usize, ) -> Arc { let _ = FlagsGuard::no_irq_region(); - if let None = active_table().get_entry(header) { - let mut current_addr = header; - while current_addr < header + size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), header, size); ixgbe.enable_irq(); diff --git a/kernel/src/drivers/net/virtio_net.rs b/kernel/src/drivers/net/virtio_net.rs index 397bd5d..d149ec3 100644 --- a/kernel/src/drivers/net/virtio_net.rs +++ b/kernel/src/drivers/net/virtio_net.rs @@ -1,7 +1,8 @@ use alloc::alloc::{GlobalAlloc, Layout}; use alloc::format; -use alloc::prelude::*; +use alloc::string::String; use alloc::sync::Arc; +use alloc::vec::Vec; use core::mem::size_of; use core::slice; diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 488dcb2..9414c47 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -37,15 +37,15 @@ lazy_static! { pub static ref ROOT_INODE: Arc = { #[cfg(not(feature = "link_user"))] let device = { - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "x86_64"))] { crate::drivers::BLK_DRIVERS.read().iter() - .next().expect("VirtIOBlk not found") + .next().expect("Block device not found") .clone() } - #[cfg(target_arch = "x86_64")] + #[cfg(target_arch = "aarch64")] { - Arc::new(ide::IDE::new(1)) + unimplemented!() } }; #[cfg(feature = "link_user")] diff --git a/kernel/src/syscall/custom.rs b/kernel/src/syscall/custom.rs index 94ef99a..e21fa12 100644 --- a/kernel/src/syscall/custom.rs +++ b/kernel/src/syscall/custom.rs @@ -13,13 +13,13 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { vendor, product ); - let tag = pci::find_device(vendor as u32, product as u32).ok_or(SysError::ENOENT)?; + let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?; if pci::detach_driver(&tag) { info!("Kernel driver detached"); } // Get BAR0 memory - let (base, len) = unsafe { tag.get_bar_mem(0) }.ok_or(SysError::ENOENT)?; + let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?; let mut proc = process(); let virt_addr = proc.vm.find_free_area(0, len); diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index fc6779f..ac3ff39 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -1,8 +1,8 @@ use super::*; use crate::arch::cpu; +use crate::consts::USER_STACK_SIZE; use core::mem::size_of; use core::sync::atomic::{AtomicI32, Ordering}; -use crate::consts::USER_STACK_SIZE; pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult { const ARCH_SET_FS: i32 = 0x1002; @@ -177,7 +177,7 @@ pub fn sys_prlimit64( } } Ok(0) - }, + } RLIMIT_RSS | RLIMIT_AS => { if !old_limit.is_null() { proc.vm.check_write_ptr(old_limit)?; diff --git a/user b/user index 69febc9..97bae0c 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 69febc9fcc64df60329687b4f24b9b5309c99adf +Subproject commit 97bae0c39a7aeaab07654d99c3ba3bcb4d01658c