    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98

    //! Loading user applications into memory
    //!
    //! For chapter 3, user applications are simply part of the data included in the
    //! kernel binary, so we only need to copy them to the space allocated for each
    //! app to load them. We also allocate fixed spaces for each task's
    //! [`KernelStack`] and [`UserStack`].

    use crate::config::*;
    use crate::trap::TrapContext;
    use core::arch::asm;

    #[repr(align(4096))]
    #[derive(Copy, Clone)]
    struct KernelStack {
        data: [u8; KERNEL_STACK_SIZE],
    }

    #[repr(align(4096))]
    #[derive(Copy, Clone)]
    struct UserStack {
        data: [u8; USER_STACK_SIZE],
    }

    static KERNEL_STACK: [KernelStack; MAX_APP_NUM] = [KernelStack {
        data: [0; KERNEL_STACK_SIZE],
    }; MAX_APP_NUM];

    static USER_STACK: [UserStack; MAX_APP_NUM] = [UserStack {
        data: [0; USER_STACK_SIZE],
    }; MAX_APP_NUM];

    impl KernelStack {
        fn get_sp(&self) -> usize {
            self.data.as_ptr() as usize + KERNEL_STACK_SIZE
        }
        pub fn push_context(&self, trap_cx: TrapContext) -> usize {
            let trap_cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext;
            unsafe {
                *trap_cx_ptr = trap_cx;
            }
            trap_cx_ptr as usize
        }
    }

    impl UserStack {
        fn get_sp(&self) -> usize {
            self.data.as_ptr() as usize + USER_STACK_SIZE
        }
    }

    /// Get base address of app i.
    fn get_base_i(app_id: usize) -> usize {
        APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
    }

    /// Get the total number of applications.
    pub fn get_num_app() -> usize {
        extern "C" {
            fn _num_app();
        }
        unsafe { (_num_app as usize as *const usize).read_volatile() }
    }

    /// Load nth user app at
    /// [APP_BASE_ADDRESS + n * APP_SIZE_LIMIT, APP_BASE_ADDRESS + (n+1) * APP_SIZE_LIMIT).
    pub fn load_apps() {
        extern "C" {
            fn _num_app();
        }
        let num_app_ptr = _num_app as usize as *const usize;
        let num_app = get_num_app();
        let app_start = unsafe { core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) };
        // clear i-cache first
        unsafe {
            asm!("fence.i");
        }
        // load apps
        for i in 0..num_app {
            let base_i = get_base_i(i);
            // clear region
            (base_i..base_i + APP_SIZE_LIMIT)
                .for_each(|addr| unsafe { (addr as *mut u8).write_volatile(0) });
            // load app from data section to memory
            let src = unsafe {
                core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i])
            };
            let dst = unsafe { core::slice::from_raw_parts_mut(base_i as *mut u8, src.len()) };
            dst.copy_from_slice(src);
        }
    }

    /// get app info with entry and sp and save `TrapContext` in kernel stack
    pub fn init_app_cx(app_id: usize) -> usize {
        KERNEL_STACK[app_id].push_context(TrapContext::app_init_context(
            get_base_i(app_id),
            USER_STACK[app_id].get_sp(),
        ))
    }