support dynamic linking

This commit is contained in:
Jianfeng Jiang 2023-03-28 23:35:02 -04:00 committed by Tate, Hongliang Tian
parent 567ac612e5
commit d19dc09563
14 changed files with 307 additions and 65 deletions

121
src/Cargo.lock generated
View File

@ -24,6 +24,23 @@ dependencies = [
"version_check",
]
[[package]]
name = "align_ext"
version = "0.1.0"
[[package]]
name = "aml"
version = "0.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dcf92e2afd8d6607e435cdc1d8ea76260fa467f6cf821f6af40e88dca15d183"
dependencies = [
"bit_field",
"bitvec",
"byteorder",
"log",
"spinning_top",
]
[[package]]
name = "anyhow"
version = "1.0.32"
@ -60,6 +77,18 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "buddy_system_allocator"
version = "0.9.0"
@ -69,6 +98,12 @@ dependencies = [
"spin 0.9.4",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -131,6 +166,12 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e63201c624b8c8883921b1a1accc8916c4fa9dbfb15d122b26e4dde945b86bbf"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "ghost"
version = "0.1.7"
@ -179,7 +220,7 @@ dependencies = [
[[package]]
name = "inventory"
version = "0.3.3"
source = "git+https://github.com/sdww0/inventory#6356dc79fb15ae4e72ddb6fe826a3ea76d9046a5"
source = "git+https://github.com/sdww0/inventory?rev=6356dc7#6356dc79fb15ae4e72ddb6fe826a3ea76d9046a5"
dependencies = [
"ctor",
"ghost",
@ -200,7 +241,9 @@ version = "0.1.0"
dependencies = [
"component",
"jinux-frame",
"jinux-framebuffer",
"jinux-std",
"jinux-time",
"limine",
"x86_64",
]
@ -217,7 +260,6 @@ dependencies = [
"jinux-virtio",
"lazy_static",
"log",
"pod",
"spin 0.9.4",
]
@ -234,9 +276,11 @@ name = "jinux-frame"
version = "0.1.0"
dependencies = [
"acpi",
"align_ext",
"aml",
"bitflags",
"buddy_system_allocator",
"font8x8",
"cfg-if",
"intrusive-collections",
"lazy_static",
"limine",
@ -244,12 +288,22 @@ dependencies = [
"pod",
"spin 0.9.4",
"trapframe",
"uart_16550",
"volatile",
"x86",
"x86_64",
]
[[package]]
name = "jinux-framebuffer"
version = "0.1.0"
dependencies = [
"component",
"font8x8",
"jinux-frame",
"log",
"spin 0.9.4",
]
[[package]]
name = "jinux-input"
version = "0.1.0"
@ -262,7 +316,6 @@ dependencies = [
"jinux-virtio",
"lazy_static",
"log",
"pod",
"spin 0.9.4",
"virtio-input-decoder",
]
@ -294,6 +347,7 @@ dependencies = [
name = "jinux-std"
version = "0.1.0"
dependencies = [
"align_ext",
"ascii",
"bitflags",
"controlled",
@ -303,6 +357,7 @@ dependencies = [
"jinux-frame",
"jinux-input",
"jinux-rights-proc",
"jinux-time",
"jinux-util",
"lazy_static",
"log",
@ -318,6 +373,16 @@ dependencies = [
"xmas-elf",
]
[[package]]
name = "jinux-time"
version = "0.1.0"
dependencies = [
"component",
"jinux-frame",
"log",
"spin 0.9.4",
]
[[package]]
name = "jinux-util"
version = "0.1.0"
@ -422,6 +487,7 @@ checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "pod"
version = "0.1.0"
source = "git+https://github.com/jinzhao-dev/pod?rev=7fa2ed2#7fa2ed2bb8344856f98f0d533ecb1bab238f79ba"
dependencies = [
"pod-derive",
]
@ -429,6 +495,7 @@ dependencies = [
[[package]]
name = "pod-derive"
version = "0.1.0"
source = "git+https://github.com/jinzhao-dev/pod?rev=7fa2ed2#7fa2ed2bb8344856f98f0d533ecb1bab238f79ba"
dependencies = [
"proc-macro2",
"quote",
@ -453,6 +520,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "raw-cpuid"
version = "10.7.0"
@ -529,6 +602,15 @@ dependencies = [
"lock_api",
]
[[package]]
name = "spinning_top"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
dependencies = [
"lock_api",
]
[[package]]
name = "syn"
version = "1.0.109"
@ -540,6 +622,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "thiserror"
version = "1.0.37"
@ -613,9 +701,10 @@ dependencies = [
[[package]]
name = "trapframe"
version = "0.9.0"
source = "git+https://github.com/sdww0/trapframe-rs?rev=13e1065#13e106595d3cde9988e101e6b51e8fb9da38053d"
source = "git+https://github.com/sdww0/trapframe-rs?rev=4234db5#4234db5ceb667a46c3a7b68b63a5e9ef25993ef9"
dependencies = [
"log",
"pod",
"raw-cpuid",
"x86_64",
]
@ -634,17 +723,6 @@ dependencies = [
name = "typeflags-util"
version = "0.1.0"
[[package]]
name = "uart_16550"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b074eb9300ad949edd74c529c0e8d451625af71bb948e6b65fe69f72dc1363d9"
dependencies = [
"bitflags",
"rustversion",
"x86_64",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"
@ -720,6 +798,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "x86"
version = "0.52.0"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da31082cbaabc14fb9f6b62933844d61a73942dd23a28ac920d86c163126b530
oid sha256:64b67cf4ad247d668833888447ec7f12d37f5f816abd549d5c2c08fecfa4dd09
size 16696

View File

@ -1,6 +1,6 @@
#include <stdio.h>
int main() {
printf("hello world from hello_c!\n");
printf("hello world from hello_pie!\n");
return 0;
}

View File

@ -9,6 +9,7 @@
#![feature(btree_drain_filter)]
#![feature(const_option)]
#![feature(extend_one)]
#![feature(let_chains)]
// FIXME: This feature is used to support vm capbility now as a work around.
// Since this is an incomplete feature, use this feature is unsafe.
// We should find a proper method to replace this feature with min_specialization, which is a sound feature.

View File

@ -1,7 +1,7 @@
/// A wrapper of xmas_elf's elf parsing
use xmas_elf::{
header::{self, Header, HeaderPt1, HeaderPt2, HeaderPt2_, Machine_, Type_},
program::ProgramHeader64,
program::{self, ProgramHeader64},
};
use crate::prelude::*;
@ -86,6 +86,34 @@ impl Elf {
pub fn is_shared_object(&self) -> bool {
self.elf_header.pt2.type_.as_type() == header::Type::SharedObject
}
/// read the ldso path from the elf interpret section
pub fn ldso_path(&self, file_header_buf: &[u8]) -> Result<String> {
for program_header in &self.program_headers {
let type_ = program_header.get_type().map_err(|_| {
Error::with_message(Errno::ENOEXEC, "parse program header type fails")
})?;
if type_ == program::Type::Interp {
let file_size = program_header.file_size as usize;
let file_offset = program_header.offset as usize;
debug_assert!(file_offset + file_size <= file_header_buf.len());
let ldso = CStr::from_bytes_with_nul(
&file_header_buf[file_offset..file_offset + file_size],
)?;
return Ok(ldso.to_string_lossy().to_string());
}
}
return_errno_with_message!(
Errno::ENOEXEC,
"cannot find interpreter section in dyn-link program"
)
}
// An offset to be subtracted from ELF vaddr for PIE
pub fn base_load_address_offset(&self) -> u64 {
let phdr = self.program_headers.iter().nth(0).unwrap();
phdr.virtual_addr - phdr.offset
}
}
pub struct ElfHeader {

View File

@ -15,6 +15,7 @@ use jinux_frame::vm::{VmIo, VmPerm};
use super::aux_vec::{AuxKey, AuxVec};
use super::elf_file::Elf;
use super::load_elf::LdsoLoadInfo;
pub const INIT_STACK_BASE: Vaddr = 0x0000_0000_2000_0000;
pub const INIT_STACK_SIZE: usize = 0x1000 * 16; // 64KB
@ -109,9 +110,15 @@ impl InitStack {
self.init_stack_top - self.init_stack_size
}
pub fn init(&mut self, root_vmar: &Vmar<Full>, elf: &Elf, aux_vec: &mut AuxVec) -> Result<()> {
pub fn init(
&mut self,
root_vmar: &Vmar<Full>,
elf: &Elf,
ldso_load_info: &Option<LdsoLoadInfo>,
aux_vec: &mut AuxVec,
) -> Result<()> {
self.map_and_zeroed(root_vmar)?;
self.write_stack_content(root_vmar, elf, aux_vec)?;
self.write_stack_content(root_vmar, elf, ldso_load_info, aux_vec)?;
self.debug_print_stack_content(root_vmar);
Ok(())
}
@ -155,6 +162,7 @@ impl InitStack {
&mut self,
root_vmar: &Vmar<Full>,
elf: &Elf,
ldso_load_info: &Option<LdsoLoadInfo>,
aux_vec: &mut AuxVec,
) -> Result<()> {
// write a zero page. When a user program tries to read a cstring(like argv) from init stack,
@ -173,6 +181,10 @@ impl InitStack {
let random_value = generate_random_for_aux_vec();
let random_value_pointer = self.write_bytes(&random_value, root_vmar)?;
aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer)?;
if let Some(ldso_load_info) = ldso_load_info {
let ldso_base = ldso_load_info.base_addr();
aux_vec.set(AuxKey::AT_BASE, ldso_base as u64)?;
}
self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers, &aux_vec)?;
self.write_aux_vec(root_vmar, aux_vec)?;
self.write_envp_pointers(root_vmar, envp_pointers)?;
@ -331,6 +343,13 @@ pub fn init_aux_vec(elf: &Elf, elf_map_addr: Option<Vaddr>) -> Result<AuxVec> {
aux_vec.set(AuxKey::AT_PHDR, ph_addr as u64)?;
aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?;
aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
let elf_entry = if elf.is_shared_object() {
let base_load_offset = elf.base_load_address_offset();
elf.entry_point() + elf_map_addr.unwrap() - base_load_offset as usize
} else {
elf.entry_point()
};
aux_vec.set(AuxKey::AT_ENTRY, elf_entry as u64)?;
Ok(aux_vec)
}

View File

@ -2,6 +2,8 @@
//! When create a process from elf file, we will use the elf_load_info to construct the VmSpace
use crate::fs::file_handle::FileHandle;
use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD};
use crate::fs::utils::AccessMode;
use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack};
use crate::vm::perms::VmPerms;
use crate::vm::vmo::VmoRightsOp;
@ -28,24 +30,87 @@ pub fn load_elf_to_root_vmar(
root_vmar: &Vmar<Full>,
file_header: &[u8],
elf_file: Arc<FileHandle>,
fs_resolver: &FsResolver,
argv: Vec<CString>,
envp: Vec<CString>,
) -> Result<ElfLoadInfo> {
let elf = Elf::parse_elf(file_header)?;
let ldso_load_info = if let Ok(ldso_load_info) =
load_ldso_for_shared_object(root_vmar, &elf, file_header, fs_resolver)
{
Some(ldso_load_info)
} else {
None
};
let map_addr = map_segment_vmos(&elf, root_vmar, elf_file)?;
let mut aux_vec = init_aux_vec(&elf, map_addr)?;
let mut init_stack = InitStack::new_default_config(argv, envp);
init_stack.init(root_vmar, &elf, &mut aux_vec)?;
let entry_point = if elf.is_shared_object() {
elf.entry_point() + map_addr.unwrap()
init_stack.init(root_vmar, &elf, &ldso_load_info, &mut aux_vec)?;
let entry_point = if let Some(ldso_load_info) = ldso_load_info {
// Normal shared object
ldso_load_info.entry_point()
} else {
elf.entry_point()
if elf.is_shared_object() {
// ldso itself
elf.entry_point() + map_addr.unwrap()
} else {
// statically linked executable
elf.entry_point()
}
};
let elf_load_info = ElfLoadInfo::new(entry_point, init_stack.user_stack_top());
debug!("load elf succeeds.");
Ok(elf_load_info)
}
fn load_ldso_for_shared_object(
root_vmar: &Vmar<Full>,
elf: &Elf,
file_header: &[u8],
fs_resolver: &FsResolver,
) -> Result<LdsoLoadInfo> {
if let Ok(ldso_path) = elf.ldso_path(file_header) && elf.is_shared_object(){
trace!("ldso_path = {:?}", ldso_path);
let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?;
let ldso_file = fs_resolver.open(&fs_path, AccessMode::O_RDONLY as u32, 0)?;
let mut buf = Box::new([0u8; PAGE_SIZE]);
let ldso_header = ldso_file.read(&mut *buf)?;
let ldso_elf = Elf::parse_elf(&*buf)?;
let ldso_file = Arc::new(FileHandle::new_inode_handle(ldso_file));
let map_addr = map_segment_vmos(&ldso_elf, root_vmar, ldso_file)?.unwrap();
return Ok(LdsoLoadInfo::new(ldso_elf.entry_point() + map_addr, map_addr));
}
// There are three reasons that an executable may lack ldso_path,
// 1. this is a statically linked executable,
// 2. the shared object is invalid,
// 3. the shared object is ldso itself,
// we don't try to distinguish these cases and just let it go.
return_errno_with_message!(Errno::ENOEXEC, "cannot find ldso for shared object");
}
pub struct LdsoLoadInfo {
entry_point: Vaddr,
base_addr: Vaddr,
}
impl LdsoLoadInfo {
pub fn new(entry_point: Vaddr, base_addr: Vaddr) -> Self {
Self {
entry_point,
base_addr,
}
}
pub fn entry_point(&self) -> Vaddr {
self.entry_point
}
pub fn base_addr(&self) -> Vaddr {
self.base_addr
}
}
pub struct ElfLoadInfo {
entry_point: Vaddr,
user_stack_top: Vaddr,
@ -74,8 +139,13 @@ pub fn map_segment_vmos(
root_vmar: &Vmar<Full>,
elf_file: Arc<FileHandle>,
) -> Result<Option<Vaddr>> {
let is_shared_object = elf.is_shared_object();
let mut file_map_addr = None;
// all segments of the shared object must be mapped to a continuous vm range
// to ensure the relative offset of each segment not changed.
let file_map_addr = if elf.is_shared_object() {
Some(hint_elf_map_addr(elf, root_vmar)?)
} else {
None
};
for program_header in &elf.program_headers {
let type_ = program_header
.get_type()
@ -87,43 +157,49 @@ pub fn map_segment_vmos(
vmo,
root_vmar,
elf_file.clone(),
&mut file_map_addr,
is_shared_object,
&file_map_addr,
)?;
}
}
Ok(file_map_addr)
}
fn hint_elf_map_addr(elf: &Elf, root_vmar: &Vmar<Full>) -> Result<Vaddr> {
let mut size = 0;
for program_header in &elf.program_headers {
let ph_size = program_header.virtual_addr + program_header.mem_size;
if ph_size > size {
size = ph_size;
}
}
root_vmar.hint_map_addr(size as usize)
}
/// map the segment vmo to root_vmar
fn map_segment_vmo(
program_header: &ProgramHeader64,
vmo: Vmo,
root_vmar: &Vmar<Full>,
elf_file: Arc<FileHandle>,
file_map_addr: &mut Option<Vaddr>,
is_shared_object: bool,
file_map_addr: &Option<Vaddr>,
) -> Result<()> {
let perms = VmPerms::from(parse_segment_perm(program_header.flags)?);
// let perms = VmPerms::READ | VmPerms::WRITE | VmPerms::EXEC;
let offset = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE);
debug!(
"map segment vmo: offset = 0x{:x}, virtual_addr = 0x{:x}",
offset, program_header.virtual_addr
trace!(
"map segment vmo: virtual addr = 0x{:x}, size = 0x{:x}, perms = {:?}",
program_header.virtual_addr,
program_header.file_size,
perms
);
let mut vm_map_options = root_vmar.new_map(vmo, perms)?;
// offset = 0 means the vmo can be put at any address
if is_shared_object {
if let Some(file_init_addr) = *file_map_addr {
let offset = file_init_addr + offset;
vm_map_options = vm_map_options.offset(offset);
}
if let Some(file_map_addr) = *file_map_addr {
let offset = file_map_addr + offset;
vm_map_options = vm_map_options.offset(offset);
} else {
vm_map_options = vm_map_options.offset(offset);
}
let map_addr = vm_map_options.build()?;
if is_shared_object && *file_map_addr == None {
*file_map_addr = Some(map_addr);
}
Ok(())
}

View File

@ -38,11 +38,11 @@ pub fn load_program_to_root_vmar(
let file = fs_resolver.open(&fs_path, AccessMode::O_RDONLY as u32, 0)?;
let file_header = {
// read the first page of file header
let mut file_header_buffer = [0u8; PAGE_SIZE];
file.read(&mut file_header_buffer)?;
let mut file_header_buffer = Box::new([0u8; PAGE_SIZE]);
file.read(&mut *file_header_buffer)?;
file_header_buffer
};
if let Some(mut new_argv) = parse_shebang_line(&file_header)? {
if let Some(mut new_argv) = parse_shebang_line(&*file_header)? {
if recursion_limit == 0 {
return_errno_with_message!(Errno::EINVAL, "the recursieve limit is reached");
}
@ -60,5 +60,5 @@ pub fn load_program_to_root_vmar(
let elf_file = Arc::new(FileHandle::new_inode_handle(file));
debug!("load executable, path = {}", executable_path);
load_elf_to_root_vmar(root_vmar, &file_header, elf_file, argv, envp)
load_elf_to_root_vmar(root_vmar, &*file_header, elf_file, fs_resolver, argv, envp)
}

View File

@ -21,20 +21,20 @@ pub fn handle_exception(context: &mut UserContext) {
}
fn handle_page_fault(trap_info: &TrapInformation) {
const PAGE_NOT_PRESENT_ERROR_MASK: usize = 0x1 << 0;
const WRITE_ACCESS_MASK: usize = 0x1 << 1;
const PAGE_NOT_PRESENT_ERROR_MASK: u64 = 0x1 << 0;
const WRITE_ACCESS_MASK: u64 = 0x1 << 1;
let page_fault_addr = trap_info.cr2 as Vaddr;
trace!(
"page fault error code: 0x{:x}, Page fault address: 0x{:x}",
trap_info.err,
page_fault_addr
);
let not_present = trap_info.err & PAGE_NOT_PRESENT_ERROR_MASK == 0;
let write = trap_info.err & WRITE_ACCESS_MASK != 0;
if not_present || write {
// If page is not present or due to write access, we should ask the vmar try to commit this page
let current = current!();
let root_vmar = current.root_vmar();
let page_fault_addr = trap_info.cr2 as Vaddr;
trace!(
"Page fault address: 0x{:x}, write access: {}",
page_fault_addr,
write
);
if let Err(e) = root_vmar.handle_page_fault(page_fault_addr, not_present, write) {
error!(
"page fault handler failed: addr: 0x{:x}, err: {:?}",

View File

@ -144,6 +144,12 @@ impl Vmar<Rights> {
self.check_rights(Rights::DUP)?;
Ok(Vmar(self.0.clone(), self.1.clone()))
}
/// Given a map size, returns the possible map address without doing actual allocation.
pub fn hint_map_addr(&self, map_size: usize) -> Result<Vaddr> {
self.check_rights(Rights::READ)?;
self.0.hint_map_addr(map_size)
}
}
impl VmIo for Vmar<Rights> {

View File

@ -265,7 +265,7 @@ impl Vmar_ {
inner.free_regions.append(&mut free_regions);
for (_, vm_mapping) in &inner.vm_mappings {
vm_mapping.unmap(vm_mapping.range(), true)?;
vm_mapping.unmap(&vm_mapping.range(), true)?;
let free_region = FreeRegion::new(vm_mapping.range());
free_regions.insert(free_region.start(), free_region);
}
@ -515,6 +515,8 @@ impl Vmar_ {
for (child_vmo_base, child_vmo) in &inner.vm_mappings {
let child_vmo_range = *child_vmo_base..*child_vmo_base + child_vmo.map_size();
if is_intersected(&vmo_range, &child_vmo_range) {
debug!("vmo_range = {:x?}", vmo_range);
debug!("child_vmo_range = {:x?}", child_vmo_range);
return_errno_with_message!(
Errno::EACCES,
"vmo range overlapped with another vmo"
@ -593,6 +595,16 @@ impl Vmar_ {
}
}
fn hint_map_addr(&self, size: usize) -> Result<Vaddr> {
let inner = self.inner.lock();
for (free_region_base, free_region) in &inner.free_regions {
if free_region.size() >= size {
return Ok(*free_region_base);
}
}
return_errno_with_message!(Errno::ENOMEM, "cannot find a suitale free region");
}
fn trim_existing_mappings(&self, trim_range: Range<usize>) -> Result<()> {
let mut inner = self.inner.lock();
let mut mappings_to_remove = BTreeSet::new();

View File

@ -5,7 +5,7 @@ use jinux_frame::vm::VmIo;
use jinux_rights_proc::require;
use crate::{
rights::{Dup, Rights, TRights},
rights::{Dup, Read, Rights, TRights},
vm::{page_fault_handler::PageFaultHandler, vmo::Vmo},
};
@ -148,6 +148,12 @@ impl<R: TRights> Vmar<R> {
Ok(Vmar(self.0.clone(), self.1))
}
/// Given a map size, returns the possible map address without doing actual allocation.
#[require(R > Read)]
pub fn hint_map_addr(&self, map_size: usize) -> Result<Vaddr> {
self.0.hint_map_addr(map_size)
}
/// Strict the access rights.
#[require(R > R1)]
pub fn restrict<R1: TRights>(self) -> Vmar<R1> {

View File

@ -79,8 +79,8 @@ impl VmMapping {
align,
can_overwrite,
)?;
debug!(
"build mapping, map_to_addr = 0x{:x}- 0x{:x}",
trace!(
"build mapping, map_range = 0x{:x}- 0x{:x}",
map_to_addr,
map_to_addr + size
);
@ -188,14 +188,14 @@ impl VmMapping {
}
/// Unmap pages in the range
pub fn unmap(&self, range: Range<usize>, destroy: bool) -> Result<()> {
pub fn unmap(&self, range: &Range<usize>, destroy: bool) -> Result<()> {
let map_to_addr = self.map_to_addr();
let vmo_map_range = (range.start - map_to_addr)..(range.end - map_to_addr);
let page_idx_range = get_page_idx_range(&vmo_map_range);
for page_idx in page_idx_range {
self.unmap_one_page(page_idx)?;
}
if destroy && range == self.range() {
if destroy && *range == self.range() {
self.inner.lock().is_destroyed = false;
}
Ok(())
@ -204,7 +204,7 @@ impl VmMapping {
pub fn unmap_and_decommit(&self, range: Range<usize>) -> Result<()> {
let map_to_addr = self.map_to_addr();
let vmo_range = (range.start - map_to_addr)..(range.end - map_to_addr);
self.unmap(range, false)?;
self.unmap(&range, false)?;
self.vmo.decommit(vmo_range)?;
Ok(())
}
@ -267,6 +267,7 @@ impl VmMapping {
let VmMapping { inner, parent, vmo } = self;
let parent_vmo = vmo.dup().unwrap();
let vmo_size = parent_vmo.size();
debug!("fork vmo in forkmapping, parent size = 0x{:x}", vmo_size);
let child_vmo = VmoChildOptions::new_cow(parent_vmo, 0..vmo_size).alloc()?;
let parent_vmar = new_parent.upgrade().unwrap();
let vm_space = parent_vmar.vm_space();
@ -335,6 +336,11 @@ impl VmMapping {
if !is_intersected(&range, &trim_range) {
return Ok(());
}
if trim_range.start == map_to_addr && trim_range.end == map_to_addr + map_size {
// fast path: the whole mapping was trimed
self.unmap(trim_range, true)?;
mappings_to_remove.insert(map_to_addr);
}
let vm_mapping_left = range.start;
let vm_mapping_right = range.end;

View File

@ -465,6 +465,7 @@ fn alloc_child_vmo_(
}
let parent_vmo_size = parent_vmo_.size();
let parent_vmo_inner = parent_vmo_.inner.lock();
match child_type {
ChildType::Slice => {
// A slice child should be inside parent vmo's range
@ -478,8 +479,8 @@ fn alloc_child_vmo_(
}
ChildType::Cow => {
// A copy on Write child should intersect with parent vmo
debug_assert!(range.start < parent_vmo_inner.size);
if range.start >= parent_vmo_inner.size {
debug_assert!(range.start <= parent_vmo_inner.size);
if range.start > parent_vmo_inner.size {
return_errno_with_message!(Errno::EINVAL, "COW vmo should overlap with its parent");
}
}