use alloc::string::ToString;
use axerrno::AxResult;
use axhal::{
paging::MappingFlags,
trap::{register_trap_handler, PAGE_FAULT},
};
use axmm::AddrSpace;
use axtask::TaskExtRef;
use memory_addr::VirtAddr;
use crate::{config, loader};
pub fn load_user_app(app_name: &str) -> AxResult<(VirtAddr, VirtAddr, AddrSpace)> {
let mut uspace = axmm::new_user_aspace(
VirtAddr::from_usize(config::USER_SPACE_BASE),
config::USER_SPACE_SIZE,
)?;
let elf_info = loader::load_elf(app_name, uspace.base());
for segement in elf_info.segments {
debug!(
"Mapping ELF segment: [{:#x?}, {:#x?}) flags: {:#x?}",
segement.start_vaddr,
segement.start_vaddr + segement.size,
segement.flags
);
uspace.map_alloc(segement.start_vaddr, segement.size, segement.flags, true)?;
if segement.data.is_empty() {
continue;
}
uspace.write(segement.start_vaddr + segement.offset, segement.data)?;
}
let ustack_end = VirtAddr::from_usize(config::USER_STACK_TOP);
let ustack_size = config::USER_STACK_SIZE;
let ustack_start = ustack_end - ustack_size;
debug!(
"Mapping user stack: {:#x?} -> {:#x?}",
ustack_start, ustack_end
);
let (stack_data, ustack_pointer) = kernel_elf_parser::get_app_stack_region(
&[app_name.to_string()],
&[],
&elf_info.auxv,
ustack_start,
ustack_size,
);
uspace.map_alloc(
ustack_start,
ustack_size,
MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER,
true,
)?;
uspace.write(VirtAddr::from_usize(ustack_pointer), stack_data.as_slice())?;
Ok((elf_info.entry, VirtAddr::from(ustack_pointer), uspace))
}
#[register_trap_handler(PAGE_FAULT)]
fn handle_page_fault(vaddr: VirtAddr, access_flags: MappingFlags, is_user: bool) -> bool {
if is_user {
if !axtask::current()
.task_ext()
.aspace
.lock()
.handle_page_fault(vaddr, access_flags)
{
warn!(
"{}: segmentation fault at {:#x}, exit!",
axtask::current().id_name(),
vaddr
);
axtask::exit(-1);
}
true
} else {
false
}
}