From d11132ae23701779b4bb95a411c77e80976d51f5 Mon Sep 17 00:00:00 2001
From: linfeng <1925466036@qq.com>
Date: Fri, 20 May 2022 18:54:24 +0800
Subject: [PATCH] fear: Support multi-program loading

modify batch.rs --> loader.rs
---
 loongrCore/src/batch.rs    |   7 +--
 loongrCore/src/config.rs   |   7 +++
 loongrCore/src/loader.rs   | 120 +++++++++++++++++++++++++++++++++++++
 loongrCore/src/main.rs     |   8 ++-
 loongrCore/src/trap/mod.rs |   2 +-
 user/Makefile              |   9 +--
 user/build.py              |  23 +++++++
 7 files changed, 163 insertions(+), 13 deletions(-)
 create mode 100644 loongrCore/src/loader.rs
 create mode 100644 user/build.py

diff --git a/loongrCore/src/batch.rs b/loongrCore/src/batch.rs
index f1a193e..7054380 100644
--- a/loongrCore/src/batch.rs
+++ b/loongrCore/src/batch.rs
@@ -2,12 +2,7 @@ use crate::println;
 use crate::sync::UPSafeCell;
 use crate::trap::TrapContext;
 use lazy_static::*;
-
-const USER_STACK_SIZE: usize = 4096 * 2;
-const KERNEL_STACK_SIZE: usize = 4096 * 2;
-const MAX_APP_NUM: usize = 16;
-const APP_BASE_ADDRESS: usize = 0x00200000;
-const APP_SIZE_LIMIT: usize = 0x30000;
+use crate::config::*;
 
 #[repr(align(4096))]
 struct KernelStack {
diff --git a/loongrCore/src/config.rs b/loongrCore/src/config.rs
index ae65765..9f5c10f 100644
--- a/loongrCore/src/config.rs
+++ b/loongrCore/src/config.rs
@@ -14,3 +14,10 @@ const LOONGARCH_CSR_DMWIN0: u32 = 0x180;
 const LOONGARCH_CSR_DMWIN1: u32 = 0x181;
 const LOONGARCH_CSR_DMWIN2: u32 = 0x182;
 const LOONGARCH_CSR_DMWIN3: u32 = 0x183;
+
+
+pub const MAX_APP_NUM: usize = 10;
+pub const APP_BASE_ADDRESS: usize = 0x00200000; //应用程序起始地址
+pub const APP_SIZE_LIMIT: usize = 0x20000; //应用程序的空间限制
+pub const USER_STACK_SIZE:usize = 4096*2;//用户栈大小
+pub const KERNEL_STACK_SIZE:usize = 4096*2;//内核栈大小
\ No newline at end of file
diff --git a/loongrCore/src/loader.rs b/loongrCore/src/loader.rs
new file mode 100644
index 0000000..1941b54
--- /dev/null
+++ b/loongrCore/src/loader.rs
@@ -0,0 +1,120 @@
+///将应用程序全部加载到内存中
+use crate::config::*;
+use core::slice::{from_raw_parts,from_raw_parts_mut};
+use crate::{INFO,DEBUG};
+use lazy_static::lazy_static;
+use crate::trap::context::TrapContext;
+
+lazy_static!{
+    static ref LOADAPP:usize = load_app();
+}
+static mut CURRENTAPP:usize = 0;
+
+static KERNEL_STACK:KernelStack = KernelStack{data:[0;KERNEL_STACK_SIZE]};
+static USER_STACK:UserStack = UserStack{data:[0;USER_STACK_SIZE]};
+
+#[repr(align(4096))]
+struct KernelStack{
+    data:[u8;KERNEL_STACK_SIZE]
+}
+#[repr(align(4096))]
+struct UserStack{
+    data:[u8;USER_STACK_SIZE],
+}
+
+
+impl UserStack {
+    //获取栈顶地址
+    fn get_sp(&self)->usize{
+        self.data.as_ptr() as usize + USER_STACK_SIZE
+    }
+}
+
+impl KernelStack {
+    //获取内核栈栈顶地址
+    fn get_sp(&self)->usize{
+        self.data.as_ptr() as usize + KERNEL_STACK_SIZE
+    }
+    fn push_context(&self,cx:TrapContext)->&'static mut TrapContext{
+        //在内核栈上压入trap上下文
+        let cx_ptr = (self.get_sp()-core::mem::size_of::<TrapContext>() )as *mut TrapContext;
+        unsafe {
+            *cx_ptr = cx;
+            cx_ptr.as_mut().unwrap()
+            //返回内核栈地址
+        }
+    }
+}
+
+
+ fn load_app()->usize{
+    extern "C"{ fn _num_app();}
+    //取出app所在位置的地址
+    //link_apps按8字节对其
+    let num_app_ptr = _num_app as usize as *const usize;//取地址
+    let num_app = unsafe{ num_app_ptr.read_volatile()};//读内容 应用数量
+    let mut app_start :[usize;MAX_APP_NUM+1] = [0;MAX_APP_NUM+1];
+    let app_start_raw:&[usize] = unsafe{
+        //形成一个指针切片,存放的三个应用的起始地址和最后一个应用的开始地址
+        from_raw_parts(num_app_ptr.add(1),num_app+1)
+    };
+    app_start[..=num_app].copy_from_slice(app_start_raw);//复制地址
+    for i in 0..num_app{
+        //清除应用程序段
+        let app_i_address = get_base_address(i);
+        (app_i_address..app_i_address + APP_SIZE_LIMIT).for_each(|addr| {
+           unsafe { (addr as *mut u8).write_volatile(0); }//取地址并写入0,以字节写入
+        });
+        let app_src = unsafe{
+            from_raw_parts(
+                app_start[i] as *const u8,//起始地址
+                app_start[i + 1] - app_start[i],//长度,以字节记
+            )
+        };
+        let app_dst = unsafe{from_raw_parts_mut(app_i_address as *mut u8, app_src.len())};
+        app_dst.copy_from_slice(app_src); //写入数据
+    }
+    num_app
+}
+
+fn get_base_address(app_id:usize) ->usize{
+    APP_BASE_ADDRESS + APP_SIZE_LIMIT*app_id
+}
+
+pub fn init_load(){
+    INFO!("[kernel] Loading {} apps...",*LOADAPP);
+    INFO!("[kernel] Apps all loaded!");
+}
+pub  fn run_next_app()->!{
+    unsafe {
+        if CURRENTAPP >=*LOADAPP {
+            panic!("[kernel] Apps run over");
+        }
+    }
+
+    extern "C"{
+        fn __restore(cx_addr:usize); //定义外部接口,来自trap.asm用于恢复上下文
+    }
+    unsafe {
+        CURRENTAPP +=1;
+        // DEBUG!("[kernel] Run the {} app!",CURRENTAPP-1);
+    }
+    // 复用_restore函数
+    // 在内核栈上压入一个Trap上下文
+    // sepc 是应用程序入口地址  0x80400000 ,
+    // 其 sp 寄存器指向用户栈,其sstatus 的 SPP 字段被设置为 User 。
+    // push_context 的返回值是内核栈压入 Trap 上下文之后的内核栈顶,
+    // 它会被作为 __restore 的参
+    unsafe {
+        // println!("[kernel] Begin run application!");
+        __restore({
+            KERNEL_STACK.push_context(
+                TrapContext::app_init_context(
+                    get_base_address(CURRENTAPP-1),
+                    USER_STACK.get_sp()))as * const _ as usize
+        }
+        );
+        //此时sp指向的是用户栈地址,sscratch指向的是内核栈地址
+    }
+    panic!("The end of application")
+}
\ No newline at end of file
diff --git a/loongrCore/src/main.rs b/loongrCore/src/main.rs
index 3b8db6e..927a7d6 100644
--- a/loongrCore/src/main.rs
+++ b/loongrCore/src/main.rs
@@ -16,6 +16,8 @@ mod syscall;
 mod test;
 mod trap;
 mod uart;
