mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-21 23:56:18 +04:00
Basic loadable kernel module support, with a module template written in Rust.
Under aarch64 and x86_64, hello_rust can be built and loaded by `/busybox insmod hello_rust.ko`.
This commit is contained in:
parent
da028c1f10
commit
7b8252eb1b
6
.gitignore
vendored
6
.gitignore
vendored
@ -23,3 +23,9 @@ Cargo.lock
|
||||
|
||||
# for idea
|
||||
.idea
|
||||
|
||||
# for kernel module building
|
||||
# C & Rust
|
||||
modules/*/objs
|
||||
# Rust
|
||||
modules/*/target
|
||||
|
@ -3,4 +3,4 @@ members = [
|
||||
"crate/memory",
|
||||
"crate/sync",
|
||||
]
|
||||
exclude = ["kernel", "bootloader", "user/rust"]
|
||||
exclude = ["kernel", "bootloader", "user/rust", "modules"]
|
||||
|
28
kernel/Cargo.lock
generated
28
kernel/Cargo.lock
generated
@ -40,6 +40,11 @@ dependencies = [
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.4"
|
||||
@ -126,6 +131,17 @@ name = "cfg-if"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "compression"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console-traits"
|
||||
version = "0.3.0"
|
||||
@ -261,6 +277,14 @@ name = "nodrop"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_bootinfo"
|
||||
version = "0.2.1"
|
||||
@ -382,6 +406,7 @@ dependencies = [
|
||||
"bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader?branch=vga)",
|
||||
"buddy_system_allocator 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compression 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)",
|
||||
"heapless 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -687,6 +712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)" = "<none>"
|
||||
"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72"
|
||||
"checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27"
|
||||
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
||||
"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a"
|
||||
"checksum bcm2837 1.0.0 (git+https://github.com/rcore-os/bcm2837)" = "<none>"
|
||||
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
|
||||
@ -700,6 +726,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||
"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
|
||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||
"checksum compression 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e259c97a5da10842ee4d97388d7dd0f4a0b61d50063abdf173507c717b2b0c"
|
||||
"checksum console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f711b3d1d5c3f7ae7d6428901c0f3e5d5f5c800fcfac86bf0252e96373a2cec6"
|
||||
"checksum deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)" = "<none>"
|
||||
"checksum device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)" = "<none>"
|
||||
@ -719,6 +746,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
|
||||
"checksum mips 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "053a14b59d7b828efefebf92b557015d99383264f4714a959b1d970d8c6c32fb"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
|
||||
"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79"
|
||||
"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6"
|
||||
|
@ -67,6 +67,8 @@ rcore-memory = { path = "../crate/memory" }
|
||||
rcore-thread = { git = "https://github.com/rcore-os/rcore-thread" }
|
||||
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs" }
|
||||
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs" }
|
||||
compression = { version="0.1.3", default-features = false, features=["gzip"]}
|
||||
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
bootloader = { git = "https://github.com/rcore-os/bootloader", branch = "vga" }
|
||||
|
@ -312,6 +312,10 @@ sym:
|
||||
|
||||
$(bootloader): $(kernel)
|
||||
ifeq ($(need_bootloader), true)
|
||||
ifeq ($(arch), aarch64)
|
||||
@echo "Patching symbols into kernel."
|
||||
../tools/fill_symbols/aarch64.sh target/aarch64/release/rcore
|
||||
endif
|
||||
@echo Building $(arch) bootloader
|
||||
@$(strip) $(kernel) -o $(kernel)_stripped
|
||||
@cd $(bootloader_dir) && make arch=$(arch) mode=$(mode) payload=../kernel/$(kernel)_stripped
|
||||
@ -331,6 +335,10 @@ endif
|
||||
kernel: $(dtb)
|
||||
@echo Building $(arch) kernel
|
||||
ifeq ($(arch), x86_64)
|
||||
@bootimage build $(build_args)
|
||||
@echo "Now patching kernel symbols onto kernel."
|
||||
../tools/fill_symbols/x86_64.sh target/x86_64/release/rcore
|
||||
@echo "Generate bootimage again."
|
||||
@bootimage build $(build_args)
|
||||
@mv target/x86_64/bootimage.bin $(bootimage)
|
||||
else ifeq ($(arch), $(filter $(arch), riscv32 riscv64))
|
||||
|
@ -25,6 +25,7 @@ pub extern "C" fn rust_main() -> ! {
|
||||
crate::logging::init();
|
||||
interrupt::init();
|
||||
memory::init();
|
||||
crate::lkm::manager::ModuleManager::init();
|
||||
driver::init();
|
||||
println!("{}", LOGO);
|
||||
|
||||
|
@ -56,6 +56,8 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
|
||||
memory::init_kernel_kseg2_map();
|
||||
//get local apic id of cpu
|
||||
cpu::init();
|
||||
// now we can start LKM.
|
||||
crate::lkm::manager::ModuleManager::init();
|
||||
// Use IOAPIC instead of PIC, use APIC Timer instead of PIT, init serial&keyboard in x86_64
|
||||
driver::init(boot_info);
|
||||
// init pci/bus-based devices ,e.g. Intel 10Gb NIC, ...
|
||||
|
@ -20,25 +20,26 @@ extern crate log;
|
||||
extern crate lazy_static;
|
||||
|
||||
pub use crate::process::{new_kernel_context, processor};
|
||||
use buddy_system_allocator::LockedHeapWithRescue;
|
||||
use rcore_thread::std_thread as thread;
|
||||
pub use buddy_system_allocator::LockedHeapWithRescue;
|
||||
pub use rcore_thread::std_thread as thread;
|
||||
|
||||
#[macro_use] // print!
|
||||
mod logging;
|
||||
pub mod logging;
|
||||
#[macro_use]
|
||||
mod util;
|
||||
mod backtrace;
|
||||
mod consts;
|
||||
mod drivers;
|
||||
mod fs;
|
||||
mod lang;
|
||||
mod memory;
|
||||
mod net;
|
||||
mod process;
|
||||
mod shell;
|
||||
mod sync;
|
||||
mod syscall;
|
||||
mod trap;
|
||||
pub mod util;
|
||||
pub mod backtrace;
|
||||
pub mod consts;
|
||||
pub mod drivers;
|
||||
pub mod fs;
|
||||
pub mod lang;
|
||||
pub mod lkm;
|
||||
pub mod memory;
|
||||
pub mod net;
|
||||
pub mod process;
|
||||
pub mod shell;
|
||||
pub mod sync;
|
||||
pub mod syscall;
|
||||
pub mod trap;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
86
kernel/src/lkm/api.rs
Normal file
86
kernel/src/lkm/api.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use super::*;
|
||||
use crate::lkm::manager::ModuleManager;
|
||||
use crate::lkm::structs::LoadedModule;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::slice::from_raw_parts;
|
||||
|
||||
pub fn get_module(this_module: usize) -> &'static mut LoadedModule {
|
||||
unsafe {
|
||||
let ptr = this_module as *mut LoadedModule;
|
||||
&mut (*ptr) as (&'static mut LoadedModule)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn cstr_to_str(ptr: *const u8, max_size: usize) -> String {
|
||||
(0..max_size)
|
||||
.find(|&i| ptr.offset(i as isize).read() == 0)
|
||||
.and_then(|len| core::str::from_utf8(core::slice::from_raw_parts(ptr, len)).ok())
|
||||
.map(|s| String::from(s))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn lkm_api_pong() -> usize {
|
||||
println!("Pong from Kernel Module!");
|
||||
println!(
|
||||
"This indicates that a kernel module is successfully loaded into kernel and called a stub."
|
||||
);
|
||||
114514
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn lkm_api_debug(this_module: usize) {
|
||||
let module = get_module(this_module);
|
||||
module.lock.lock();
|
||||
println!(
|
||||
"[LKM] Current module info: name={} version={} api_version={}\nref_count={} dep_count={}",
|
||||
module.info.name,
|
||||
module.info.version,
|
||||
module.info.api_version,
|
||||
Arc::strong_count(&module.using_counts),
|
||||
module.used_counts
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn lkm_api_query_symbol(symbol: *const u8) -> usize {
|
||||
manager::ModuleManager::with(|man| {
|
||||
match man.resolve_symbol(&unsafe { cstr_to_str(symbol, 256) }) {
|
||||
Some(x) => x,
|
||||
None => 0,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn lkm_api_kmalloc(size: usize) -> usize {
|
||||
unsafe { crate::HEAP_ALLOCATOR.alloc(Layout::from_size_align(size, 8).unwrap()) as usize }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn lkm_api_kfree(ptr: usize, size: usize) {
|
||||
unsafe {
|
||||
crate::HEAP_ALLOCATOR.dealloc(ptr as *mut u8, Layout::from_size_align(size, 8).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn lkm_api_info(ptr: *const u8) {
|
||||
let text = unsafe { cstr_to_str(ptr, 1024) };
|
||||
info!("{}", text);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn lkm_api_add_kernel_symbols(start: usize, end: usize) {
|
||||
use crate::lkm::manager::LKM_MANAGER;
|
||||
let length = end - start;
|
||||
use core::str::from_utf8;
|
||||
let symbols = unsafe { from_utf8(from_raw_parts(start as *const u8, length)) }.unwrap();
|
||||
let global_lkmm = &LKM_MANAGER;
|
||||
let mut locked_lkmm = global_lkmm.lock();
|
||||
let mut lkmm = locked_lkmm.as_mut().unwrap();
|
||||
lkmm.init_kernel_symbols(symbols);
|
||||
}
|
149
kernel/src/lkm/const_reloc/aarch64.rs
Normal file
149
kernel/src/lkm/const_reloc/aarch64.rs
Normal file
@ -0,0 +1,149 @@
|
||||
///AArch64 Relocation Constants.
|
||||
pub const R_AARCH64_NONE: usize = 0;
|
||||
pub const R_AARCH64_P32_ABS32: usize = 1;
|
||||
pub const R_AARCH64_P32_COPY: usize = 180;
|
||||
pub const R_AARCH64_P32_GLOB_DAT: usize = 181;
|
||||
pub const R_AARCH64_P32_JUMP_SLOT: usize = 182;
|
||||
pub const R_AARCH64_P32_RELATIVE: usize = 183;
|
||||
pub const R_AARCH64_P32_TLS_DTPMOD: usize = 184;
|
||||
pub const R_AARCH64_P32_TLS_DTPREL: usize = 185;
|
||||
pub const R_AARCH64_P32_TLS_TPREL: usize = 186;
|
||||
pub const R_AARCH64_P32_TLSDESC: usize = 187;
|
||||
pub const R_AARCH64_P32_IRELATIVE: usize = 188;
|
||||
pub const R_AARCH64_ABS64: usize = 257;
|
||||
pub const R_AARCH64_ABS32: usize = 258;
|
||||
pub const R_AARCH64_ABS16: usize = 259;
|
||||
pub const R_AARCH64_PREL64: usize = 260;
|
||||
pub const R_AARCH64_PREL32: usize = 261;
|
||||
pub const R_AARCH64_PREL16: usize = 262;
|
||||
pub const R_AARCH64_MOVW_UABS_G0: usize = 263;
|
||||
pub const R_AARCH64_MOVW_UABS_G0_NC: usize = 264;
|
||||
pub const R_AARCH64_MOVW_UABS_G1: usize = 265;
|
||||
pub const R_AARCH64_MOVW_UABS_G1_NC: usize = 266;
|
||||
pub const R_AARCH64_MOVW_UABS_G2: usize = 267;
|
||||
pub const R_AARCH64_MOVW_UABS_G2_NC: usize = 268;
|
||||
pub const R_AARCH64_MOVW_UABS_G3: usize = 269;
|
||||
pub const R_AARCH64_MOVW_SABS_G0: usize = 270;
|
||||
pub const R_AARCH64_MOVW_SABS_G1: usize = 271;
|
||||
pub const R_AARCH64_MOVW_SABS_G2: usize = 272;
|
||||
pub const R_AARCH64_LD_PREL_LO19: usize = 273;
|
||||
pub const R_AARCH64_ADR_PREL_LO21: usize = 274;
|
||||
pub const R_AARCH64_ADR_PREL_PG_HI21: usize = 275;
|
||||
pub const R_AARCH64_ADR_PREL_PG_HI21_NC: usize = 276;
|
||||
pub const R_AARCH64_ADD_ABS_LO12_NC: usize = 277;
|
||||
pub const R_AARCH64_LDST8_ABS_LO12_NC: usize = 278;
|
||||
pub const R_AARCH64_TSTBR14: usize = 279;
|
||||
pub const R_AARCH64_CONDBR19: usize = 280;
|
||||
pub const R_AARCH64_JUMP26: usize = 282;
|
||||
pub const R_AARCH64_CALL26: usize = 283;
|
||||
pub const R_AARCH64_LDST16_ABS_LO12_NC: usize = 284;
|
||||
pub const R_AARCH64_LDST32_ABS_LO12_NC: usize = 285;
|
||||
pub const R_AARCH64_LDST64_ABS_LO12_NC: usize = 286;
|
||||
pub const R_AARCH64_MOVW_PREL_G0: usize = 287;
|
||||
pub const R_AARCH64_MOVW_PREL_G0_NC: usize = 288;
|
||||
pub const R_AARCH64_MOVW_PREL_G1: usize = 289;
|
||||
pub const R_AARCH64_MOVW_PREL_G1_NC: usize = 290;
|
||||
pub const R_AARCH64_MOVW_PREL_G2: usize = 291;
|
||||
pub const R_AARCH64_MOVW_PREL_G2_NC: usize = 292;
|
||||
pub const R_AARCH64_MOVW_PREL_G3: usize = 293;
|
||||
pub const R_AARCH64_LDST128_ABS_LO12_NC: usize = 299;
|
||||
pub const R_AARCH64_MOVW_GOTOFF_G0: usize = 300;
|
||||
pub const R_AARCH64_MOVW_GOTOFF_G0_NC: usize = 301;
|
||||
pub const R_AARCH64_MOVW_GOTOFF_G1: usize = 302;
|
||||
pub const R_AARCH64_MOVW_GOTOFF_G1_NC: usize = 303;
|
||||
pub const R_AARCH64_MOVW_GOTOFF_G2: usize = 304;
|
||||
pub const R_AARCH64_MOVW_GOTOFF_G2_NC: usize = 305;
|
||||
pub const R_AARCH64_MOVW_GOTOFF_G3: usize = 306;
|
||||
pub const R_AARCH64_GOTREL64: usize = 307;
|
||||
pub const R_AARCH64_GOTREL32: usize = 308;
|
||||
pub const R_AARCH64_GOT_LD_PREL19: usize = 309;
|
||||
pub const R_AARCH64_LD64_GOTOFF_LO15: usize = 310;
|
||||
pub const R_AARCH64_ADR_GOT_PAGE: usize = 311;
|
||||
pub const R_AARCH64_LD64_GOT_LO12_NC: usize = 312;
|
||||
pub const R_AARCH64_LD64_GOTPAGE_LO15: usize = 313;
|
||||
pub const R_AARCH64_TLSGD_ADR_PREL21: usize = 512;
|
||||
pub const R_AARCH64_TLSGD_ADR_PAGE21: usize = 513;
|
||||
pub const R_AARCH64_TLSGD_ADD_LO12_NC: usize = 514;
|
||||
pub const R_AARCH64_TLSGD_MOVW_G1: usize = 515;
|
||||
pub const R_AARCH64_TLSGD_MOVW_G0_NC: usize = 516;
|
||||
pub const R_AARCH64_TLSLD_ADR_PREL21: usize = 517;
|
||||
pub const R_AARCH64_TLSLD_ADR_PAGE21: usize = 518;
|
||||
pub const R_AARCH64_TLSLD_ADD_LO12_NC: usize = 519;
|
||||
pub const R_AARCH64_TLSLD_MOVW_G1: usize = 520;
|
||||
pub const R_AARCH64_TLSLD_MOVW_G0_NC: usize = 521;
|
||||
pub const R_AARCH64_TLSLD_LD_PREL19: usize = 522;
|
||||
pub const R_AARCH64_TLSLD_MOVW_DTPREL_G2: usize = 523;
|
||||
pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1: usize = 524;
|
||||
pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: usize = 525;
|
||||
pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0: usize = 526;
|
||||
pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: usize = 527;
|
||||
pub const R_AARCH64_TLSLD_ADD_DTPREL_HI12: usize = 528;
|
||||
pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12: usize = 529;
|
||||
pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: usize = 530;
|
||||
pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12: usize = 531;
|
||||
pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: usize = 532;
|
||||
pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12: usize = 533;
|
||||
pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: usize = 534;
|
||||
pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12: usize = 535;
|
||||
pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: usize = 536;
|
||||
pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12: usize = 537;
|
||||
pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: usize = 538;
|
||||
pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G1: usize = 539;
|
||||
pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: usize = 540;
|
||||
pub const R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: usize = 541;
|
||||
pub const R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: usize = 542;
|
||||
pub const R_AARCH64_TLSIE_LD_GOTTPREL_PREL19: usize = 543;
|
||||
pub const R_AARCH64_TLSLE_MOVW_TPREL_G2: usize = 544;
|
||||
pub const R_AARCH64_TLSLE_MOVW_TPREL_G1: usize = 545;
|
||||
pub const R_AARCH64_TLSLE_MOVW_TPREL_G1_NC: usize = 546;
|
||||
pub const R_AARCH64_TLSLE_MOVW_TPREL_G0: usize = 547;
|
||||
pub const R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: usize = 548;
|
||||
pub const R_AARCH64_TLSLE_ADD_TPREL_HI12: usize = 549;
|
||||
pub const R_AARCH64_TLSLE_ADD_TPREL_LO12: usize = 550;
|
||||
pub const R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: usize = 551;
|
||||
pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12: usize = 552;
|
||||
pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: usize = 553;
|
||||
pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12: usize = 554;
|
||||
pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: usize = 555;
|
||||
pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12: usize = 556;
|
||||
pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: usize = 557;
|
||||
pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12: usize = 558;
|
||||
pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: usize = 559;
|
||||
pub const R_AARCH64_TLSDESC_LD_PREL19: usize = 560;
|
||||
pub const R_AARCH64_TLSDESC_ADR_PREL21: usize = 561;
|
||||
pub const R_AARCH64_TLSDESC_ADR_PAGE21: usize = 562;
|
||||
pub const R_AARCH64_TLSDESC_LD64_LO12: usize = 563;
|
||||
pub const R_AARCH64_TLSDESC_ADD_LO12: usize = 564;
|
||||
pub const R_AARCH64_TLSDESC_OFF_G1: usize = 565;
|
||||
pub const R_AARCH64_TLSDESC_OFF_G0_NC: usize = 566;
|
||||
pub const R_AARCH64_TLSDESC_LDR: usize = 567;
|
||||
pub const R_AARCH64_TLSDESC_ADD: usize = 568;
|
||||
pub const R_AARCH64_TLSDESC_CALL: usize = 569;
|
||||
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: usize = 570;
|
||||
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: usize = 571;
|
||||
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: usize = 572;
|
||||
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: usize = 573;
|
||||
pub const R_AARCH64_COPY: usize = 1024;
|
||||
pub const R_AARCH64_GLOB_DAT: usize = 1025;
|
||||
pub const R_AARCH64_JUMP_SLOT: usize = 1026;
|
||||
pub const R_AARCH64_RELATIVE: usize = 1027;
|
||||
pub const R_AARCH64_TLS_DTPMOD: usize = 1028;
|
||||
pub const R_AARCH64_TLS_DTPMOD64: usize = 1028;
|
||||
pub const R_AARCH64_TLS_DTPREL: usize = 1029;
|
||||
pub const R_AARCH64_TLS_DTPREL64: usize = 1029;
|
||||
pub const R_AARCH64_TLS_TPREL: usize = 1030;
|
||||
pub const R_AARCH64_TLS_TPREL64: usize = 1030;
|
||||
pub const R_AARCH64_TLSDESC: usize = 1031;
|
||||
|
||||
// REL_OFFSET32 does not exist.
|
||||
pub const REL_NONE: usize = R_AARCH64_NONE;
|
||||
pub const REL_SYMBOLIC: usize = R_AARCH64_ABS64;
|
||||
pub const REL_OFFSET32: usize = (-95 as isize) as usize;
|
||||
pub const REL_GOT: usize = R_AARCH64_GLOB_DAT;
|
||||
pub const REL_PLT: usize = R_AARCH64_JUMP_SLOT;
|
||||
pub const REL_RELATIVE: usize = R_AARCH64_RELATIVE;
|
||||
pub const REL_COPY: usize = R_AARCH64_COPY;
|
||||
pub const REL_DTPMOD: usize = R_AARCH64_TLS_DTPMOD64;
|
||||
pub const REL_DTPOFF: usize = R_AARCH64_TLS_DTPREL64;
|
||||
pub const REL_TPOFF: usize = R_AARCH64_TLS_TPREL64;
|
||||
pub const REL_TLSDESC: usize = R_AARCH64_TLSDESC;
|
9
kernel/src/lkm/const_reloc/mod.rs
Normal file
9
kernel/src/lkm/const_reloc/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// Copied from musl ldso.
|
||||
pub mod aarch64;
|
||||
pub mod x86_64;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use self::x86_64::*;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub use self::aarch64::*;
|
60
kernel/src/lkm/const_reloc/x86_64.rs
Normal file
60
kernel/src/lkm/const_reloc/x86_64.rs
Normal file
@ -0,0 +1,60 @@
|
||||
/// x86_64 Relocation Constants.
|
||||
pub const R_X86_64_NONE: usize = 0;
|
||||
pub const R_X86_64_64: usize = 1;
|
||||
pub const R_X86_64_PC32: usize = 2;
|
||||
pub const R_X86_64_GOT32: usize = 3;
|
||||
pub const R_X86_64_PLT32: usize = 4;
|
||||
pub const R_X86_64_COPY: usize = 5;
|
||||
pub const R_X86_64_GLOB_DAT: usize = 6;
|
||||
pub const R_X86_64_JUMP_SLOT: usize = 7;
|
||||
pub const R_X86_64_RELATIVE: usize = 8;
|
||||
pub const R_X86_64_GOTPCREL: usize = 9;
|
||||
|
||||
pub const R_X86_64_32: usize = 10;
|
||||
pub const R_X86_64_32S: usize = 11;
|
||||
pub const R_X86_64_16: usize = 12;
|
||||
pub const R_X86_64_PC16: usize = 13;
|
||||
pub const R_X86_64_8: usize = 14;
|
||||
pub const R_X86_64_PC8: usize = 15;
|
||||
pub const R_X86_64_DTPMOD64: usize = 16;
|
||||
pub const R_X86_64_DTPOFF64: usize = 17;
|
||||
pub const R_X86_64_TPOFF64: usize = 18;
|
||||
pub const R_X86_64_TLSGD: usize = 19;
|
||||
|
||||
pub const R_X86_64_TLSLD: usize = 20;
|
||||
|
||||
pub const R_X86_64_DTPOFF32: usize = 21;
|
||||
pub const R_X86_64_GOTTPOFF: usize = 22;
|
||||
|
||||
pub const R_X86_64_TPOFF32: usize = 23;
|
||||
pub const R_X86_64_PC64: usize = 24;
|
||||
pub const R_X86_64_GOTOFF64: usize = 25;
|
||||
pub const R_X86_64_GOTPC32: usize = 26;
|
||||
pub const R_X86_64_GOT64: usize = 27;
|
||||
pub const R_X86_64_GOTPCREL64: usize = 28;
|
||||
pub const R_X86_64_GOTPC64: usize = 29;
|
||||
pub const R_X86_64_GOTPLT64: usize = 30;
|
||||
pub const R_X86_64_PLTOFF64: usize = 31;
|
||||
pub const R_X86_64_SIZE32: usize = 32;
|
||||
pub const R_X86_64_SIZE64: usize = 33;
|
||||
|
||||
pub const R_X86_64_GOTPC32_TLSDESC: usize = 34;
|
||||
pub const R_X86_64_TLSDESC_CALL: usize = 35;
|
||||
pub const R_X86_64_TLSDESC: usize = 36;
|
||||
pub const R_X86_64_IRELATIVE: usize = 37;
|
||||
pub const R_X86_64_RELATIVE64: usize = 38;
|
||||
pub const R_X86_64_GOTPCRELX: usize = 41;
|
||||
pub const R_X86_64_REX_GOTPCRELX: usize = 42;
|
||||
pub const R_X86_64_NUM: usize = 43;
|
||||
|
||||
pub const REL_NONE: usize = R_X86_64_NONE;
|
||||
pub const REL_SYMBOLIC: usize = R_X86_64_64;
|
||||
pub const REL_OFFSET32: usize = R_X86_64_PC32;
|
||||
pub const REL_GOT: usize = R_X86_64_GLOB_DAT;
|
||||
pub const REL_PLT: usize = R_X86_64_JUMP_SLOT;
|
||||
pub const REL_RELATIVE: usize = R_X86_64_RELATIVE;
|
||||
pub const REL_COPY: usize = R_X86_64_COPY;
|
||||
pub const REL_DTPMOD: usize = R_X86_64_DTPMOD64;
|
||||
pub const REL_DTPOFF: usize = R_X86_64_DTPOFF64;
|
||||
pub const REL_TPOFF: usize = R_X86_64_TPOFF64;
|
||||
pub const REL_TLSDESC: usize = R_X86_64_TLSDESC;
|
145
kernel/src/lkm/kernelvm.rs
Normal file
145
kernel/src/lkm/kernelvm.rs
Normal file
@ -0,0 +1,145 @@
|
||||
// Simple kernel memory set for kernel virtual memory
|
||||
use crate::arch::paging::PageTableImpl;
|
||||
use crate::consts::*;
|
||||
use crate::memory::GlobalFrameAlloc;
|
||||
use crate::sync::SpinLock as Mutex;
|
||||
use alloc::vec::*;
|
||||
use buddy_system_allocator::*;
|
||||
use core::alloc::Layout;
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::ops::DerefMut;
|
||||
use core::ptr::NonNull;
|
||||
use lazy_static::lazy_static;
|
||||
use rcore_memory::memory_set::handler::{ByFrame, MemoryHandler};
|
||||
use rcore_memory::memory_set::MemoryAttr;
|
||||
use rcore_memory::{Page, PAGE_SIZE};
|
||||
|
||||
///Allocated virtual memory space by pages. returns some vaddr.
|
||||
pub trait MemorySpaceManager {
|
||||
fn new() -> Self;
|
||||
fn alloc(&mut self, size: usize) -> Option<(usize, usize)>;
|
||||
fn free(&mut self, target: (usize, usize));
|
||||
fn kernel_table(&self) -> ManuallyDrop<PageTableImpl> {
|
||||
// Only one process can change the kernel table at a time.
|
||||
// If you want to change the mapping item, you have to lock the MemorySpaceManager.
|
||||
unsafe { PageTableImpl::kernel_table() }
|
||||
}
|
||||
}
|
||||
|
||||
/// The most simple strategy: no free and allocate ahead.
|
||||
/// TODO: A better allocation strategy required.
|
||||
pub struct LinearManager {
|
||||
last_page: usize,
|
||||
}
|
||||
use crate::arch::consts::KSEG2_START;
|
||||
|
||||
impl MemorySpaceManager for LinearManager {
|
||||
fn new() -> LinearManager {
|
||||
LinearManager { last_page: 0 }
|
||||
}
|
||||
fn alloc(&mut self, size: usize) -> Option<(usize, usize)> {
|
||||
let mut required_pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
|
||||
let current = self.last_page * PAGE_SIZE + KSEG2_START;
|
||||
self.last_page += required_pages;
|
||||
Some((current, required_pages * PAGE_SIZE))
|
||||
}
|
||||
|
||||
fn free(&mut self, (addr, size): (usize, usize)) {
|
||||
//Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
type VirtualMemorySpaceManager = LinearManager;
|
||||
type LockedVMM = Mutex<VirtualMemorySpaceManager>;
|
||||
lazy_static! {
|
||||
pub static ref KERNELVM_MANAGER: LockedVMM = Mutex::new(VirtualMemorySpaceManager::new());
|
||||
}
|
||||
|
||||
/// Represents a contiguous virtual area: like the ancient const_reloc.
|
||||
/// Use RAII for exception handling
|
||||
pub struct VirtualSpace {
|
||||
start: usize,
|
||||
size: usize,
|
||||
areas: Vec<VirtualArea>,
|
||||
allocator: &'static LockedVMM,
|
||||
page_allocator: ByFrame<GlobalFrameAlloc>,
|
||||
}
|
||||
|
||||
impl VirtualSpace {
|
||||
pub fn new(allocator: &'static LockedVMM, size: usize) -> Option<VirtualSpace> {
|
||||
let mut vmm = allocator.lock();
|
||||
let (start, rsize) = vmm.alloc(size)?;
|
||||
Some(VirtualSpace {
|
||||
start: start,
|
||||
size: rsize,
|
||||
areas: Vec::new(),
|
||||
allocator: allocator,
|
||||
page_allocator: ByFrame::new(GlobalFrameAlloc),
|
||||
})
|
||||
}
|
||||
pub fn start(&self) -> usize {
|
||||
self.start
|
||||
}
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub fn add_area(
|
||||
&mut self,
|
||||
start_addr: usize,
|
||||
end_addr: usize,
|
||||
attr: &MemoryAttr,
|
||||
) -> &VirtualArea {
|
||||
let area = VirtualArea::new(start_addr, end_addr - start_addr, attr, self);
|
||||
self.areas.push(area);
|
||||
self.areas.last().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VirtualSpace {
|
||||
fn drop(&mut self) {
|
||||
for mut v in self.areas.iter_mut() {
|
||||
v.unmap(self.allocator, &mut self.page_allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VirtualArea {
|
||||
start: usize,
|
||||
end: usize,
|
||||
attr: MemoryAttr,
|
||||
}
|
||||
|
||||
impl VirtualArea {
|
||||
pub fn new(
|
||||
page_addr: usize,
|
||||
size: usize,
|
||||
attr: &MemoryAttr,
|
||||
parent: &mut VirtualSpace,
|
||||
) -> VirtualArea {
|
||||
let aligned_start_addr = page_addr - page_addr % PAGE_SIZE;
|
||||
let mut aligned_end = (page_addr + size + PAGE_SIZE - 1);
|
||||
aligned_end = aligned_end - aligned_end % PAGE_SIZE;
|
||||
let lock = parent.allocator.lock();
|
||||
let mut active_pt = unsafe { lock.kernel_table() };
|
||||
for p in Page::range_of(aligned_start_addr, aligned_end) {
|
||||
parent
|
||||
.page_allocator
|
||||
.map(active_pt.deref_mut(), p.start_address(), attr);
|
||||
}
|
||||
|
||||
VirtualArea {
|
||||
start: aligned_start_addr,
|
||||
end: aligned_end,
|
||||
attr: attr.clone(),
|
||||
}
|
||||
}
|
||||
pub fn unmap(&mut self, allocator: &LockedVMM, parent: &mut ByFrame<GlobalFrameAlloc>) {
|
||||
let lock = allocator.lock();
|
||||
let mut active_pt = unsafe { lock.kernel_table() };
|
||||
for p in Page::range_of(self.start, self.end) {
|
||||
parent.unmap(active_pt.deref_mut(), p.start_address());
|
||||
}
|
||||
}
|
||||
}
|
628
kernel/src/lkm/manager.rs
Normal file
628
kernel/src/lkm/manager.rs
Normal file
@ -0,0 +1,628 @@
|
||||
use super::api::*;
|
||||
use super::const_reloc as loader;
|
||||
use super::kernelvm::*;
|
||||
use super::structs::*;
|
||||
use crate::consts::*;
|
||||
use crate::lkm::structs::ModuleState::{Ready, Unloading};
|
||||
use crate::memory::GlobalFrameAlloc;
|
||||
use crate::sync::{Condvar, SpinLock as Mutex};
|
||||
use crate::syscall::SysError::*;
|
||||
use crate::syscall::SysResult;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::btree_map::BTreeMap;
|
||||
use alloc::prelude::*;
|
||||
use alloc::string::*;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::*;
|
||||
use core::borrow::BorrowMut;
|
||||
use core::mem::transmute;
|
||||
use core::slice;
|
||||
use lazy_static::lazy_static;
|
||||
use rcore_memory::memory_set::handler::{ByFrame, MemoryHandler};
|
||||
use rcore_memory::memory_set::MemoryAttr;
|
||||
use rcore_memory::{Page, PAGE_SIZE};
|
||||
use xmas_elf::dynamic::Tag;
|
||||
use xmas_elf::program::Type::Load;
|
||||
use xmas_elf::sections::SectionData;
|
||||
use xmas_elf::sections::SectionData::{DynSymbolTable64, Dynamic64, Undefined};
|
||||
use xmas_elf::symbol_table::DynEntry64;
|
||||
use xmas_elf::symbol_table::Entry;
|
||||
use xmas_elf::{
|
||||
header,
|
||||
program::{Flags, Type},
|
||||
ElfFile,
|
||||
};
|
||||
// The symbol data table.
|
||||
global_asm!(include_str!("symbol_table.asm"));
|
||||
|
||||
/// Module Manager is the core part of LKM.
|
||||
/// It does these jobs: Load preset(API) symbols; manage module loading dependency and linking modules.
|
||||
pub struct ModuleManager {
|
||||
stub_symbols: BTreeMap<String, ModuleSymbol>,
|
||||
loaded_modules: Vec<Box<LoadedModule>>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref LKM_MANAGER: Mutex<Option<ModuleManager>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
macro_rules! export_stub {
|
||||
($stub_name:ident) => {
|
||||
ModuleManager::create_stub_symbol(stringify!($stub_name), $stub_name as usize)
|
||||
};
|
||||
}
|
||||
|
||||
fn neg(u: usize) -> usize {
|
||||
(-(u as i64)) as usize
|
||||
}
|
||||
unsafe fn write_to_addr(base: usize, offset: usize, val: usize) {
|
||||
unsafe {
|
||||
let addr = base + offset;
|
||||
*(addr as *mut usize) = val;
|
||||
}
|
||||
}
|
||||
impl ModuleManager {
|
||||
fn create_stub_symbol(symbol_name: &str, symbol_loc: usize) -> ModuleSymbol {
|
||||
ModuleSymbol {
|
||||
name: String::from(symbol_name),
|
||||
loc: symbol_loc,
|
||||
}
|
||||
}
|
||||
fn init_stub_symbols() -> BTreeMap<String, ModuleSymbol> {
|
||||
let vector: Vec<ModuleSymbol> = vec![
|
||||
export_stub!(lkm_api_pong),
|
||||
export_stub!(lkm_api_debug),
|
||||
export_stub!(lkm_api_query_symbol),
|
||||
export_stub!(lkm_api_info),
|
||||
];
|
||||
let mut map: BTreeMap<String, ModuleSymbol> = BTreeMap::new();
|
||||
for module in vector.into_iter() {
|
||||
map.insert(module.name.clone(), module);
|
||||
}
|
||||
map
|
||||
}
|
||||
pub fn load_kernel_symbols_from_elf(&mut self) {
|
||||
extern "C" {
|
||||
fn rcore_symbol_table();
|
||||
fn rcore_symbol_table_size();
|
||||
}
|
||||
let symbol_table_start: usize = rcore_symbol_table as usize;
|
||||
let symbol_table_len: usize =
|
||||
unsafe { *(rcore_symbol_table_size as usize as *const usize) };
|
||||
info!(
|
||||
"Loading kernel symbol table {:08x} with size {:08x}",
|
||||
symbol_table_start as usize, symbol_table_len as usize
|
||||
);
|
||||
if symbol_table_len == 0 {
|
||||
info!("Load kernel symbol table failed! This is because you didn't attach kernel table onto binary.");
|
||||
return;
|
||||
}
|
||||
use compression::prelude::*;
|
||||
let zipped_symbols =
|
||||
unsafe { slice::from_raw_parts(symbol_table_start as *const u8, symbol_table_len) }
|
||||
.to_vec();
|
||||
|
||||
let real_symbols = zipped_symbols
|
||||
.decode(&mut GZipDecoder::new())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.unwrap();
|
||||
use core::slice;
|
||||
use core::str::from_utf8;
|
||||
self.init_kernel_symbols(unsafe { from_utf8(&real_symbols).unwrap() });
|
||||
}
|
||||
pub fn init_kernel_symbols(&mut self, kernel_symbols: &str) {
|
||||
let lines = kernel_symbols.lines();
|
||||
for l in lines.into_iter() {
|
||||
let mut words = l.split_whitespace();
|
||||
let address = words.next().unwrap();
|
||||
let stype = words.next().unwrap();
|
||||
let name = words.next().unwrap();
|
||||
// Simply add the symbol into stub.
|
||||
self.stub_symbols.insert(
|
||||
String::from(name),
|
||||
ModuleSymbol {
|
||||
name: String::from(name),
|
||||
loc: usize::from_str_radix(address, 16).unwrap(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
pub fn resolve_symbol(&self, symbol: &str) -> Option<usize> {
|
||||
self.find_symbol_in_deps(symbol, 0)
|
||||
}
|
||||
fn find_symbol_in_deps(&self, symbol: &str, this_module: usize) -> Option<usize> {
|
||||
if symbol == "THIS_MODULE" {
|
||||
return Some(this_module);
|
||||
}
|
||||
if let Some(sym) = self.stub_symbols.get(symbol) {
|
||||
return Some(sym.loc);
|
||||
}
|
||||
|
||||
for km in self.loaded_modules.iter().rev() {
|
||||
for sym in km.exported_symbols.iter() {
|
||||
if (&sym.name) == symbol {
|
||||
return Some(sym.loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
fn get_symbol_loc(
|
||||
&self,
|
||||
symbol_index: usize,
|
||||
elf: &ElfFile,
|
||||
dynsym: &[DynEntry64],
|
||||
base: usize,
|
||||
find_dependency: bool,
|
||||
this_module: usize,
|
||||
) -> Option<usize> {
|
||||
info!("symbol index: {}", symbol_index);
|
||||
if symbol_index == 0 {
|
||||
return Some(0);
|
||||
}
|
||||
let selected_symbol = &dynsym[symbol_index];
|
||||
if selected_symbol.shndx() == 0 {
|
||||
if find_dependency {
|
||||
info!("symbol name: {}", selected_symbol.get_name(elf).unwrap());
|
||||
self.find_symbol_in_deps(selected_symbol.get_name(elf).unwrap(), this_module)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some(base + (selected_symbol.value() as usize))
|
||||
}
|
||||
}
|
||||
pub fn init_module(&mut self, module_image: &[u8], param_values: &str) -> SysResult {
|
||||
let elf = ElfFile::new(module_image).expect("[LKM] failed to read elf");
|
||||
let is32 = match elf.header.pt2 {
|
||||
header::HeaderPt2::Header32(_) => true,
|
||||
header::HeaderPt2::Header64(_) => false,
|
||||
};
|
||||
if is32 {
|
||||
error!("[LKM] 32-bit elf is not supported!");
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
match elf.header.pt2.type_().as_type() {
|
||||
header::Type::Executable => {
|
||||
error!("[LKM] a kernel module must be some shared object!");
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
header::Type::SharedObject => {}
|
||||
_ => {
|
||||
error!("[LKM] ELF is not executable or shared object");
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
}
|
||||
let lkm_info = elf.find_section_by_name(".rcore-lkm").ok_or_else(|| {
|
||||
error!("[LKM] rcore-lkm metadata not found!");
|
||||
ENOEXEC
|
||||
})?;
|
||||
|
||||
if let Undefined(info_content) = lkm_info.get_data(&elf).map_err(|_| {
|
||||
error!("[LKM] load rcore-lkm error!");
|
||||
ENOEXEC
|
||||
})? {
|
||||
let minfo = ModuleInfo::parse(core::str::from_utf8(info_content).unwrap()).ok_or_else(
|
||||
|| {
|
||||
error!("[LKM] parse info error!");
|
||||
ENOEXEC
|
||||
},
|
||||
)?;
|
||||
//Check dependencies
|
||||
info!(
|
||||
"[LKM] loading module {} version {} api_version {}",
|
||||
minfo.name, minfo.version, minfo.api_version
|
||||
);
|
||||
for i in 0..self.loaded_modules.len() {
|
||||
if self.loaded_modules[i].info.name == minfo.name {
|
||||
error!(
|
||||
"[LKM] another instance of module {} (api version {}) has been loaded!",
|
||||
self.loaded_modules[i].info.name, self.loaded_modules[i].info.api_version
|
||||
);
|
||||
return Err(EEXIST);
|
||||
}
|
||||
}
|
||||
let mut used_dependents: Vec<usize> = vec![];
|
||||
//let loaded_module_list=&mut self.loaded_modules;
|
||||
for module in minfo.dependent_modules.iter() {
|
||||
let mut module_found = false;
|
||||
for i in 0..self.loaded_modules.len() {
|
||||
let loaded_module = &(self.loaded_modules[i]);
|
||||
if loaded_module.info.name == module.name {
|
||||
if loaded_module.info.api_version == module.api_version {
|
||||
used_dependents.push(i);
|
||||
module_found = true;
|
||||
break;
|
||||
} else {
|
||||
error!("[LKM] dependent module {} found but with a different api version {}!", loaded_module.info.name, loaded_module.info.api_version);
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !module_found {
|
||||
error!("[LKM] dependent module not found! {}", module.name);
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
}
|
||||
for module in used_dependents {
|
||||
self.loaded_modules[module].used_counts += 1;
|
||||
}
|
||||
let mut max_addr: usize;
|
||||
let mut min_addr: usize;
|
||||
let mut off_start: usize;
|
||||
max_addr = 0;
|
||||
min_addr = 0xffffffff_ffffffff;
|
||||
off_start = 0;
|
||||
for ph in elf.program_iter() {
|
||||
if ph.get_type().unwrap() == Load {
|
||||
if (ph.virtual_addr() as usize) < min_addr {
|
||||
min_addr = ph.virtual_addr() as usize;
|
||||
off_start = ph.offset() as usize;
|
||||
}
|
||||
if (ph.virtual_addr() + ph.mem_size()) as usize > max_addr {
|
||||
max_addr = (ph.virtual_addr() + ph.mem_size()) as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
max_addr += PAGE_SIZE - 1;
|
||||
max_addr &= neg(PAGE_SIZE);
|
||||
min_addr &= neg(PAGE_SIZE);
|
||||
off_start &= neg(PAGE_SIZE);
|
||||
let map_len = max_addr - min_addr + off_start;
|
||||
// We first map a huge piece. This requires the kernel model to be dense and not abusing vaddr.
|
||||
let mut vspace =
|
||||
{ VirtualSpace::new(&KERNELVM_MANAGER, map_len) }.ok_or_else(|| {
|
||||
error!("[LKM] valloc failed!");
|
||||
ENOMEM
|
||||
})?;
|
||||
let base = vspace.start();
|
||||
|
||||
//loaded_minfo.mem_start=base as usize;
|
||||
//loaded_minfo.mem_size=(map_len/PAGE_SIZE) as usize;
|
||||
//if map_len%PAGE_SIZE>0{
|
||||
// loaded_minfo.mem_size+=1;
|
||||
//}
|
||||
{
|
||||
for ph in elf.program_iter() {
|
||||
if ph.get_type().map_err(|_| {
|
||||
error!("[LKM] program header error!");
|
||||
ENOEXEC
|
||||
})? == Load
|
||||
{
|
||||
let vspace_ref = &mut vspace;
|
||||
let prog_start_addr = base + (ph.virtual_addr() as usize);
|
||||
let prog_end_addr = prog_start_addr + (ph.mem_size() as usize);
|
||||
let offset = ph.offset() as usize;
|
||||
let flags = ph.flags();
|
||||
let mut attr = MemoryAttr::default();
|
||||
if flags.is_write() {
|
||||
attr = attr.writable();
|
||||
}
|
||||
if flags.is_execute() {
|
||||
attr = attr.execute();
|
||||
}
|
||||
let area_ref = vspace_ref.add_area(prog_start_addr, prog_end_addr, &attr);
|
||||
//self.vallocator.map_pages(prog_start_addr, prog_end_addr, &attr);
|
||||
//No need to flush TLB.
|
||||
let target = unsafe {
|
||||
::core::slice::from_raw_parts_mut(
|
||||
prog_start_addr as *mut u8,
|
||||
ph.mem_size() as usize,
|
||||
)
|
||||
};
|
||||
let file_size = ph.file_size() as usize;
|
||||
if file_size > 0 {
|
||||
target[..file_size]
|
||||
.copy_from_slice(&elf.input[offset..offset + file_size]);
|
||||
}
|
||||
target[file_size..].iter_mut().for_each(|x| *x = 0);
|
||||
//drop(vspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut loaded_minfo = Box::new(LoadedModule {
|
||||
info: minfo,
|
||||
exported_symbols: Vec::new(),
|
||||
used_counts: 0,
|
||||
using_counts: Arc::new(ModuleRef {}),
|
||||
vspace: vspace,
|
||||
lock: Mutex::new(()),
|
||||
state: Ready,
|
||||
});
|
||||
info!(
|
||||
"[LKM] module load done at {}, now need to do the relocation job.",
|
||||
base
|
||||
);
|
||||
// We only search two tables for relocation info: the symbols from itself, and the symbols from the global exported symbols.
|
||||
let dynsym_table = {
|
||||
let elffile = &elf;
|
||||
if let DynSymbolTable64(dsym) = elffile
|
||||
.find_section_by_name(".dynsym")
|
||||
.ok_or_else(|| {
|
||||
error!("[LKM] .dynsym not found!");
|
||||
ENOEXEC
|
||||
})?
|
||||
.get_data(elffile)
|
||||
.map_err(|_| {
|
||||
error!("[LKM] corrupted .dynsym!");
|
||||
ENOEXEC
|
||||
})?
|
||||
{
|
||||
dsym
|
||||
} else {
|
||||
error!("[LKM] Bad .dynsym!");
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
};
|
||||
info!("[LKM] Loading dynamic entry");
|
||||
if let Dynamic64(dynamic_entries) = elf
|
||||
.find_section_by_name(".dynamic")
|
||||
.ok_or_else(|| {
|
||||
error!("[LKM] .dynamic not found!");
|
||||
ENOEXEC
|
||||
})?
|
||||
.get_data(&elf)
|
||||
.map_err(|_| {
|
||||
error!("[LKM] corrupted .dynamic!");
|
||||
ENOEXEC
|
||||
})?
|
||||
{
|
||||
info!("[LKM] Iterating modules");
|
||||
// start, total_size, single_size
|
||||
let mut reloc_jmprel: (usize, usize, usize) = (0, 0, 0);
|
||||
let mut reloc_rel: (usize, usize, usize) = (0, 0, 16);
|
||||
let mut reloc_rela: (usize, usize, usize) = (0, 0, 24);
|
||||
for dent in dynamic_entries.iter() {
|
||||
match dent.get_tag().map_err(|_| {
|
||||
error! {"[LKM] invalid dynamic entry!"};
|
||||
ENOEXEC
|
||||
})? {
|
||||
Tag::JmpRel => {
|
||||
reloc_jmprel.0 = dent.get_ptr().unwrap() as usize;
|
||||
}
|
||||
Tag::PltRelSize => {
|
||||
reloc_jmprel.1 = dent.get_val().unwrap() as usize;
|
||||
}
|
||||
Tag::PltRel => {
|
||||
reloc_jmprel.2 = if (dent.get_val().unwrap()) == 7 {
|
||||
24
|
||||
} else {
|
||||
16
|
||||
}
|
||||
}
|
||||
Tag::Rel => {
|
||||
reloc_rel.0 = dent.get_ptr().unwrap() as usize;
|
||||
}
|
||||
Tag::RelSize => {
|
||||
reloc_rel.1 = dent.get_val().unwrap() as usize;
|
||||
}
|
||||
Tag::Rela => {
|
||||
reloc_rela.0 = dent.get_ptr().unwrap() as usize;
|
||||
}
|
||||
Tag::RelaSize => {
|
||||
reloc_rela.1 = dent.get_val().unwrap() as usize;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
info!("[LKM] relocating three sections");
|
||||
let this_module = &(*loaded_minfo) as *const _ as usize;
|
||||
self.reloc_symbols(&elf, reloc_jmprel, base, dynsym_table, this_module);
|
||||
self.reloc_symbols(&elf, reloc_rel, base, dynsym_table, this_module);
|
||||
self.reloc_symbols(&elf, reloc_rela, base, dynsym_table, this_module);
|
||||
info!("[LKM] relocation done. adding module to manager and call init_module");
|
||||
let mut lkm_entry: usize = 0;
|
||||
for exported in loaded_minfo.info.exported_symbols.iter() {
|
||||
for sym in dynsym_table.iter() {
|
||||
if exported
|
||||
== sym.get_name(&elf).map_err(|_| {
|
||||
error!("[LKM] load symbol name error!");
|
||||
ENOEXEC
|
||||
})?
|
||||
{
|
||||
let exported_symbol = ModuleSymbol {
|
||||
name: exported.clone(),
|
||||
loc: base + (sym.value() as usize),
|
||||
};
|
||||
|
||||
if exported == "init_module" {
|
||||
lkm_entry = base + (sym.value() as usize);
|
||||
} else {
|
||||
loaded_minfo.exported_symbols.push(exported_symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now everything is done, and the entry can be safely plugged into the vector.
|
||||
self.loaded_modules.push(loaded_minfo);
|
||||
if lkm_entry > 0 {
|
||||
info!("[LKM] calling init_module at {}", lkm_entry);
|
||||
unsafe {
|
||||
LKM_MANAGER.force_unlock();
|
||||
let init_module: fn() = transmute(lkm_entry);
|
||||
(init_module)();
|
||||
}
|
||||
} else {
|
||||
error!("[LKM] this module does not have init_module()!");
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
} else {
|
||||
error!("[LKM] Load dynamic field error!\n");
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
} else {
|
||||
error!("[LKM] metadata section type wrong! this is not likely to happen...");
|
||||
return Err(ENOEXEC);
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn relocate_single_symbol(
|
||||
&mut self,
|
||||
base: usize,
|
||||
reloc_addr: usize,
|
||||
addend: usize,
|
||||
sti: usize,
|
||||
itype: usize,
|
||||
elf: &ElfFile,
|
||||
dynsym: &[DynEntry64],
|
||||
this_module: usize,
|
||||
) {
|
||||
info!("Resolving symbol {}", sti);
|
||||
let sym_val = self
|
||||
.get_symbol_loc(sti, elf, dynsym, base, true, this_module)
|
||||
.expect("[LKM] resolve symbol failed!");
|
||||
match itype as usize {
|
||||
loader::REL_NONE => {}
|
||||
loader::REL_OFFSET32 => {
|
||||
panic!("[LKM] REL_OFFSET32 detected!")
|
||||
// addend-=reloc_addr;
|
||||
}
|
||||
loader::REL_SYMBOLIC => unsafe {
|
||||
write_to_addr(base, reloc_addr, sym_val + addend);
|
||||
},
|
||||
loader::REL_GOT => unsafe {
|
||||
write_to_addr(base, reloc_addr, sym_val + addend);
|
||||
},
|
||||
loader::REL_PLT => unsafe {
|
||||
write_to_addr(base, reloc_addr, sym_val + addend);
|
||||
},
|
||||
loader::REL_RELATIVE => unsafe {
|
||||
write_to_addr(base, reloc_addr, base + addend);
|
||||
},
|
||||
_ => {
|
||||
panic!("[LKM] unsupported relocation type: {}", itype);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn reloc_symbols(
|
||||
&mut self,
|
||||
elf: &ElfFile,
|
||||
(start, total_size, single_size): (usize, usize, usize),
|
||||
base: usize,
|
||||
dynsym: &[DynEntry64],
|
||||
this_module: usize,
|
||||
) {
|
||||
if total_size == 0 {
|
||||
return;
|
||||
}
|
||||
for s in elf.section_iter() {
|
||||
if (s.offset() as usize) == start {
|
||||
{
|
||||
match s.get_data(elf).unwrap() {
|
||||
SectionData::Rela64(rela_items) => {
|
||||
for item in rela_items.iter() {
|
||||
let mut addend = item.get_addend() as usize;
|
||||
let mut reloc_addr = item.get_offset() as usize;
|
||||
let sti = item.get_symbol_table_index() as usize;
|
||||
let itype = item.get_type() as usize;
|
||||
self.relocate_single_symbol(
|
||||
base,
|
||||
reloc_addr,
|
||||
addend,
|
||||
sti,
|
||||
itype,
|
||||
elf,
|
||||
dynsym,
|
||||
this_module,
|
||||
);
|
||||
}
|
||||
}
|
||||
SectionData::Rel64(rel_items) => {
|
||||
for item in rel_items.iter() {
|
||||
let mut addend = 0 as usize;
|
||||
let mut reloc_addr = item.get_offset() as usize;
|
||||
let sti = item.get_symbol_table_index() as usize;
|
||||
let itype = item.get_type() as usize;
|
||||
self.relocate_single_symbol(
|
||||
base,
|
||||
reloc_addr,
|
||||
addend,
|
||||
sti,
|
||||
itype,
|
||||
elf,
|
||||
dynsym,
|
||||
this_module,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("[LKM] bad relocation section type!");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn delete_module(&mut self, name: &str, flags: u32) -> SysResult {
|
||||
//unimplemented!("[LKM] You can't plug out what's INSIDE you, RIGHT?");
|
||||
|
||||
info!("[LKM] now you can plug out a kernel module!");
|
||||
let mut found = false;
|
||||
for i in 0..self.loaded_modules.len() {
|
||||
if &(self.loaded_modules[i].info.name) == name {
|
||||
let mut current_module = &mut (self.loaded_modules[i]);
|
||||
let mod_lock = current_module.lock.lock();
|
||||
if current_module.used_counts > 0 {
|
||||
error!("[LKM] some module depends on this module!");
|
||||
return Err(EAGAIN);
|
||||
}
|
||||
if Arc::strong_count(¤t_module.using_counts) > 0 {
|
||||
error!("[LKM] there are references to the module!");
|
||||
}
|
||||
let mut cleanup_func: usize = 0;
|
||||
for entry in current_module.exported_symbols.iter() {
|
||||
if (&(entry.name)) == "cleanup_module" {
|
||||
cleanup_func = entry.loc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if cleanup_func > 0 {
|
||||
unsafe {
|
||||
current_module.state = Unloading;
|
||||
let cleanup_module: fn() = transmute(cleanup_func);
|
||||
(cleanup_module)();
|
||||
}
|
||||
} else {
|
||||
error!("[LKM] you cannot plug this module out.");
|
||||
return Err(EBUSY);
|
||||
}
|
||||
drop(mod_lock);
|
||||
|
||||
let my_box = self.loaded_modules.remove(i);
|
||||
unsafe {
|
||||
LKM_MANAGER.force_unlock();
|
||||
}
|
||||
//drop(mod_lock);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if found {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(ENOENT)
|
||||
}
|
||||
}
|
||||
pub fn with<T>(f: impl FnOnce(&mut ModuleManager) -> T) -> T {
|
||||
let global_lkmm: &Mutex<Option<ModuleManager>> = &LKM_MANAGER;
|
||||
let mut locked_lkmm = global_lkmm.lock();
|
||||
let mut lkmm = locked_lkmm.as_mut().unwrap();
|
||||
f(lkmm)
|
||||
}
|
||||
pub fn init() {
|
||||
//assert_has_not_been_called!("[LKM] ModuleManager::init must be called only once");
|
||||
info!("[LKM] Loadable Kernel Module Manager loading...");
|
||||
let mut kmm = ModuleManager {
|
||||
stub_symbols: ModuleManager::init_stub_symbols(),
|
||||
loaded_modules: Vec::new(),
|
||||
};
|
||||
kmm.load_kernel_symbols_from_elf();
|
||||
|
||||
//let lkmm: Mutex<Option<ModuleManager>>=Mutex::new(None);
|
||||
LKM_MANAGER.lock().replace(kmm);
|
||||
info!("[LKM] Loadable Kernel Module Manager loaded!");
|
||||
}
|
||||
}
|
5
kernel/src/lkm/mod.rs
Normal file
5
kernel/src/lkm/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod api;
|
||||
pub mod const_reloc;
|
||||
pub mod kernelvm;
|
||||
pub mod manager;
|
||||
pub mod structs;
|
107
kernel/src/lkm/structs.rs
Normal file
107
kernel/src/lkm/structs.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use super::kernelvm::*;
|
||||
use crate::sync::SpinLock as Mutex;
|
||||
use alloc::string::*;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::*;
|
||||
|
||||
pub struct ModuleSymbol {
|
||||
pub name: String,
|
||||
pub loc: usize,
|
||||
}
|
||||
pub struct ModuleDependence {
|
||||
pub name: String,
|
||||
pub api_version: i32,
|
||||
}
|
||||
pub struct ModuleInfo {
|
||||
pub name: String,
|
||||
pub version: i32,
|
||||
pub api_version: i32,
|
||||
pub exported_symbols: Vec<String>,
|
||||
pub dependent_modules: Vec<ModuleDependence>,
|
||||
}
|
||||
|
||||
impl ModuleInfo {
|
||||
pub fn parse(input: &str) -> Option<ModuleInfo> {
|
||||
let lines: Vec<&str> = input.split('\n').collect();
|
||||
let mut minfo = ModuleInfo {
|
||||
name: String::from("<anonymous module>"),
|
||||
version: 0,
|
||||
api_version: 0,
|
||||
exported_symbols: Vec::new(),
|
||||
dependent_modules: Vec::new(),
|
||||
};
|
||||
for l in lines {
|
||||
if l.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
let columns: Vec<&str> = l.split(':').collect();
|
||||
if columns.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
match columns[0] {
|
||||
"name" => {
|
||||
minfo.name = String::from(columns[1]);
|
||||
}
|
||||
"version" => {
|
||||
minfo.version = columns[1].parse::<i32>().unwrap();
|
||||
}
|
||||
"api_version" => {
|
||||
minfo.api_version = columns[1].parse::<i32>().unwrap();
|
||||
}
|
||||
"exported_symbols" => {
|
||||
let symbols: Vec<&str> = columns[1].split(",").collect();
|
||||
minfo.exported_symbols = symbols.iter().map(|s| String::from(*s)).collect();
|
||||
}
|
||||
"dependence" => {
|
||||
let dependences: Vec<&str> = columns[1].split(",").collect();
|
||||
for dep in dependences.iter() {
|
||||
if dep.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
let pair: Vec<&str> = dep.split("=").collect();
|
||||
|
||||
minfo.dependent_modules.push(ModuleDependence {
|
||||
name: String::from(pair[0]),
|
||||
api_version: pair[1].parse::<i32>().unwrap(),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(minfo)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ModuleState {
|
||||
Ready,
|
||||
PrepareUnload,
|
||||
Unloading,
|
||||
}
|
||||
|
||||
pub struct ModuleRef;
|
||||
pub struct LoadedModule {
|
||||
pub info: ModuleInfo,
|
||||
pub exported_symbols: Vec<ModuleSymbol>,
|
||||
pub used_counts: i32,
|
||||
pub using_counts: Arc<ModuleRef>,
|
||||
pub vspace: VirtualSpace,
|
||||
pub lock: Mutex<()>,
|
||||
pub state: ModuleState,
|
||||
}
|
||||
|
||||
impl LoadedModule {
|
||||
// Grabs a reference to the kernel module.
|
||||
// For example, a file descriptor to a device file controlled by the module is a reference.
|
||||
// This must be called without the lock!
|
||||
pub fn grab(&self) -> Arc<ModuleRef> {
|
||||
Arc::clone(&self.using_counts)
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent of Linux kobject. Has a reference counter to module
|
||||
pub struct KObject {
|
||||
pub name: String,
|
||||
}
|
10
kernel/src/lkm/symbol_table.asm
Normal file
10
kernel/src/lkm/symbol_table.asm
Normal file
@ -0,0 +1,10 @@
|
||||
# this reserves space for storing symbol table.
|
||||
# We just put zero here, and link it in the last.
|
||||
# 1M is enough. (But too large for Thinpad, so for Thinpad we need better approach.)
|
||||
.section .data
|
||||
.global rcore_symbol_table
|
||||
.global rcore_symbol_table_size
|
||||
rcore_symbol_table:
|
||||
.zero 1048576
|
||||
rcore_symbol_table_size:
|
||||
.zero 32
|
@ -180,10 +180,10 @@ impl Thread {
|
||||
let inode = crate::fs::ROOT_INODE
|
||||
.lookup_follow(loader_path, FOLLOW_MAX_DEPTH)
|
||||
.map_err(|_| "interpreter not found")?;
|
||||
// modify args for loader
|
||||
// modify args for const_reloc
|
||||
args[0] = exec_path.into();
|
||||
args.insert(0, loader_path.into());
|
||||
// Elf loader should not have INTERP
|
||||
// Elf const_reloc should not have INTERP
|
||||
// No infinite loop
|
||||
return Thread::new_user_vm(&inode, exec_path, args, envs);
|
||||
}
|
||||
|
29
kernel/src/syscall/lkm.rs
Normal file
29
kernel/src/syscall/lkm.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use crate::lkm::manager::ModuleManager;
|
||||
use crate::sync::Mutex;
|
||||
use crate::syscall::{check_and_clone_cstr, SysResult, Syscall};
|
||||
use alloc::collections::btree_map::BTreeMap;
|
||||
use compression::prelude::Action;
|
||||
|
||||
impl Syscall<'_> {
|
||||
pub fn sys_init_module(
|
||||
&mut self,
|
||||
module_image: *const u8,
|
||||
len: usize,
|
||||
param_values: *const u8,
|
||||
) -> SysResult {
|
||||
let mut proc = self.process();
|
||||
let modimg = unsafe { self.vm().check_read_array(module_image, len)? };
|
||||
let copied_param_values = check_and_clone_cstr(param_values)?;
|
||||
|
||||
ModuleManager::with(|kmm| kmm.init_module(modimg, &copied_param_values))
|
||||
}
|
||||
|
||||
pub fn sys_delete_module(&mut self, module_name: *const u8, flags: u32) -> SysResult {
|
||||
let mut proc = self.process();
|
||||
let copied_modname = check_and_clone_cstr(module_name)?;
|
||||
info!("[LKM] Removing module {:?}", copied_modname);
|
||||
let ret = ModuleManager::with(|kmm| kmm.delete_module(&copied_modname, flags));
|
||||
info!("[LKM] Remove module {:?} done!", copied_modname);
|
||||
ret
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ use crate::util;
|
||||
|
||||
pub use self::custom::*;
|
||||
pub use self::fs::*;
|
||||
pub use self::lkm::*;
|
||||
pub use self::mem::*;
|
||||
pub use self::misc::*;
|
||||
pub use self::net::*;
|
||||
@ -26,6 +27,7 @@ pub use self::time::*;
|
||||
|
||||
mod custom;
|
||||
mod fs;
|
||||
mod lkm;
|
||||
mod mem;
|
||||
mod misc;
|
||||
mod net;
|
||||
@ -298,11 +300,22 @@ impl Syscall<'_> {
|
||||
}
|
||||
SYS_RT_SIGQUEUEINFO => self.unimplemented("rt_sigqueueinfo", Ok(0)),
|
||||
|
||||
// kernel module
|
||||
SYS_INIT_MODULE => {
|
||||
self.sys_init_module(args[0] as *const u8, args[1] as usize, args[2] as *const u8)
|
||||
}
|
||||
SYS_FINIT_MODULE => {
|
||||
debug!("[LKM] sys_finit_module is unimplemented");
|
||||
Err(SysError::ENOSYS)
|
||||
}
|
||||
SYS_DELETE_MODULE => self.sys_delete_module(args[0] as *const u8, args[1] as u32),
|
||||
|
||||
// custom
|
||||
SYS_MAP_PCI_DEVICE => self.sys_map_pci_device(args[0], args[1]),
|
||||
SYS_GET_PADDR => {
|
||||
self.sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2])
|
||||
}
|
||||
|
||||
_ => {
|
||||
let ret = match () {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
@ -10,12 +10,14 @@
|
||||
"arch": "aarch64",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||
"executables": true,
|
||||
"dynamic-linking": true,
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker-is-gnu": true,
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"-Tsrc/arch/aarch64/boot/linker.ld"
|
||||
"-Tsrc/arch/aarch64/boot/linker.ld",
|
||||
"-export-dynamic"
|
||||
]
|
||||
},
|
||||
"llvm-target": "aarch64-unknown-none",
|
||||
|
@ -8,10 +8,12 @@
|
||||
"arch": "x86_64",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"dynamic-linking": true,
|
||||
"linker": "rust-lld",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"-Tsrc/arch/x86_64/linker.ld"
|
||||
"-Tsrc/arch/x86_64/linker.ld",
|
||||
"-export-dynamic"
|
||||
]
|
||||
},
|
||||
"disable-redzone": true,
|
||||
|
9
modules/hello_rust/Cargo.toml
Normal file
9
modules/hello_rust/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "hello_rust"
|
||||
version = "0.1.0"
|
||||
authors = ["gjz010 <gjz010944@gmail.com>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
6
modules/hello_rust/README.txt
Normal file
6
modules/hello_rust/README.txt
Normal file
@ -0,0 +1,6 @@
|
||||
rCore Kernel Module Template: Rust
|
||||
This may be a good startpoint for developing your own kernel module. Just copy the folder and start your work.
|
||||
Known problems:
|
||||
- You have to execute the given build script.
|
||||
- The kernel and the module have to follow the same toolchain strictly. This means you are likely to rebuild the module after you build the kernel with the same tool.
|
||||
This makes developing "portable" kernel module a severe problem, although not rebuilding the module rarely cause problems.
|
31
modules/hello_rust/build-aarch64.sh
Executable file
31
modules/hello_rust/build-aarch64.sh
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
ARCH=aarch64
|
||||
TEXT_TYPE=elf64-littleaarch64
|
||||
BIN_ARCH=aarch64
|
||||
PREFIX=aarch64-elf-
|
||||
echo "Step 1. Fetching dependencies according to cargo."
|
||||
echo "// Dummy file" > src/lib.rs
|
||||
echo '#![no_std]' >> src/lib.rs
|
||||
echo "extern crate rcore;" >> src/lib.rs
|
||||
cargo xbuild --target=../../kernel/targets/$ARCH.json -vv --release
|
||||
echo "Step 2. Compile the library"
|
||||
echo '#![no_std]' > src/lib.rs
|
||||
echo '#![feature(alloc)]' >> src/lib.rs
|
||||
echo "extern crate rcore;" >> src/lib.rs
|
||||
echo "mod main;" >> src/lib.rs
|
||||
rustc --edition=2018 --crate-name hello_rust src/lib.rs \
|
||||
--color always --crate-type cdylib -C debuginfo=2 \
|
||||
--out-dir ./target/$ARCH/release/objs \
|
||||
--target ../../kernel/targets/$ARCH.json \
|
||||
-L dependency=target/$ARCH/release/deps \
|
||||
-L dependency=target/release/deps \
|
||||
--emit=obj --sysroot target/sysroot \
|
||||
-L all=../../kernel/target/$ARCH/release/deps
|
||||
echo "Step 3. Packing the library into kernel module."
|
||||
"$PREFIX"objcopy --input binary --output $TEXT_TYPE \
|
||||
--binary-architecture $BIN_ARCH\
|
||||
--rename-section .data=.rcore-lkm,CONTENTS,READONLY\
|
||||
lkm_info.txt target/$ARCH/release/objs/lkm_info.o
|
||||
"$PREFIX"strip target/$ARCH/release/objs/lkm_info.o
|
||||
"$PREFIX"gcc -shared -o target/$ARCH/release/hello_rust.ko -nostdlib target/$ARCH/release/objs/*.o
|
||||
#cargo xbuild --target=../../kernel/targets/x86_64.json -vv
|
6
modules/hello_rust/build.rs
Normal file
6
modules/hello_rust/build.rs
Normal file
@ -0,0 +1,6 @@
|
||||
fn main() {
|
||||
let path = "../../kernel/target/x86_64/release/deps";
|
||||
println!("cargo:rustc-link-search=all={}", path);
|
||||
let path = "../../kernel/target/aarch64/release/deps";
|
||||
println!("cargo:rustc-link-search=all={}", path);
|
||||
}
|
31
modules/hello_rust/build.sh
Executable file
31
modules/hello_rust/build.sh
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
ARCH=x86_64
|
||||
TEXT_TYPE=elf64-x86-64
|
||||
BIN_ARCH=i386:x86-64
|
||||
PREFIX=
|
||||
echo "Step 1. Fetching dependencies according to cargo."
|
||||
echo "// Dummy file" > src/lib.rs
|
||||
echo '#![no_std]' >> src/lib.rs
|
||||
echo "extern crate rcore;" >> src/lib.rs
|
||||
cargo xbuild --target=../../kernel/targets/$ARCH.json -vv --release
|
||||
echo "Step 2. Compile the library"
|
||||
echo '#![no_std]' > src/lib.rs
|
||||
echo '#![feature(alloc)]' >> src/lib.rs
|
||||
echo "extern crate rcore;" >> src/lib.rs
|
||||
echo "mod main;" >> src/lib.rs
|
||||
rustc --edition=2018 --crate-name hello_rust src/lib.rs \
|
||||
--color always --crate-type cdylib -C debuginfo=2 \
|
||||
--out-dir ./target/$ARCH/release/objs \
|
||||
--target ../../kernel/targets/$ARCH.json \
|
||||
-L dependency=target/$ARCH/release/deps \
|
||||
-L dependency=target/release/deps \
|
||||
--emit=obj --sysroot target/sysroot \
|
||||
-L all=../../kernel/target/$ARCH/release/deps
|
||||
echo "Step 3. Packing the library into kernel module."
|
||||
"$PREFIX"objcopy --input binary --output $TEXT_TYPE \
|
||||
--binary-architecture $BIN_ARCH\
|
||||
--rename-section .data=.rcore-lkm,CONTENTS,READONLY\
|
||||
lkm_info.txt target/$ARCH/release/objs/lkm_info.o
|
||||
"$PREFIX"strip target/$ARCH/release/objs/lkm_info.o
|
||||
"$PREFIX"gcc -shared -o target/$ARCH/release/hello_rust.ko -nostdlib target/$ARCH/release/objs/*.o
|
||||
#cargo xbuild --target=../../kernel/targets/x86_64.json -vv
|
5
modules/hello_rust/lkm_info.txt
Normal file
5
modules/hello_rust/lkm_info.txt
Normal file
@ -0,0 +1,5 @@
|
||||
name:hello_lkm_rust
|
||||
version:1
|
||||
api_version:1
|
||||
exported_symbols:init_module
|
||||
dependence:
|
35
modules/hello_rust/src/arch/x86_64/linker.ld
Normal file
35
modules/hello_rust/src/arch/x86_64/linker.ld
Normal file
@ -0,0 +1,35 @@
|
||||
ENTRY(init_module)
|
||||
|
||||
LIBRARY_BEGIN = 0x0000000000000000;
|
||||
|
||||
SECTIONS {
|
||||
|
||||
. = LIBRARY_BEGIN;
|
||||
|
||||
.rodata ALIGN(4K):
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
|
||||
.text ALIGN(4K):
|
||||
{
|
||||
stext = .;
|
||||
*(.text .text.*)
|
||||
etext = .;
|
||||
}
|
||||
|
||||
.data ALIGN(4K):
|
||||
{
|
||||
*(.data .data.*)
|
||||
}
|
||||
|
||||
.got ALIGN(4K):
|
||||
{
|
||||
*(.got .got.*)
|
||||
}
|
||||
|
||||
.bss ALIGN(4K):
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
}
|
4
modules/hello_rust/src/lib.rs
Normal file
4
modules/hello_rust/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#![no_std]
|
||||
#![feature(alloc)]
|
||||
extern crate rcore;
|
||||
mod main;
|
7
modules/hello_rust/src/main/hello.rs
Normal file
7
modules/hello_rust/src/main/hello.rs
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
extern crate rcore;
|
||||
|
||||
pub fn hello_again(){
|
||||
rcore::lkm::api::lkm_api_pong();
|
||||
}
|
||||
|
15
modules/hello_rust/src/main/mod.rs
Normal file
15
modules/hello_rust/src/main/mod.rs
Normal file
@ -0,0 +1,15 @@
|
||||
extern crate rcore;
|
||||
extern crate alloc;
|
||||
use rcore::lkm::api::lkm_api_pong;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub mod hello;
|
||||
#[no_mangle]
|
||||
pub extern "C" fn init_module(){
|
||||
lkm_api_pong();
|
||||
let mut v: Vec<u8>=Vec::new();
|
||||
v.push(10);
|
||||
v.push(20);
|
||||
hello::hello_again();
|
||||
}
|
||||
|
5
tools/fill_symbols/README.md
Normal file
5
tools/fill_symbols/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
Tools that are used to fill in kernel symbols into rcore ELF file.
|
||||
The tool will use `nm` to extract symbols from the kernel (a bit like System.map), and put it back into the `rcore_symbol_table` section.
|
||||
To reduce the size required, the symbol table will be compressed using gzip.
|
||||
The tool tries to limit its dependencies. Only necessary tools (bash, objdump, nm, gzip, grep, dd, python3) are required to run the script.
|
||||
TODO: Why don't we just do the job using a single Python script?
|
22
tools/fill_symbols/aarch64.sh
Executable file
22
tools/fill_symbols/aarch64.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
echo "Filling kernel symbols."
|
||||
rcore=$1
|
||||
tmpfile=$(mktemp /tmp/rcore-symbols.txt.XXXXXX)
|
||||
echo "Writing symbol table."
|
||||
aarch64-elf-nm $1 >$tmpfile
|
||||
gzip $tmpfile
|
||||
tmpfile=$tmpfile.gz
|
||||
symbol_table_loc=$((16#$(aarch64-elf-objdump -D $rcore -j .data -F |grep "<rcore_symbol_table>" |grep -oEi "0x[0-9a-f]+" |grep -oEi "[0-9a-f][0-9a-f]+")))
|
||||
symbol_table_size_loc=$((16#$(aarch64-elf-objdump -D $rcore -j .data -F |grep "<rcore_symbol_table_size>" |grep -oEi "0x[0-9a-f]+" |grep -oEi "[0-9a-f][0-9a-f]+")))
|
||||
echo $symbol_table_loc
|
||||
echo $symbol_table_size_loc
|
||||
FILESIZE=$(stat -c%s "$tmpfile")
|
||||
echo $FILESIZE
|
||||
dd bs=4096 count=$FILESIZE if=$tmpfile of=$rcore seek=$symbol_table_loc conv=notrunc iflag=count_bytes oflag=seek_bytes
|
||||
echo "Writing size"
|
||||
python3 -c "open('$tmpfile', 'wb').write(($FILESIZE).to_bytes(8,'little'))"
|
||||
FILESIZE=$(stat -c%s "$tmpfile")
|
||||
echo $FILESIZE
|
||||
dd bs=1 count=$FILESIZE if=$tmpfile of=$rcore seek=$symbol_table_size_loc conv=notrunc
|
||||
rm $tmpfile
|
||||
echo "Done."
|
22
tools/fill_symbols/x86_64.sh
Executable file
22
tools/fill_symbols/x86_64.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
echo "Filling kernel symbols."
|
||||
rcore=$1
|
||||
tmpfile=$(mktemp /tmp/rcore-symbols.txt.XXXXXX)
|
||||
echo "Writing symbol table."
|
||||
nm $1 >$tmpfile
|
||||
gzip $tmpfile
|
||||
tmpfile=$tmpfile.gz
|
||||
symbol_table_loc=$((16#$(objdump -D $rcore -j .data -F |grep "<rcore_symbol_table>" |grep -oEi "0x[0-9a-f]+" |grep -oEi "[0-9a-f][0-9a-f]+")))
|
||||
symbol_table_size_loc=$((16#$(objdump -D $rcore -j .data -F |grep "<rcore_symbol_table_size>" |grep -oEi "0x[0-9a-f]+" |grep -oEi "[0-9a-f][0-9a-f]+")))
|
||||
echo $symbol_table_loc
|
||||
echo $symbol_table_size_loc
|
||||
FILESIZE=$(stat -c%s "$tmpfile")
|
||||
echo $FILESIZE
|
||||
dd bs=4096 count=$FILESIZE if=$tmpfile of=$rcore seek=$symbol_table_loc conv=notrunc iflag=count_bytes oflag=seek_bytes
|
||||
echo "Writing size"
|
||||
python3 -c "open('$tmpfile', 'wb').write(($FILESIZE).to_bytes(8,'little'))"
|
||||
FILESIZE=$(stat -c%s "$tmpfile")
|
||||
echo $FILESIZE
|
||||
dd bs=1 count=$FILESIZE if=$tmpfile of=$rcore seek=$symbol_table_size_loc conv=notrunc
|
||||
rm $tmpfile
|
||||
echo "Done."
|
Loading…
Reference in New Issue
Block a user