mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-23 08:26:17 +04:00
Merge branch 'mipsel' of github.com:oscourse-tsinghua/rcore_plus into mipsel
This commit is contained in:
commit
40e4d23c19
14
kernel/Cargo.lock
generated
14
kernel/Cargo.lock
generated
@ -125,12 +125,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "deque"
|
name = "deque"
|
||||||
version = "0.3.2"
|
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]]
|
[[package]]
|
||||||
name = "device_tree"
|
name = "device_tree"
|
||||||
version = "1.0.3"
|
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]]
|
[[package]]
|
||||||
name = "fixedvec"
|
name = "fixedvec"
|
||||||
@ -252,6 +252,14 @@ name = "pc-keyboard"
|
|||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "pulldown-cmark"
|
name = "pulldown-cmark"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
@ -317,6 +325,7 @@ dependencies = [
|
|||||||
"mips 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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 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)",
|
"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 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 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 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)" = "<none>"
|
||||||
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
"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 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"
|
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
|
@ -13,7 +13,9 @@ authors = [
|
|||||||
"chenqiuhao <haohao0924@126.com>",
|
"chenqiuhao <haohao0924@126.com>",
|
||||||
"maoyuchaxue <wangjt15@mails.tsinghua.edu.cn>",
|
"maoyuchaxue <wangjt15@mails.tsinghua.edu.cn>",
|
||||||
"Jiajie Chen <jiegec@qq.com>",
|
"Jiajie Chen <jiegec@qq.com>",
|
||||||
"chyyuu <yuchen@mail.tsinghua.edu.cn>"
|
"chyyuu <yuchen@mail.tsinghua.edu.cn>",
|
||||||
|
"Shengqi Chen <harry-chen@outlok.com>",
|
||||||
|
"Yuhao Zhou <miskcoo@gmail.com>"
|
||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@ -26,6 +28,8 @@ board_raspi3 = ["bcm2837", "link_user"]
|
|||||||
raspi3_use_generic_timer = ["bcm2837/use_generic_timer"]
|
raspi3_use_generic_timer = ["bcm2837/use_generic_timer"]
|
||||||
# for mipsel qemu malta machine
|
# for mipsel qemu malta machine
|
||||||
board_malta = []
|
board_malta = []
|
||||||
|
# for thinpad
|
||||||
|
board_thinpad = []
|
||||||
# Hard link user program
|
# Hard link user program
|
||||||
link_user = []
|
link_user = []
|
||||||
# Run cmdline instead of user shell, useful for automatic testing
|
# Run cmdline instead of user shell, useful for automatic testing
|
||||||
@ -46,6 +50,7 @@ volatile = "0.2"
|
|||||||
heapless = "0.4"
|
heapless = "0.4"
|
||||||
console-traits = "0.3"
|
console-traits = "0.3"
|
||||||
buddy_system_allocator = "0.1"
|
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" }
|
device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
|
||||||
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" }
|
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" }
|
||||||
lazy_static = { version = "1.3", features = ["spin_no_std"] }
|
lazy_static = { version = "1.3", features = ["spin_no_std"] }
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+
|
# | 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
|
# 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
|
# 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
|
arch ?= riscv64
|
||||||
board ?= none
|
board ?= none
|
||||||
@ -36,6 +37,7 @@ graphic ?= off
|
|||||||
smp ?= 4
|
smp ?= 4
|
||||||
pci_passthru ?=
|
pci_passthru ?=
|
||||||
init ?=
|
init ?=
|
||||||
|
extra_nic ?= off
|
||||||
|
|
||||||
target := $(arch)
|
target := $(arch)
|
||||||
build_path := target/$(target)/$(mode)
|
build_path := target/$(target)/$(mode)
|
||||||
@ -49,20 +51,22 @@ user_dir := ../user
|
|||||||
|
|
||||||
|
|
||||||
### export environments ###
|
### export environments ###
|
||||||
export ARCH = $(arch)
|
|
||||||
export BOARD = $(board)
|
|
||||||
export SMP = $(smp)
|
|
||||||
export DTB = $(dtb)
|
|
||||||
export SFSIMG = $(user_dir)/build/$(arch).qcow2
|
export SFSIMG = $(user_dir)/build/$(arch).qcow2
|
||||||
|
|
||||||
ifeq ($(arch), aarch64)
|
ifeq ($(arch), aarch64)
|
||||||
board := raspi3
|
board := raspi3
|
||||||
export SFSIMG = $(user_dir)/build/$(arch).img
|
export SFSIMG = $(user_dir)/build/$(arch).img
|
||||||
else ifeq ($(arch), mipsel)
|
|
||||||
board := malta
|
|
||||||
endif
|
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 ###
|
### qemu options ###
|
||||||
@ -74,7 +78,9 @@ qemu_net_opts := \
|
|||||||
ifeq ($(arch), x86_64)
|
ifeq ($(arch), x86_64)
|
||||||
qemu_opts += \
|
qemu_opts += \
|
||||||
-drive format=raw,file=$(bootimage) \
|
-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 \
|
-serial mon:stdio \
|
||||||
-m 4G \
|
-m 4G \
|
||||||
-device isa-debug-exit
|
-device isa-debug-exit
|
||||||
@ -83,10 +89,15 @@ qemu_net_opts += \
|
|||||||
-device e1000e,netdev=net0
|
-device e1000e,netdev=net0
|
||||||
else
|
else
|
||||||
qemu_opts += \
|
qemu_opts += \
|
||||||
-machine ubuntu,accel=kvm
|
-machine accel=kvm
|
||||||
qemu_net_opts += \
|
qemu_net_opts += \
|
||||||
-device vfio-pci,host=$(pci_passthru)
|
-device vfio-pci,host=$(pci_passthru)
|
||||||
endif
|
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)
|
else ifeq ($(arch), riscv32)
|
||||||
qemu_opts += \
|
qemu_opts += \
|
||||||
@ -113,11 +124,13 @@ qemu_opts += \
|
|||||||
-kernel $(kernel_img)
|
-kernel $(kernel_img)
|
||||||
|
|
||||||
else ifeq ($(arch), mipsel)
|
else ifeq ($(arch), mipsel)
|
||||||
|
ifeq ($(board), malta)
|
||||||
qemu_opts += \
|
qemu_opts += \
|
||||||
-machine $(board) \
|
-machine $(board) \
|
||||||
-serial null -serial null -serial mon:stdio \
|
-serial none -serial none -serial mon:stdio \
|
||||||
-kernel $(kernel_img)
|
-kernel $(kernel_img)
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef d
|
ifdef d
|
||||||
qemu_opts += -d $(d)
|
qemu_opts += -d $(d)
|
||||||
|
@ -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();
|
let dtb = std::env::var("DTB").unwrap();
|
||||||
|
|
||||||
if !Path::new(&dtb).is_file() {
|
if !Path::new(&dtb).is_file() {
|
||||||
|
@ -2,13 +2,18 @@
|
|||||||
|
|
||||||
use bcm2837::atags::Atags;
|
use bcm2837::atags::Atags;
|
||||||
use once::*;
|
use once::*;
|
||||||
|
use alloc::string::String;
|
||||||
|
|
||||||
|
|
||||||
|
#[path = "../../../../drivers/gpu/fb.rs"]
|
||||||
pub mod fb;
|
pub mod fb;
|
||||||
pub mod irq;
|
pub mod irq;
|
||||||
pub mod mailbox;
|
pub mod mailbox;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
||||||
|
use fb::FramebufferInfo;
|
||||||
|
|
||||||
pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE;
|
pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE;
|
||||||
pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000;
|
pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000;
|
||||||
|
|
||||||
@ -41,3 +46,43 @@ pub fn probe_memory() -> Option<(usize, usize)> {
|
|||||||
}
|
}
|
||||||
None
|
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))
|
||||||
|
}
|
@ -5,6 +5,7 @@ use once::*;
|
|||||||
|
|
||||||
pub use self::board::fb;
|
pub use self::board::fb;
|
||||||
pub use self::board::serial;
|
pub use self::board::serial;
|
||||||
|
#[path = "../../../drivers/console/mod.rs"]
|
||||||
pub mod console;
|
pub mod console;
|
||||||
|
|
||||||
/// Initialize ARM64 common drivers
|
/// Initialize ARM64 common drivers
|
||||||
|
13
kernel/src/arch/mipsel/board/malta/fb.rs
Normal file
13
kernel/src/arch/mipsel/board/malta/fb.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//! stub frame buffer driver for malta board
|
||||||
|
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref FRAME_BUFFER: Mutex<Option<Framebuffer>> = Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Framebuffer {}
|
||||||
|
|
||||||
|
pub struct FramebufferInfo {}
|
||||||
|
|
||||||
|
pub enum ColorDepth {}
|
19
kernel/src/arch/mipsel/board/malta/mod.rs
Normal file
19
kernel/src/arch/mipsel/board/malta/mod.rs
Normal file
@ -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();
|
||||||
|
}
|
122
kernel/src/arch/mipsel/board/malta/serial.rs
Normal file
122
kernel/src/arch/mipsel/board/malta/serial.rs
Normal file
@ -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::<u8>(self.base + COM_LSR) & COM_LSR_DATA) == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let c = read::<u8>(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<char> {
|
||||||
|
match read::<u8>(self.base + COM_LSR) & COM_LSR_DATA {
|
||||||
|
0 => None,
|
||||||
|
_ => Some(read::<u8>(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<T>(addr: usize, content: T) {
|
||||||
|
let cell = (addr) as *mut T;
|
||||||
|
write_volatile(cell, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read<T>(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<SerialPort> = Mutex::new(SerialPort::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(base: usize) {
|
||||||
|
SERIAL_PORT.lock().init(base);
|
||||||
|
}
|
85
kernel/src/arch/mipsel/board/thinpad/device.dts
Normal file
85
kernel/src/arch/mipsel/board/thinpad/device.dts
Normal file
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
36
kernel/src/arch/mipsel/board/thinpad/mod.rs
Normal file
36
kernel/src/arch/mipsel/board/thinpad/mod.rs
Normal file
@ -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))
|
||||||
|
}
|
94
kernel/src/arch/mipsel/board/thinpad/serial.rs
Normal file
94
kernel/src/arch/mipsel/board/thinpad/serial.rs
Normal file
@ -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::<u8>(self.base + UART_STATUS) & UART_STATUS_DR) == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let c = read::<u8>(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<char> {
|
||||||
|
match read::<u8>(self.base + UART_STATUS) & UART_STATUS_DR {
|
||||||
|
0 => None,
|
||||||
|
_ => Some(read::<u8>(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<T>(addr: usize, content: T) {
|
||||||
|
let cell = (addr) as *mut T;
|
||||||
|
write_volatile(cell, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read<T>(addr: usize) -> T {
|
||||||
|
let cell = (addr) as *const T;
|
||||||
|
read_volatile(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(base: usize) {
|
||||||
|
SERIAL_PORT.lock().init(base);
|
||||||
|
}
|
16
kernel/src/arch/mipsel/driver/mod.rs
Normal file
16
kernel/src/arch/mipsel/driver/mod.rs
Normal file
@ -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();
|
||||||
|
}
|
@ -74,9 +74,6 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
|
|||||||
|
|
||||||
fn external() {
|
fn external() {
|
||||||
// TODO
|
// TODO
|
||||||
#[cfg(feature = "board_u540")]
|
|
||||||
unsafe { super::board::handle_external_interrupt(); }
|
|
||||||
|
|
||||||
// true means handled, false otherwise
|
// true means handled, false otherwise
|
||||||
let handlers = [try_process_serial, try_process_drivers];
|
let handlers = [try_process_serial, try_process_drivers];
|
||||||
for handler in handlers.iter() {
|
for handler in handlers.iter() {
|
||||||
@ -87,7 +84,6 @@ fn external() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_process_serial() -> bool {
|
fn try_process_serial() -> bool {
|
||||||
// TODO
|
|
||||||
match super::io::getchar_option() {
|
match super::io::getchar_option() {
|
||||||
Some(ch) => {
|
Some(ch) => {
|
||||||
crate::trap::serial(ch);
|
crate::trap::serial(ch);
|
||||||
@ -119,10 +115,9 @@ fn timer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn syscall(tf: &mut TrapFrame) {
|
fn syscall(tf: &mut TrapFrame) {
|
||||||
// TODO
|
|
||||||
tf.sepc += 4; // Must before syscall, because of fork.
|
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);
|
let ret = crate::syscall::syscall(tf.t0, [tf.x0, tf.x1, tf.x2, tf.x3, tf.s0, tf.s1], tf);
|
||||||
tf.x[10] = ret as usize;
|
tf.v0 = ret as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn page_fault(tf: &mut TrapFrame) {
|
fn page_fault(tf: &mut TrapFrame) {
|
||||||
|
@ -1,48 +1,30 @@
|
|||||||
use core::fmt::{Write, Result, Arguments};
|
//! Input/output for mipsel.
|
||||||
|
|
||||||
struct SerialPort;
|
use super::driver::console::CONSOLE;
|
||||||
|
use super::driver::serial::*;
|
||||||
impl Write for SerialPort {
|
use core::fmt::{Arguments, Write};
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getchar() -> char {
|
pub fn getchar() -> char {
|
||||||
// TODO: get char from uart
|
unsafe { SERIAL_PORT.force_unlock() }
|
||||||
let c = 0 as u8;
|
SERIAL_PORT.lock().getchar()
|
||||||
|
|
||||||
match c {
|
|
||||||
255 => '\0', // null
|
|
||||||
c => c as char,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getchar_option() -> Option<char> {
|
pub fn getchar_option() -> Option<char> {
|
||||||
// TODO: get char from uart
|
unsafe { SERIAL_PORT.force_unlock() }
|
||||||
let c = 0 as u8;
|
SERIAL_PORT.lock().getchar_option()
|
||||||
match c {
|
|
||||||
-1 => None,
|
|
||||||
c => Some(c as u8 as char),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn putfmt(fmt: Arguments) {
|
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;
|
pub fn putchar(c: u8) {
|
||||||
const RXDATA: *mut u32 = 0x38000004 as *mut u32;
|
unsafe { SERIAL_PORT.force_unlock() }
|
||||||
|
SERIAL_PORT.lock().putchar(c);
|
||||||
|
}
|
||||||
|
@ -8,11 +8,20 @@ pub mod consts;
|
|||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod syscall;
|
pub mod syscall;
|
||||||
pub mod rand;
|
pub mod rand;
|
||||||
|
pub mod driver;
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use mips::registers::cp0;
|
use mips::registers::cp0;
|
||||||
use mips::instructions;
|
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" {
|
extern "C" {
|
||||||
fn _dtb_start();
|
fn _dtb_start();
|
||||||
fn _dtb_end();
|
fn _dtb_end();
|
||||||
@ -38,12 +47,16 @@ pub extern fn rust_main() -> ! {
|
|||||||
|
|
||||||
unsafe { memory::clear_bss(); }
|
unsafe { memory::clear_bss(); }
|
||||||
|
|
||||||
|
board::init_serial_early();
|
||||||
|
driver::init();
|
||||||
|
|
||||||
println!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start);
|
println!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start);
|
||||||
|
|
||||||
crate::logging::init();
|
|
||||||
interrupt::init();
|
interrupt::init();
|
||||||
memory::init();
|
memory::init();
|
||||||
timer::init();
|
timer::init();
|
||||||
|
|
||||||
|
crate::logging::init();
|
||||||
crate::drivers::init(dtb_start);
|
crate::drivers::init(dtb_start);
|
||||||
crate::process::init();
|
crate::process::init();
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@ use crate::consts::KERNEL_OFFSET;
|
|||||||
use bit_allocator::BitAlloc;
|
use bit_allocator::BitAlloc;
|
||||||
// Depends on kernel
|
// Depends on kernel
|
||||||
use super::{BootInfo, MemoryRegionType};
|
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 crate::HEAP_ALLOCATOR;
|
||||||
use rcore_memory::PAGE_SIZE;
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use log::*;
|
use log::*;
|
||||||
use once::*;
|
use once::*;
|
||||||
use rcore_memory::paging::*;
|
use rcore_memory::paging::*;
|
||||||
|
use rcore_memory::PAGE_SIZE;
|
||||||
|
|
||||||
pub fn init(boot_info: &BootInfo) {
|
pub fn init(boot_info: &BootInfo) {
|
||||||
assert_has_not_been_called!("memory::init must be called only once");
|
assert_has_not_been_called!("memory::init must be called only once");
|
||||||
@ -60,14 +60,12 @@ fn enlarge_heap() {
|
|||||||
addrs.push((va, PAGE_SIZE));
|
addrs.push((va, PAGE_SIZE));
|
||||||
}
|
}
|
||||||
for (addr, len) in addrs.into_iter() {
|
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();
|
page_table.map(va, va - va_offset).update();
|
||||||
}
|
}
|
||||||
info!("Adding {:#X} {:#X} to heap", addr, len);
|
info!("Adding {:#X} {:#X} to heap", addr, len);
|
||||||
unsafe {
|
unsafe {
|
||||||
HEAP_ALLOCATOR
|
HEAP_ALLOCATOR.lock().init(addr, len);
|
||||||
.lock()
|
|
||||||
.init(addr, len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
497
kernel/src/drivers/block/ahci.rs
Normal file
497
kernel/src/drivers/block/ahci.rs
Normal file
@ -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>);
|
||||||
|
|
||||||
|
/// AHCI Generic Host Control (3.1)
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AHCIGHC {
|
||||||
|
/// Host capability
|
||||||
|
capability: Volatile<AHCICap>,
|
||||||
|
/// Global host control
|
||||||
|
global_host_control: Volatile<u32>,
|
||||||
|
/// Interrupt status
|
||||||
|
interrupt_status: Volatile<u32>,
|
||||||
|
/// Port implemented
|
||||||
|
port_implemented: Volatile<u32>,
|
||||||
|
/// Version
|
||||||
|
version: Volatile<u32>,
|
||||||
|
/// Command completion coalescing control
|
||||||
|
ccc_control: Volatile<u32>,
|
||||||
|
/// Command completion coalescing ports
|
||||||
|
ccc_ports: Volatile<u32>,
|
||||||
|
/// Enclosure management location
|
||||||
|
em_location: Volatile<u32>,
|
||||||
|
/// Enclosure management control
|
||||||
|
em_control: Volatile<u32>,
|
||||||
|
/// Host capabilities extended
|
||||||
|
capabilities2: Volatile<u32>,
|
||||||
|
/// BIOS/OS handoff control and status
|
||||||
|
bios_os_handoff_control: Volatile<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<u64>,
|
||||||
|
fis_base_address: Volatile<u64>,
|
||||||
|
interrupt_status: Volatile<u32>,
|
||||||
|
interrupt_enable: Volatile<u32>,
|
||||||
|
command: Volatile<u32>,
|
||||||
|
reserved: Volatile<u32>,
|
||||||
|
task_file_data: Volatile<u32>,
|
||||||
|
signature: Volatile<u32>,
|
||||||
|
sata_status: Volatile<u32>,
|
||||||
|
sata_control: Volatile<u32>,
|
||||||
|
sata_error: Volatile<u32>,
|
||||||
|
sata_active: Volatile<u32>,
|
||||||
|
command_issue: Volatile<u32>,
|
||||||
|
sata_notification: Volatile<u32>,
|
||||||
|
fis_based_switch_control: Volatile<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<u32>) -> 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<u32>, header: usize, size: usize) -> Arc<AHCIDriver> {
|
||||||
|
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::<AHCICommandHeader>(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
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!();
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
|
pub mod ahci;
|
||||||
pub mod virtio_blk;
|
pub mod virtio_blk;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use alloc::boxed::Box;
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
@ -14,6 +15,7 @@ use volatile::Volatile;
|
|||||||
|
|
||||||
use rcore_fs::dev::BlockDevice;
|
use rcore_fs::dev::BlockDevice;
|
||||||
|
|
||||||
|
use crate::drivers::BlockDriver;
|
||||||
use crate::memory::active_table;
|
use crate::memory::active_table;
|
||||||
use crate::sync::SpinNoIrqLock as Mutex;
|
use crate::sync::SpinNoIrqLock as Mutex;
|
||||||
|
|
||||||
@ -125,11 +127,8 @@ impl Driver for VirtIOBlkDriver {
|
|||||||
fn get_id(&self) -> String {
|
fn get_id(&self) -> String {
|
||||||
format!("virtio_block")
|
format!("virtio_block")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockDevice for VirtIOBlkDriver {
|
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool {
|
||||||
const BLOCK_SIZE_LOG2: u8 = 9; // 512
|
|
||||||
fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool {
|
|
||||||
let mut driver = self.0.lock();
|
let mut driver = self.0.lock();
|
||||||
// ensure header page is mapped
|
// ensure header page is mapped
|
||||||
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
|
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();
|
let mut driver = self.0.lock();
|
||||||
// ensure header page is mapped
|
// ensure header page is mapped
|
||||||
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
|
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);
|
let driver = Arc::new(driver);
|
||||||
DRIVERS.write().push(driver.clone());
|
DRIVERS.write().push(driver.clone());
|
||||||
BLK_DRIVERS.write().push(driver);
|
BLK_DRIVERS.write().push(Arc::new(BlockDriver(driver)));
|
||||||
}
|
}
|
||||||
|
@ -1,309 +1,159 @@
|
|||||||
|
use crate::consts::KERNEL_OFFSET;
|
||||||
|
use crate::drivers::block::*;
|
||||||
use crate::drivers::net::*;
|
use crate::drivers::net::*;
|
||||||
use crate::drivers::{Driver, DRIVERS, NET_DRIVERS};
|
use crate::drivers::{Driver, DRIVERS, NET_DRIVERS};
|
||||||
|
use crate::memory::active_table;
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
|
use pci::*;
|
||||||
|
use rcore_memory::{paging::PageTable, PAGE_SIZE};
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
const PCI_VENDOR: u32 = 0x00;
|
const PCI_COMMAND: u16 = 0x04;
|
||||||
const PCI_DEVICE: u32 = 0x02;
|
const PCI_CAP_PTR: u16 = 0x34;
|
||||||
const PCI_COMMAND: u32 = 0x04;
|
const PCI_INTERRUPT_LINE: u16 = 0x3c;
|
||||||
const PCI_STATUS: u32 = 0x06;
|
const PCI_INTERRUPT_PIN: u16 = 0x3d;
|
||||||
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_CTRL_CAP: u16 = 0x00;
|
||||||
const PCI_MSI_ADDR: u32 = 0x04;
|
const PCI_MSI_ADDR: u16 = 0x04;
|
||||||
const PCI_MSI_UPPER_ADDR: u32 = 0x08;
|
const PCI_MSI_UPPER_ADDR: u16 = 0x08;
|
||||||
const PCI_MSI_DATA: u32 = 0x0C;
|
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;
|
struct PortOpsImpl;
|
||||||
const PCI_DATA_PORT: u16 = 0xcfc;
|
|
||||||
|
|
||||||
const PCI_BASE_ADDRESS_SPACE: u32 = 0x01;
|
impl PortOps for PortOpsImpl {
|
||||||
const PCI_BASE_ADDRESS_SPACE_IO: u32 = 0x01;
|
unsafe fn read8(&self, port: u16) -> u8 {
|
||||||
const PCI_BASE_ADDRESS_SPACE_MEMORY: u32 = 0x00;
|
Port::new(port).read()
|
||||||
|
}
|
||||||
const PCI_BASE_ADDRESS_MEM_TYPE_MASK: u32 = 0x06;
|
unsafe fn read16(&self, port: u16) -> u16 {
|
||||||
const PCI_BASE_ADDRESS_MEM_TYPE_32: u32 = 0x00;
|
Port::new(port).read()
|
||||||
const PCI_BASE_ADDRESS_MEM_TYPE_1M: u32 = 0x02;
|
}
|
||||||
const PCI_BASE_ADDRESS_MEM_TYPE_64: u32 = 0x04;
|
unsafe fn read32(&self, port: u16) -> u32 {
|
||||||
const PCI_BASE_ADDRESS_MEM_PREFETCH: u32 = 0x08;
|
Port::new(port).read()
|
||||||
const PCI_BASE_ADDRESS_MEM_MASK: u32 = 0xfffffff0;
|
}
|
||||||
|
unsafe fn write8(&self, port: u16, val: u8) {
|
||||||
#[derive(Copy, Clone)]
|
Port::new(port).write(val);
|
||||||
pub struct PciTag(u32);
|
}
|
||||||
|
unsafe fn write16(&self, port: u16, val: u16) {
|
||||||
impl Ord for PciTag {
|
Port::new(port).write(val);
|
||||||
fn cmp(&self, other: &PciTag) -> Ordering {
|
}
|
||||||
self.0.cmp(&other.0)
|
unsafe fn write32(&self, port: u16, val: u32) {
|
||||||
|
Port::new(port).write(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for PciTag {
|
/// Enable the pci device and its interrupt
|
||||||
fn partial_cmp(&self, other: &PciTag) -> Option<Ordering> {
|
/// Return assigned MSI interrupt number when applicable
|
||||||
Some(self.cmp(other))
|
unsafe fn enable(loc: Location) -> Option<u32> {
|
||||||
}
|
let ops = &PortOpsImpl;
|
||||||
}
|
let am = CSpaceAccessMethod::IO;
|
||||||
|
|
||||||
impl Eq for PciTag {}
|
// 23 and lower are used
|
||||||
|
static mut MSI_IRQ: u32 = 23;
|
||||||
|
|
||||||
impl PartialEq for PciTag {
|
let orig = am.read16(ops, loc, PCI_COMMAND);
|
||||||
fn eq(&self, other: &PciTag) -> bool {
|
// IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable
|
||||||
self.0 == other.0
|
am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PciTag {
|
// find MSI cap
|
||||||
pub fn new(bus: u32, dev: u32, func: u32) -> PciTag {
|
let mut msi_found = false;
|
||||||
assert!(bus < 256);
|
let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16;
|
||||||
assert!(dev < 32);
|
let mut assigned_irq = None;
|
||||||
assert!(func < 8);
|
while cap_ptr > 0 {
|
||||||
PciTag(bus << 16 | dev << 11 | func << 8)
|
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);
|
||||||
|
|
||||||
pub fn bus(&self) -> u32 {
|
// enable MSI interrupt, assuming 64bit for now
|
||||||
(self.0 >> 16) & 0xFF
|
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);
|
||||||
|
|
||||||
pub fn dev(&self) -> u32 {
|
|
||||||
(self.0 >> 11) & 0x1F
|
|
||||||
}
|
|
||||||
|
|
||||||
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<u32> = Port::new(PCI_ADDR_PORT);
|
|
||||||
let mut pci_data: Port<u32> = 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<u32> = Port::new(PCI_ADDR_PORT);
|
|
||||||
let mut pci_data: Port<u32> = 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<u32> {
|
|
||||||
// 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!(
|
debug!(
|
||||||
"PCI device has cap id {} at {:#X}",
|
"MSI control {:#b}, enabling MSI interrupts",
|
||||||
self.read(cap_ptr, 1),
|
orig_ctrl >> 16
|
||||||
cap_ptr
|
|
||||||
);
|
);
|
||||||
cap_ptr = self.read(cap_ptr + 1, 1);
|
msi_found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr);
|
||||||
if !msi_found {
|
cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16;
|
||||||
// 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);
|
|
||||||
debug!(
|
|
||||||
"MSI not found, using PCI interrupt line {} pin {}",
|
|
||||||
line, pin
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
pub fn init_driver(dev: &PCIDevice) {
|
||||||
if vid == 0x8086 {
|
let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function);
|
||||||
if did == 0x100e || did == 0x100f || did == 0x10d3 {
|
match (dev.id.vendor_id, dev.id.device_id) {
|
||||||
|
(0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => {
|
||||||
// 0x100e
|
// 0x100e
|
||||||
// 82540EM Gigabit Ethernet Controller
|
// 82540EM Gigabit Ethernet Controller
|
||||||
// 0x100f
|
// 0x100f
|
||||||
// 82545EM Gigabit Ethernet Controller (Copper)
|
// 82545EM Gigabit Ethernet Controller (Copper)
|
||||||
// 0x10d3
|
// 0x10d3
|
||||||
// 82574L Gigabit Network Connection
|
// 82574L Gigabit Network Connection
|
||||||
if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } {
|
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
|
||||||
unsafe {
|
let irq = unsafe { enable(dev.loc) };
|
||||||
tag.enable();
|
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 {
|
|
||||||
// 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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(0x8086, 0x10fb) => {
|
||||||
|
// 82599ES 10-Gigabit SFI/SFP+ Network Connection
|
||||||
|
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(dev.loc, ahci::ahci_init(irq, vaddr, len as usize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn detach_driver(tag: &PciTag) -> bool {
|
pub fn detach_driver(loc: &Location) -> bool {
|
||||||
match PCI_DRIVERS.lock().remove(tag) {
|
match PCI_DRIVERS.lock().remove(loc) {
|
||||||
Some(driver) => {
|
Some(driver) => {
|
||||||
DRIVERS
|
DRIVERS
|
||||||
.write()
|
.write()
|
||||||
@ -318,51 +168,44 @@ pub fn detach_driver(tag: &PciTag) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
for bus in 0..256 {
|
let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
|
||||||
for dev in 0..32 {
|
for dev in pci_iter {
|
||||||
let tag = PciTag::new(bus, dev, 0);
|
info!(
|
||||||
if let Some((vid, did, next)) = tag.probe() {
|
"pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}",
|
||||||
let name = format!("enp{}s{}f0", bus, dev);
|
dev.loc.bus,
|
||||||
init_driver(name, vid, did, tag);
|
dev.loc.device,
|
||||||
if next {
|
dev.loc.function,
|
||||||
for func in 1..8 {
|
dev.id.vendor_id,
|
||||||
let tag = PciTag::new(bus, dev, func);
|
dev.id.device_id,
|
||||||
if let Some((vid, did, _)) = tag.probe() {
|
dev.id.class,
|
||||||
let name = format!("enp{}s{}f{}", bus, dev, func);
|
dev.id.subclass,
|
||||||
init_driver(name, vid, did, tag);
|
dev.pic_interrupt_line,
|
||||||
}
|
dev.interrupt_pin,
|
||||||
}
|
);
|
||||||
}
|
init_driver(&dev);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_device(vendor: u32, product: u32) -> Option<PciTag> {
|
pub fn find_device(vendor: u16, product: u16) -> Option<Location> {
|
||||||
for bus in 0..256 {
|
let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
|
||||||
for dev in 0..32 {
|
for dev in pci_iter {
|
||||||
let tag = PciTag::new(bus, dev, 0);
|
if dev.id.vendor_id == vendor && dev.id.device_id == product {
|
||||||
if let Some((vid, did, next)) = tag.probe() {
|
return Some(dev.loc);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> {
|
||||||
pub static ref PCI_DRIVERS: Arc<Mutex<BTreeMap<PciTag, Arc<Driver>>>> =
|
unsafe { probe_function(&PortOpsImpl, loc, CSpaceAccessMethod::IO) }
|
||||||
Arc::new(Mutex::new(BTreeMap::new()));
|
.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: Mutex<BTreeMap<Location, Arc<Driver>>> =
|
||||||
|
Mutex::new(BTreeMap::new());
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
use crate::util::color::ConsoleColor;
|
use crate::util::color::ConsoleColor;
|
||||||
|
|
||||||
pub trait FramebufferColor {
|
pub trait FramebufferColor {
|
||||||
|
/// pack as 8-bit integer
|
||||||
|
fn pack8(&self) -> u8;
|
||||||
|
|
||||||
/// pack as 16-bit integer
|
/// pack as 16-bit integer
|
||||||
fn pack16(&self) -> u16;
|
fn pack16(&self) -> u16;
|
||||||
|
|
||||||
@ -42,6 +45,12 @@ impl From<ConsoleColor> for RgbColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FramebufferColor for RgbColor {
|
impl FramebufferColor for RgbColor {
|
||||||
|
#[inline]
|
||||||
|
fn pack8(&self) -> u8 {
|
||||||
|
// RGB332
|
||||||
|
((self.0 >> 5) << 5) | ((self.1 >> 5) << 2) | (self.2 >> 6)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pack16(&self) -> u16 {
|
fn pack16(&self) -> u16 {
|
||||||
// BGR565
|
// BGR565
|
||||||
@ -58,6 +67,11 @@ impl FramebufferColor for RgbColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FramebufferColor for ConsoleColor {
|
impl FramebufferColor for ConsoleColor {
|
||||||
|
#[inline]
|
||||||
|
fn pack8(&self) -> u8 {
|
||||||
|
RgbColor::from(*self).pack8()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pack16(&self) -> u16 {
|
fn pack16(&self) -> u16 {
|
||||||
RgbColor::from(*self).pack16()
|
RgbColor::from(*self).pack16()
|
@ -63,6 +63,10 @@ impl<F: Font> ConsoleBuffer<F> {
|
|||||||
let off_y = row * F::HEIGHT;
|
let off_y = row * F::HEIGHT;
|
||||||
if let Some(fb) = FRAME_BUFFER.lock().as_mut() {
|
if let Some(fb) = FRAME_BUFFER.lock().as_mut() {
|
||||||
let (mut foreground, mut background) = match fb.color_depth {
|
let (mut foreground, mut background) = match fb.color_depth {
|
||||||
|
ColorDepth8 => (
|
||||||
|
ch.attr.foreground.pack8() as u32,
|
||||||
|
ch.attr.background.pack8() as u32,
|
||||||
|
),
|
||||||
ColorDepth16 => (
|
ColorDepth16 => (
|
||||||
ch.attr.foreground.pack16() as u32,
|
ch.attr.foreground.pack16() as u32,
|
||||||
ch.attr.background.pack16() as u32,
|
ch.attr.background.pack16() as u32,
|
@ -1,6 +1,5 @@
|
|||||||
//! Framebuffer
|
//! Framebuffer
|
||||||
|
|
||||||
use super::mailbox;
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -40,6 +39,7 @@ pub struct FramebufferInfo {
|
|||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ColorDepth {
|
pub enum ColorDepth {
|
||||||
|
ColorDepth8 = 8,
|
||||||
ColorDepth16 = 16,
|
ColorDepth16 = 16,
|
||||||
ColorDepth32 = 32,
|
ColorDepth32 = 32,
|
||||||
}
|
}
|
||||||
@ -48,6 +48,7 @@ use self::ColorDepth::*;
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
union ColorBuffer {
|
union ColorBuffer {
|
||||||
base_addr: usize,
|
base_addr: usize,
|
||||||
|
buf8: &'static mut [u8],
|
||||||
buf16: &'static mut [u16],
|
buf16: &'static mut [u16],
|
||||||
buf32: &'static mut [u32],
|
buf32: &'static mut [u32],
|
||||||
}
|
}
|
||||||
@ -56,6 +57,9 @@ impl ColorBuffer {
|
|||||||
fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer {
|
fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer {
|
||||||
unsafe {
|
unsafe {
|
||||||
match color_depth {
|
match color_depth {
|
||||||
|
ColorDepth8 => ColorBuffer {
|
||||||
|
buf8: core::slice::from_raw_parts_mut(base_addr as *mut u8, size),
|
||||||
|
},
|
||||||
ColorDepth16 => ColorBuffer {
|
ColorDepth16 => ColorBuffer {
|
||||||
buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2),
|
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]
|
#[inline]
|
||||||
fn read16(&self, index: u32) -> u16 {
|
fn read16(&self, index: u32) -> u16 {
|
||||||
unsafe { self.buf16[index as usize] }
|
unsafe { self.buf16[index as usize] }
|
||||||
@ -76,6 +85,11 @@ impl ColorBuffer {
|
|||||||
unsafe { self.buf32[index as usize] }
|
unsafe { self.buf32[index as usize] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write8(&mut self, index: u32, pixel: u8) {
|
||||||
|
unsafe { self.buf8[index as usize] = pixel }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write16(&mut self, index: u32, pixel: u16) {
|
fn write16(&mut self, index: u32, pixel: u16) {
|
||||||
unsafe { self.buf16[index as usize] = pixel }
|
unsafe { self.buf16[index as usize] = pixel }
|
||||||
@ -108,49 +122,27 @@ impl Framebuffer {
|
|||||||
fn new(width: u32, height: u32, depth: u32) -> Result<Framebuffer, String> {
|
fn new(width: u32, height: u32, depth: u32) -> Result<Framebuffer, String> {
|
||||||
assert_has_not_been_called!("Framebuffer::new must be called only once");
|
assert_has_not_been_called!("Framebuffer::new must be called only once");
|
||||||
|
|
||||||
let (width, height) = if width == 0 || height == 0 {
|
let probed_info = super::probe_fb_info(width, height, depth);
|
||||||
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)?;
|
match probed_info {
|
||||||
let color_depth = match info.depth {
|
Ok((info, addr)) => {
|
||||||
16 => ColorDepth16,
|
let color_depth = match info.depth {
|
||||||
32 => ColorDepth32,
|
8 => ColorDepth8,
|
||||||
_ => Err(format!("unsupported color depth {}", 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"))?;
|
Ok(Framebuffer {
|
||||||
}
|
buf: ColorBuffer::new(color_depth, addr, info.screen_size as usize),
|
||||||
if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 {
|
color_depth,
|
||||||
Err(format!(
|
fb_info: info,
|
||||||
"mailbox call returned an invalid pitch value {}",
|
})
|
||||||
info.pitch
|
},
|
||||||
))?;
|
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]
|
#[inline]
|
||||||
@ -162,6 +154,7 @@ impl Framebuffer {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn read(&self, x: u32, y: u32) -> u32 {
|
pub fn read(&self, x: u32, y: u32) -> u32 {
|
||||||
match self.color_depth {
|
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,
|
ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32,
|
||||||
ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x),
|
ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x),
|
||||||
}
|
}
|
||||||
@ -171,6 +164,7 @@ impl Framebuffer {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn write(&mut self, x: u32, y: u32, pixel: u32) {
|
pub fn write(&mut self, x: u32, y: u32, pixel: u32) {
|
||||||
match self.color_depth {
|
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),
|
ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16),
|
||||||
ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel),
|
ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel),
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
use alloc::prelude::*;
|
use alloc::boxed::Box;
|
||||||
|
use alloc::string::String;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use core::mem::transmute_copy;
|
use core::mem::transmute_copy;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use alloc::prelude::*;
|
use alloc::string::String;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use smoltcp::wire::{EthernetAddress, Ipv4Address};
|
use smoltcp::wire::{EthernetAddress, Ipv4Address};
|
||||||
use spin::RwLock;
|
use spin::RwLock;
|
||||||
|
|
||||||
use self::block::virtio_blk::VirtIOBlkDriver;
|
|
||||||
use crate::sync::Condvar;
|
use crate::sync::Condvar;
|
||||||
|
use rcore_fs::dev::BlockDevice;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod block;
|
pub mod block;
|
||||||
@ -64,13 +65,35 @@ pub trait Driver: Send + Sync {
|
|||||||
fn poll(&self) {
|
fn poll(&self) {
|
||||||
unimplemented!("not a net driver")
|
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! {
|
lazy_static! {
|
||||||
// NOTE: RwLock only write when initializing drivers
|
// NOTE: RwLock only write when initializing drivers
|
||||||
pub static ref DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
|
pub static ref DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
|
||||||
pub static ref NET_DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
|
pub static ref NET_DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
|
||||||
pub static ref BLK_DRIVERS: RwLock<Vec<Arc<VirtIOBlkDriver>>> = RwLock::new(Vec::new());
|
pub static ref BLK_DRIVERS: RwLock<Vec<Arc<BlockDriver>>> = RwLock::new(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BlockDriver(Arc<Driver>);
|
||||||
|
|
||||||
|
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! {
|
lazy_static! {
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
use alloc::alloc::{GlobalAlloc, Layout};
|
use alloc::alloc::{GlobalAlloc, Layout};
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use alloc::prelude::*;
|
use alloc::string::String;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use core::sync::atomic::{fence, Ordering};
|
use core::sync::atomic::{fence, Ordering};
|
||||||
@ -72,20 +73,19 @@ const E1000_RAH: usize = 0x5404 / 4;
|
|||||||
pub struct E1000Interface {
|
pub struct E1000Interface {
|
||||||
iface: Mutex<EthernetInterface<'static, 'static, 'static, E1000Driver>>,
|
iface: Mutex<EthernetInterface<'static, 'static, 'static, E1000Driver>>,
|
||||||
driver: E1000Driver,
|
driver: E1000Driver,
|
||||||
|
name: String,
|
||||||
|
irq: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Driver for E1000Interface {
|
impl Driver for E1000Interface {
|
||||||
fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool {
|
fn try_handle_interrupt(&self, irq: Option<u32>) -> bool {
|
||||||
let irq = {
|
if irq.is_some() && self.irq.is_some() && irq != self.irq {
|
||||||
let driver = self.driver.0.lock();
|
// not ours, skip it
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if let None = active_table().get_entry(driver.header) {
|
let data = {
|
||||||
let mut current_addr = driver.header;
|
let driver = self.driver.0.lock();
|
||||||
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 {
|
let e1000 = unsafe {
|
||||||
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
|
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, 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 timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
|
||||||
let mut sockets = SOCKETS.lock();
|
let mut sockets = SOCKETS.lock();
|
||||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
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 {
|
fn device_type(&self) -> DeviceType {
|
||||||
@ -130,7 +130,7 @@ impl Driver for E1000Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_ifname(&self) -> String {
|
fn get_ifname(&self) -> String {
|
||||||
format!("e1000")
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ipv4_address(&self) -> Option<Ipv4Address> {
|
fn ipv4_address(&self) -> Option<Ipv4Address> {
|
||||||
@ -184,14 +184,6 @@ impl<'a> phy::Device<'a> for E1000Driver {
|
|||||||
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||||
let driver = self.0.lock();
|
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 {
|
let e1000 = unsafe {
|
||||||
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
|
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
|
||||||
};
|
};
|
||||||
@ -237,14 +229,6 @@ impl<'a> phy::Device<'a> for E1000Driver {
|
|||||||
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
||||||
let driver = self.0.lock();
|
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 {
|
let e1000 = unsafe {
|
||||||
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
|
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
|
||||||
};
|
};
|
||||||
@ -353,8 +337,8 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// JudgeDuck-OS/kern/e1000.c
|
// JudgeDuck-OS/kern/e1000.c
|
||||||
pub fn e1000_init(header: usize, size: usize) {
|
pub fn e1000_init(name: String, irq: Option<u32>, header: usize, size: usize) {
|
||||||
info!("Probing e1000");
|
info!("Probing e1000 {}", name);
|
||||||
assert_eq!(size_of::<E1000SendDesc>(), 16);
|
assert_eq!(size_of::<E1000SendDesc>(), 16);
|
||||||
assert_eq!(size_of::<E1000RecvDesc>(), 16);
|
assert_eq!(size_of::<E1000RecvDesc>(), 16);
|
||||||
|
|
||||||
@ -386,12 +370,6 @@ pub fn e1000_init(header: usize, size: usize) {
|
|||||||
first_trans: true,
|
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<u32>, size / 4) };
|
let e1000 = unsafe { slice::from_raw_parts_mut(header as *mut Volatile<u32>, size / 4) };
|
||||||
debug!(
|
debug!(
|
||||||
"status before setup: {:#?}",
|
"status before setup: {:#?}",
|
||||||
@ -501,6 +479,8 @@ pub fn e1000_init(header: usize, size: usize) {
|
|||||||
let e1000_iface = E1000Interface {
|
let e1000_iface = E1000Interface {
|
||||||
iface: Mutex::new(iface),
|
iface: Mutex::new(iface),
|
||||||
driver: net_driver.clone(),
|
driver: net_driver.clone(),
|
||||||
|
name,
|
||||||
|
irq,
|
||||||
};
|
};
|
||||||
|
|
||||||
let driver = Arc::new(e1000_iface);
|
let driver = Arc::new(e1000_iface);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
//! Intel 10Gb Network Adapter 82599 i.e. ixgbe network driver
|
//! 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
|
//! 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::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
use isomorphic_drivers::net::ethernet::intel::ixgbe;
|
use isomorphic_drivers::net::ethernet::intel::ixgbe;
|
||||||
@ -20,7 +21,6 @@ use crate::memory::active_table;
|
|||||||
use crate::net::SOCKETS;
|
use crate::net::SOCKETS;
|
||||||
use crate::sync::FlagsGuard;
|
use crate::sync::FlagsGuard;
|
||||||
use crate::sync::SpinNoIrqLock as Mutex;
|
use crate::sync::SpinNoIrqLock as Mutex;
|
||||||
use crate::sync::{MutexGuard, SpinNoIrq};
|
|
||||||
|
|
||||||
use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
|
use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
|
||||||
|
|
||||||
@ -32,21 +32,6 @@ struct IXGBEDriver {
|
|||||||
mtu: usize,
|
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 {
|
pub struct IXGBEInterface {
|
||||||
iface: Mutex<EthernetInterface<'static, 'static, 'static, IXGBEDriver>>,
|
iface: Mutex<EthernetInterface<'static, 'static, 'static, IXGBEDriver>>,
|
||||||
driver: IXGBEDriver,
|
driver: IXGBEDriver,
|
||||||
@ -64,16 +49,6 @@ impl Driver for IXGBEInterface {
|
|||||||
|
|
||||||
let handled = {
|
let handled = {
|
||||||
let _ = FlagsGuard::no_irq_region();
|
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()
|
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)> {
|
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||||
let _ = FlagsGuard::no_irq_region();
|
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 self.inner.can_send() {
|
||||||
if let Some(data) = self.inner.recv() {
|
if let Some(data) = self.inner.recv() {
|
||||||
Some((IXGBERxToken(data), IXGBETxToken(self.clone())))
|
Some((IXGBERxToken(data), IXGBETxToken(self.clone())))
|
||||||
@ -157,15 +123,6 @@ impl<'a> phy::Device<'a> for IXGBEDriver {
|
|||||||
|
|
||||||
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
||||||
let _ = FlagsGuard::no_irq_region();
|
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 self.inner.can_send() {
|
||||||
Some(IXGBETxToken(self.clone()))
|
Some(IXGBETxToken(self.clone()))
|
||||||
} else {
|
} else {
|
||||||
@ -200,15 +157,6 @@ impl phy::TxToken for IXGBETxToken {
|
|||||||
F: FnOnce(&mut [u8]) -> Result<R>,
|
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||||
{
|
{
|
||||||
let _ = FlagsGuard::no_irq_region();
|
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 mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()];
|
||||||
let result = f(&mut buffer[..len]);
|
let result = f(&mut buffer[..len]);
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
@ -225,13 +173,6 @@ pub fn ixgbe_init(
|
|||||||
size: usize,
|
size: usize,
|
||||||
) -> Arc<IXGBEInterface> {
|
) -> Arc<IXGBEInterface> {
|
||||||
let _ = FlagsGuard::no_irq_region();
|
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);
|
let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), header, size);
|
||||||
ixgbe.enable_irq();
|
ixgbe.enable_irq();
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use alloc::alloc::{GlobalAlloc, Layout};
|
use alloc::alloc::{GlobalAlloc, Layout};
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use alloc::prelude::*;
|
use alloc::string::String;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
|
|
||||||
|
@ -37,15 +37,15 @@ lazy_static! {
|
|||||||
pub static ref ROOT_INODE: Arc<INode> = {
|
pub static ref ROOT_INODE: Arc<INode> = {
|
||||||
#[cfg(not(feature = "link_user"))]
|
#[cfg(not(feature = "link_user"))]
|
||||||
let device = {
|
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()
|
crate::drivers::BLK_DRIVERS.read().iter()
|
||||||
.next().expect("VirtIOBlk not found")
|
.next().expect("Block device not found")
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
{
|
{
|
||||||
Arc::new(ide::IDE::new(1))
|
unimplemented!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#[cfg(feature = "link_user")]
|
#[cfg(feature = "link_user")]
|
||||||
|
@ -13,13 +13,13 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult {
|
|||||||
vendor, product
|
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) {
|
if pci::detach_driver(&tag) {
|
||||||
info!("Kernel driver detached");
|
info!("Kernel driver detached");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get BAR0 memory
|
// 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 mut proc = process();
|
||||||
let virt_addr = proc.vm.find_free_area(0, len);
|
let virt_addr = proc.vm.find_free_area(0, len);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::cpu;
|
use crate::arch::cpu;
|
||||||
|
use crate::consts::USER_STACK_SIZE;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use core::sync::atomic::{AtomicI32, Ordering};
|
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 {
|
pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult {
|
||||||
const ARCH_SET_FS: i32 = 0x1002;
|
const ARCH_SET_FS: i32 = 0x1002;
|
||||||
@ -177,7 +177,7 @@ pub fn sys_prlimit64(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(0)
|
Ok(0)
|
||||||
},
|
}
|
||||||
RLIMIT_RSS | RLIMIT_AS => {
|
RLIMIT_RSS | RLIMIT_AS => {
|
||||||
if !old_limit.is_null() {
|
if !old_limit.is_null() {
|
||||||
proc.vm.check_write_ptr(old_limit)?;
|
proc.vm.check_write_ptr(old_limit)?;
|
||||||
|
2
user
2
user
@ -1 +1 @@
|
|||||||
Subproject commit 69febc9fcc64df60329687b4f24b9b5309c99adf
|
Subproject commit 97bae0c39a7aeaab07654d99c3ba3bcb4d01658c
|
Loading…
Reference in New Issue
Block a user