forked from rcore-os/zCore
buggy vmo.create_child, just use create_clone now
This commit is contained in:
parent
bd0ac9242e
commit
2e1785ad78
|
@ -132,6 +132,15 @@ pub fn pmem_write(paddr: PhysAddr, buf: &[u8]) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Copy content of `src` frame to `target` frame
|
||||
#[export_name = "hal_frame_copy"]
|
||||
pub fn frame_copy(src: PhysAddr, target: PhysAddr) {
|
||||
unsafe {
|
||||
let buf = phys_to_virt(src) as *const u8;
|
||||
buf.copy_to_nonoverlapping(phys_to_virt(target) as _, 4096);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the HAL.
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
|
|
|
@ -150,6 +150,13 @@ pub fn pmem_write(_paddr: PhysAddr, _buf: &[u8]) {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Copy content of `src` frame to `target` frame
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_frame_copy"]
|
||||
pub fn frame_copy(_src: PhysAddr, _target: PhysAddr) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Output a char to console.
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_serial_write"]
|
||||
|
|
|
@ -152,11 +152,36 @@ pub fn run_userboot(images: &Images<impl AsRef<[u8]>>, cmdline: &str) -> Arc<Pro
|
|||
handles[K_ROOTJOB] = Handle::new(job, Rights::DEFAULT_JOB);
|
||||
handles[K_ROOTRESOURCE] = Handle::new(resource, Rights::DEFAULT_RESOURCE);
|
||||
handles[K_ZBI] = Handle::new(zbi_vmo, Rights::DEFAULT_VMO);
|
||||
handles[K_FIRSTVDSO] = Handle::new(vdso_vmo, Rights::DEFAULT_VMO | Rights::EXECUTE);
|
||||
handles[K_FIRSTVDSO] = Handle::new(vdso_vmo.clone(), Rights::DEFAULT_VMO | Rights::EXECUTE);
|
||||
let vdso_test1 = vdso_vmo.create_clone(0, vdso_vmo.len());
|
||||
vdso_test1.set_name("vdso/test1");
|
||||
let vdso_test2 = vdso_vmo.create_clone(0, vdso_vmo.len());
|
||||
vdso_test2.set_name("vdso/test2");
|
||||
handles[K_FIRSTVDSO + 1] = Handle::new(vdso_test1, Rights::DEFAULT_VMO | Rights::EXECUTE);
|
||||
handles[K_FIRSTVDSO + 2] = Handle::new(vdso_test2, Rights::DEFAULT_VMO | Rights::EXECUTE);
|
||||
// FIXME correct rights for decompressor engine
|
||||
handles[K_USERBOOT_DECOMPRESSOR] =
|
||||
Handle::new(decompressor_vmo, Rights::DEFAULT_VMO | Rights::EXECUTE);
|
||||
// TODO CrashLogVmo handle
|
||||
// TODO to use correct CrashLogVmo handle
|
||||
let crash_log_vmo = VMObjectPaged::new(1);
|
||||
handles[K_CRASHLOG] = Handle::new(crash_log_vmo, Rights::DEFAULT_VMO);
|
||||
// TODO to use correct CounterName handle
|
||||
let counter_name_vmo = VMObjectPaged::new(1);
|
||||
counter_name_vmo.set_name("counters/desc");
|
||||
handles[K_COUNTERNAMES] = Handle::new(counter_name_vmo, Rights::DEFAULT_VMO);
|
||||
// TODO to use correct CounterName handle
|
||||
let kcounters_vmo = VMObjectPaged::new(1);
|
||||
kcounters_vmo.set_name("counters/arena");
|
||||
handles[K_COUNTERS] = Handle::new(kcounters_vmo, Rights::DEFAULT_VMO);
|
||||
// TODO to use correct Instrumentation data handle
|
||||
let instrumentation_data_vmo = VMObjectPaged::new(1);
|
||||
instrumentation_data_vmo.set_name("UNIMPLEMENTED_VMO");
|
||||
handles[K_FISTINSTRUMENTATIONDATA] =
|
||||
Handle::new(instrumentation_data_vmo.clone(), Rights::DEFAULT_VMO);
|
||||
handles[K_FISTINSTRUMENTATIONDATA + 1] =
|
||||
Handle::new(instrumentation_data_vmo.clone(), Rights::DEFAULT_VMO);
|
||||
handles[K_FISTINSTRUMENTATIONDATA + 2] =
|
||||
Handle::new(instrumentation_data_vmo.clone(), Rights::DEFAULT_VMO);
|
||||
|
||||
// check: handle to root proc should be only
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn set() {
|
||||
let timer = Timer::new();
|
||||
let timer = Timer::create(0);
|
||||
timer.set(timer_now() + Duration::from_millis(10), Duration::default());
|
||||
timer.set(timer_now() + Duration::from_millis(20), Duration::default());
|
||||
|
||||
|
@ -95,7 +95,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn cancel() {
|
||||
let timer = Timer::new();
|
||||
let timer = Timer::create(0);
|
||||
timer.set(timer_now() + Duration::from_millis(10), Duration::default());
|
||||
|
||||
std::thread::sleep(Duration::from_millis(5));
|
||||
|
|
|
@ -533,7 +533,12 @@ mod tests {
|
|||
// duplicate handle which does not have `Rights::DUPLICATE` should fail.
|
||||
let handle_value = proc.add_handle(Handle::new(proc.clone(), Rights::empty()));
|
||||
assert_eq!(
|
||||
proc.dup_handle_operating_rights(handle_value, |_| Ok(Rights::SAME_RIGHTS)),
|
||||
proc.dup_handle_operating_rights(handle_value, |handle_rights| {
|
||||
if !handle_rights.contains(Rights::DUPLICATE) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
Ok(handle_rights)
|
||||
}),
|
||||
Err(ZxError::ACCESS_DENIED)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,3 +27,11 @@ pub fn check_aligned(x: usize, align: usize) -> bool {
|
|||
pub fn pages(size: usize) -> usize {
|
||||
(size + PAGE_SIZE - 1) / PAGE_SIZE
|
||||
}
|
||||
|
||||
pub fn roundup_pages(size: usize) -> usize {
|
||||
if page_aligned(size) {
|
||||
size
|
||||
} else {
|
||||
pages(size) * PAGE_SIZE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use {super::*, crate::object::*, kernel_hal::PageTable};
|
||||
use {super::*, crate::object::*, alloc::sync::Arc, kernel_hal::PageTable};
|
||||
|
||||
mod paged;
|
||||
mod physical;
|
||||
|
@ -44,6 +44,11 @@ pub trait VMObject: KernelObject {
|
|||
|
||||
/// Decommit allocated physical memory.
|
||||
fn decommit(&self, offset: usize, len: usize);
|
||||
|
||||
/// Create a child vmo
|
||||
fn create_child(&self, offset: usize, len: usize) -> Arc<dyn VMObject>;
|
||||
|
||||
fn create_clone(&self, offset: usize, len: usize) -> Arc<dyn KernelObject>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -16,6 +16,8 @@ pub struct VMObjectPaged {
|
|||
|
||||
/// The mutable part of `VMObjectPaged`.
|
||||
struct VMObjectPagedInner {
|
||||
parent: Option<Arc<VMObjectPaged>>,
|
||||
parent_offset: usize,
|
||||
frames: Vec<Option<PhysFrame>>,
|
||||
}
|
||||
|
||||
|
@ -29,83 +31,14 @@ impl VMObjectPaged {
|
|||
|
||||
Arc::new(VMObjectPaged {
|
||||
base: KObjectBase::default(),
|
||||
inner: Mutex::new(VMObjectPagedInner { frames }),
|
||||
inner: Mutex::new(VMObjectPagedInner {
|
||||
parent: None,
|
||||
parent_offset: 0usize,
|
||||
frames,
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl VMObject for VMObjectPaged {
|
||||
fn read(&self, offset: usize, buf: &mut [u8]) {
|
||||
self.inner
|
||||
.lock()
|
||||
.for_each_page(offset, buf.len(), |paddr, buf_range| {
|
||||
kernel_hal::pmem_read(paddr, &mut buf[buf_range]);
|
||||
});
|
||||
}
|
||||
|
||||
fn write(&self, offset: usize, buf: &[u8]) {
|
||||
self.inner
|
||||
.lock()
|
||||
.for_each_page(offset, buf.len(), |paddr, buf_range| {
|
||||
kernel_hal::pmem_write(paddr, &buf[buf_range]);
|
||||
});
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.inner.lock().frames.len() * PAGE_SIZE
|
||||
}
|
||||
|
||||
fn set_len(&self, len: usize) {
|
||||
// FIXME parent and children? len < old_len?
|
||||
let old_len = self.inner.lock().frames.len();
|
||||
warn!("old_len: {:#x}, len: {:#x}", old_len, len);
|
||||
if old_len < len {
|
||||
self.inner.lock().frames.resize_with(len, Default::default);
|
||||
self.commit(old_len, len - old_len);
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn map_to(
|
||||
&self,
|
||||
page_table: &mut PageTable,
|
||||
vaddr: usize,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
flags: MMUFlags,
|
||||
) {
|
||||
let start_page = offset / PAGE_SIZE;
|
||||
let pages = len / PAGE_SIZE;
|
||||
let mut inner = self.inner.lock();
|
||||
for i in 0..pages {
|
||||
let frame = inner.commit(start_page + i);
|
||||
page_table
|
||||
.map(vaddr + i * PAGE_SIZE, frame.addr(), flags)
|
||||
.expect("failed to map");
|
||||
}
|
||||
}
|
||||
|
||||
fn commit(&self, offset: usize, len: usize) {
|
||||
let start_page = offset / PAGE_SIZE;
|
||||
let pages = len / PAGE_SIZE;
|
||||
let mut inner = self.inner.lock();
|
||||
for i in 0..pages {
|
||||
inner.commit(start_page + i);
|
||||
}
|
||||
}
|
||||
|
||||
fn decommit(&self, offset: usize, len: usize) {
|
||||
let start_page = offset / PAGE_SIZE;
|
||||
let pages = len / PAGE_SIZE;
|
||||
let mut inner = self.inner.lock();
|
||||
for i in 0..pages {
|
||||
inner.decommit(start_page + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VMObjectPagedInner {
|
||||
/// Helper function to split range into sub-ranges within pages.
|
||||
///
|
||||
/// All covered pages will be committed implicitly.
|
||||
|
@ -129,9 +62,10 @@ impl VMObjectPagedInner {
|
|||
/// * `paddr`: the start physical address of the in-page range.
|
||||
/// * `buf_range`: the range in view of the input buffer.
|
||||
fn for_each_page(
|
||||
&mut self,
|
||||
&self,
|
||||
offset: usize,
|
||||
buf_len: usize,
|
||||
for_write: bool,
|
||||
mut f: impl FnMut(PhysAddr, Range<usize>),
|
||||
) {
|
||||
let iter = BlockIter {
|
||||
|
@ -140,13 +74,155 @@ impl VMObjectPagedInner {
|
|||
block_size_log2: 12,
|
||||
};
|
||||
for block in iter {
|
||||
self.commit(block.block);
|
||||
let paddr = self.frames[block.block].as_ref().unwrap().addr();
|
||||
let paddr = self.inner.lock().get_page(block.block, for_write);
|
||||
let buf_range = block.origin_begin() - offset..block.origin_end() - offset;
|
||||
f(paddr + block.begin, buf_range);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_page(&self, page_idx: usize, for_write: bool) -> PhysAddr {
|
||||
self.inner.lock().get_page(page_idx, for_write)
|
||||
}
|
||||
}
|
||||
|
||||
impl VMObject for VMObjectPaged {
|
||||
fn read(&self, offset: usize, buf: &mut [u8]) {
|
||||
self.for_each_page(offset, buf.len(), false, |paddr, buf_range| {
|
||||
kernel_hal::pmem_read(paddr, &mut buf[buf_range]);
|
||||
});
|
||||
}
|
||||
|
||||
fn write(&self, offset: usize, buf: &[u8]) {
|
||||
self.for_each_page(offset, buf.len(), true, |paddr, buf_range| {
|
||||
kernel_hal::pmem_write(paddr, &buf[buf_range]);
|
||||
});
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.inner.lock().frames.len() * PAGE_SIZE
|
||||
}
|
||||
|
||||
fn set_len(&self, len: usize) {
|
||||
assert!(page_aligned(len));
|
||||
// FIXME parent and children? len < old_len?
|
||||
let mut inner = self.inner.lock();
|
||||
let old_pages = inner.frames.len();
|
||||
let new_pages = len / PAGE_SIZE;
|
||||
warn!("old_pages: {:#x}, new_pages: {:#x}", old_pages, new_pages);
|
||||
if old_pages < new_pages {
|
||||
inner.frames.resize_with(len, Default::default);
|
||||
(old_pages..new_pages).for_each(|idx| {
|
||||
inner.commit(idx);
|
||||
});
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn map_to(
|
||||
&self,
|
||||
page_table: &mut PageTable,
|
||||
vaddr: usize,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
flags: MMUFlags,
|
||||
) {
|
||||
let start_page = offset / PAGE_SIZE;
|
||||
let pages = len / PAGE_SIZE;
|
||||
let mut inner = self.inner.lock();
|
||||
for i in 0..pages {
|
||||
let paddr = inner.get_page(start_page + i, true);
|
||||
page_table
|
||||
.map(vaddr + i * PAGE_SIZE, paddr, flags)
|
||||
.expect("failed to map");
|
||||
}
|
||||
}
|
||||
|
||||
fn commit(&self, offset: usize, len: usize) {
|
||||
let start_page = offset / PAGE_SIZE;
|
||||
let pages = len / PAGE_SIZE;
|
||||
let mut inner = self.inner.lock();
|
||||
warn!("start_page: {:#x}, pages: {:#x}", start_page, pages);
|
||||
for i in 0..pages {
|
||||
inner.commit(start_page + i);
|
||||
}
|
||||
}
|
||||
|
||||
fn decommit(&self, offset: usize, len: usize) {
|
||||
let start_page = offset / PAGE_SIZE;
|
||||
let pages = len / PAGE_SIZE;
|
||||
let mut inner = self.inner.lock();
|
||||
for i in 0..pages {
|
||||
inner.decommit(start_page + i);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_child(&self, offset: usize, len: usize) -> Arc<dyn VMObject> {
|
||||
assert!(page_aligned(offset));
|
||||
assert!(page_aligned(len));
|
||||
let mut frames = Vec::new();
|
||||
let pages = self.len() / PAGE_SIZE;
|
||||
let mut inner = self.inner.lock();
|
||||
frames.append(&mut inner.frames);
|
||||
let old_parent = inner.parent.take();
|
||||
|
||||
// construct hidden_vmo as shared parent
|
||||
let hidden_vmo = Arc::new(VMObjectPaged {
|
||||
base: KObjectBase::default(),
|
||||
inner: Mutex::new(VMObjectPagedInner {
|
||||
parent: old_parent,
|
||||
parent_offset: 0usize,
|
||||
frames,
|
||||
}),
|
||||
});
|
||||
|
||||
// change current vmo's parent
|
||||
inner.parent = Some(hidden_vmo.clone());
|
||||
inner.frames.resize_with(pages, Default::default);
|
||||
|
||||
// create hidden_vmo's another child as result
|
||||
let mut child_frames = Vec::new();
|
||||
child_frames.resize_with(len / PAGE_SIZE, Default::default);
|
||||
Arc::new(VMObjectPaged {
|
||||
base: KObjectBase::default(),
|
||||
inner: Mutex::new(VMObjectPagedInner {
|
||||
parent: Some(hidden_vmo),
|
||||
parent_offset: offset,
|
||||
frames: child_frames,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
fn create_clone(&self, offset: usize, len: usize) -> Arc<dyn KernelObject> {
|
||||
assert!(page_aligned(offset));
|
||||
assert!(page_aligned(len));
|
||||
let frames_offset = pages(offset);
|
||||
let clone_size = pages(len);
|
||||
let mut frames = Vec::new();
|
||||
frames.resize_with(clone_size, || {
|
||||
Some(PhysFrame::alloc().expect("faild to alloc frame"))
|
||||
});
|
||||
let inner = self.inner.lock();
|
||||
for i in 0..clone_size {
|
||||
if inner.frames[frames_offset + i].is_some() {
|
||||
kernel_hal::frame_copy(
|
||||
inner.frames[frames_offset + i].as_ref().unwrap().addr(),
|
||||
frames[i].as_ref().unwrap().addr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Arc::new(VMObjectPaged {
|
||||
base: KObjectBase::default(),
|
||||
inner: Mutex::new(VMObjectPagedInner {
|
||||
parent: None,
|
||||
parent_offset: offset,
|
||||
frames,
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl VMObjectPagedInner {
|
||||
fn commit(&mut self, page_idx: usize) -> &PhysFrame {
|
||||
self.frames[page_idx]
|
||||
.get_or_insert_with(|| PhysFrame::alloc().expect("failed to alloc frame"))
|
||||
|
@ -155,6 +231,42 @@ impl VMObjectPagedInner {
|
|||
fn decommit(&mut self, page_idx: usize) {
|
||||
self.frames[page_idx] = None;
|
||||
}
|
||||
|
||||
fn get_page(&mut self, page_idx: usize, for_write: bool) -> PhysAddr {
|
||||
if self.frames[page_idx].is_some() {
|
||||
self.frames[page_idx].as_ref().unwrap().addr()
|
||||
} else {
|
||||
let parent_idx_offset = self.parent_offset / PAGE_SIZE;
|
||||
//info!(
|
||||
//"page_idx {:#x}, parent_offset {:#x}",
|
||||
//page_idx, parent_idx_offset
|
||||
//);
|
||||
if for_write {
|
||||
let target_addr = self.commit(page_idx).addr();
|
||||
if self.parent.is_some() {
|
||||
// TODO copy a page from parent if need write
|
||||
//warn!("doing copy");
|
||||
kernel_hal::frame_copy(
|
||||
self.parent
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_page(parent_idx_offset + page_idx, false),
|
||||
target_addr,
|
||||
);
|
||||
}
|
||||
target_addr
|
||||
} else {
|
||||
if self.parent.is_some() {
|
||||
self.parent
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_page(parent_idx_offset + page_idx, false)
|
||||
} else {
|
||||
self.commit(page_idx).addr()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -166,4 +278,21 @@ mod tests {
|
|||
let vmo = VMObjectPaged::new(2);
|
||||
super::super::tests::read_write(&*vmo);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_child() {
|
||||
let vmo = VMObjectPaged::new(10);
|
||||
vmo.write(0, &[1, 2, 3, 4]);
|
||||
let mut buf = [0u8; 4];
|
||||
vmo.read(0, &mut buf);
|
||||
assert_eq!(&buf, &[1, 2, 3, 4]);
|
||||
let child_vmo = vmo.create_child(0, 4 * 4096);
|
||||
child_vmo.read(0, &mut buf);
|
||||
assert_eq!(&buf, &[1, 2, 3, 4]);
|
||||
child_vmo.write(0, &[6, 7, 8, 9]);
|
||||
vmo.read(0, &mut buf);
|
||||
assert_eq!(&buf, &[1, 2, 3, 4]);
|
||||
child_vmo.read(0, &mut buf);
|
||||
assert_eq!(&buf, &[6, 7, 8, 9]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,14 @@ impl VMObject for VMObjectPhysical {
|
|||
fn decommit(&self, _offset: usize, _len: usize) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn create_child(&self, _offset: usize, _len: usize) -> Arc<dyn VMObject> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn create_clone(&self, _offset: usize, _len: usize) -> Arc<dyn KernelObject> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -94,8 +94,8 @@ impl Syscall<'_> {
|
|||
&self,
|
||||
handle_value: HandleValue,
|
||||
options: u32,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
mut out: UserOutPtr<HandleValue>,
|
||||
) -> ZxResult<usize> {
|
||||
let options = VmoCloneFlags::from_bits(options).ok_or(ZxError::INVALID_ARGS)?;
|
||||
|
@ -108,16 +108,14 @@ impl Syscall<'_> {
|
|||
}
|
||||
let proc = self.thread.proc();
|
||||
let vmo = proc.get_vmo_with_rights(handle_value, Rights::READ)?;
|
||||
// TODO: optimize
|
||||
let mut buffer = vec![0u8; size as usize];
|
||||
vmo.read(offset as usize, &mut buffer);
|
||||
let child_vmo = VMObjectPaged::new(pages(size as usize));
|
||||
child_vmo.write(0, &buffer);
|
||||
let child_size = roundup_pages(size);
|
||||
info!("size of child vmo: {:#x}", child_size);
|
||||
let child_vmo = vmo.create_clone(offset as usize, child_size);
|
||||
out.write(proc.add_handle(Handle::new(child_vmo, Rights::DEFAULT_VMO)))?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn sys_vmo_set_size(&self, handle_value: HandleValue, size: u64) -> ZxResult<usize> {
|
||||
pub fn sys_vmo_set_size(&self, handle_value: HandleValue, size: usize) -> ZxResult<usize> {
|
||||
let vmo = self
|
||||
.thread
|
||||
.proc()
|
||||
|
@ -128,7 +126,7 @@ impl Syscall<'_> {
|
|||
size,
|
||||
vmo.len()
|
||||
);
|
||||
vmo.set_len(pages(size as usize));
|
||||
vmo.set_len(size);
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue