diff --git a/.gitignore b/.gitignore index 88bd924de63001c779990c541bc345539171f510..b22d33ce09555500c6924f5068bece1f1ae75a92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ /target -/user/linker.debug.ld -/user/linker.ld +/user/.linkers/* /src/app_loader.asm \ No newline at end of file diff --git a/Makefile b/Makefile index 5c217a0bccf74062d015769aca13a6245508f747..fa05d78bbccb5cd102a151d497975f01f4cdbb12 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,9 @@ KERNEL_BINARY_NAME := $(shell cargo metadata --no-deps --format-version 1 | jq - USER_BINARY_NAMES := $(shell cargo metadata --no-deps --format-version 1 | jq -r ' \ . as $$root | \ .packages[] | \ - .targets[] | \ - select( .kind | map(. == "bin") | any ) | \ - .name \ -' | grep -v $(KERNEL_BINARY_NAME)) - + select(.name == "user") | \ + .metadata.applications.order[] \ +') TARGET_DIR := target/riscv64gc-unknown-none-elf KERNEL_ELF := $(TARGET_DIR)/debug/$(KERNEL_BINARY_NAME) diff --git a/src/app_loader.rs b/src/app_loader.rs new file mode 100644 index 0000000000000000000000000000000000000000..2c873b109a2ed6cf9e11ba75e620c5b7463c5293 --- /dev/null +++ b/src/app_loader.rs @@ -0,0 +1,28 @@ +use core::arch::asm; + +use crate::{APP_MANAGER, batch::AppManager}; + +pub fn load_apps() { + let app_manager = APP_MANAGER.ref_cell.borrow(); + for i in 0..app_manager.app_count { + load_app(&app_manager, i); + } + unsafe { + asm!("fence.i"); + } +} + +fn load_app(app_manager: &AppManager, app_id: usize) { + let app_start = app_manager.app_table[app_id]; + let app_end = if app_id + 1 < app_manager.app_count { + app_manager.app_table[app_id + 1] + } else { + app_manager.apps_end + }; + let app_size = app_end - app_start; + let app_base = AppManager::get_app_base_addr(app_id); + unsafe { core::slice::from_raw_parts_mut(app_base as *mut u8, 0x20000).fill(0) }; + let app_src = unsafe { core::slice::from_raw_parts(app_start as *const u8, app_size) }; + let app_dst = unsafe { core::slice::from_raw_parts_mut(app_base as *mut u8, app_size) }; + app_dst.copy_from_slice(app_src); +} diff --git a/src/batch.rs b/src/batch.rs index 185541d788fa3972271054dba7d35982f136e3b4..0e63de626616f295d636d3295d427e90e2eeaf45 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -4,7 +4,8 @@ use crate::{APP_MANAGER, info, printkln, sbi::sbi_shutdown, trap::context::TrapC pub const MAX_APP_NUM: usize = 64; /// 与 user-build ä¸ linker.ld ä¸çš„ BASE_ADDRESS ä¿æŒä¸€è‡´ -pub const APP_BASE_ADDRESS: usize = 0x80400000; +pub const USER_BASE_ADDRESS: usize = 0x80400000; +pub const USER_SPACE_SIZE: usize = 0x00200000; pub const KERNEL_STACK_SIZE: usize = 0x8000; pub const USER_STACK_SIZE: usize = 0x8000; @@ -122,25 +123,8 @@ impl AppManager { } } - pub fn load_app(&self, app_id: usize) { - let app_start = self.app_table[app_id]; - let app_end = if app_id + 1 < self.app_count { - self.app_table[app_id + 1] - } else { - self.apps_end - }; - let app_size = app_end - app_start; - let app_base = APP_BASE_ADDRESS; - unsafe { core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, 0x20000).fill(0) }; - let app_src = unsafe { core::slice::from_raw_parts(app_start as *const u8, app_size) }; - let app_dst = unsafe { core::slice::from_raw_parts_mut(app_base as *mut u8, app_size) }; - app_dst.copy_from_slice(app_src); - unsafe { - asm!("fence.i"); - } - // let app_entry = app_base; - // let app_entry: extern "C" fn() -> ! = unsafe { core::mem::transmute(app_entry) }; - // app_entry(); + pub fn get_app_base_addr(app_id: usize) -> usize { + USER_BASE_ADDRESS + app_id * USER_SPACE_SIZE } pub fn get_app_name(app_name_ptr: *const i8) -> &'static str { @@ -157,7 +141,7 @@ impl AppManager { pub fn print_app_info(&self, app_id: usize) { info!( - "App {} - Name: {}, Start: {:#x}, End: {:#x}", + "App {} - Name: {}, Offset: [{:#x}, {:#x}), Base: {:#x}", app_id, self.app_name_table[app_id], self.app_table[app_id], @@ -165,7 +149,8 @@ impl AppManager { self.app_table[app_id + 1] } else { self.apps_end - } + }, + Self::get_app_base_addr(app_id) ); } } @@ -177,28 +162,19 @@ pub fn run_next_app() { info!("All apps have been run."); sbi_shutdown(false); } - app_manager.load_app(app_manager.current); - app_manager.print_app_info(app_manager.current); + let app_id = app_manager.current; + app_manager.print_app_info(app_id); app_manager.current = app_manager.current + 1; drop(app_manager); unsafe extern "C" { fn __restore_trap(ctx_ptr: usize); } - // panic!("{}", __restore_trap as usize); - printkln!("{:#x}", __restore_trap as usize); - printkln!("{:#x}", USER_STACK.top()); unsafe { - let a = KERNEL_STACK.push_ctx(TrapCtx::init_app_context( - APP_BASE_ADDRESS, + let ctx = KERNEL_STACK.push_ctx(TrapCtx::init_app_context( + AppManager::get_app_base_addr(app_id), USER_STACK.top(), )); - // print the context - let ctx = &*(a as *const TrapCtx); - printkln!("{:#x}", ctx.sstatus); - printkln!("{:#x}", ctx.sepc); - printkln!("{:#x}", ctx.x[2]); - - __restore_trap(a); + __restore_trap(ctx); } unreachable!(); } diff --git a/src/main.rs b/src/main.rs index b6e2a607748c721599ac379322ad477b95641a31..2befdaf9c12fc70f191b43f0ae0d3f670840ca61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ #![no_main] #![feature(inline_const_pat)] +mod app_loader; mod batch; mod io; mod language_item; @@ -38,6 +39,7 @@ pub extern "C" fn _kernel_entry() -> ! { startup_log(); trap::init(); APP_MANAGER.ref_cell.borrow().print_apps_info(); + app_loader::load_apps(); batch::run_next_app(); printkln!("Hello, {}!", "World"); diff --git a/user-build/src/lib.rs b/user-build/src/lib.rs index 94bfa8a164b6a3e14fdc6d0841696ce6e5fb8cc1..a2856cae62451305758b949ffb00bade961ec21c 100644 --- a/user-build/src/lib.rs +++ b/user-build/src/lib.rs @@ -1,36 +1,115 @@ use core::include_str; -pub fn setup_linker(profile: &str) { - let linker = format!( + +const USER_BASE_ADDRESS: usize = 0x80400000; +const USER_SPACE_SIZE: usize = 0x00200000; + +pub fn setup() { + let linker_dir = get_linker_dir(); + clean_linkers(&linker_dir); + + let current_profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); + let apps = get_apps_in_order(); + for profile in &["debug", "release"] { + for (app_id, app_name) in apps.iter().enumerate() { + setup_linker(profile, app_name, app_id, &linker_dir); + } + } + + for (app_id, app_name) in apps.iter().enumerate() { + println!( + "cargo:rustc-link-arg-bin={app_name}=-T{linker_dir}/{linker_name}", + app_name = app_name, + linker_dir = linker_dir, + linker_name = get_linker_name(&app_name, app_id, ¤t_profile), + ); + } + + println!("cargo:rergun-if-changed=user-build"); + println!("cargo:rergun-if-changed=user/Cargo.toml"); + println!("cargo:rustc-force-frame-pointers=yes"); +} + +/// ä¸ºä¸€ä¸ªäºŒè¿›åˆ¶ç›®æ ‡æ–‡ä»¶ç”Ÿæˆé“¾æŽ¥è„šæœ¬ï¼Œ +/// 生æˆçš„链接脚本将会被写入到 `linkers` 目录下 +/// +/// ## 傿•° +/// - `profile`:编译é…置,`debug` 或 `release` +/// - `app_name`ï¼šäºŒè¿›åˆ¶ç›®æ ‡çš„åç§° +/// - `app_id`ï¼šäºŒè¿›åˆ¶ç›®æ ‡çš„ ID, ç”± manifest ä¸çš„ `package.metadata.applications.order` 定义 +fn setup_linker(profile: &str, app_name: &str, app_id: usize, linker_dir: &str) { + let mut linker = format!( r#"/************************************************************************** * This is a linker script is generated automatically by the build script. * * DO NOT MODIFY IT MANUALLY. * ***************************************************************************/ + +/* Linker script for {app_name} ({app_id}) in {profile} mode. */ + {}"#, - if profile == "release" { - include_str!("linker.ld") - } else { - include_str!("linker.debug.ld") - } + include_str!("linker.template.ld") ); - // copy the linker script to the src directory - let out_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let linker_path = std::path::Path::new(&out_dir).join(if profile == "release" { - "linker.ld" + + /*TEMPLATE {DEBUG-DISCARD}*/ + if profile == "release" { + linker = replace_template(linker, "DEBUG-DISCARD", "*(.debug*)"); } else { - "linker.debug.ld" - }); + linker = replace_template(linker, "DEBUG-DISCARD", ""); + } + + /*TEMPLATE {base-address}*/ + let base_address = format!("0x{:08x}", USER_BASE_ADDRESS + app_id * USER_SPACE_SIZE); + linker = replace_template(linker, "BASE_ADDRESS", &base_address); + + let linker_path = + std::path::Path::new(linker_dir).join(get_linker_name(app_name, app_id, profile)); + std::fs::write(&linker_path, linker).unwrap(); } -pub fn setup() { - let profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); - setup_linker(&profile); - if profile == "release" { - println!("cargo:rergun-if-changed=linker.ld"); - println!("cargo:rustc-link-arg=-Tuser/linker.ld"); - } else { - println!("cargo:rerun-if-changed=linker.debug.ld"); - println!("cargo:rustc-link-arg=-Tuser/linker.debug.ld"); +fn get_linker_dir() -> String { + let out_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let linker_dir_path = std::path::Path::new(&out_dir).join(".linkers"); + linker_dir_path.to_str().unwrap().to_string() +} + +fn get_linker_name(app_name: &str, app_id: usize, profile: &str) -> String { + format!("linker-{app_id}-{app_name}-{profile}.ld") +} + +fn replace_template(template: String, key: &str, value: &str) -> String { + template.replace(&format!("/*TEMPLATE {{{}}}*/", key), value) +} + +fn clean_linkers(linker_dir: &str) { + let linker_dir = std::path::Path::new(linker_dir); + assert!(linker_dir.ends_with(".linkers")); + assert!(linker_dir.starts_with(std::env::var("CARGO_MANIFEST_DIR").unwrap())); + std::fs::create_dir_all(linker_dir).unwrap(); + for entry in std::fs::read_dir(linker_dir).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_file() { + std::fs::remove_file(path).unwrap(); + } } - println!("cargo:rustc-force-frame-pointers=yes"); +} + +pub fn get_apps_in_order() -> Vec<String> { + // 应用程åºé¡ºåºå·²åœ¨ user/Cargo.toml package.metadata.applications.order ä¸å®šä¹‰ + // Make 会获å–该值 + let user_root = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let user_root = user_root.split("/").collect::<Vec<_>>(); + // remove the last part of the path + let workspace_root = user_root[..user_root.len() - 1].join("/"); + let make_args = std::process::Command::new("make") + .current_dir(workspace_root) + .arg("echo-make-args") + .arg("GET_MAKE_ARG=USER_BINARY_NAMES") + .arg("--no-print-directory") + .output() + .unwrap() + .stdout; + let make_args = std::str::from_utf8(&make_args).unwrap(); + let make_args = make_args.trim().split(' ').map(|s| s.to_string()); + make_args.collect::<Vec<_>>() } diff --git a/user-build/src/linker.ld b/user-build/src/linker.ld deleted file mode 100644 index 1dc9acc66ddbfc66ec8bdc0ff3a7d26323a80816..0000000000000000000000000000000000000000 --- a/user-build/src/linker.ld +++ /dev/null @@ -1,48 +0,0 @@ -/* linker for app */ -OUTPUT_ARCH(riscv) -ENTRY(_start) -BASE_ADDRESS = 0x80400000; - -SECTIONS -{ - /* put entry at the start */ - . = BASE_ADDRESS; - __app_start = .; - __text_start = .; - .text : { - *(.text.entry) - *(.text .text.*) - } - - __text_end = .; - - __rodata_start = .; - .rodata : { - *(.rodata .rodata.*) - *(.srodata .srodata.*) - } - - __rodata_end = .; - - __data_start = .; - .data : { - *(.data .data.*) - *(.sdata .sdata.*) - } - - __data_end = .; - - .bss : { - __bss_start = .; - *(.bss .bss.*) - *(.sbss .sbss.*) - } - - __bss_end = .; - __app_end = .; - - /DISCARD/ : { - *(.eh_frame) - *(.debug*) - } -} \ No newline at end of file diff --git a/user-build/src/linker.debug.ld b/user-build/src/linker.template.ld similarity index 88% rename from user-build/src/linker.debug.ld rename to user-build/src/linker.template.ld index e35984665cb05cdbbef76e6db289d4a6d78b0121..0e8a54b31abd25d5147a01b32f1c881b8b197d41 100644 --- a/user-build/src/linker.debug.ld +++ b/user-build/src/linker.template.ld @@ -1,7 +1,6 @@ -/* linker for app, debug version */ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0x80400000; +BASE_ADDRESS = /*TEMPLATE {BASE_ADDRESS}*/; SECTIONS { @@ -43,5 +42,6 @@ SECTIONS /DISCARD/ : { *(.eh_frame) + /*TEMPLATE {DEBUG-DISCARD}*/ } } \ No newline at end of file diff --git a/user/Cargo.toml b/user/Cargo.toml index 9885344ed865a339654cfda6d6cf6709fef0399e..1f8b3d1253fba8ba8af0945954178fd2a0cf963d 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -17,3 +17,7 @@ lib = { path = "../user-lib" } [build-dependencies] build = { path = "../user-build" } + +[package.metadata.applications] +# 应用程åºé¡ºåº +order = ["hello", "bye"] \ No newline at end of file