From e4323f808c54c26c698e770e3b2ba87655c93f2a Mon Sep 17 00:00:00 2001 From: Yuke Peng Date: Mon, 27 Feb 2023 16:18:04 +0800 Subject: [PATCH] Component initialization mechanism complete --- src/Cargo.toml | 7 +- src/Components.toml | 2 + src/framework/jinux-frame/src/lib.rs | 17 ++ src/framework/jinux-frame/src/linker.ld | 11 + src/jinux-boot/src/main.rs | 7 +- .../comp-sys/component-macro/Cargo.toml | 19 ++ .../comp-sys/component-macro/src/init_comp.rs | 33 +++ .../comp-sys/component-macro/src/lib.rs | 83 +++++++ .../comp-sys/component-macro/src/priority.rs | 215 ++++++++++++++++++ src/services/comp-sys/component/Cargo.toml | 14 ++ src/services/comp-sys/component/README.md | 57 +++++ src/services/comp-sys/component/src/lib.rs | 178 +++++++++++++++ .../component/tests/kernel/Cargo.toml | 17 ++ .../component/tests/kernel/Components.toml | 5 + .../component/tests/kernel/bar/Cargo.toml | 10 + .../component/tests/kernel/bar/src/lib.rs | 13 ++ .../component/tests/kernel/foo/Cargo.toml | 15 ++ .../component/tests/kernel/foo/src/lib.rs | 15 ++ .../component/tests/kernel/foo/tests/test.rs | 9 + .../component/tests/kernel/src/main.rs | 19 ++ .../component/tests/kernel/tests/test.rs | 17 ++ src/services/comps/block/Cargo.toml | 24 ++ src/services/comps/block/src/lib.rs | 71 ++++++ src/services/comps/block/src/virtio.rs | 54 +++++ src/services/comps/input/Cargo.toml | 25 ++ src/services/comps/input/src/lib.rs | 90 ++++++++ src/services/comps/input/src/virtio.rs | 122 ++++++++++ src/services/comps/jinux-pci/src/lib.rs | 64 ------ .../comps/{jinux-pci => pci}/Cargo.toml | 3 +- .../{jinux-pci => pci}/src/capability/exp.rs | 0 .../{jinux-pci => pci}/src/capability/mod.rs | 0 .../{jinux-pci => pci}/src/capability/msi.rs | 0 .../{jinux-pci => pci}/src/capability/msix.rs | 0 .../{jinux-pci => pci}/src/capability/pm.rs | 0 .../{jinux-pci => pci}/src/capability/sata.rs | 0 .../src/capability/vendor/mod.rs | 0 .../src/capability/vendor/virtio.rs | 0 src/services/comps/pci/src/lib.rs | 86 +++++++ .../comps/{jinux-pci => pci}/src/msix.rs | 0 .../comps/{jinux-pci => pci}/src/util.rs | 0 .../comps/{jinux-virtio => virtio}/Cargo.toml | 7 +- .../src/device/block/device.rs | 64 +++++- .../src/device/block/mod.rs | 0 .../src/device/input/device.rs | 0 .../src/device/input/mod.rs | 0 .../src/device/mod.rs | 1 + .../comps/{jinux-virtio => virtio}/src/lib.rs | 113 ++++++++- .../{jinux-virtio => virtio}/src/queue.rs | 48 +++- src/services/libs/jinux-std/Cargo.toml | 4 +- src/services/libs/jinux-std/src/driver/mod.rs | 27 ++- .../libs/jinux-std/src/driver/pci/mod.rs | 21 -- .../jinux-std/src/driver/pci/virtio/block.rs | 106 --------- .../jinux-std/src/driver/pci/virtio/input.rs | 182 --------------- .../jinux-std/src/driver/pci/virtio/mod.rs | 10 - .../src/process/posix_thread/robust_list.rs | 2 +- src/src/main.rs | 2 +- 56 files changed, 1473 insertions(+), 416 deletions(-) create mode 100644 src/services/comp-sys/component-macro/Cargo.toml create mode 100644 src/services/comp-sys/component-macro/src/init_comp.rs create mode 100644 src/services/comp-sys/component-macro/src/lib.rs create mode 100644 src/services/comp-sys/component-macro/src/priority.rs create mode 100644 src/services/comp-sys/component/Cargo.toml create mode 100644 src/services/comp-sys/component/README.md create mode 100644 src/services/comp-sys/component/src/lib.rs create mode 100644 src/services/comp-sys/component/tests/kernel/Cargo.toml create mode 100644 src/services/comp-sys/component/tests/kernel/Components.toml create mode 100644 src/services/comp-sys/component/tests/kernel/bar/Cargo.toml create mode 100644 src/services/comp-sys/component/tests/kernel/bar/src/lib.rs create mode 100644 src/services/comp-sys/component/tests/kernel/foo/Cargo.toml create mode 100644 src/services/comp-sys/component/tests/kernel/foo/src/lib.rs create mode 100644 src/services/comp-sys/component/tests/kernel/foo/tests/test.rs create mode 100644 src/services/comp-sys/component/tests/kernel/src/main.rs create mode 100644 src/services/comp-sys/component/tests/kernel/tests/test.rs create mode 100644 src/services/comps/block/Cargo.toml create mode 100644 src/services/comps/block/src/lib.rs create mode 100644 src/services/comps/block/src/virtio.rs create mode 100644 src/services/comps/input/Cargo.toml create mode 100644 src/services/comps/input/src/lib.rs create mode 100644 src/services/comps/input/src/virtio.rs delete mode 100644 src/services/comps/jinux-pci/src/lib.rs rename src/services/comps/{jinux-pci => pci}/Cargo.toml (89%) rename src/services/comps/{jinux-pci => pci}/src/capability/exp.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/capability/mod.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/capability/msi.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/capability/msix.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/capability/pm.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/capability/sata.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/capability/vendor/mod.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/capability/vendor/virtio.rs (100%) create mode 100644 src/services/comps/pci/src/lib.rs rename src/services/comps/{jinux-pci => pci}/src/msix.rs (100%) rename src/services/comps/{jinux-pci => pci}/src/util.rs (100%) rename src/services/comps/{jinux-virtio => virtio}/Cargo.toml (83%) rename src/services/comps/{jinux-virtio => virtio}/src/device/block/device.rs (70%) rename src/services/comps/{jinux-virtio => virtio}/src/device/block/mod.rs (100%) rename src/services/comps/{jinux-virtio => virtio}/src/device/input/device.rs (100%) rename src/services/comps/{jinux-virtio => virtio}/src/device/input/mod.rs (100%) rename src/services/comps/{jinux-virtio => virtio}/src/device/mod.rs (99%) rename src/services/comps/{jinux-virtio => virtio}/src/lib.rs (72%) rename src/services/comps/{jinux-virtio => virtio}/src/queue.rs (87%) delete mode 100644 src/services/libs/jinux-std/src/driver/pci/mod.rs delete mode 100644 src/services/libs/jinux-std/src/driver/pci/virtio/block.rs delete mode 100644 src/services/libs/jinux-std/src/driver/pci/virtio/input.rs delete mode 100644 src/services/libs/jinux-std/src/driver/pci/virtio/mod.rs diff --git a/src/Cargo.toml b/src/Cargo.toml index b285c0bc8..6c03e61e0 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bootloader = {version="0.10.12"} jinux-frame = {path = "framework/jinux-frame"} jinux-std = {path = "services/libs/jinux-std"} +component = {path = "services/comp-sys/component"} [workspace] @@ -15,8 +16,10 @@ members = [ "framework/jinux-frame", "framework/pod", "framework/pod-derive", - "services/comps/jinux-pci", - "services/comps/jinux-virtio", + "services/comps/pci", + "services/comps/virtio", + "services/comps/input", + "services/comps/block", "services/libs/jinux-std", "services/libs/jinux-rights-proc", "services/libs/typeflags", diff --git a/src/Components.toml b/src/Components.toml index 76498fc93..312b03114 100644 --- a/src/Components.toml +++ b/src/Components.toml @@ -3,6 +3,8 @@ std = { name = "jinux-std" } pci = { name = "jinux-pci" } virtio = { name = "jinux-virtio"} +input = { name = "jinux-input"} +block = { name = "jinux-block"} main = { name = "jinux" } [whitelist] diff --git a/src/framework/jinux-frame/src/lib.rs b/src/framework/jinux-frame/src/lib.rs index b93849a19..9592751df 100644 --- a/src/framework/jinux-frame/src/lib.rs +++ b/src/framework/jinux-frame/src/lib.rs @@ -100,7 +100,24 @@ pub fn init(boot_info: &'static mut BootInfo) { } let value = x86_64_util::cpuid(1); } + invoke_c_init_funcs(); } + +fn invoke_c_init_funcs() { + extern "C" { + fn sinit_array(); + fn einit_array(); + } + let call_len = (einit_array as u64 - sinit_array as u64) / 8; + for i in 0..call_len { + unsafe { + let address = (sinit_array as u64 + 8 * i) as *const u64; + let function = address as *const fn(); + (*function)(); + } + } +} + fn general_handler(trap_frame: &TrapFrame) { // info!("general handler"); // println!("{:#x?}", trap_frame); diff --git a/src/framework/jinux-frame/src/linker.ld b/src/framework/jinux-frame/src/linker.ld index a641c122f..8a60c924f 100644 --- a/src/framework/jinux-frame/src/linker.ld +++ b/src/framework/jinux-frame/src/linker.ld @@ -9,6 +9,17 @@ SECTIONS { *(.rodata .rodata.*) } + .got ALIGN(4K):{ + *(.got .got.*) + } + + . = ALIGN(4K); + sinit_array = .; + .init_array : { + *(.init_array .init_array.*) + } + einit_array = .; + .text ALIGN(4K): { *(.text .text.*) } diff --git a/src/jinux-boot/src/main.rs b/src/jinux-boot/src/main.rs index 0897962fb..86e91d45b 100644 --- a/src/jinux-boot/src/main.rs +++ b/src/jinux-boot/src/main.rs @@ -46,7 +46,9 @@ fn main() -> anyhow::Result<()> { println!("Created disk image at `{}`", bios.display()); return Ok(()); } - + #[cfg(windows)] + let mut run_cmd = Command::new("qemu-system-x86_64.exe"); + #[cfg(not(windows))] let mut run_cmd = Command::new("qemu-system-x86_64"); run_cmd .arg("-drive") @@ -80,6 +82,9 @@ fn main() -> anyhow::Result<()> { fn create_fs_image(path: &Path) -> anyhow::Result { let mut fs_img_path = path.parent().unwrap().to_str().unwrap().to_string(); + #[cfg(windows)] + fs_img_path.push_str("\\fs.img"); + #[cfg(not(windows))] fs_img_path.push_str("/fs.img"); let path = Path::new(fs_img_path.as_str()); if path.exists() { diff --git a/src/services/comp-sys/component-macro/Cargo.toml b/src/services/comp-sys/component-macro/Cargo.toml new file mode 100644 index 000000000..91edb6b89 --- /dev/null +++ b/src/services/comp-sys/component-macro/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "component-macro" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0" +quote = "1.0" +syn = "1.0.104" +itertools = "0.10.5" +toml = "0.7.2" + +[dependencies.json] +version = "0.12.4" diff --git a/src/services/comp-sys/component-macro/src/init_comp.rs b/src/services/comp-sys/component-macro/src/init_comp.rs new file mode 100644 index 000000000..4f3f6624d --- /dev/null +++ b/src/services/comp-sys/component-macro/src/init_comp.rs @@ -0,0 +1,33 @@ +use proc_macro2::{TokenStream, TokenTree}; +use quote::{ToTokens, TokenStreamExt}; +use syn::parse::Parse; + +/// The content inside typeflag macro +pub struct ComponentInitFunction { + function: Vec, + pub function_name: TokenTree, +} + +impl Parse for ComponentInitFunction { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let mut vec: Vec = Vec::new(); + vec.push(input.parse().unwrap()); + let function_name: TokenTree = input.parse().unwrap(); + vec.push(function_name.clone()); + while !input.is_empty() { + vec.push(input.parse().unwrap()) + } + Ok(ComponentInitFunction { + function: vec, + function_name, + }) + } +} + +impl ToTokens for ComponentInitFunction { + fn to_tokens(&self, tokens: &mut TokenStream) { + for token in &self.function { + tokens.append(token.clone()); + } + } +} diff --git a/src/services/comp-sys/component-macro/src/lib.rs b/src/services/comp-sys/component-macro/src/lib.rs new file mode 100644 index 000000000..19bbdc2cb --- /dev/null +++ b/src/services/comp-sys/component-macro/src/lib.rs @@ -0,0 +1,83 @@ +//!This crate defines the component system related macros. +//! + +#![feature(proc_macro_diagnostic)] +#![allow(dead_code)] +#![forbid(unsafe_code)] + +mod init_comp; +mod priority; + +use init_comp::ComponentInitFunction; +use proc_macro::TokenStream; +use quote::quote; +use syn::parse_macro_input; + +pub(crate) const COMPONENT_FILE_NAME: &str = "Components.toml"; + +/// Register a function to be called when the component system is initialized. The function should not public. +/// +/// Example: +/// ```rust +/// #[init_component] +/// fn init() -> Result<(), component::ComponentInitError> { +/// Ok(()) +/// } +/// +/// ``` +/// +/// It will expand to +/// ```rust +/// fn init() -> Result<(), component::ComponentInitError> { +/// Ok(()) +/// } +/// +/// const fn file() -> &'static str{ +/// file!() +/// } +/// +/// component::submit!(component::ComponentRegistry::new(&init,file())); +/// ``` +/// The priority will calculate automatically +/// +#[proc_macro_attribute] +pub fn init_component(_: TokenStream, input: TokenStream) -> proc_macro::TokenStream { + let function = parse_macro_input!(input as ComponentInitFunction); + let function_name = &function.function_name; + quote! { + #function + + const fn file() -> &'static str{ + file!() + } + + component::submit!(component::ComponentRegistry::new(&#function_name,file())); + } + .into() +} + +/// Automatically generate all component information required by the component system. +/// +/// It is often used with `component::init`. +/// +/// Example: +/// +/// ```rust +/// component::init(component::component_generate!()); +/// ``` +/// +#[proc_macro] +pub fn generate_information(_: TokenStream) -> proc_macro::TokenStream { + let out = priority::component_generate(); + let path = priority::get_component_toml_path(); + quote! { + { + include_str!(#path); + extern crate alloc; + alloc::vec![ + #(component::ComponentInfo::new #out),* + ] + } + } + .into() +} diff --git a/src/services/comp-sys/component-macro/src/priority.rs b/src/services/comp-sys/component-macro/src/priority.rs new file mode 100644 index 000000000..39ff5af62 --- /dev/null +++ b/src/services/comp-sys/component-macro/src/priority.rs @@ -0,0 +1,215 @@ +use std::{collections::HashMap, fs::File, io::Read, ops::Add, process::Command, str::FromStr}; + +use json::JsonValue; +use proc_macro2::{Group, TokenStream}; +use quote::{ToTokens, TokenStreamExt}; + +use crate::COMPONENT_FILE_NAME; + +#[derive(Debug)] +pub struct ComponentInfo { + name: String, + path: String, + priority: u16, +} + +impl ToTokens for ComponentInfo { + fn to_tokens(&self, tokens: &mut TokenStream) { + let token = TokenStream::from_str( + format!("\"{}\",\"{}\",{}", self.name, self.path, self.priority).as_str(), + ) + .unwrap(); + tokens.append(Group::new(proc_macro2::Delimiter::Parenthesis, token)); + } +} + +/// Automatic generate all the component information +pub fn component_generate() -> Vec { + // extract components information + let mut metadata = metadata(); + + let mut component_packages = vec![]; + let workspace_root = metadata["workspace_root"].as_str().unwrap(); + let workspace_root = String::from_str(workspace_root).unwrap().replace("\\", "/"); + + let comps_name = get_components_name(&workspace_root, &metadata["packages"]); + for package in metadata["packages"].members_mut() { + let name = package["name"].as_str().unwrap(); + if comps_name.contains(&name.to_string()) { + // remove useless depend + let mut depends = JsonValue::Array(Vec::new()); + loop { + let depend = package["dependencies"].pop(); + if depend == JsonValue::Null { + break; + } + if comps_name.contains(&depend["name"].as_str().unwrap().to_string()) { + depends.push(depend).unwrap(); + } + } + package["dependencies"] = depends; + component_packages.push(package); + } + } + + // calculate priority + let mut mapping: HashMap = HashMap::new(); + let mut component_packages_map: HashMap = HashMap::new(); + for i in component_packages.iter_mut() { + component_packages_map.insert(i["name"].as_str().unwrap().to_string(), i); + } + + for (name, package) in component_packages_map.iter() { + if mapping.contains_key(package["name"].as_str().unwrap()) { + continue; + } + calculate_priority(&mut mapping, &component_packages_map, name.clone()); + } + drop(component_packages_map); + + // priority calculation complete + let mut components_info = Vec::new(); + for package in component_packages { + let temp_id = package["id"].as_str().unwrap(); + // extract path, let's take `(path+file:///path/to/comps/pci)` as an example + let path = { + // use the last element, `pci)` + let mut paths: Vec<&str> = temp_id.split(&workspace_root).collect(); + // remove the last character + let mut path1 = paths.pop().unwrap().to_string(); + path1.pop(); + if path1.starts_with("/") { + path1.remove(0); + } + path1 + }; + let component_info = ComponentInfo { + name: package["name"].as_str().unwrap().to_string(), + path: path.to_owned(), + priority: *mapping + .get(&package["name"].as_str().unwrap().to_string()) + .unwrap(), + }; + components_info.push(component_info) + } + components_info +} + +/// Get the path to the Components.toml file +pub fn get_component_toml_path() -> TokenStream { + let metadata = metadata(); + let workspace_root = metadata["workspace_root"].as_str().unwrap(); + let mut workspace_root = String::from_str(workspace_root) + .unwrap() + .replace("\\", "/") + .add("/") + .add(COMPONENT_FILE_NAME) + .add("\""); + workspace_root.insert(0, '\"'); + TokenStream::from_str(workspace_root.as_str()).unwrap() +} + +fn is_component(package: &JsonValue) -> bool { + for depend in package["dependencies"].members() { + if depend["name"].as_str().unwrap() == "component" { + return true; + } + } + false +} + +/// Get all the components name, this function will also check if the Components.toml contain all the components. +fn get_components_name(workspace_root: &String, packages: &JsonValue) -> Vec { + let file_components_name = read_component_file(workspace_root); + let mut comps_name = Vec::new(); + for package in packages.members() { + if is_component(package) { + if !file_components_name.contains(&package["name"].as_str().unwrap().to_string()) { + // if the package is in the workspace_root + if package["id"].as_str().unwrap().contains(workspace_root) { + panic!( + "Package {} in the workspace that not written in the {} file", + package["name"].as_str().unwrap(), + COMPONENT_FILE_NAME + ); + } + } + comps_name.push(package["name"].as_str().unwrap().to_string()); + } + } + comps_name +} + +/// read component file, return all the components name +fn read_component_file(workspace_root: &String) -> Vec { + let component_toml: toml::Value = { + let mut component_file_path = workspace_root.clone(); + component_file_path.push_str("/"); + component_file_path.push_str(COMPONENT_FILE_NAME); + let mut file = File::open(component_file_path) + .expect("Components.toml file not found, please check if the file exists"); + let mut str_val = String::new(); + file.read_to_string(&mut str_val).unwrap(); + toml::from_str(&str_val).unwrap() + }; + for (name, value) in component_toml.as_table().unwrap() { + if name.as_str() == "components" { + return value + .as_table() + .unwrap() + .values() + .map(|value| { + value + .as_table() + .unwrap() + .values() + .map(|str_val| str_val.as_str().unwrap().to_string()) + .collect() + }) + .collect(); + } + } + panic!("Componets.toml file not valid") +} + +/// calculate the priority of one node +fn calculate_priority( + prioritys: &mut HashMap, + package_mapping: &HashMap, + node_name: String, +) -> u16 { + if prioritys.contains_key(&node_name) { + return prioritys.get(&node_name).unwrap().clone(); + } + + let package = &package_mapping[&node_name]; + let mut lowest_priority: u16 = 0; + for depends in package["dependencies"].members() { + lowest_priority = lowest_priority.max( + calculate_priority( + prioritys, + package_mapping, + depends["name"].as_str().unwrap().to_string(), + ) + 1, + ); + } + + prioritys.insert(node_name.to_string(), lowest_priority); + lowest_priority +} + +fn metadata() -> json::JsonValue { + let mut cmd = Command::new(env!("CARGO")); + cmd.arg("metadata"); + cmd.arg("--format-version").arg("1"); + let output = cmd.output().unwrap(); + + if !output.status.success() { + panic!("cannot get metadata"); + } + + let output = String::from_utf8(output.stdout).unwrap(); + let parsed = json::parse(&output).unwrap(); + + parsed +} diff --git a/src/services/comp-sys/component/Cargo.toml b/src/services/comp-sys/component/Cargo.toml new file mode 100644 index 000000000..08561cb6a --- /dev/null +++ b/src/services/comp-sys/component/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "component" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +inventory = {git="https://github.com/sdww0/inventory"} +log = "0.4" +component-macro = {path = "../component-macro"} + +[build-dependencies] +json= "0.12.4" diff --git a/src/services/comp-sys/component/README.md b/src/services/comp-sys/component/README.md new file mode 100644 index 000000000..f50c29244 --- /dev/null +++ b/src/services/comp-sys/component/README.md @@ -0,0 +1,57 @@ +# Component + +## Overview +This crate is used for the initialization of the component system, which provides a priority initialization scheme based on the inventory crate. + +## Usage + +### Register component + +Registering a crate as component by marking a function in the lib.rs with `#[init_component]` macro. The specific definition of the function can refer to the comments in the macro. + +### Component initialization + +Component system need to be initialized by calling `componet::init` function and it needs information about all components. Usually it is used with the `component::generate_information` macro. + +## Example + +```rust +// comp1/lib.rs +use std::sync::atomic::AtomicU16; +use std::sync::atomic::Ordering::Relaxed; + +use component::init_component; + +pub static INIT_COUNT : AtomicU16 = AtomicU16::new(0); + +#[init_component] +fn comp1_init() -> Result<(), component::ComponentInitError> { + assert_eq!(INIT_COUNT.load(Relaxed),0); + INIT_COUNT.fetch_add(1,Relaxed); + Ok(()) +} + +// src/main.rs +use std::sync::atomic::Ordering::Relaxed; + +use component::init_component; +use comp1::INIT_COUNT; + +#[init_component] +fn init() -> Result<(), component::ComponentInitError> { + assert_eq!(INIT_COUNT.load(Relaxed),1); + INIT_COUNT.fetch_add(1,Relaxed); + Ok(()) +} + +fn main(){ + component::init(component::generate_information!()).unwrap(); + assert_eq!(INIT_COUNT.load(Relaxed),2); +} +``` + +## Notes + +- Currently, initialization requires the presence of a `Components.toml` file, which stores some information about components and access control. The [tests](tests/kernel/Components.toml) provides a sample file of it. If the components declared inside `Components.toml` is inconsistent with the component found by `generate_information` macro (i.e. A crate depends on the component library but is not declared in `Components.toml`), then a compilation error will occur. + +- The `generate_information` macro will generate the information of all components. But ultimately which functions are called still depends on which `#[init_component]` macros are extended. If you want to test a component. Then, other components with a lower priority than it or other unused high-priority components will not be initialized at runtime. diff --git a/src/services/comp-sys/component/src/lib.rs b/src/services/comp-sys/component/src/lib.rs new file mode 100644 index 000000000..d82653208 --- /dev/null +++ b/src/services/comp-sys/component/src/lib.rs @@ -0,0 +1,178 @@ +//! Component system +//! + +#![no_std] +#![forbid(unsafe_code)] +#![feature(fn_traits)] +#![feature(once_cell)] + +extern crate alloc; + +use alloc::collections::BTreeMap; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use alloc::{borrow::ToOwned, fmt::Debug}; +use log::{debug, error, info}; + +pub use component_macro::*; +pub use inventory::submit; + +#[derive(Debug)] +pub enum ComponentInitError { + UninitializedDependencies(String), + Unknown, +} + +pub struct ComponentRegistry { + function: &'static (dyn Fn() -> Result<(), ComponentInitError> + Sync), + path: &'static str, +} + +impl ComponentRegistry { + pub const fn new( + function: &'static (dyn Fn() -> Result<(), ComponentInitError> + Sync), + path: &'static str, + ) -> Self { + Self { function, path } + } +} + +inventory::collect!(ComponentRegistry); + +impl Debug for ComponentRegistry { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ComponentRegistry") + .field("path", &self.path) + .finish() + } +} + +pub struct ComponentInfo { + name: String, + path: String, + priority: u32, + function: Option<&'static (dyn Fn() -> Result<(), ComponentInitError> + Sync)>, +} + +impl ComponentInfo { + pub fn new(name: &str, path: &str, priority: u32) -> Self { + Self { + name: name.to_string(), + path: path.to_string(), + priority, + function: None, + } + } +} + +impl PartialEq for ComponentInfo { + fn eq(&self, other: &Self) -> bool { + self.priority == other.priority + } +} + +impl PartialOrd for ComponentInfo { + fn partial_cmp(&self, other: &Self) -> Option { + self.priority.partial_cmp(&other.priority) + } +} + +impl Eq for ComponentInfo {} +impl Ord for ComponentInfo { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.priority.cmp(&other.priority) + } +} + +impl Debug for ComponentInfo { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ComponentInfo") + .field("name", &self.name) + .field("path", &self.path) + .field("priority", &self.priority) + .finish() + } +} + +#[derive(Debug)] +pub enum ComponentSystemInitError { + FileNotValid, + NotIncludeAllComponent(String), +} + +/// Component system initialization. It will collect invoke all functions that are marked by init_component based on dependencies between crates. +/// +/// The collection of ComponentInfo usually generate by `component_generate` macro. +/// +/// ```rust +/// component::init(component::component_generate!()); +/// ``` +/// +pub fn init(components: Vec) -> Result<(), ComponentSystemInitError> { + let components_info = parse_input(components); + match_and_call(components_info)?; + Ok(()) +} + +fn parse_input(components: Vec) -> BTreeMap { + debug!("All component:{components:?}"); + let mut out = BTreeMap::new(); + for component in components { + out.insert(component.path.clone(), component); + } + out +} + +/// Match the ComponetInfo with ComponentRegistry. The key is the relative path of one component +fn match_and_call( + mut components: BTreeMap, +) -> Result<(), ComponentSystemInitError> { + let mut infos = Vec::new(); + for registry in inventory::iter:: { + // relative/path/to/comps/pci/src/lib.rs + let mut str: String = registry.path.to_owned(); + str = str.replace("\\", "/"); + // relative/path/to/comps/pci + // There are two cases, one in the test folder and one in the src folder. + // There may be multiple directories within the folder. + // There we assume it will not have such directories: 'comp1/src/comp2/src/lib.rs' so that we can split by tests or src string + if str.contains("src/") { + str = str + .trim_end_matches(str.get(str.find("src/").unwrap()..str.len()).unwrap()) + .to_string(); + } else if str.contains("tests/") { + str = str + .trim_end_matches(str.get(str.find("tests/").unwrap()..str.len()).unwrap()) + .to_string(); + } else { + panic!("The path of {} cannot recognized by component system", str); + } + str = str.trim_end_matches("/").to_owned(); + + let mut info = components + .remove(&str) + .ok_or(ComponentSystemInitError::NotIncludeAllComponent(str))?; + info.function.replace(registry.function); + infos.push(info); + } + + debug!("Remain componets:{components:?}"); + + if components.len() != 0 { + info!("Exists components that are not initialized"); + } + + infos.sort(); + info!("Components initializing..."); + + for i in infos { + info!("Component initializing:{:?}", i); + if let Err(res) = i.function.unwrap().call(()) { + error!("Component initalize error:{:?}", res); + } else { + info!("Component initalize complete"); + } + } + info!("All components initalization completed"); + Ok(()) +} diff --git a/src/services/comp-sys/component/tests/kernel/Cargo.toml b/src/services/comp-sys/component/tests/kernel/Cargo.toml new file mode 100644 index 000000000..dfa9df896 --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "kernel" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +component = {path="../../../component"} +foo = {path="foo"} +bar = {path="bar"} +simple_logger = "4.0.0" +log = "0.4" + +[workspace] +foo = {path="foo"} +bar = {path="bar"} diff --git a/src/services/comp-sys/component/tests/kernel/Components.toml b/src/services/comp-sys/component/tests/kernel/Components.toml new file mode 100644 index 000000000..bd3f3c1dc --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/Components.toml @@ -0,0 +1,5 @@ +# template +[components] +kernel = {name = "kernel"} +foo = {name = "foo"} +bar = {name = "bar"} diff --git a/src/services/comp-sys/component/tests/kernel/bar/Cargo.toml b/src/services/comp-sys/component/tests/kernel/bar/Cargo.toml new file mode 100644 index 000000000..f3a793d66 --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/bar/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bar" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +component = {path="../../../../component"} + diff --git a/src/services/comp-sys/component/tests/kernel/bar/src/lib.rs b/src/services/comp-sys/component/tests/kernel/bar/src/lib.rs new file mode 100644 index 000000000..4504a34b1 --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/bar/src/lib.rs @@ -0,0 +1,13 @@ +use std::sync::atomic::AtomicU16; +use std::sync::atomic::Ordering::Relaxed; + +use component::init_component; + +pub static INIT_COUNT: AtomicU16 = AtomicU16::new(0); + +#[init_component] +fn bar_init() -> Result<(), component::ComponentInitError> { + assert_eq!(INIT_COUNT.load(Relaxed), 0); + INIT_COUNT.fetch_add(1, Relaxed); + Ok(()) +} diff --git a/src/services/comp-sys/component/tests/kernel/foo/Cargo.toml b/src/services/comp-sys/component/tests/kernel/foo/Cargo.toml new file mode 100644 index 000000000..dd4594f57 --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/foo/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "foo" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +component = {path="../../../../component"} +bar = {path = "../bar"} +log = "0.4" + +[dev-dependencies] +simple_logger = "4.0.0" + diff --git a/src/services/comp-sys/component/tests/kernel/foo/src/lib.rs b/src/services/comp-sys/component/tests/kernel/foo/src/lib.rs new file mode 100644 index 000000000..a6b30fba0 --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/foo/src/lib.rs @@ -0,0 +1,15 @@ +use std::sync::atomic::Ordering::Relaxed; +use std::sync::Once; + +use bar::INIT_COUNT; +use component::init_component; + +pub static FOO_VALUE: Once = Once::new(); + +#[init_component] +fn foo_init() -> Result<(), component::ComponentInitError> { + assert_eq!(INIT_COUNT.load(Relaxed), 1); + INIT_COUNT.fetch_add(1, Relaxed); + FOO_VALUE.call_once(|| {}); + Ok(()) +} diff --git a/src/services/comp-sys/component/tests/kernel/foo/tests/test.rs b/src/services/comp-sys/component/tests/kernel/foo/tests/test.rs new file mode 100644 index 000000000..4c236437d --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/foo/tests/test.rs @@ -0,0 +1,9 @@ +use bar::INIT_COUNT; +use std::sync::atomic::Ordering::Relaxed; + +#[test] +fn test() { + simple_logger::init_with_level(log::Level::Debug).unwrap(); + component::init(component::generate_information!()).unwrap(); + assert_eq!(INIT_COUNT.load(Relaxed), 1); +} diff --git a/src/services/comp-sys/component/tests/kernel/src/main.rs b/src/services/comp-sys/component/tests/kernel/src/main.rs new file mode 100644 index 000000000..ce137092b --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/src/main.rs @@ -0,0 +1,19 @@ +use std::sync::atomic::Ordering::Relaxed; + +use bar::INIT_COUNT; +use component::init_component; +use foo::FOO_VALUE; + +#[init_component] +fn kernel_init() -> Result<(), component::ComponentInitError> { + assert_eq!(INIT_COUNT.load(Relaxed), 2); + assert!(FOO_VALUE.is_completed()); + INIT_COUNT.fetch_add(1, Relaxed); + Ok(()) +} + +fn main() { + simple_logger::init_with_level(log::Level::Info).unwrap(); + component::init(component::generate_information!()).unwrap(); + assert_eq!(INIT_COUNT.load(Relaxed), 3); +} diff --git a/src/services/comp-sys/component/tests/kernel/tests/test.rs b/src/services/comp-sys/component/tests/kernel/tests/test.rs new file mode 100644 index 000000000..0f53abace --- /dev/null +++ b/src/services/comp-sys/component/tests/kernel/tests/test.rs @@ -0,0 +1,17 @@ +use bar::INIT_COUNT; +use component::init_component; +use std::sync::atomic::Ordering::Relaxed; + +#[init_component] +fn kernel_init() -> Result<(), component::ComponentInitError> { + assert_eq!(INIT_COUNT.load(Relaxed), 1); + INIT_COUNT.fetch_add(1, Relaxed); + Ok(()) +} + +#[test] +fn test() { + simple_logger::init_with_level(log::Level::Debug).unwrap(); + component::init(component::generate_information!()).unwrap(); + assert_eq!(INIT_COUNT.load(Relaxed), 2); +} diff --git a/src/services/comps/block/Cargo.toml b/src/services/comps/block/Cargo.toml new file mode 100644 index 000000000..f6138f1dd --- /dev/null +++ b/src/services/comps/block/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "jinux-block" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bitflags = "1.3" +spin = "0.9.4" +jinux-frame = {path = "../../../framework/jinux-frame"} +jinux-pci = {path="../pci"} +jinux-virtio = {path="../virtio"} +jinux-util = {path="../../libs/jinux-util"} +pod = {path = "../../../framework/pod"} +pod-derive = {path = "../../../framework/pod-derive"} +component = {path="../../comp-sys/component"} +log = "0.4" + +[features] + +[dependencies.lazy_static] +version = "1.0" +features = ["spin_no_std"] diff --git a/src/services/comps/block/src/lib.rs b/src/services/comps/block/src/lib.rs new file mode 100644 index 000000000..ef7cc1a3c --- /dev/null +++ b/src/services/comps/block/src/lib.rs @@ -0,0 +1,71 @@ +//! The block device of jinux +#![no_std] +#![forbid(unsafe_code)] +#![feature(fn_traits)] + +mod virtio; + +extern crate alloc; + +use core::any::Any; + +use alloc::string::ToString; +use alloc::sync::Arc; +use component::init_component; +use component::ComponentInitError; +use jinux_virtio::VirtioDeviceType; +use spin::Once; +use virtio::VirtioBlockDevice; + +pub const BLK_SIZE: usize = 512; + +pub trait BlockDevice: Send + Sync + Any { + fn init(&self) {} + fn read_block(&self, block_id: usize, buf: &mut [u8]); + fn write_block(&self, block_id: usize, buf: &[u8]); + fn handle_irq(&self); +} + +pub static BLK_COMPONENT: Once = Once::new(); + +#[init_component] +fn blk_component_init() -> Result<(), ComponentInitError> { + let a = BLKComponent::init()?; + BLK_COMPONENT.call_once(|| a); + Ok(()) +} + +pub struct BLKComponent { + /// Input device map, key is the irq number, value is the Input device + blk_device: Arc, +} + +impl BLKComponent { + pub fn init() -> Result { + let virtio = jinux_virtio::VIRTIO_COMPONENT.get().unwrap(); + let devices = virtio.get_device(VirtioDeviceType::Block); + for device in devices { + let v_device = VirtioBlockDevice::new(device); + return Ok(Self { + blk_device: Arc::new(v_device), + }); + } + Err(ComponentInitError::UninitializedDependencies( + "Virtio".to_string(), + )) + } + + pub const fn name() -> &'static str { + "Block device" + } + // 0~65535 + pub const fn priority() -> u16 { + 8192 + } +} + +impl BLKComponent { + pub fn get_device(self: &Self) -> Arc { + self.blk_device.clone() + } +} diff --git a/src/services/comps/block/src/virtio.rs b/src/services/comps/block/src/virtio.rs new file mode 100644 index 000000000..5e5d6d694 --- /dev/null +++ b/src/services/comps/block/src/virtio.rs @@ -0,0 +1,54 @@ +//! Block device based on Virtio + +use jinux_frame::TrapFrame; +use jinux_pci::msix::MSIX; +use jinux_util::frame_ptr::InFramePtr; +use jinux_virtio::{device::block::device::BLKDevice, PCIVirtioDevice, VitrioPciCommonCfg}; +use log::debug; +use spin::Mutex; + +use crate::{BlockDevice, BLK_COMPONENT}; + +pub struct VirtioBlockDevice { + blk_device: Mutex, + pub common_cfg: InFramePtr, + msix: MSIX, +} + +impl BlockDevice for VirtioBlockDevice { + fn read_block(&self, block_id: usize, buf: &mut [u8]) { + self.blk_device.lock().read_block(block_id, buf); + } + + /// it is blocking now + fn write_block(&self, block_id: usize, buf: &[u8]) { + self.blk_device.lock().write_block(block_id, buf); + } + + fn handle_irq(&self) { + debug!("block device handle irq"); + } +} + +impl VirtioBlockDevice { + pub(crate) fn new(mut virtio_device: PCIVirtioDevice) -> Self { + fn handle_block_device(_: &TrapFrame) { + BLK_COMPONENT.get().unwrap().blk_device.handle_irq() + } + fn config_space_change(_: &TrapFrame) { + debug!("block device config space change"); + } + virtio_device.register_interrupt_functions(&config_space_change, &handle_block_device); + let blk_device = Mutex::new(match virtio_device.device { + jinux_virtio::device::VirtioDevice::Block(blk) => blk, + _ => { + panic!("Error when creating new block device, the input device is other type of virtio device"); + } + }); + Self { + blk_device, + common_cfg: virtio_device.common_cfg, + msix: virtio_device.msix, + } + } +} diff --git a/src/services/comps/input/Cargo.toml b/src/services/comps/input/Cargo.toml new file mode 100644 index 000000000..a67db2946 --- /dev/null +++ b/src/services/comps/input/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "jinux-input" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bitflags = "1.3" +spin = "0.9.4" +jinux-frame = {path = "../../../framework/jinux-frame"} +jinux-pci = {path="../pci"} +jinux-virtio = {path="../virtio"} +jinux-util = {path="../../libs/jinux-util"} +pod = {path = "../../../framework/pod"} +pod-derive = {path = "../../../framework/pod-derive"} +component = {path="../../comp-sys/component"} +virtio-input-decoder = "0.1.4" +log = "0.4" + +[features] + +[dependencies.lazy_static] +version = "1.0" +features = ["spin_no_std"] diff --git a/src/services/comps/input/src/lib.rs b/src/services/comps/input/src/lib.rs new file mode 100644 index 000000000..8f987250d --- /dev/null +++ b/src/services/comps/input/src/lib.rs @@ -0,0 +1,90 @@ +//! The input device of jinux +#![no_std] +#![forbid(unsafe_code)] +#![feature(fn_traits)] + +mod virtio; + +extern crate alloc; +use core::any::Any; + +use alloc::collections::BTreeMap; +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec::Vec; +use component::init_component; +use component::ComponentInitError; +use jinux_virtio::VirtioDeviceType; + +use spin::{Mutex, Once}; +use virtio::VirtioInputDevice; +use virtio_input_decoder::DecodeType; + +pub trait INPUTDevice: Send + Sync + Any { + fn handle_irq(&self) -> Option<()>; + fn register_callbacks(&self, function: &'static (dyn Fn(DecodeType) + Send + Sync)); + fn name(&self) -> &String; +} + +pub static INPUT_COMPONENT: Once = Once::new(); + +#[init_component] +fn input_component_init() -> Result<(), ComponentInitError> { + let a = INPUTComponent::init()?; + INPUT_COMPONENT.call_once(|| a); + Ok(()) +} + +pub struct INPUTComponent { + /// Input device map, key is the irq number, value is the Input device + input_device_map: Mutex>>, +} + +impl INPUTComponent { + pub fn init() -> Result { + let mut input_device_map: BTreeMap> = BTreeMap::new(); + let virtio = jinux_virtio::VIRTIO_COMPONENT.get().unwrap(); + let devices = virtio.get_device(VirtioDeviceType::Input); + for device in devices { + let (v_device, irq_num) = VirtioInputDevice::new(device); + input_device_map.insert(irq_num, Arc::new(v_device)); + } + Ok(Self { + input_device_map: Mutex::new(input_device_map), + }) + } + + pub const fn name() -> &'static str { + "Input Device" + } + // 0~65535 + pub const fn priority() -> u16 { + 8192 + } +} + +impl INPUTComponent { + fn call(self: &Self, irq_number: u8) -> Result<(), InputDeviceHandleError> { + // FIXME: use Result instead + let binding = self.input_device_map.lock(); + let device = binding + .get(&irq_number) + .ok_or(InputDeviceHandleError::DeviceNotExists)?; + device.handle_irq(); + Ok(()) + } + + pub fn get_input_device(self: &Self) -> Vec> { + self.input_device_map + .lock() + .iter() + .map(|(_, device)| device.clone()) + .collect::>>() + } +} + +#[derive(Debug)] +enum InputDeviceHandleError { + DeviceNotExists, + Unknown, +} diff --git a/src/services/comps/input/src/virtio.rs b/src/services/comps/input/src/virtio.rs new file mode 100644 index 000000000..316a1c543 --- /dev/null +++ b/src/services/comps/input/src/virtio.rs @@ -0,0 +1,122 @@ +//! Input device based on Virtio + +use alloc::{string::String, sync::Arc, vec::Vec}; +use jinux_frame::{offset_of, TrapFrame}; +use jinux_pci::msix::MSIX; +use jinux_util::frame_ptr::InFramePtr; +use jinux_virtio::device::input::device::InputProp; +use jinux_virtio::VitrioPciCommonCfg; +use jinux_virtio::{ + device::input::{device::InputDevice, InputConfigSelect}, + PCIVirtioDevice, +}; +use log::{debug, info}; +use spin::Mutex; +use virtio_input_decoder::{DecodeType, Decoder}; + +use crate::INPUTDevice; +pub struct VirtioInputDevice { + input_device: InputDevice, + common_cfg: InFramePtr, + msix: Mutex, + name: String, + callbacks: Mutex>>, +} + +impl VirtioInputDevice { + /// Create a new Virtio Input Device, return value contains the irq number it will use + pub(crate) fn new(virtio_device: PCIVirtioDevice) -> (Self, u8) { + let input_device = match virtio_device.device { + jinux_virtio::device::VirtioDevice::Input(dev) => dev, + _ => { + panic!("Error when creating new input device, the input device is other type of virtio device"); + } + }; + let mut raw_name: [u8; 128] = [0; 128]; + input_device.query_config_select(InputConfigSelect::IdName, 0, &mut raw_name); + let name = String::from_utf8(raw_name.to_vec()).unwrap(); + info!("input device name:{}", name); + + let mut prop: [u8; 128] = [0; 128]; + input_device.query_config_select(InputConfigSelect::PropBits, 0, &mut prop); + + let input_prop = InputProp::from_bits(prop[0]).unwrap(); + debug!("input device prop:{:?}", input_prop); + + fn handle_input(frame: &TrapFrame) { + debug!("in handle input"); + let input_component = crate::INPUT_COMPONENT.get().unwrap(); + input_component.call(frame.id as u8); + } + fn config_space_change(_: &TrapFrame) { + debug!("input device config space change"); + } + + let common_cfg = virtio_device.common_cfg; + let mut msix = virtio_device.msix; + + let config_msix_vector = + common_cfg.read_at(offset_of!(VitrioPciCommonCfg, config_msix_vector)) as usize; + + let mut event_irq_number = 0; + for i in 0..msix.table_size as usize { + let msix = msix.table.get_mut(i).unwrap(); + if !msix.irq_handle.is_empty() { + panic!("msix already have irq functions"); + } + if config_msix_vector == i { + msix.irq_handle.on_active(config_space_change); + } else { + event_irq_number = msix.irq_handle.num(); + msix.irq_handle.on_active(handle_input); + } + } + + ( + Self { + input_device, + common_cfg, + msix: Mutex::new(msix), + name, + callbacks: Mutex::new(Vec::new()), + }, + event_irq_number, + ) + } +} + +impl INPUTDevice for VirtioInputDevice { + fn handle_irq(&self) -> Option<()> { + let input = &self.input_device; + // one interrupt may contains serval input, so it should loop + loop { + let event = input.pop_pending_event()?; + let dtype = match Decoder::decode( + event.event_type as usize, + event.code as usize, + event.value as usize, + ) { + Ok(dtype) => dtype, + Err(_) => return Some(()), + }; + let lock = self.callbacks.lock(); + for callback in lock.iter() { + callback.call((dtype,)); + } + match dtype { + virtio_input_decoder::DecodeType::Key(key, r#type) => { + info!("{:?} {:?}", key, r#type); + } + virtio_input_decoder::DecodeType::Mouse(mouse) => info!("{:?}", mouse), + } + } + } + + fn register_callbacks(&self, function: &'static (dyn Fn(DecodeType) + Send + Sync)) { + self.callbacks.lock().push(Arc::new(function)) + } + + fn name(&self) -> &String { + &self.name + } +} diff --git a/src/services/comps/jinux-pci/src/lib.rs b/src/services/comps/jinux-pci/src/lib.rs deleted file mode 100644 index 1d3e16fd7..000000000 --- a/src/services/comps/jinux-pci/src/lib.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! The pci of jinux -#![no_std] -#![forbid(unsafe_code)] -#![allow(dead_code)] -pub mod capability; -pub mod msix; -pub mod util; -extern crate alloc; -extern crate pod_derive; - -use alloc::{sync::Arc, vec::Vec}; -use lazy_static::lazy_static; -use log::info; -use spin::mutex::Mutex; -use util::CSpaceAccessMethod; - -pub use crate::util::PCIDevice; - -pub const PCI_COMMAND: u16 = 0x04; -pub const PCI_BAR: u16 = 0x10; -pub const PCI_CAP_PTR: u16 = 0x34; -pub const PCI_INTERRUPT_LINE: u16 = 0x3c; -pub const PCI_INTERRUPT_PIN: u16 = 0x3d; - -pub const PCI_MSIX_CTRL_CAP: u16 = 0x00; -pub const PCI_MSIX_TABLE: u16 = 0x04; -pub const PCI_MSIX_PBA: u16 = 0x08; - -pub const PCI_CAP_ID_MSI: u8 = 0x05; - -lazy_static! { - static ref PCI_DEVICES: Mutex>> = Mutex::new(Vec::new()); -} -pub fn init() { - if device_amount() > 0 { - panic!("initialize pci device twice time") - } - let mut devices = PCI_DEVICES.lock(); - for dev in util::scan_bus(CSpaceAccessMethod::IO) { - info!( - "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) command: {:?} status: {:?} irq: {}:{:?}", - dev.loc.bus, - dev.loc.device, - dev.loc.function, - dev.id.vendor_id, - dev.id.device_id, - dev.id.class, - dev.id.subclass, - dev.command, - dev.status, - dev.pic_interrupt_line, - dev.interrupt_pin - ); - devices.push(Arc::new(dev)); - } -} - -pub fn get_pci_devices(index: usize) -> Option> { - PCI_DEVICES.lock().get(index).cloned() -} - -pub fn device_amount() -> usize { - PCI_DEVICES.lock().len() -} diff --git a/src/services/comps/jinux-pci/Cargo.toml b/src/services/comps/pci/Cargo.toml similarity index 89% rename from src/services/comps/jinux-pci/Cargo.toml rename to src/services/comps/pci/Cargo.toml index ad2845a1a..f48e1c036 100644 --- a/src/services/comps/jinux-pci/Cargo.toml +++ b/src/services/comps/pci/Cargo.toml @@ -12,7 +12,8 @@ jinux-frame = {path = "../../../framework/jinux-frame"} jinux-util = {path="../../libs/jinux-util"} pod = {path = "../../../framework/pod"} pod-derive = {path = "../../../framework/pod-derive"} -log= "0.4" +component = {path="../../comp-sys/component"} +log = "0.4" [dependencies.lazy_static] version = "1.0" diff --git a/src/services/comps/jinux-pci/src/capability/exp.rs b/src/services/comps/pci/src/capability/exp.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/exp.rs rename to src/services/comps/pci/src/capability/exp.rs diff --git a/src/services/comps/jinux-pci/src/capability/mod.rs b/src/services/comps/pci/src/capability/mod.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/mod.rs rename to src/services/comps/pci/src/capability/mod.rs diff --git a/src/services/comps/jinux-pci/src/capability/msi.rs b/src/services/comps/pci/src/capability/msi.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/msi.rs rename to src/services/comps/pci/src/capability/msi.rs diff --git a/src/services/comps/jinux-pci/src/capability/msix.rs b/src/services/comps/pci/src/capability/msix.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/msix.rs rename to src/services/comps/pci/src/capability/msix.rs diff --git a/src/services/comps/jinux-pci/src/capability/pm.rs b/src/services/comps/pci/src/capability/pm.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/pm.rs rename to src/services/comps/pci/src/capability/pm.rs diff --git a/src/services/comps/jinux-pci/src/capability/sata.rs b/src/services/comps/pci/src/capability/sata.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/sata.rs rename to src/services/comps/pci/src/capability/sata.rs diff --git a/src/services/comps/jinux-pci/src/capability/vendor/mod.rs b/src/services/comps/pci/src/capability/vendor/mod.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/vendor/mod.rs rename to src/services/comps/pci/src/capability/vendor/mod.rs diff --git a/src/services/comps/jinux-pci/src/capability/vendor/virtio.rs b/src/services/comps/pci/src/capability/vendor/virtio.rs similarity index 100% rename from src/services/comps/jinux-pci/src/capability/vendor/virtio.rs rename to src/services/comps/pci/src/capability/vendor/virtio.rs diff --git a/src/services/comps/pci/src/lib.rs b/src/services/comps/pci/src/lib.rs new file mode 100644 index 000000000..157ca9091 --- /dev/null +++ b/src/services/comps/pci/src/lib.rs @@ -0,0 +1,86 @@ +//! The pci of jinux +#![no_std] +#![forbid(unsafe_code)] +#![allow(dead_code)] +pub mod capability; +pub mod msix; +pub mod util; +extern crate alloc; + +use component::init_component; +use component::ComponentInitError; +extern crate pod_derive; + +use alloc::{sync::Arc, vec::Vec}; +use spin::{mutex::Mutex, Once}; +use util::CSpaceAccessMethod; + +pub use crate::util::PCIDevice; + +pub const PCI_COMMAND: u16 = 0x04; +pub const PCI_BAR: u16 = 0x10; +pub const PCI_CAP_PTR: u16 = 0x34; +pub const PCI_INTERRUPT_LINE: u16 = 0x3c; +pub const PCI_INTERRUPT_PIN: u16 = 0x3d; + +pub const PCI_MSIX_CTRL_CAP: u16 = 0x00; +pub const PCI_MSIX_TABLE: u16 = 0x04; +pub const PCI_MSIX_PBA: u16 = 0x08; + +pub const PCI_CAP_ID_MSI: u8 = 0x05; + +pub static PCI_COMPONENT: Once = Once::new(); + +#[init_component] +fn pci_component_init() -> Result<(), ComponentInitError> { + let a = PCIComponent::init()?; + PCI_COMPONENT.call_once(|| a); + Ok(()) +} +pub struct PCIComponent { + pci_device: Mutex>>, +} + +impl PCIComponent { + pub fn init() -> Result { + let mut devices = Vec::new(); + for dev in util::scan_bus(CSpaceAccessMethod::IO) { + log::info!( + "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) command: {:?} status: {:?} irq: {}:{:?}", + dev.loc.bus, + dev.loc.device, + dev.loc.function, + dev.id.vendor_id, + dev.id.device_id, + dev.id.class, + dev.id.subclass, + dev.command, + dev.status, + dev.pic_interrupt_line, + dev.interrupt_pin + ); + devices.push(Arc::new(dev)); + } + Ok(Self { + pci_device: Mutex::new(devices), + }) + } + + pub const fn name() -> &'static str { + "PCI" + } + // 0~65535 + pub const fn priority() -> u16 { + 0 + } +} + +impl PCIComponent { + pub fn get_pci_devices(self: &Self, index: usize) -> Option> { + self.pci_device.lock().get(index).cloned() + } + + pub fn device_amount(self: &Self) -> usize { + self.pci_device.lock().len() + } +} diff --git a/src/services/comps/jinux-pci/src/msix.rs b/src/services/comps/pci/src/msix.rs similarity index 100% rename from src/services/comps/jinux-pci/src/msix.rs rename to src/services/comps/pci/src/msix.rs diff --git a/src/services/comps/jinux-pci/src/util.rs b/src/services/comps/pci/src/util.rs similarity index 100% rename from src/services/comps/jinux-pci/src/util.rs rename to src/services/comps/pci/src/util.rs diff --git a/src/services/comps/jinux-virtio/Cargo.toml b/src/services/comps/virtio/Cargo.toml similarity index 83% rename from src/services/comps/jinux-virtio/Cargo.toml rename to src/services/comps/virtio/Cargo.toml index d5aae8136..8f5e5632a 100644 --- a/src/services/comps/jinux-virtio/Cargo.toml +++ b/src/services/comps/virtio/Cargo.toml @@ -9,12 +9,13 @@ edition = "2021" bitflags = "1.3" spin = "0.9.4" jinux-frame = {path = "../../../framework/jinux-frame"} -jinux-pci = {path="../jinux-pci"} +jinux-pci = {path="../pci"} jinux-util = {path="../../libs/jinux-util"} pod = {path = "../../../framework/pod"} pod-derive = {path = "../../../framework/pod-derive"} -log= "0.4" - +component = {path="../../comp-sys/component"} +log = "0.4" [features] + diff --git a/src/services/comps/jinux-virtio/src/device/block/device.rs b/src/services/comps/virtio/src/device/block/device.rs similarity index 70% rename from src/services/comps/jinux-virtio/src/device/block/device.rs rename to src/services/comps/virtio/src/device/block/device.rs index 673d42f63..d81a171e6 100644 --- a/src/services/comps/jinux-virtio/src/device/block/device.rs +++ b/src/services/comps/virtio/src/device/block/device.rs @@ -9,7 +9,7 @@ use pod::Pod; use crate::{ device::block::{BlkReq, BlkResp, ReqType, RespStatus, BLK_SIZE}, device::VirtioDeviceError, - queue::VirtQueue, + queue::{QueueError, VirtQueue}, VitrioPciCommonCfg, }; @@ -65,14 +65,17 @@ impl BLKDevice { sector: block_id as u64, }; let mut resp = BlkResp::default(); - self.queue + let token = self + .queue .add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()]) .expect("add queue failed"); self.queue.notify(); while !self.queue.can_pop() { spin_loop(); } - self.queue.pop_used().expect("pop used failed"); + self.queue + .pop_used_with_token(token) + .expect("pop used failed"); match resp.status { RespStatus::Ok => {} _ => panic!("io error in block device"), @@ -87,15 +90,17 @@ impl BLKDevice { sector: block_id as u64, }; let mut resp = BlkResp::default(); - self.queue + let token = self + .queue .add(&[req.as_bytes(), buf], &[resp.as_bytes_mut()]) .expect("add queue failed"); self.queue.notify(); - while !self.queue.can_pop() { spin_loop(); } - self.queue.pop_used().expect("pop used failed"); + self.queue + .pop_used_with_token(token) + .expect("pop used failed"); let st = resp.status; match st { RespStatus::Ok => {} @@ -103,16 +108,57 @@ impl BLKDevice { }; } - pub fn read_block_nb(&mut self, block_id: usize, buf: &mut [u8], resp: &mut BlkResp) { + pub fn pop_used(&mut self) -> Result<(u16, u32), QueueError> { + self.queue.pop_used() + } + + pub fn pop_used_with_token(&mut self, token: u16) -> Result { + self.queue.pop_used_with_token(token) + } + + /// read data from block device, this function is non-blocking + /// return value is token + pub fn read_block_non_blocking( + &mut self, + block_id: usize, + buf: &mut [u8], + req: &mut BlkReq, + resp: &mut BlkResp, + ) -> u16 { assert_eq!(buf.len(), BLK_SIZE); - let req = BlkReq { + *req = BlkReq { type_: ReqType::In, reserved: 0, sector: block_id as u64, }; - self.queue + let token = self + .queue .add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()]) .unwrap(); self.queue.notify(); + token + } + + /// write data to block device, this function is non-blocking + /// return value is token + pub fn write_block_non_blocking( + &mut self, + block_id: usize, + buf: &[u8], + req: &mut BlkReq, + resp: &mut BlkResp, + ) -> u16 { + assert_eq!(buf.len(), BLK_SIZE); + *req = BlkReq { + type_: ReqType::Out, + reserved: 0, + sector: block_id as u64, + }; + let token = self + .queue + .add(&[req.as_bytes(), buf], &[resp.as_bytes_mut()]) + .expect("add queue failed"); + self.queue.notify(); + token } } diff --git a/src/services/comps/jinux-virtio/src/device/block/mod.rs b/src/services/comps/virtio/src/device/block/mod.rs similarity index 100% rename from src/services/comps/jinux-virtio/src/device/block/mod.rs rename to src/services/comps/virtio/src/device/block/mod.rs diff --git a/src/services/comps/jinux-virtio/src/device/input/device.rs b/src/services/comps/virtio/src/device/input/device.rs similarity index 100% rename from src/services/comps/jinux-virtio/src/device/input/device.rs rename to src/services/comps/virtio/src/device/input/device.rs diff --git a/src/services/comps/jinux-virtio/src/device/input/mod.rs b/src/services/comps/virtio/src/device/input/mod.rs similarity index 100% rename from src/services/comps/jinux-virtio/src/device/input/mod.rs rename to src/services/comps/virtio/src/device/input/mod.rs diff --git a/src/services/comps/jinux-virtio/src/device/mod.rs b/src/services/comps/virtio/src/device/mod.rs similarity index 99% rename from src/services/comps/jinux-virtio/src/device/mod.rs rename to src/services/comps/virtio/src/device/mod.rs index 1b59dd29f..f33e79c7a 100644 --- a/src/services/comps/jinux-virtio/src/device/mod.rs +++ b/src/services/comps/virtio/src/device/mod.rs @@ -152,6 +152,7 @@ impl VirtioDevice { VirtioDeviceType::Input => InputDevice::negotiate_features(device_specified_features), VirtioDeviceType::Crypto => todo!(), VirtioDeviceType::Socket => todo!(), + VirtioDeviceType::Unknown => todo!(), }; let support_feature = Feature::from_bits_truncate(features); // support_feature.remove(Feature::RING_EVENT_IDX); diff --git a/src/services/comps/jinux-virtio/src/lib.rs b/src/services/comps/virtio/src/lib.rs similarity index 72% rename from src/services/comps/jinux-virtio/src/lib.rs rename to src/services/comps/virtio/src/lib.rs index 6a5bd0743..d587d4150 100644 --- a/src/services/comps/jinux-virtio/src/lib.rs +++ b/src/services/comps/virtio/src/lib.rs @@ -5,14 +5,19 @@ extern crate alloc; -use alloc::{sync::Arc, vec::Vec}; +use component::init_component; +use core::str::FromStr; + +use alloc::{collections::VecDeque, string::String, sync::Arc, vec::Vec}; use bitflags::bitflags; +use component::ComponentInitError; use device::VirtioDevice; use jinux_frame::{offset_of, TrapFrame}; use jinux_pci::util::{PCIDevice, BAR}; use jinux_util::frame_ptr::InFramePtr; use log::{debug, info}; use pod_derive::Pod; +use spin::{Mutex, Once}; use crate::device::VirtioInfo; use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, msix::MSIX}; @@ -20,9 +25,72 @@ use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, msix::MSIX}; extern crate pod_derive; pub mod device; - pub mod queue; +pub static VIRTIO_COMPONENT: Once = Once::new(); + +#[init_component] +fn virtio_component_init() -> Result<(), ComponentInitError> { + let a = VIRTIOComponent::init()?; + VIRTIO_COMPONENT.call_once(|| a); + Ok(()) +} + +pub struct VIRTIOComponent { + virtio_devices: Mutex>, +} + +impl VIRTIOComponent { + pub fn init() -> Result { + let pci_devices = + jinux_pci::PCI_COMPONENT + .get() + .ok_or(ComponentInitError::UninitializedDependencies( + String::from_str("PCI").unwrap(), + ))?; + let mut virtio_devices = VecDeque::new(); + for index in 0..pci_devices.device_amount() { + let pci_device = pci_devices.get_pci_devices(index).unwrap(); + if pci_device.id.vendor_id == 0x1af4 { + virtio_devices.push_back(PCIVirtioDevice::new(pci_device)); + } + } + Ok(Self { + virtio_devices: Mutex::new(virtio_devices), + }) + } + + pub const fn name() -> &'static str { + "Virtio" + } + // 0~65535 + pub const fn priority() -> u16 { + 256 + } +} + +impl VIRTIOComponent { + pub fn pop(self: &Self) -> Option { + self.virtio_devices.lock().pop_front() + } + + pub fn get_device(self: &Self, device_type: VirtioDeviceType) -> Vec { + let mut devices = Vec::new(); + let mut lock = self.virtio_devices.lock(); + let len = lock.len(); + for i in 0..len { + let device = lock.pop_front().unwrap(); + let d_type = VirtioDeviceType::from_virtio_device(&device.device); + if d_type == device_type { + devices.push(device); + } else { + lock.push_back(device); + } + } + devices + } +} + bitflags! { /// The device status field. pub struct DeviceStatus: u8 { @@ -118,7 +186,7 @@ impl VitrioPciCommonCfg { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum VirtioDeviceType { Network, Block, @@ -130,7 +198,27 @@ pub enum VirtioDeviceType { Input, Crypto, Socket, + Unknown, } + +impl VirtioDeviceType { + pub fn from_virtio_device(device: &VirtioDevice) -> Self { + match device { + VirtioDevice::Network => VirtioDeviceType::Network, + VirtioDevice::Block(_) => VirtioDeviceType::Block, + VirtioDevice::Console => VirtioDeviceType::Console, + VirtioDevice::Entropy => VirtioDeviceType::Entropy, + VirtioDevice::TraditionalMemoryBalloon => VirtioDeviceType::TraditionalMemoryBalloon, + VirtioDevice::ScsiHost => VirtioDeviceType::ScsiHost, + VirtioDevice::GPU => VirtioDeviceType::GPU, + VirtioDevice::Input(_) => VirtioDeviceType::Input, + VirtioDevice::Crypto => VirtioDeviceType::Crypto, + VirtioDevice::Socket => VirtioDeviceType::Socket, + VirtioDevice::Unknown => VirtioDeviceType::Unknown, + } + } +} + pub struct PCIVirtioDevice { /// common config of one device pub common_cfg: InFramePtr, @@ -250,17 +338,28 @@ impl PCIVirtioDevice { } } - /// register all the interrupt functions except the config change, this function should call only once - pub fn register_interrupt_functions(&mut self, function: &'static F) - where + /// register all the interrupt functions, this function should call only once + pub fn register_interrupt_functions( + &mut self, + config_change_function: &'static F, + other_function: &'static T, + ) where F: Fn(&TrapFrame) + Send + Sync + 'static, + T: Fn(&TrapFrame) + Send + Sync + 'static, { + let config_msix_vector = + self.common_cfg + .read_at(offset_of!(VitrioPciCommonCfg, config_msix_vector)) as usize; for i in 0..self.msix.table_size as usize { let msix = self.msix.table.get_mut(i).unwrap(); if !msix.irq_handle.is_empty() { panic!("function `register_queue_interrupt_functions` called more than one time"); } - msix.irq_handle.on_active(function); + if config_msix_vector == i { + msix.irq_handle.on_active(config_change_function); + } else { + msix.irq_handle.on_active(other_function); + } } } } diff --git a/src/services/comps/jinux-virtio/src/queue.rs b/src/services/comps/virtio/src/queue.rs similarity index 87% rename from src/services/comps/jinux-virtio/src/queue.rs rename to src/services/comps/virtio/src/queue.rs index bf8757896..b107dadd2 100644 --- a/src/services/comps/jinux-virtio/src/queue.rs +++ b/src/services/comps/virtio/src/queue.rs @@ -9,12 +9,14 @@ use jinux_frame::{ vm::{VmAllocOptions, VmFrame, VmFrameVec}, }; use jinux_util::frame_ptr::InFramePtr; +use log::debug; #[derive(Debug)] pub enum QueueError { InvalidArgs, BufferTooSmall, NotReady, AlreadyUsed, + WrongToken, } /// The mechanism for bulk data transport on virtio devices. @@ -94,6 +96,7 @@ impl VirtQueue { offset_of!(VitrioPciCommonCfg, queue_desc), frame.paddr() as u64, ); + debug!("queue_desc vm frame:{:x?}", frame); frame_vec.push(frame); } @@ -105,6 +108,7 @@ impl VirtQueue { offset_of!(VitrioPciCommonCfg, queue_driver), frame.paddr() as u64, ); + debug!("queue_driver vm frame:{:x?}", frame); frame_vec.push(frame); } @@ -116,6 +120,7 @@ impl VirtQueue { offset_of!(VitrioPciCommonCfg, queue_device), frame.paddr() as u64, ); + debug!("queue_device vm frame:{:x?}", frame); frame_vec.push(frame); } @@ -278,6 +283,35 @@ impl VirtQueue { Ok((index, len)) } + /// If the given token is next on the device used queue, pops it and returns the total buffer + /// length which was used (written) by the device. + /// + /// Ref: linux virtio_ring.c virtqueue_get_buf_ctx + pub fn pop_used_with_token(&mut self, token: u16) -> Result { + if !self.can_pop() { + return Err(QueueError::NotReady); + } + // read barrier + fence(Ordering::SeqCst); + + let last_used_slot = self.last_used_idx & (self.queue_size - 1); + let index = self.used.read_at( + (offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8) as *const u32, + ) as u16; + let len = self.used.read_at( + (offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8 + 4) as *const u32, + ); + + if index != token { + return Err(QueueError::WrongToken); + } + + self.recycle_descriptors(index); + self.last_used_idx = self.last_used_idx.wrapping_add(1); + + Ok(len) + } + /// Return size of the queue. pub fn size(&self) -> u16 { self.queue_size @@ -308,10 +342,16 @@ impl Descriptor { } fn set_buf(inframe_ptr: &InFramePtr, buf: &[u8]) { - inframe_ptr.write_at( - offset_of!(Descriptor, addr), - jinux_frame::translate_not_offset_virtual_address(buf.as_ptr() as usize) as u64, - ); + let va = buf.as_ptr() as usize; + let pa = if va >= jinux_frame::config::PHYS_OFFSET && va <= jinux_frame::config::KERNEL_OFFSET { + // can use offset + jinux_frame::virt_to_phys(va) + } else { + jinux_frame::translate_not_offset_virtual_address(buf.as_ptr() as usize) + }; + debug!("set buf write virt address:{:x}", va); + debug!("set buf write phys address:{:x}", pa); + inframe_ptr.write_at(offset_of!(Descriptor, addr), pa as u64); inframe_ptr.write_at(offset_of!(Descriptor, len), buf.len() as u32); } bitflags! { diff --git a/src/services/libs/jinux-std/Cargo.toml b/src/services/libs/jinux-std/Cargo.toml index 603105957..31202f4ef 100644 --- a/src/services/libs/jinux-std/Cargo.toml +++ b/src/services/libs/jinux-std/Cargo.toml @@ -9,8 +9,8 @@ edition = "2021" jinux-frame = {path = "../../../framework/jinux-frame"} pod = {path = "../../../framework/pod"} pod-derive = {path = "../../../framework/pod-derive"} -jinux-pci = {path="../../comps/jinux-pci"} -jinux-virtio = {path="../../comps/jinux-virtio"} +jinux-input = {path="../../comps/input"} +jinux-block = {path="../../comps/block"} controlled = { path = "../../comp-sys/controlled" } typeflags = {path="../typeflags"} typeflags-util = {path="../typeflags-util"} diff --git a/src/services/libs/jinux-std/src/driver/mod.rs b/src/services/libs/jinux-std/src/driver/mod.rs index 74859daf4..f43971caf 100644 --- a/src/services/libs/jinux-std/src/driver/mod.rs +++ b/src/services/libs/jinux-std/src/driver/mod.rs @@ -1,7 +1,30 @@ -pub mod pci; pub mod tty; +use jinux_input::INPUT_COMPONENT; +use log::info; + pub fn init() { - pci::init(); + // print all the input device to make sure input crate will compile + for comp in INPUT_COMPONENT.get().unwrap().get_input_device() { + info!("input device name:{}", comp.name()); + } tty::init(); } + +#[allow(unused)] +fn block_device_test() { + let block_device = jinux_block::BLK_COMPONENT.get().unwrap().get_device(); + let mut write_buffer = [0u8; 512]; + let mut read_buffer = [0u8; 512]; + info!("write_buffer address:{:x}", write_buffer.as_ptr() as usize); + info!("read_buffer address:{:x}", read_buffer.as_ptr() as usize); + for i in 0..512 { + for byte in write_buffer.iter_mut() { + *byte = i as u8; + } + block_device.write_block(i as usize, &write_buffer); + block_device.read_block(i as usize, &mut read_buffer); + assert_eq!(write_buffer, read_buffer); + } + info!("block device test passed!"); +} diff --git a/src/services/libs/jinux-std/src/driver/pci/mod.rs b/src/services/libs/jinux-std/src/driver/pci/mod.rs deleted file mode 100644 index 8ae60b33a..000000000 --- a/src/services/libs/jinux-std/src/driver/pci/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -use log::info; - -pub mod virtio; - -pub fn init() { - jinux_pci::init(); - for index in 0..jinux_pci::device_amount() { - let pci_device = jinux_pci::get_pci_devices(index) - .expect("initialize pci device failed: pci device is None"); - if pci_device.id.vendor_id == 0x1af4 { - if pci_device.id.device_id == 0x1001 || pci_device.id.device_id == 0x1042 { - info!("found virtio block device"); - virtio::block::init(pci_device); - } else if pci_device.id.device_id == 0x1011 || pci_device.id.device_id == 0x1052 { - info!("found virtio input device"); - virtio::input::init(pci_device); - } - } - } - info!("pci initialization complete"); -} diff --git a/src/services/libs/jinux-std/src/driver/pci/virtio/block.rs b/src/services/libs/jinux-std/src/driver/pci/virtio/block.rs deleted file mode 100644 index 4bcaf0ac0..000000000 --- a/src/services/libs/jinux-std/src/driver/pci/virtio/block.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::process::Process; -use alloc::sync::Arc; -use jinux_pci::msix::MSIX; -use jinux_pci::PCIDevice; -use jinux_util::frame_ptr::InFramePtr; -use jinux_virtio::device::block::device::BLKDevice; -use jinux_virtio::device::block::BlkResp; -use jinux_virtio::PCIVirtioDevice; -use jinux_virtio::VitrioPciCommonCfg; -use lazy_static::lazy_static; -use log::info; -use spin::mutex::Mutex; - -use super::BlockDevice; -pub const BLK_SIZE: usize = 512; -use jinux_frame::TrapFrame; -pub struct VirtioBlockDevice { - blk_device: Mutex, - pub common_cfg: InFramePtr, - msix: MSIX, -} - -lazy_static! { - // TODO: use dyn BlockDevice instead - pub static ref BLOCK_DEVICE: Arc>> = Arc::new(Mutex::new(None)) ; -} - -impl VirtioBlockDevice { - pub fn read_block_nb(&self, block_id: usize, buf: &mut [u8], res: &mut BlkResp) { - self.blk_device.lock().read_block_nb(block_id, buf, res); - } -} - -impl BlockDevice for VirtioBlockDevice { - fn read_block(&self, block_id: usize, buf: &mut [u8]) { - self.blk_device.lock().read_block(block_id, buf); - } - /// it is blocking now - fn write_block(&self, block_id: usize, buf: &[u8]) { - self.blk_device.lock().write_block(block_id, buf); - } - fn handle_irq(&self) { - info!("handle irq in block device!"); - } -} - -impl VirtioBlockDevice { - fn new(mut virtio_device: PCIVirtioDevice) -> Self { - fn handle_block_device(frame: &TrapFrame) { - info!("pci block device queue interrupt"); - BLOCK_DEVICE.lock().as_ref().unwrap().handle_irq(); - } - virtio_device.register_interrupt_functions(&handle_block_device); - let blk_device = Mutex::new(match virtio_device.device { - jinux_virtio::device::VirtioDevice::Block(blk) => blk, - _ => { - panic!("Error when creating new block device, the input device is other type of virtio device"); - } - }); - Self { - blk_device, - common_cfg: virtio_device.common_cfg, - msix: virtio_device.msix, - } - } -} - -pub fn init(pci_device: Arc) { - let virtio_device = PCIVirtioDevice::new(pci_device); - let mut a = BLOCK_DEVICE.lock(); - a.replace(VirtioBlockDevice::new(virtio_device)); - let dev = a.as_ref().unwrap(); - drop(a); -} -fn inner_block_device_test() { - let block_device = BLOCK_DEVICE.clone(); - let mut write_buffer = [0u8; 512]; - let mut read_buffer = [0u8; 512]; - info!("write_buffer address:{:x}", write_buffer.as_ptr() as usize); - info!("read_buffer address:{:x}", read_buffer.as_ptr() as usize); - for i in 0..512 { - for byte in write_buffer.iter_mut() { - *byte = i as u8; - } - info!("write block"); - block_device - .lock() - .as_ref() - .unwrap() - .write_block(i as usize, &write_buffer); - info!("read block"); - block_device - .lock() - .as_ref() - .unwrap() - .read_block(i as usize, &mut read_buffer); - assert_eq!(write_buffer, read_buffer); - } - info!("block device test passed!"); -} -#[allow(unused)] -pub fn block_device_test() { - let _ = Process::spawn_kernel_process(|| { - inner_block_device_test(); - }); -} diff --git a/src/services/libs/jinux-std/src/driver/pci/virtio/input.rs b/src/services/libs/jinux-std/src/driver/pci/virtio/input.rs deleted file mode 100644 index 00d495831..000000000 --- a/src/services/libs/jinux-std/src/driver/pci/virtio/input.rs +++ /dev/null @@ -1,182 +0,0 @@ -use core::any::Any; -use core::sync::atomic::AtomicBool; - -use alloc::collections::BTreeMap; -use alloc::{string::String, sync::Arc, vec::Vec}; -use jinux_frame::{offset_of, TrapFrame}; -use jinux_pci::{msix::MSIX, PCIDevice}; -use jinux_util::frame_ptr::InFramePtr; -use jinux_virtio::device::input::device::InputProp; -use jinux_virtio::VitrioPciCommonCfg; -use jinux_virtio::{ - device::input::{device::InputDevice, InputConfigSelect}, - PCIVirtioDevice, -}; -use lazy_static::lazy_static; -use log::{debug, info}; -use spin::Mutex; -use virtio_input_decoder::{DecodeType, Decoder}; - -pub trait INPUTDevice: Send + Sync + Any { - fn handle_irq(&self) -> Option<()>; -} - -lazy_static! { - pub static ref KEYBOARD_EVENT: Mutex> = Mutex::new(Vec::new()); - pub static ref MOUSE_EVENT: Mutex> = Mutex::new(Vec::new()); - static ref KEYBOARD_CALLBACKS: Mutex>> = - Mutex::new(Vec::new()); - static ref INPUT_DEVICE_LIST: Mutex>> = - Mutex::new(Vec::with_capacity(2)); - static ref INPUT_DEVICE_IRQ_HASH: Mutex> = Mutex::new(BTreeMap::new()); -} - -pub struct VirtioInputDevice { - input_device: InputDevice, - common_cfg: InFramePtr, - msix: Mutex, - is_keyboard: AtomicBool, -} - -impl VirtioInputDevice { - fn new(virtio_device: PCIVirtioDevice, id: usize) -> Self { - let input_device = match virtio_device.device { - jinux_virtio::device::VirtioDevice::Input(dev) => dev, - _ => { - panic!("Error when creating new input device, the input device is other type of virtio device"); - } - }; - - Self { - input_device, - common_cfg: virtio_device.common_cfg, - msix: Mutex::new(virtio_device.msix), - is_keyboard: AtomicBool::new(false), - } - } - - fn register_interrupts(&self, id: usize) { - fn handle_input(frame: &TrapFrame) { - info!("in handle input"); - let id = *INPUT_DEVICE_IRQ_HASH - .lock() - .get(&(frame.id as u16)) - .expect("wrong irq number in input device trap handler"); - INPUT_DEVICE_LIST - .lock() - .get(id) - .as_ref() - .unwrap() - .handle_irq(); - } - fn config_space_change(frame: &TrapFrame) {} - - let config_msix_vector = - self.common_cfg - .read_at(offset_of!(VitrioPciCommonCfg, config_msix_vector)) as usize; - let mut device_hash_lock = INPUT_DEVICE_IRQ_HASH.lock(); - let mut msix = self.msix.lock(); - for i in 0..msix.table_size as usize { - if i == config_msix_vector { - continue; - } - device_hash_lock.insert(msix.table.get(i).unwrap().irq_handle.num() as u16, id); - } - drop(device_hash_lock); - for i in 0..msix.table_size as usize { - let msix = msix.table.get_mut(i).unwrap(); - if !msix.irq_handle.is_empty() { - panic!("function `register_queue_interrupt_functions` called more than one time"); - } - if config_msix_vector == i { - msix.irq_handle.on_active(config_space_change); - } else { - msix.irq_handle.on_active(handle_input); - } - } - } - - fn print_device_information(&self) { - let mut raw_name: [u8; 128] = [0; 128]; - self.input_device - .query_config_select(InputConfigSelect::IdName, 0, &mut raw_name); - let name = String::from_utf8(raw_name.to_vec()).unwrap(); - info!("input device name:{}", name); - let mut prop: [u8; 128] = [0; 128]; - self.input_device - .query_config_select(InputConfigSelect::PropBits, 0, &mut prop); - - let input_prop = InputProp::from_bits(prop[0]).unwrap(); - debug!("input device prop:{:?}", input_prop); - - // if name.contains("Keyboard"){ - // let mut raw_ev : [u8;128] = [0;128]; - // let size = self.input_device.query_config_select(InputConfigSelect::EvBits, KEY, &mut raw_ev); - // info!("size:{}, raw_ev :{:x?}",size, raw_ev); - - // }else{ - // let mut raw_ev : [u8;128] = [0;128]; - // let size = self.input_device.query_config_select(InputConfigSelect::EvBits, REL, &mut raw_ev); - // info!("size:{}, raw_ev :{:x?}",size, raw_ev); - // } - self.is_keyboard.store( - name.contains("Keyboard"), - core::sync::atomic::Ordering::Relaxed, - ); - } - - #[inline] - pub fn is_keyboard(&self) -> bool { - self.is_keyboard.load(core::sync::atomic::Ordering::Relaxed) - } -} - -impl INPUTDevice for VirtioInputDevice { - fn handle_irq(&self) -> Option<()> { - let input = &self.input_device; - // one interrupt may contains serval input, so it should loop - loop { - let event = input.pop_pending_event()?; - let dtype = match Decoder::decode( - event.event_type as usize, - event.code as usize, - event.value as usize, - ) { - Ok(dtype) => dtype, - Err(_) => return Some(()), - }; - if self.is_keyboard() { - let mut lock = KEYBOARD_EVENT.lock(); - lock.push(dtype); - drop(lock); - let lock = KEYBOARD_CALLBACKS.lock(); - for callback in lock.iter() { - callback.call(()); - } - } else { - let mut lock = MOUSE_EVENT.lock(); - lock.push(dtype); - } - match dtype { - virtio_input_decoder::DecodeType::Key(key, r#type) => { - info!("{:?} {:?}", key, r#type); - } - virtio_input_decoder::DecodeType::Mouse(mouse) => info!("{:?}", mouse), - } - } - } -} - -pub fn init(pci_device: Arc) { - let mut lock = INPUT_DEVICE_LIST.lock(); - let id = lock.len(); - let dev = Arc::new(VirtioInputDevice::new(PCIVirtioDevice::new(pci_device), id)); - lock.push(dev.clone()); - dev.register_interrupts(id); - drop(lock); - dev.print_device_information(); -} - -pub fn register_keyboard_callback(callback: Arc) { - KEYBOARD_CALLBACKS.lock().push(callback); -} diff --git a/src/services/libs/jinux-std/src/driver/pci/virtio/mod.rs b/src/services/libs/jinux-std/src/driver/pci/virtio/mod.rs deleted file mode 100644 index ab9270ce9..000000000 --- a/src/services/libs/jinux-std/src/driver/pci/virtio/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -use core::any::Any; - -pub mod block; -pub mod input; - -pub trait BlockDevice: Send + Sync + Any { - fn read_block(&self, block_id: usize, buf: &mut [u8]); - fn write_block(&self, block_id: usize, buf: &[u8]); - fn handle_irq(&self); -} diff --git a/src/services/libs/jinux-std/src/process/posix_thread/robust_list.rs b/src/services/libs/jinux-std/src/process/posix_thread/robust_list.rs index 9ea8410ad..d4e37a9ae 100644 --- a/src/services/libs/jinux-std/src/process/posix_thread/robust_list.rs +++ b/src/services/libs/jinux-std/src/process/posix_thread/robust_list.rs @@ -90,7 +90,7 @@ impl<'a> Iterator for FutexIter<'a> { return None; } - while self.entry_ptr != &self.robust_list.list as *const _ as _ { + while self.entry_ptr != &self.robust_list.list as *const _ as usize { if self.count == ROBUST_LIST_LIMIT { break; } diff --git a/src/src/main.rs b/src/src/main.rs index e4d0df13a..85e5b28b5 100644 --- a/src/src/main.rs +++ b/src/src/main.rs @@ -17,7 +17,7 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { test_main(); jinux_frame::init(boot_info); println!("[kernel] finish init jinux_frame"); - + component::init(component::generate_information!()).unwrap(); jinux_std::init(); jinux_std::run_first_process(); }