1use crate::arch::x86_64::gdt;
5use crate::arch::x86_64::paging::{get_root, map_range, PTEFlags};
6use crate::defs::{HWDefs, Mem};
7use crate::fs;
8use crate::fs::*;
9use crate::proc::loader::load;
10use crate::proc::task::Task;
11use core::arch::asm;
12
13pub fn exec(file_name: &str) {
18 let task = Task::current().unwrap();
19 let mm = &mut task.mm;
20 mm.vmas
23 .retain(|vma| vma.vm_range.start >= Mem::ID_MAP_START);
24
25 let archive = get_archive();
26 let file = fs::iter(archive).find(|f| f.hdr.name() == file_name);
27 if file.is_none() {
28 println!("error: no such file {}", file_name);
29 return;
30 }
31 let f = file.unwrap();
32 let entry = load(&f);
33 if entry.is_none() {
34 println!("failed to load elf");
35 return;
36 }
37 let entry = entry.unwrap();
38 println!("exec entry: {:#X}", entry);
39
40 let stack_top = Mem::USER_STACK_START + Mem::USER_STACK_SIZE;
44 let map_start = stack_top - Mem::PAGE_SIZE * 4;
45 let flags = PTEFlags::PRESENT | PTEFlags::WRITABLE | PTEFlags::USER;
46 let pt_root = get_root();
47 let range = core::ops::Range { start: map_start, end: stack_top };
48 if !map_range(pt_root, &range, flags) {
49 println!("failed to map user stack");
50 return;
51 }
52
53 let ksp = task.kernel_stack + Mem::KERNEL_STACK_SIZE;
56 unsafe { gdt::set_tss_ksp(ksp) };
57
58 let user_sp = stack_top & !0xf;
60
61 unsafe { enter_usermode(entry, user_sp) };
63}
64
65#[inline(never)]
69unsafe fn enter_usermode(entry: u64, user_sp: u64) -> ! {
70 let rflags: u64 = 1 << 9;
72 let udata: u16 = HWDefs::SEG_USER_DATA | 3;
74 let ucode: u16 = HWDefs::SEG_USER_CODE | 3;
75 unsafe {
76 asm!(
77 "mov ds, {udata:x}",
79 "mov es, {udata:x}",
80 "mov fs, {udata:x}",
81 "mov gs, {udata:x}",
82 "push {udata_q}", "push {usp}", "push {rflags}", "push {ucode_q}", "push {entry}", "xor rax, rax", "iretq",
90 udata = in(reg) udata,
91 udata_q = in(reg) udata as u64,
92 ucode_q = in(reg) ucode as u64,
93 usp = in(reg) user_sp,
94 rflags = in(reg) rflags,
95 entry = in(reg) entry,
96 options(noreturn),
97 );
98 }
99}