Commit ca7223a4 authored by Youjie Zheng's avatar Youjie Zheng
Browse files

[feat] Support for loading musl app and entering main function

No related merge requests found
Showing with 75 additions and 43 deletions
+75 -43
......@@ -10,11 +10,14 @@ repository = "https://github.com/arceos-org/starry-next"
log = "0.4"
linkme = "0.3"
axerrno = "0.1"
memory_addr = "0.2"
xmas-elf = "0.8"
memory_addr = "0.3"
xmas-elf = "0.9"
bitflags = "2.6"
axstd = { git = "https://github.com/arceos-org/arceos.git", features = ["paging"] }
arceos_posix_api = { git = "https://github.com/arceos-org/arceos.git" }
elf_parser = { git = "https://github.com/Starry-OS/elf-parser.git" }
numeric-enum-macro = { git = "https://github.com/mexus/numeric-enum-macro" }
axhal = { git = "https://github.com/arceos-org/arceos.git", features = ["uspace"] }
axmm = { git = "https://github.com/arceos-org/arceos.git" }
......
......@@ -5,9 +5,9 @@
//! Now these apps are loaded into memory as a part of the kernel image.
use core::arch::global_asm;
use alloc::vec::Vec;
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
use axhal::paging::MappingFlags;
use memory_addr::VirtAddr;
use memory_addr::{MemoryAddr, VirtAddr};
global_asm!(include_str!(concat!(env!("OUT_DIR"), "/link_app.S")));
......@@ -85,6 +85,8 @@ pub struct ELFInfo {
pub entry: VirtAddr,
/// The segments of the ELF file
pub segments: Vec<ELFSegment>,
/// The auxiliary vectors of the ELF file
pub auxv: BTreeMap<u8, usize>,
}
/// Load the ELF files by the given app name and return
......@@ -92,10 +94,11 @@ pub struct ELFInfo {
///
/// # Arguments
/// * `name` - The name of the app
/// * `base_addr` - The minimal address of user space
///
/// # Returns
/// Entry and information about segments of the given ELF file
pub(crate) fn load_user_app(name: &str) -> ELFInfo {
pub(crate) fn load_elf(name: &str, base_addr: VirtAddr) -> ELFInfo {
use xmas_elf::program::{Flags, SegmentData};
use xmas_elf::{header, ElfFile};
......@@ -105,15 +108,7 @@ pub(crate) fn load_user_app(name: &str) -> ELFInfo {
.expect("invalid ELF file");
let elf_header = elf.header;
let elf_magic_number = elf_header.pt1.magic;
assert_eq!(elf_magic_number, *b"\x7fELF", "invalid elf!");
assert_eq!(
elf.header.pt2.type_().as_type(),
header::Type::Executable,
"ELF is not an executable object"
);
assert_eq!(elf_header.pt1.magic, *b"\x7fELF", "invalid elf!");
let expect_arch = if cfg!(target_arch = "x86_64") {
header::Machine::X86_64
......@@ -145,14 +140,22 @@ pub(crate) fn load_user_app(name: &str) -> ELFInfo {
}
let mut segments = Vec::new();
let elf_offset = elf_parser::get_elf_base_addr(&elf, base_addr.as_usize()).unwrap();
assert!(
elf_offset & 0xfff == 0,
"ELF base address must be aligned to 4k"
);
elf.program_iter()
.filter(|ph| ph.get_type() == Ok(xmas_elf::program::Type::Load))
.for_each(|ph| {
// align the segment to 4k
let st_vaddr = VirtAddr::from(ph.virtual_addr() as usize);
let st_vaddr = VirtAddr::from(ph.virtual_addr() as usize) + elf_offset;
let st_vaddr_align: VirtAddr = st_vaddr.align_down_4k();
let ed_vaddr_align =
VirtAddr::from((ph.virtual_addr() + ph.mem_size()) as usize).align_up_4k();
let ed_vaddr_align = VirtAddr::from((ph.virtual_addr() + ph.mem_size()) as usize)
.align_up_4k()
+ elf_offset;
let data = match ph.get_data(&elf).unwrap() {
SegmentData::Undefined(data) => data,
_ => panic!("failed to get ELF segment data"),
......@@ -166,7 +169,8 @@ pub(crate) fn load_user_app(name: &str) -> ELFInfo {
});
});
ELFInfo {
entry: VirtAddr::from(elf.header.pt2.entry_point() as usize),
entry: VirtAddr::from(elf.header.pt2.entry_point() as usize + elf_offset),
segments,
auxv: elf_parser::get_auxv_vector(&elf, elf_offset),
}
}
......@@ -26,6 +26,7 @@ fn main() {
.split(',')
.filter(|&x| !x.is_empty());
for testcase in testcases {
log::info!("Running testcase: {}", testcase);
let (entry_vaddr, ustack_top, uspace) = mm::load_user_app(testcase).unwrap();
let user_task = task::spawn_user_task(
Arc::new(Mutex::new(uspace)),
......
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;
use axerrno::AxResult;
use memory_addr::VirtAddr;
......@@ -9,10 +12,15 @@ use axtask::TaskExtRef;
use crate::loader;
/// Load a user app.
///
/// # Returns
/// - The first return value is the entry point of the user app.
/// - The second return value is the top of the user stack.
/// - The third return value is the address space of the user app.
pub fn load_user_app(app_name: &str) -> AxResult<(VirtAddr, VirtAddr, AddrSpace)> {
let elf_info = loader::load_user_app(app_name);
let mut uspace = axmm::new_user_aspace()?;
let elf_info = loader::load_elf(app_name, uspace.base());
for segement in elf_info.segments {
debug!(
"Mapping ELF segment: [{:#x?}, {:#x?}) flags: {:#x?}",
......@@ -26,21 +34,19 @@ pub fn load_user_app(app_name: &str) -> AxResult<(VirtAddr, VirtAddr, AddrSpace)
continue;
}
let segement_page_iter = memory_addr::PageIter4K::new(
segement.start_vaddr,
segement.start_vaddr + segement.size,
)
.expect("Failed to create page iterator");
let mut segement_data_offset = 0;
for (idx, vaddr) in segement_page_iter.enumerate() {
for (idx, vaddr) in
memory_addr::PageIter4K::new(segement.start_vaddr, segement.start_vaddr + segement.size)
.expect("Failed to create page iterator")
.enumerate()
{
let (paddr, _, _) = uspace
.page_table()
.query(vaddr)
.unwrap_or_else(|_| panic!("Mapping failed for segment: {:#x?}", vaddr));
let (start_paddr, copied_size) = if idx == 0 {
let (start_paddr, mut copied_size) = if idx == 0 {
// Align the start of the segment to the start of the page
(
paddr + segement.offset,
......@@ -50,12 +56,9 @@ pub fn load_user_app(app_name: &str) -> AxResult<(VirtAddr, VirtAddr, AddrSpace)
(paddr, memory_addr::PAGE_SIZE_4K)
};
debug!(
"Copying segment data: {:#x?} -> {:#x?} size: {:#x?}",
segement.start_vaddr + segement_data_offset + segement.offset,
start_paddr,
copied_size
);
if copied_size + segement_data_offset > segement.data.len() {
copied_size = segement.data.len() - segement_data_offset;
}
unsafe {
core::ptr::copy_nonoverlapping(
......@@ -64,7 +67,7 @@ pub fn load_user_app(app_name: &str) -> AxResult<(VirtAddr, VirtAddr, AddrSpace)
copied_size,
);
}
assert!(uspace.page_table().query(vaddr).is_ok());
segement_data_offset += copied_size;
if segement_data_offset >= segement.data.len() {
break;
......@@ -73,20 +76,41 @@ pub fn load_user_app(app_name: &str) -> AxResult<(VirtAddr, VirtAddr, AddrSpace)
// TDOO: flush the I-cache
}
let ustack_top = uspace.end();
let ustack_vaddr = ustack_top - crate::USER_STACK_SIZE;
let ustack_base = uspace.end();
let ustack_size = crate::USER_STACK_SIZE;
let ustack_top = ustack_base - ustack_size;
debug!(
"Mapping user stack: {:#x?} -> {:#x?}",
ustack_vaddr, ustack_top
ustack_top, ustack_base
);
// FIXME: Add more arguments and environment variables
let args = vec![app_name.to_string()];
let (stack_data, ustack_bottom) =
elf_parser::get_app_stack_region(args, &Vec::new(), elf_info.auxv, ustack_top, ustack_size);
uspace.map_alloc(
ustack_vaddr,
crate::USER_STACK_SIZE,
ustack_top,
ustack_size,
MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER,
false,
true,
)?;
info!("New user address space: {:#x?}", uspace);
Ok((elf_info.entry, ustack_top, uspace))
for (idx, vaddr) in memory_addr::PageIter4K::new(ustack_top, ustack_base)
.expect("Failed to create page iterator")
.enumerate()
{
let (paddr, _, _) = uspace
.page_table()
.query(vaddr)
.unwrap_or_else(|e| panic!("Mapping failed for stack: {:#x?} error: {:?}", vaddr, e));
unsafe {
core::ptr::copy_nonoverlapping(
stack_data.as_ptr().add(idx * memory_addr::PAGE_SIZE_4K),
phys_to_virt(paddr).as_mut_ptr(),
memory_addr::PAGE_SIZE_4K,
);
}
}
Ok((elf_info.entry, VirtAddr::from(ustack_bottom), uspace))
}
#[register_trap_handler(PAGE_FAULT)]
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment