buggy vmo.create_child, just use create_clone now

This commit is contained in:
PanQL 2020-03-11 01:20:16 +08:00
parent bd0ac9242e
commit 2e1785ad78
10 changed files with 286 additions and 92 deletions

View File

@ -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 {

View File

@ -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"]

View File

@ -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

View File

@ -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));

View File

@ -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)
);
}

View File

@ -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
}
}

View File

@ -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)]

View File

@ -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]);
}
}

View File

@ -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)]

View File

@ -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)
}