mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-14 15:56:47 +00:00
Component initialization mechanism complete
This commit is contained in:
parent
4f3e359892
commit
e4323f808c
@ -7,6 +7,7 @@ edition = "2021"
|
|||||||
bootloader = {version="0.10.12"}
|
bootloader = {version="0.10.12"}
|
||||||
jinux-frame = {path = "framework/jinux-frame"}
|
jinux-frame = {path = "framework/jinux-frame"}
|
||||||
jinux-std = {path = "services/libs/jinux-std"}
|
jinux-std = {path = "services/libs/jinux-std"}
|
||||||
|
component = {path = "services/comp-sys/component"}
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
@ -15,8 +16,10 @@ members = [
|
|||||||
"framework/jinux-frame",
|
"framework/jinux-frame",
|
||||||
"framework/pod",
|
"framework/pod",
|
||||||
"framework/pod-derive",
|
"framework/pod-derive",
|
||||||
"services/comps/jinux-pci",
|
"services/comps/pci",
|
||||||
"services/comps/jinux-virtio",
|
"services/comps/virtio",
|
||||||
|
"services/comps/input",
|
||||||
|
"services/comps/block",
|
||||||
"services/libs/jinux-std",
|
"services/libs/jinux-std",
|
||||||
"services/libs/jinux-rights-proc",
|
"services/libs/jinux-rights-proc",
|
||||||
"services/libs/typeflags",
|
"services/libs/typeflags",
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
std = { name = "jinux-std" }
|
std = { name = "jinux-std" }
|
||||||
pci = { name = "jinux-pci" }
|
pci = { name = "jinux-pci" }
|
||||||
virtio = { name = "jinux-virtio"}
|
virtio = { name = "jinux-virtio"}
|
||||||
|
input = { name = "jinux-input"}
|
||||||
|
block = { name = "jinux-block"}
|
||||||
main = { name = "jinux" }
|
main = { name = "jinux" }
|
||||||
|
|
||||||
[whitelist]
|
[whitelist]
|
||||||
|
@ -100,7 +100,24 @@ pub fn init(boot_info: &'static mut BootInfo) {
|
|||||||
}
|
}
|
||||||
let value = x86_64_util::cpuid(1);
|
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) {
|
fn general_handler(trap_frame: &TrapFrame) {
|
||||||
// info!("general handler");
|
// info!("general handler");
|
||||||
// println!("{:#x?}", trap_frame);
|
// println!("{:#x?}", trap_frame);
|
||||||
|
@ -9,6 +9,17 @@ SECTIONS {
|
|||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.got ALIGN(4K):{
|
||||||
|
*(.got .got.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
sinit_array = .;
|
||||||
|
.init_array : {
|
||||||
|
*(.init_array .init_array.*)
|
||||||
|
}
|
||||||
|
einit_array = .;
|
||||||
|
|
||||||
.text ALIGN(4K): {
|
.text ALIGN(4K): {
|
||||||
*(.text .text.*)
|
*(.text .text.*)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,9 @@ fn main() -> anyhow::Result<()> {
|
|||||||
println!("Created disk image at `{}`", bios.display());
|
println!("Created disk image at `{}`", bios.display());
|
||||||
return Ok(());
|
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");
|
let mut run_cmd = Command::new("qemu-system-x86_64");
|
||||||
run_cmd
|
run_cmd
|
||||||
.arg("-drive")
|
.arg("-drive")
|
||||||
@ -80,6 +82,9 @@ fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
fn create_fs_image(path: &Path) -> anyhow::Result<String> {
|
fn create_fs_image(path: &Path) -> anyhow::Result<String> {
|
||||||
let mut fs_img_path = path.parent().unwrap().to_str().unwrap().to_string();
|
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");
|
fs_img_path.push_str("/fs.img");
|
||||||
let path = Path::new(fs_img_path.as_str());
|
let path = Path::new(fs_img_path.as_str());
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
|
19
src/services/comp-sys/component-macro/Cargo.toml
Normal file
19
src/services/comp-sys/component-macro/Cargo.toml
Normal file
@ -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"
|
33
src/services/comp-sys/component-macro/src/init_comp.rs
Normal file
33
src/services/comp-sys/component-macro/src/init_comp.rs
Normal file
@ -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<TokenTree>,
|
||||||
|
pub function_name: TokenTree,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ComponentInitFunction {
|
||||||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
|
let mut vec: Vec<TokenTree> = 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
src/services/comp-sys/component-macro/src/lib.rs
Normal file
83
src/services/comp-sys/component-macro/src/lib.rs
Normal file
@ -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()
|
||||||
|
}
|
215
src/services/comp-sys/component-macro/src/priority.rs
Normal file
215
src/services/comp-sys/component-macro/src/priority.rs
Normal file
@ -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<ComponentInfo> {
|
||||||
|
// 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<String, u16> = HashMap::new();
|
||||||
|
let mut component_packages_map: HashMap<String, &mut JsonValue> = 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<String> {
|
||||||
|
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<String> {
|
||||||
|
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<String, u16>,
|
||||||
|
package_mapping: &HashMap<String, &mut JsonValue>,
|
||||||
|
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
|
||||||
|
}
|
14
src/services/comp-sys/component/Cargo.toml
Normal file
14
src/services/comp-sys/component/Cargo.toml
Normal file
@ -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"
|
57
src/services/comp-sys/component/README.md
Normal file
57
src/services/comp-sys/component/README.md
Normal file
@ -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.
|
178
src/services/comp-sys/component/src/lib.rs
Normal file
178
src/services/comp-sys/component/src/lib.rs
Normal file
@ -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<core::cmp::Ordering> {
|
||||||
|
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<ComponentInfo>) -> Result<(), ComponentSystemInitError> {
|
||||||
|
let components_info = parse_input(components);
|
||||||
|
match_and_call(components_info)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(components: Vec<ComponentInfo>) -> BTreeMap<String, ComponentInfo> {
|
||||||
|
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<String, ComponentInfo>,
|
||||||
|
) -> Result<(), ComponentSystemInitError> {
|
||||||
|
let mut infos = Vec::new();
|
||||||
|
for registry in inventory::iter::<ComponentRegistry> {
|
||||||
|
// 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(())
|
||||||
|
}
|
17
src/services/comp-sys/component/tests/kernel/Cargo.toml
Normal file
17
src/services/comp-sys/component/tests/kernel/Cargo.toml
Normal file
@ -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"}
|
@ -0,0 +1,5 @@
|
|||||||
|
# template
|
||||||
|
[components]
|
||||||
|
kernel = {name = "kernel"}
|
||||||
|
foo = {name = "foo"}
|
||||||
|
bar = {name = "bar"}
|
10
src/services/comp-sys/component/tests/kernel/bar/Cargo.toml
Normal file
10
src/services/comp-sys/component/tests/kernel/bar/Cargo.toml
Normal file
@ -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"}
|
||||||
|
|
13
src/services/comp-sys/component/tests/kernel/bar/src/lib.rs
Normal file
13
src/services/comp-sys/component/tests/kernel/bar/src/lib.rs
Normal file
@ -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(())
|
||||||
|
}
|
15
src/services/comp-sys/component/tests/kernel/foo/Cargo.toml
Normal file
15
src/services/comp-sys/component/tests/kernel/foo/Cargo.toml
Normal file
@ -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"
|
||||||
|
|
15
src/services/comp-sys/component/tests/kernel/foo/src/lib.rs
Normal file
15
src/services/comp-sys/component/tests/kernel/foo/src/lib.rs
Normal file
@ -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(())
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
19
src/services/comp-sys/component/tests/kernel/src/main.rs
Normal file
19
src/services/comp-sys/component/tests/kernel/src/main.rs
Normal file
@ -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);
|
||||||
|
}
|
17
src/services/comp-sys/component/tests/kernel/tests/test.rs
Normal file
17
src/services/comp-sys/component/tests/kernel/tests/test.rs
Normal file
@ -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);
|
||||||
|
}
|
24
src/services/comps/block/Cargo.toml
Normal file
24
src/services/comps/block/Cargo.toml
Normal file
@ -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"]
|
71
src/services/comps/block/src/lib.rs
Normal file
71
src/services/comps/block/src/lib.rs
Normal file
@ -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<BLKComponent> = 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<dyn BlockDevice>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BLKComponent {
|
||||||
|
pub fn init() -> Result<Self, ComponentInitError> {
|
||||||
|
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<dyn BlockDevice> {
|
||||||
|
self.blk_device.clone()
|
||||||
|
}
|
||||||
|
}
|
54
src/services/comps/block/src/virtio.rs
Normal file
54
src/services/comps/block/src/virtio.rs
Normal file
@ -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<BLKDevice>,
|
||||||
|
pub common_cfg: InFramePtr<VitrioPciCommonCfg>,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/services/comps/input/Cargo.toml
Normal file
25
src/services/comps/input/Cargo.toml
Normal file
@ -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"]
|
90
src/services/comps/input/src/lib.rs
Normal file
90
src/services/comps/input/src/lib.rs
Normal file
@ -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<INPUTComponent> = 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<BTreeMap<u8, Arc<dyn INPUTDevice>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl INPUTComponent {
|
||||||
|
pub fn init() -> Result<Self, ComponentInitError> {
|
||||||
|
let mut input_device_map: BTreeMap<u8, Arc<dyn INPUTDevice>> = 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<Arc<dyn INPUTDevice>> {
|
||||||
|
self.input_device_map
|
||||||
|
.lock()
|
||||||
|
.iter()
|
||||||
|
.map(|(_, device)| device.clone())
|
||||||
|
.collect::<Vec<Arc<dyn INPUTDevice>>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum InputDeviceHandleError {
|
||||||
|
DeviceNotExists,
|
||||||
|
Unknown,
|
||||||
|
}
|
122
src/services/comps/input/src/virtio.rs
Normal file
122
src/services/comps/input/src/virtio.rs
Normal file
@ -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<VitrioPciCommonCfg>,
|
||||||
|
msix: Mutex<MSIX>,
|
||||||
|
name: String,
|
||||||
|
callbacks: Mutex<Vec<Arc<dyn Fn(DecodeType) + Send + Sync + 'static>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -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<Vec<Arc<PCIDevice>>> = 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<Arc<PCIDevice>> {
|
|
||||||
PCI_DEVICES.lock().get(index).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn device_amount() -> usize {
|
|
||||||
PCI_DEVICES.lock().len()
|
|
||||||
}
|
|
@ -12,7 +12,8 @@ jinux-frame = {path = "../../../framework/jinux-frame"}
|
|||||||
jinux-util = {path="../../libs/jinux-util"}
|
jinux-util = {path="../../libs/jinux-util"}
|
||||||
pod = {path = "../../../framework/pod"}
|
pod = {path = "../../../framework/pod"}
|
||||||
pod-derive = {path = "../../../framework/pod-derive"}
|
pod-derive = {path = "../../../framework/pod-derive"}
|
||||||
log= "0.4"
|
component = {path="../../comp-sys/component"}
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
86
src/services/comps/pci/src/lib.rs
Normal file
86
src/services/comps/pci/src/lib.rs
Normal file
@ -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<PCIComponent> = 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<Vec<Arc<PCIDevice>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PCIComponent {
|
||||||
|
pub fn init() -> Result<Self, ComponentInitError> {
|
||||||
|
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<Arc<PCIDevice>> {
|
||||||
|
self.pci_device.lock().get(index).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_amount(self: &Self) -> usize {
|
||||||
|
self.pci_device.lock().len()
|
||||||
|
}
|
||||||
|
}
|
@ -9,12 +9,13 @@ edition = "2021"
|
|||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
spin = "0.9.4"
|
spin = "0.9.4"
|
||||||
jinux-frame = {path = "../../../framework/jinux-frame"}
|
jinux-frame = {path = "../../../framework/jinux-frame"}
|
||||||
jinux-pci = {path="../jinux-pci"}
|
jinux-pci = {path="../pci"}
|
||||||
jinux-util = {path="../../libs/jinux-util"}
|
jinux-util = {path="../../libs/jinux-util"}
|
||||||
pod = {path = "../../../framework/pod"}
|
pod = {path = "../../../framework/pod"}
|
||||||
pod-derive = {path = "../../../framework/pod-derive"}
|
pod-derive = {path = "../../../framework/pod-derive"}
|
||||||
log= "0.4"
|
component = {path="../../comp-sys/component"}
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
||||||
|
|
@ -9,7 +9,7 @@ use pod::Pod;
|
|||||||
use crate::{
|
use crate::{
|
||||||
device::block::{BlkReq, BlkResp, ReqType, RespStatus, BLK_SIZE},
|
device::block::{BlkReq, BlkResp, ReqType, RespStatus, BLK_SIZE},
|
||||||
device::VirtioDeviceError,
|
device::VirtioDeviceError,
|
||||||
queue::VirtQueue,
|
queue::{QueueError, VirtQueue},
|
||||||
VitrioPciCommonCfg,
|
VitrioPciCommonCfg,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,14 +65,17 @@ impl BLKDevice {
|
|||||||
sector: block_id as u64,
|
sector: block_id as u64,
|
||||||
};
|
};
|
||||||
let mut resp = BlkResp::default();
|
let mut resp = BlkResp::default();
|
||||||
self.queue
|
let token = self
|
||||||
|
.queue
|
||||||
.add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()])
|
.add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()])
|
||||||
.expect("add queue failed");
|
.expect("add queue failed");
|
||||||
self.queue.notify();
|
self.queue.notify();
|
||||||
while !self.queue.can_pop() {
|
while !self.queue.can_pop() {
|
||||||
spin_loop();
|
spin_loop();
|
||||||
}
|
}
|
||||||
self.queue.pop_used().expect("pop used failed");
|
self.queue
|
||||||
|
.pop_used_with_token(token)
|
||||||
|
.expect("pop used failed");
|
||||||
match resp.status {
|
match resp.status {
|
||||||
RespStatus::Ok => {}
|
RespStatus::Ok => {}
|
||||||
_ => panic!("io error in block device"),
|
_ => panic!("io error in block device"),
|
||||||
@ -87,15 +90,17 @@ impl BLKDevice {
|
|||||||
sector: block_id as u64,
|
sector: block_id as u64,
|
||||||
};
|
};
|
||||||
let mut resp = BlkResp::default();
|
let mut resp = BlkResp::default();
|
||||||
self.queue
|
let token = self
|
||||||
|
.queue
|
||||||
.add(&[req.as_bytes(), buf], &[resp.as_bytes_mut()])
|
.add(&[req.as_bytes(), buf], &[resp.as_bytes_mut()])
|
||||||
.expect("add queue failed");
|
.expect("add queue failed");
|
||||||
self.queue.notify();
|
self.queue.notify();
|
||||||
|
|
||||||
while !self.queue.can_pop() {
|
while !self.queue.can_pop() {
|
||||||
spin_loop();
|
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;
|
let st = resp.status;
|
||||||
match st {
|
match st {
|
||||||
RespStatus::Ok => {}
|
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<u32, QueueError> {
|
||||||
|
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);
|
assert_eq!(buf.len(), BLK_SIZE);
|
||||||
let req = BlkReq {
|
*req = BlkReq {
|
||||||
type_: ReqType::In,
|
type_: ReqType::In,
|
||||||
reserved: 0,
|
reserved: 0,
|
||||||
sector: block_id as u64,
|
sector: block_id as u64,
|
||||||
};
|
};
|
||||||
self.queue
|
let token = self
|
||||||
|
.queue
|
||||||
.add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()])
|
.add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.queue.notify();
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -152,6 +152,7 @@ impl VirtioDevice {
|
|||||||
VirtioDeviceType::Input => InputDevice::negotiate_features(device_specified_features),
|
VirtioDeviceType::Input => InputDevice::negotiate_features(device_specified_features),
|
||||||
VirtioDeviceType::Crypto => todo!(),
|
VirtioDeviceType::Crypto => todo!(),
|
||||||
VirtioDeviceType::Socket => todo!(),
|
VirtioDeviceType::Socket => todo!(),
|
||||||
|
VirtioDeviceType::Unknown => todo!(),
|
||||||
};
|
};
|
||||||
let support_feature = Feature::from_bits_truncate(features);
|
let support_feature = Feature::from_bits_truncate(features);
|
||||||
// support_feature.remove(Feature::RING_EVENT_IDX);
|
// support_feature.remove(Feature::RING_EVENT_IDX);
|
@ -5,14 +5,19 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
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 bitflags::bitflags;
|
||||||
|
use component::ComponentInitError;
|
||||||
use device::VirtioDevice;
|
use device::VirtioDevice;
|
||||||
use jinux_frame::{offset_of, TrapFrame};
|
use jinux_frame::{offset_of, TrapFrame};
|
||||||
use jinux_pci::util::{PCIDevice, BAR};
|
use jinux_pci::util::{PCIDevice, BAR};
|
||||||
use jinux_util::frame_ptr::InFramePtr;
|
use jinux_util::frame_ptr::InFramePtr;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use pod_derive::Pod;
|
use pod_derive::Pod;
|
||||||
|
use spin::{Mutex, Once};
|
||||||
|
|
||||||
use crate::device::VirtioInfo;
|
use crate::device::VirtioInfo;
|
||||||
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, msix::MSIX};
|
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;
|
extern crate pod_derive;
|
||||||
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
|
|
||||||
pub mod queue;
|
pub mod queue;
|
||||||
|
|
||||||
|
pub static VIRTIO_COMPONENT: Once<VIRTIOComponent> = 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<VecDeque<PCIVirtioDevice>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VIRTIOComponent {
|
||||||
|
pub fn init() -> Result<Self, ComponentInitError> {
|
||||||
|
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<PCIVirtioDevice> {
|
||||||
|
self.virtio_devices.lock().pop_front()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_device(self: &Self, device_type: VirtioDeviceType) -> Vec<PCIVirtioDevice> {
|
||||||
|
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! {
|
bitflags! {
|
||||||
/// The device status field.
|
/// The device status field.
|
||||||
pub struct DeviceStatus: u8 {
|
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 {
|
pub enum VirtioDeviceType {
|
||||||
Network,
|
Network,
|
||||||
Block,
|
Block,
|
||||||
@ -130,7 +198,27 @@ pub enum VirtioDeviceType {
|
|||||||
Input,
|
Input,
|
||||||
Crypto,
|
Crypto,
|
||||||
Socket,
|
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 {
|
pub struct PCIVirtioDevice {
|
||||||
/// common config of one device
|
/// common config of one device
|
||||||
pub common_cfg: InFramePtr<VitrioPciCommonCfg>,
|
pub common_cfg: InFramePtr<VitrioPciCommonCfg>,
|
||||||
@ -250,17 +338,28 @@ impl PCIVirtioDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// register all the interrupt functions except the config change, this function should call only once
|
/// register all the interrupt functions, this function should call only once
|
||||||
pub fn register_interrupt_functions<F>(&mut self, function: &'static F)
|
pub fn register_interrupt_functions<F, T>(
|
||||||
where
|
&mut self,
|
||||||
|
config_change_function: &'static F,
|
||||||
|
other_function: &'static T,
|
||||||
|
) where
|
||||||
F: Fn(&TrapFrame) + Send + Sync + 'static,
|
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 {
|
for i in 0..self.msix.table_size as usize {
|
||||||
let msix = self.msix.table.get_mut(i).unwrap();
|
let msix = self.msix.table.get_mut(i).unwrap();
|
||||||
if !msix.irq_handle.is_empty() {
|
if !msix.irq_handle.is_empty() {
|
||||||
panic!("function `register_queue_interrupt_functions` called more than one time");
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,12 +9,14 @@ use jinux_frame::{
|
|||||||
vm::{VmAllocOptions, VmFrame, VmFrameVec},
|
vm::{VmAllocOptions, VmFrame, VmFrameVec},
|
||||||
};
|
};
|
||||||
use jinux_util::frame_ptr::InFramePtr;
|
use jinux_util::frame_ptr::InFramePtr;
|
||||||
|
use log::debug;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum QueueError {
|
pub enum QueueError {
|
||||||
InvalidArgs,
|
InvalidArgs,
|
||||||
BufferTooSmall,
|
BufferTooSmall,
|
||||||
NotReady,
|
NotReady,
|
||||||
AlreadyUsed,
|
AlreadyUsed,
|
||||||
|
WrongToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The mechanism for bulk data transport on virtio devices.
|
/// The mechanism for bulk data transport on virtio devices.
|
||||||
@ -94,6 +96,7 @@ impl VirtQueue {
|
|||||||
offset_of!(VitrioPciCommonCfg, queue_desc),
|
offset_of!(VitrioPciCommonCfg, queue_desc),
|
||||||
frame.paddr() as u64,
|
frame.paddr() as u64,
|
||||||
);
|
);
|
||||||
|
debug!("queue_desc vm frame:{:x?}", frame);
|
||||||
frame_vec.push(frame);
|
frame_vec.push(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +108,7 @@ impl VirtQueue {
|
|||||||
offset_of!(VitrioPciCommonCfg, queue_driver),
|
offset_of!(VitrioPciCommonCfg, queue_driver),
|
||||||
frame.paddr() as u64,
|
frame.paddr() as u64,
|
||||||
);
|
);
|
||||||
|
debug!("queue_driver vm frame:{:x?}", frame);
|
||||||
frame_vec.push(frame);
|
frame_vec.push(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +120,7 @@ impl VirtQueue {
|
|||||||
offset_of!(VitrioPciCommonCfg, queue_device),
|
offset_of!(VitrioPciCommonCfg, queue_device),
|
||||||
frame.paddr() as u64,
|
frame.paddr() as u64,
|
||||||
);
|
);
|
||||||
|
debug!("queue_device vm frame:{:x?}", frame);
|
||||||
frame_vec.push(frame);
|
frame_vec.push(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,6 +283,35 @@ impl VirtQueue {
|
|||||||
Ok((index, len))
|
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<u32, QueueError> {
|
||||||
|
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.
|
/// Return size of the queue.
|
||||||
pub fn size(&self) -> u16 {
|
pub fn size(&self) -> u16 {
|
||||||
self.queue_size
|
self.queue_size
|
||||||
@ -308,10 +342,16 @@ impl Descriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_buf(inframe_ptr: &InFramePtr<Descriptor>, buf: &[u8]) {
|
fn set_buf(inframe_ptr: &InFramePtr<Descriptor>, buf: &[u8]) {
|
||||||
inframe_ptr.write_at(
|
let va = buf.as_ptr() as usize;
|
||||||
offset_of!(Descriptor, addr),
|
let pa = if va >= jinux_frame::config::PHYS_OFFSET && va <= jinux_frame::config::KERNEL_OFFSET {
|
||||||
jinux_frame::translate_not_offset_virtual_address(buf.as_ptr() as usize) as u64,
|
// 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);
|
inframe_ptr.write_at(offset_of!(Descriptor, len), buf.len() as u32);
|
||||||
}
|
}
|
||||||
bitflags! {
|
bitflags! {
|
@ -9,8 +9,8 @@ edition = "2021"
|
|||||||
jinux-frame = {path = "../../../framework/jinux-frame"}
|
jinux-frame = {path = "../../../framework/jinux-frame"}
|
||||||
pod = {path = "../../../framework/pod"}
|
pod = {path = "../../../framework/pod"}
|
||||||
pod-derive = {path = "../../../framework/pod-derive"}
|
pod-derive = {path = "../../../framework/pod-derive"}
|
||||||
jinux-pci = {path="../../comps/jinux-pci"}
|
jinux-input = {path="../../comps/input"}
|
||||||
jinux-virtio = {path="../../comps/jinux-virtio"}
|
jinux-block = {path="../../comps/block"}
|
||||||
controlled = { path = "../../comp-sys/controlled" }
|
controlled = { path = "../../comp-sys/controlled" }
|
||||||
typeflags = {path="../typeflags"}
|
typeflags = {path="../typeflags"}
|
||||||
typeflags-util = {path="../typeflags-util"}
|
typeflags-util = {path="../typeflags-util"}
|
||||||
|
@ -1,7 +1,30 @@
|
|||||||
pub mod pci;
|
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
|
|
||||||
|
use jinux_input::INPUT_COMPONENT;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
pub fn init() {
|
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();
|
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!");
|
||||||
|
}
|
||||||
|
@ -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");
|
|
||||||
}
|
|
@ -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<BLKDevice>,
|
|
||||||
pub common_cfg: InFramePtr<VitrioPciCommonCfg>,
|
|
||||||
msix: MSIX,
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
// TODO: use dyn BlockDevice instead
|
|
||||||
pub static ref BLOCK_DEVICE: Arc<Mutex<Option<VirtioBlockDevice>>> = 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<PCIDevice>) {
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
|
@ -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<Vec<DecodeType>> = Mutex::new(Vec::new());
|
|
||||||
pub static ref MOUSE_EVENT: Mutex<Vec<DecodeType>> = Mutex::new(Vec::new());
|
|
||||||
static ref KEYBOARD_CALLBACKS: Mutex<Vec<Arc<dyn Fn() + Send + Sync + 'static>>> =
|
|
||||||
Mutex::new(Vec::new());
|
|
||||||
static ref INPUT_DEVICE_LIST: Mutex<Vec<Arc<VirtioInputDevice>>> =
|
|
||||||
Mutex::new(Vec::with_capacity(2));
|
|
||||||
static ref INPUT_DEVICE_IRQ_HASH: Mutex<BTreeMap<u16, usize>> = Mutex::new(BTreeMap::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VirtioInputDevice {
|
|
||||||
input_device: InputDevice,
|
|
||||||
common_cfg: InFramePtr<VitrioPciCommonCfg>,
|
|
||||||
msix: Mutex<MSIX>,
|
|
||||||
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<PCIDevice>) {
|
|
||||||
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<dyn Fn() + 'static + Send + Sync>) {
|
|
||||||
KEYBOARD_CALLBACKS.lock().push(callback);
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -90,7 +90,7 @@ impl<'a> Iterator for FutexIter<'a> {
|
|||||||
return None;
|
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 {
|
if self.count == ROBUST_LIST_LIMIT {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
|||||||
test_main();
|
test_main();
|
||||||
jinux_frame::init(boot_info);
|
jinux_frame::init(boot_info);
|
||||||
println!("[kernel] finish init jinux_frame");
|
println!("[kernel] finish init jinux_frame");
|
||||||
|
component::init(component::generate_information!()).unwrap();
|
||||||
jinux_std::init();
|
jinux_std::init();
|
||||||
jinux_std::run_first_process();
|
jinux_std::run_first_process();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user