1
0
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:
gjz010 2019-06-07 20:59:51 +08:00
parent da028c1f10
commit 7b8252eb1b
35 changed files with 1512 additions and 21 deletions

6
.gitignore vendored
View File

@ -23,3 +23,9 @@ Cargo.lock
# for idea
.idea
# for kernel module building
# C & Rust
modules/*/objs
# Rust
modules/*/target

View File

@ -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
View File

@ -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"

View File

@ -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" }

View File

@ -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))

View File

@ -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);

View File

@ -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, ...

View File

@ -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
View 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);
}

View 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;

View 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::*;

View 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
View 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
View 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(&current_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
View 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
View 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,
}

View 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

View File

@ -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
View 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
}
}

View File

@ -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")]

View File

@ -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",

View File

@ -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,

View 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"

View 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.

View 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

View 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
View 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

View File

@ -0,0 +1,5 @@
name:hello_lkm_rust
version:1
api_version:1
exported_symbols:init_module
dependence:

View 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.*)
}
}

View File

@ -0,0 +1,4 @@
#![no_std]
#![feature(alloc)]
extern crate rcore;
mod main;

View File

@ -0,0 +1,7 @@
extern crate rcore;
pub fn hello_again(){
rcore::lkm::api::lkm_api_pong();
}

View 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();
}

View 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
View 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
View 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."