+mod loader;
+
 extern crate bit_field;
 extern crate rlibc;
 
@@ -42,6 +44,8 @@ pub extern "C" fn main() {
     INFO!("{}", FLAG);
     trap::init();
     // test_csr_register();
-    batch::init();
-    run_next_app();
+    // batch::init();
+    // run_next_app();
+    loader::init_load();
+    loader::run_next_app();
 }
diff --git a/loongrCore/src/trap/mod.rs b/loongrCore/src/trap/mod.rs
index 3905844..f1a3a20 100644
--- a/loongrCore/src/trap/mod.rs
+++ b/loongrCore/src/trap/mod.rs
@@ -1,4 +1,4 @@
-mod context;
+pub(crate) mod context;
 
 use crate::loong_arch::register::{
     crmd::Crmd, ecfg::Ecfg, eentry::Eentry, estat::Estat, estat::Trap,
diff --git a/user/Makefile b/user/Makefile
index c59f294..5c62591 100644
--- a/user/Makefile
+++ b/user/Makefile
@@ -11,10 +11,11 @@ OBJDUMP := rust-objdump --arch-name=riscv64
 OBJCOPY := loongarch64-unknown-linux-gnu-objcopy
 
 elf:
-	@cargo build --release
-	@echo $(APPS)
-	@echo $(ELFS)
-	@echo $(BINS)
+	@#cargo build --release
+	@#echo $(APPS)
+	@#echo $(ELFS)
+	@#echo $(BINS)
+	@python3 build.py
 
 binary: elf
 	$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
diff --git a/user/build.py b/user/build.py
new file mode 100644
index 0000000..d5dd971
--- /dev/null
+++ b/user/build.py
@@ -0,0 +1,23 @@
+import os
+
+base_address = 0x00200000
+app_address = 0x20000
+
+linker = "linker.ld"
+apps = os.listdir("src/bin")
+ori_text = [];
+with open(linker,'r') as f:
+    for line in f.readlines():
+        ori_text.append(line)
+apps.sort()
+for i,app in enumerate(apps):
+    app_name = app.split('.')[0]
+    with open(linker,'w+') as f:
+        for line in ori_text:
+            new_text = line.replace(hex(base_address),hex(base_address+app_address*i))
+            f.write(new_text)
+    os.system('cargo build --bin {} --release'.format(app_name))
+    print("[build.py] application {} start with address {}" .format(app, hex(base_address+app_address*i)))
+    with open(linker,"w+") as f:
+        for line in ori_text:
+            f.write(line)
\ No newline at end of file
-- 
GitLab