forked from rcore-os/zCore
Merge branch 'master' into hypervisor
This commit is contained in:
commit
d0b45e7a09
|
@ -89,7 +89,7 @@ jobs:
|
|||
args: --all-features --no-fail-fast --workspace --exclude zircon-loader
|
||||
env:
|
||||
CARGO_INCREMENTAL: '0'
|
||||
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Coverflow-checks=off'
|
||||
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off'
|
||||
- name: Cache grcov
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
|
@ -131,7 +131,9 @@ jobs:
|
|||
toolchain: nightly-2020-06-04
|
||||
components: rust-src
|
||||
- name: Install QEMU
|
||||
run: sudo apt install qemu-system-x86
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install qemu-system-x86
|
||||
- name: Build zCore
|
||||
run: |
|
||||
cd zCore
|
||||
|
|
|
@ -43,7 +43,6 @@ mod context;
|
|||
mod dummy;
|
||||
mod future;
|
||||
pub mod user;
|
||||
pub mod user_io_vec;
|
||||
pub mod vdso;
|
||||
|
||||
pub use self::context::*;
|
||||
|
|
|
@ -2,6 +2,7 @@ use alloc::string::String;
|
|||
use alloc::vec::Vec;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct UserPtr<T, P: Policy> {
|
||||
|
@ -36,6 +37,8 @@ pub enum Error {
|
|||
InvalidUtf8,
|
||||
InvalidPointer,
|
||||
BufferTooSmall,
|
||||
InvalidLength,
|
||||
InvalidVectorAddress,
|
||||
}
|
||||
|
||||
impl<T, P: Policy> Debug for UserPtr<T, P> {
|
||||
|
@ -193,3 +196,121 @@ impl<P: Write> UserPtr<u8, P> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct IoVec<P: Policy> {
|
||||
/// Starting address
|
||||
ptr: UserPtr<u8, P>,
|
||||
/// Number of bytes to transfer
|
||||
len: usize,
|
||||
}
|
||||
|
||||
pub type IoVecIn = IoVec<In>;
|
||||
pub type IoVecOut = IoVec<Out>;
|
||||
|
||||
/// A valid IoVecs request from user
|
||||
#[derive(Debug)]
|
||||
pub struct IoVecs<P: Policy> {
|
||||
vec: Vec<IoVec<P>>,
|
||||
}
|
||||
|
||||
impl<P: Policy> UserInPtr<IoVec<P>> {
|
||||
pub fn read_iovecs(&self, count: usize) -> Result<IoVecs<P>> {
|
||||
if self.ptr.is_null() {
|
||||
return Err(Error::InvalidPointer);
|
||||
}
|
||||
let vec = self.read_array(count)?;
|
||||
// The sum of length should not overflow.
|
||||
let mut total_count = 0usize;
|
||||
for io_vec in vec.iter() {
|
||||
let (result, overflow) = total_count.overflowing_add(io_vec.len());
|
||||
if overflow {
|
||||
return Err(Error::InvalidLength);
|
||||
}
|
||||
total_count = result;
|
||||
}
|
||||
Ok(IoVecs { vec })
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Policy> IoVecs<P> {
|
||||
pub fn total_len(&self) -> usize {
|
||||
self.vec.iter().map(|vec| vec.len).sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Read> IoVecs<P> {
|
||||
pub fn read_to_vec(&self) -> Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
for vec in self.vec.iter() {
|
||||
buf.extend(vec.ptr.read_array(vec.len)?);
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Write> IoVecs<P> {
|
||||
pub fn write_from_buf(&mut self, mut buf: &[u8]) -> Result<usize> {
|
||||
let buf_len = buf.len();
|
||||
for vec in self.vec.iter_mut() {
|
||||
let copy_len = vec.len.min(buf.len());
|
||||
if copy_len == 0 {
|
||||
continue;
|
||||
}
|
||||
vec.ptr.write_array(&buf[..copy_len])?;
|
||||
buf = &buf[copy_len..];
|
||||
}
|
||||
Ok(buf_len - buf.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Policy> Deref for IoVecs<P> {
|
||||
type Target = [IoVec<P>];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.vec.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Write> DerefMut for IoVecs<P> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.vec.as_mut_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Policy> IoVec<P> {
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ptr.is_null()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
pub fn check(&self) -> Result<()> {
|
||||
self.ptr.check()
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> Result<&[u8]> {
|
||||
if self.ptr.is_null() {
|
||||
return Err(Error::InvalidVectorAddress);
|
||||
}
|
||||
let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
|
||||
Ok(slice)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Write> IoVec<P> {
|
||||
pub fn as_mut_slice(&mut self) -> Result<&mut [u8]> {
|
||||
if self.ptr.is_null() {
|
||||
return Err(Error::InvalidVectorAddress);
|
||||
}
|
||||
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
|
||||
Ok(slice)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
use super::user::*;
|
||||
use core::slice;
|
||||
|
||||
type VecResult<T> = core::result::Result<T, VecError>;
|
||||
|
||||
const MAX_LENGTH: usize = 0x1000;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IoVec<T, P: Policy> {
|
||||
ptr: UserPtr<T, P>,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
pub type InIoVec<T> = IoVec<T, In>;
|
||||
pub type OutIoVec<T> = IoVec<T, Out>;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum VecError {
|
||||
PtrErr(Error),
|
||||
LengthErr,
|
||||
}
|
||||
|
||||
impl From<Error> for VecError {
|
||||
fn from(err: Error) -> VecError {
|
||||
VecError::PtrErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P: Policy> IoVec<T, P> {
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ptr.is_null()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
pub fn as_user_ptr(&self) -> UserPtr<T, P> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
|
||||
pub fn check(&self) -> VecResult<()> {
|
||||
self.ptr.check()?;
|
||||
if self.len > MAX_LENGTH {
|
||||
return Err(VecError::LengthErr);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> VecResult<&[T]> {
|
||||
self.check()?;
|
||||
let slice = unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
|
||||
Ok(slice)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P: Write> IoVec<T, P> {
|
||||
pub fn as_mut_slice(&self) -> VecResult<&mut [T]> {
|
||||
self.check()?;
|
||||
let slice = unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
|
||||
Ok(slice)
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&self) -> *mut T {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
}
|
|
@ -166,6 +166,8 @@ impl From<Error> for LxError {
|
|||
Error::InvalidUtf8 => LxError::EINVAL,
|
||||
Error::InvalidPointer => LxError::EFAULT,
|
||||
Error::BufferTooSmall => LxError::ENOBUFS,
|
||||
Error::InvalidLength => LxError::EINVAL,
|
||||
Error::InvalidVectorAddress => LxError::EINVAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,11 +71,11 @@ impl Syscall<'_> {
|
|||
pub fn sys_readv(
|
||||
&self,
|
||||
fd: FileDesc,
|
||||
iov_ptr: UserInPtr<IoVec<Out>>,
|
||||
iov_ptr: UserInPtr<IoVecOut>,
|
||||
iov_count: usize,
|
||||
) -> SysResult {
|
||||
info!("readv: fd={:?}, iov={:?}, count={}", fd, iov_ptr, iov_count);
|
||||
let mut iovs = IoVecs::new(iov_ptr, iov_count)?;
|
||||
let mut iovs = iov_ptr.read_iovecs(iov_count)?;
|
||||
let proc = self.linux_process();
|
||||
let file_like = proc.get_file_like(fd)?;
|
||||
let mut buf = vec![0u8; iovs.total_len()];
|
||||
|
@ -87,14 +87,14 @@ impl Syscall<'_> {
|
|||
pub fn sys_writev(
|
||||
&self,
|
||||
fd: FileDesc,
|
||||
iov_ptr: UserInPtr<IoVec<In>>,
|
||||
iov_ptr: UserInPtr<IoVecIn>,
|
||||
iov_count: usize,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"writev: fd={:?}, iov={:?}, count={}",
|
||||
fd, iov_ptr, iov_count
|
||||
);
|
||||
let iovs = IoVecs::new(iov_ptr, iov_count)?;
|
||||
let iovs = iov_ptr.read_iovecs(iov_count)?;
|
||||
let buf = iovs.read_to_vec()?;
|
||||
let proc = self.linux_process();
|
||||
let file_like = proc.get_file_like(fd)?;
|
||||
|
|
|
@ -11,7 +11,7 @@ extern crate alloc;
|
|||
extern crate log;
|
||||
|
||||
use {
|
||||
self::{consts::SyscallType as Sys, util::*},
|
||||
self::consts::SyscallType as Sys,
|
||||
alloc::sync::Arc,
|
||||
core::convert::TryFrom,
|
||||
kernel_hal::{user::*, GeneralRegs},
|
||||
|
@ -24,7 +24,6 @@ mod file;
|
|||
mod misc;
|
||||
mod task;
|
||||
mod time;
|
||||
mod util;
|
||||
mod vm;
|
||||
|
||||
pub struct Syscall<'a> {
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
use alloc::vec::Vec;
|
||||
use kernel_hal::user::*;
|
||||
use linux_object::error::LxResult;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct IoVec<P: Policy> {
|
||||
/// Starting address
|
||||
base: UserPtr<u8, P>,
|
||||
/// Number of bytes to transfer
|
||||
len: usize,
|
||||
}
|
||||
|
||||
/// A valid IoVecs request from user
|
||||
#[derive(Debug)]
|
||||
pub struct IoVecs<P: Policy> {
|
||||
vec: Vec<IoVec<P>>,
|
||||
}
|
||||
|
||||
impl<P: Policy> IoVecs<P> {
|
||||
pub fn new(ptr: UserInPtr<IoVec<P>>, count: usize) -> LxResult<Self> {
|
||||
Ok(IoVecs {
|
||||
vec: ptr.read_array(count)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn total_len(&self) -> usize {
|
||||
self.vec.iter().map(|vec| vec.len).sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Read> IoVecs<P> {
|
||||
pub fn read_to_vec(&self) -> LxResult<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
for vec in self.vec.iter() {
|
||||
buf.extend(vec.base.read_array(vec.len)?);
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Write> IoVecs<P> {
|
||||
pub fn write_from_buf(&mut self, mut buf: &[u8]) -> LxResult<usize> {
|
||||
let buf_len = buf.len();
|
||||
for vec in self.vec.iter_mut() {
|
||||
let copy_len = vec.len.min(buf.len());
|
||||
if copy_len == 0 {
|
||||
continue;
|
||||
}
|
||||
vec.base.write_array(&buf[..copy_len])?;
|
||||
buf = &buf[copy_len..];
|
||||
}
|
||||
Ok(buf_len - buf.len())
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import pexpect
|
||||
import sys
|
||||
import re
|
||||
|
||||
TIMEOUT = 300
|
||||
ZCORE_PATH = '../zCore'
|
||||
|
@ -31,7 +32,7 @@ with open(TEST_CASE_FILE, "r") as f:
|
|||
lines = f.readlines()
|
||||
positive = [line for line in lines if not line.startswith('-')]
|
||||
negative = [line[1:] for line in lines if line.startswith('-')]
|
||||
test_filter = (','.join(positive) + '-' + ','.join(negative)).replace('\n', '')
|
||||
test_filter = (','.join(positive) + (('-' + ','.join(negative) if len(negative) > 0 else "") )).replace('\n', '')
|
||||
|
||||
child = pexpect.spawn("make -C %s test mode=release test_filter='%s'" % (ZCORE_PATH, test_filter),
|
||||
timeout=TIMEOUT, encoding='utf-8')
|
||||
|
@ -44,8 +45,13 @@ print(result)
|
|||
passed = []
|
||||
failed = []
|
||||
passed_case = set()
|
||||
|
||||
# see https://stackoverflow.com/questions/59379174/ignore-ansi-colors-in-pexpect-response
|
||||
ansi_escape = re.compile(r"\x1B[@-_][0-?]*[ -/]*[@-~]")
|
||||
|
||||
with open(OUTPUT_FILE, "r") as f:
|
||||
for line in f.readlines():
|
||||
line=ansi_escape.sub('',line)
|
||||
if line.startswith('[ OK ]'):
|
||||
passed += line
|
||||
passed_case.add(line[13:].split(' ')[0])
|
||||
|
|
|
@ -342,6 +342,7 @@ Threads.Detach
|
|||
Threads.EmptyNameSucceeds
|
||||
Threads.LongNameSucceeds
|
||||
Threads.ThreadStartOnInitialThread
|
||||
Threads.ThreadStartWithZeroInstructionPointer
|
||||
Threads.NonstartedThread
|
||||
Threads.InfoTaskStatsFails
|
||||
Threads.ResumeSuspended
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
-Pthread.*
|
||||
-PThreadBarrierTest.SingleThreadWinsBarrierObjectResetsBetweenIterations
|
||||
-SyncMutex.NoRecursion
|
||||
-Threads.ThreadStartWithZeroInstructionPointer
|
||||
-Threads.SuspendMultiple
|
||||
-Threads.Reading*State
|
||||
-Threads.WriteReadDebugRegisterState
|
||||
|
|
|
@ -244,17 +244,31 @@ fn spawn(thread: Arc<Thread>) {
|
|||
e
|
||||
);
|
||||
error!("Page Fault from user mode {:#x?}", cx);
|
||||
//TODO: implement exception channel
|
||||
if !thread.handle_exception().await {
|
||||
let exception = Exception::create(
|
||||
thread.clone(),
|
||||
ExceptionType::FatalPageFault,
|
||||
Some(&cx),
|
||||
);
|
||||
if !exception.handle().await {
|
||||
exit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!("not supported interrupt from user mode. {:#x?}", cx);
|
||||
//TODO: implement exception channel
|
||||
if !thread.handle_exception().await {
|
||||
0x8 => {
|
||||
panic!("Double fault from user mode! {:#x?}", cx);
|
||||
}
|
||||
num => {
|
||||
let type_ = match num {
|
||||
0x1 => ExceptionType::HardwareBreakpoint,
|
||||
0x3 => ExceptionType::SoftwareBreakpoint,
|
||||
0x6 => ExceptionType::UndefinedInstruction,
|
||||
0x17 => ExceptionType::UnalignedAccess,
|
||||
_ => ExceptionType::General,
|
||||
};
|
||||
error!("User mode exception:{:?} {:#x?}", type_, cx);
|
||||
let exception = Exception::create(thread.clone(), type_, Some(&cx));
|
||||
if !exception.handle().await {
|
||||
exit = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,17 +235,8 @@ impl From<Error> for ZxError {
|
|||
Error::InvalidUtf8 => ZxError::INVALID_ARGS,
|
||||
Error::InvalidPointer => ZxError::INVALID_ARGS,
|
||||
Error::BufferTooSmall => ZxError::BUFFER_TOO_SMALL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use kernel_hal::user_io_vec::VecError;
|
||||
|
||||
impl From<VecError> for ZxError {
|
||||
fn from(e: VecError) -> Self {
|
||||
match e {
|
||||
VecError::PtrErr(err) => ZxError::from(err),
|
||||
VecError::LengthErr => ZxError::INVALID_ARGS,
|
||||
Error::InvalidLength => ZxError::INVALID_ARGS,
|
||||
Error::InvalidVectorAddress => ZxError::NOT_FOUND,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,19 @@ pub const INVALID_HANDLE: HandleValue = 0;
|
|||
/// A Handle is how a specific process refers to a specific kernel object.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Handle {
|
||||
/// The object referred to by the handle.
|
||||
pub object: Arc<dyn KernelObject>,
|
||||
/// The handle's associated rights.
|
||||
pub rights: Rights,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
/// Create a new handle referring to the given object with given rights.
|
||||
pub fn new(object: Arc<dyn KernelObject>, rights: Rights) -> Self {
|
||||
Handle { object, rights }
|
||||
}
|
||||
|
||||
/// Get information about the provided handle and the object the handle refers to.
|
||||
pub fn get_info(&self) -> HandleBasicInfo {
|
||||
HandleBasicInfo {
|
||||
koid: self.object.id(),
|
||||
|
@ -33,6 +37,9 @@ impl Handle {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get information about the handle itself.
|
||||
///
|
||||
/// The returned `HandleInfo`'s `handle` field should set manually.
|
||||
pub fn get_handle_info(&self) -> HandleInfo {
|
||||
HandleInfo {
|
||||
obj_type: obj_type(&self.object),
|
||||
|
@ -42,6 +49,7 @@ impl Handle {
|
|||
}
|
||||
}
|
||||
|
||||
/// Information about a handle and the object it refers to.
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct HandleBasicInfo {
|
||||
|
@ -53,6 +61,7 @@ pub struct HandleBasicInfo {
|
|||
padding: u32,
|
||||
}
|
||||
|
||||
/// Get an object's type.
|
||||
pub fn obj_type(object: &Arc<dyn KernelObject>) -> u32 {
|
||||
match object.type_name() {
|
||||
"Process" => 1,
|
||||
|
@ -79,7 +88,7 @@ pub fn obj_type(object: &Arc<dyn KernelObject>) -> u32 {
|
|||
"Pmt" => 26,
|
||||
"SuspendToken" => 27,
|
||||
"Pager" => 28,
|
||||
"Exception" => 29,
|
||||
"Exception" | "ExceptionObject" => 29,
|
||||
"Clock" => 30,
|
||||
"Stream" => 31,
|
||||
"PcieDeviceKObject" => 32,
|
||||
|
@ -87,9 +96,11 @@ pub fn obj_type(object: &Arc<dyn KernelObject>) -> u32 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Information about a handle itself, including its `HandleValue`.
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct HandleInfo {
|
||||
/// The handle's value in user space.
|
||||
pub handle: HandleValue,
|
||||
obj_type: u32,
|
||||
rights: u32,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![deny(missing_docs)]
|
||||
//! Kernel object basis.
|
||||
//!
|
||||
//! # Create new kernel object
|
||||
|
@ -120,23 +121,51 @@ mod signal;
|
|||
///
|
||||
/// [`impl_kobject`]: impl_kobject
|
||||
pub trait KernelObject: DowncastSync + Debug {
|
||||
/// Get object's KoID.
|
||||
fn id(&self) -> KoID;
|
||||
/// Get the name of the type of the kernel object.
|
||||
fn type_name(&self) -> &str;
|
||||
/// Get object's name.
|
||||
fn name(&self) -> alloc::string::String;
|
||||
/// Set object's name.
|
||||
fn set_name(&self, name: &str);
|
||||
/// Get the signal status.
|
||||
fn signal(&self) -> Signal;
|
||||
/// Assert `signal`.
|
||||
fn signal_set(&self, signal: Signal);
|
||||
/// Change signal status: first `clear` then `set` indicated bits.
|
||||
///
|
||||
/// All signal callbacks will be called.
|
||||
fn signal_change(&self, clear: Signal, set: Signal);
|
||||
/// Add `callback` for signal status changes.
|
||||
///
|
||||
/// The `callback` is a function of `Fn(Signal) -> bool`.
|
||||
/// It returns a bool indicating whether the handle process is over.
|
||||
/// If true, the function will never be called again.
|
||||
fn add_signal_callback(&self, callback: SignalHandler);
|
||||
/// Attempt to find a child of the object with given KoID.
|
||||
///
|
||||
/// If the object is a *Process*, the *Threads* it contains may be obtained.
|
||||
///
|
||||
/// If the object is a *Job*, its (immediate) child *Jobs* and the *Processes*
|
||||
/// it contains may be obtained.
|
||||
///
|
||||
/// If the object is a *Resource*, its (immediate) child *Resources* may be obtained.
|
||||
fn get_child(&self, _id: KoID) -> ZxResult<Arc<dyn KernelObject>> {
|
||||
Err(ZxError::WRONG_TYPE)
|
||||
}
|
||||
/// Attempt to get the object's peer.
|
||||
///
|
||||
/// An object peer is the opposite endpoint of a `Channel`, `Socket`, `Fifo`, or `EventPair`.
|
||||
fn peer(&self) -> ZxResult<Arc<dyn KernelObject>> {
|
||||
Err(ZxError::NOT_SUPPORTED)
|
||||
}
|
||||
/// If the object is related to another (such as the other end of a channel, or the parent of
|
||||
/// a job), returns the KoID of that object, otherwise returns zero.
|
||||
fn related_koid(&self) -> KoID {
|
||||
0
|
||||
}
|
||||
/// Get object's allowed signals.
|
||||
fn allowed_signals(&self) -> Signal {
|
||||
Signal::USER_ALL
|
||||
}
|
||||
|
@ -146,6 +175,7 @@ impl_downcast!(sync KernelObject);
|
|||
|
||||
/// The base struct of a kernel object.
|
||||
pub struct KObjectBase {
|
||||
/// The object's KoID.
|
||||
pub id: KoID,
|
||||
inner: Mutex<KObjectBaseInner>,
|
||||
}
|
||||
|
@ -485,6 +515,7 @@ pub struct DummyObject {
|
|||
impl_kobject!(DummyObject);
|
||||
|
||||
impl DummyObject {
|
||||
/// Create a new `DummyObject`.
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(DummyObject {
|
||||
base: KObjectBase::new(),
|
||||
|
|
|
@ -69,37 +69,94 @@ bitflags! {
|
|||
/// Allows suspending/resuming threads, etc.
|
||||
const MANAGE_THREAD = 1 << 18;
|
||||
|
||||
/// Not used.
|
||||
const APPLY_PROFILE = 1 << 19;
|
||||
|
||||
/// Used to duplicate a handle with the same rights.
|
||||
const SAME_RIGHTS = 1 << 31;
|
||||
|
||||
|
||||
/// TRANSFER | DUPLICATE | WAIT | INSPECT
|
||||
const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits;
|
||||
|
||||
/// READ | WRITE
|
||||
const IO = Self::READ.bits | Self::WRITE.bits;
|
||||
|
||||
/// GET_PROPERTY | SET_PROPERTY
|
||||
const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits;
|
||||
|
||||
/// GET_POLICY | SET_POLICY
|
||||
const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits;
|
||||
|
||||
/// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER
|
||||
const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits;
|
||||
|
||||
/// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD
|
||||
const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits
|
||||
| Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits;
|
||||
|
||||
/// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD
|
||||
const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits;
|
||||
|
||||
/// BASIC | IO | PROPERTY | MAP | SIGNAL
|
||||
const DEFAULT_VMO = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::MAP.bits | Self::SIGNAL.bits;
|
||||
|
||||
/// BASIC | WAIT
|
||||
const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits;
|
||||
|
||||
/// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD
|
||||
const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits
|
||||
| Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits;
|
||||
|
||||
/// TRANSFER | DUPLICATE | WRITE | INSPECT
|
||||
const DEFAULT_RESOURCE = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WRITE.bits | Self::INSPECT.bits;
|
||||
|
||||
/// BASIC | WRITE | SIGNAL
|
||||
const DEFAULT_DEBUGLOG = Self::BASIC.bits | Self::WRITE.bits | Self::SIGNAL.bits;
|
||||
|
||||
/// TRANSFER | INSPECT
|
||||
const DEFAULT_SUSPEND_TOKEN = Self::TRANSFER.bits | Self::INSPECT.bits;
|
||||
|
||||
/// (BASIC & !WAIT) | IO
|
||||
const DEFAULT_PORT = (Self::BASIC.bits & !Self::WAIT.bits) | Self::IO.bits;
|
||||
|
||||
/// BASIC | WRITE | SIGNAL
|
||||
const DEFAULT_TIMER = Self::BASIC.bits | Self::WRITE.bits | Self::SIGNAL.bits;
|
||||
|
||||
/// BASIC | SIGNAL
|
||||
const DEFAULT_EVENT = Self::BASIC.bits | Self::SIGNAL.bits;
|
||||
|
||||
/// BASIC | SIGNAL | SIGNAL_PEER
|
||||
const DEFAULT_EVENTPAIR = Self::BASIC.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits;
|
||||
|
||||
/// BASIC | IO | SIGNAL | SIGNAL_PEER
|
||||
const DEFAULT_FIFO = Self::BASIC.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits;
|
||||
|
||||
/// BASIC | IO | PROPERTY | SIGNAL | SIGNAL_PEER
|
||||
const DEFAULT_SOCKET = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits;
|
||||
|
||||
/// BASIC | PROPERTY | SIGNAL
|
||||
const DEFAULT_STREAM = Self::BASIC.bits | Self::PROPERTY.bits | Self::SIGNAL.bits;
|
||||
|
||||
/// (BASIC & !WAIT) | IO | MAP
|
||||
const DEFAULT_BTI = (Self::BASIC.bits & !Self::WAIT.bits) | Self::IO.bits | Self::MAP.bits;
|
||||
|
||||
/// BASIC | IO | SIGNAL
|
||||
const DEFAULT_INTERRUPT = Self::BASIC.bits | Self::IO.bits | Self::SIGNAL.bits;
|
||||
|
||||
/// BASIC | IO
|
||||
const DEFAULT_DEVICE = Self::BASIC.bits | Self::IO.bits;
|
||||
|
||||
/// BASIC | IO | SIGNAL
|
||||
const DEFAULT_PCI_INTERRUPT = Self::BASIC.bits | Self::IO.bits | Self::SIGNAL.bits;
|
||||
|
||||
/// TRANSFER | PROPERTY | INSPECT
|
||||
const DEFAULT_EXCEPTION = Self::TRANSFER.bits | Self::PROPERTY.bits | Self::INSPECT.bits;
|
||||
|
||||
/// TRANSFER | DUPLICATE | WRITE | INSPECT | MANAGE_PROCESS
|
||||
const DEFAULT_GUEST = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WRITE.bits | Self::INSPECT.bits | Self::MANAGE_PROCESS.bits;
|
||||
|
||||
/// BASIC | IO | EXECUTE | SIGNAL
|
||||
const DEFAULT_VCPU = Self::BASIC.bits | Self::IO.bits | Self::EXECUTE.bits | Self::SIGNAL.bits;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
use {super::*, bitflags::bitflags};
|
||||
|
||||
bitflags! {
|
||||
|
@ -58,6 +59,7 @@ bitflags! {
|
|||
}
|
||||
|
||||
impl Signal {
|
||||
/// Verify whether `number` only sets the bits specified in `allowed_signals`.
|
||||
pub fn verify_user_signal(allowed_signals: Signal, number: u32) -> ZxResult<Signal> {
|
||||
if (number & !allowed_signals.bits()) != 0 {
|
||||
Err(ZxError::INVALID_ARGS)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use {
|
||||
super::*, crate::ipc::Channel, crate::object::*, alloc::sync::Arc, alloc::vec::Vec,
|
||||
core::mem::size_of, spin::Mutex,
|
||||
super::*, crate::ipc::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec,
|
||||
core::mem::size_of, core::time::Duration, futures::channel::oneshot, futures::pin_mut,
|
||||
kernel_hal::UserContext, spin::Mutex,
|
||||
};
|
||||
|
||||
/// Kernel-owned exception channel endpoint.
|
||||
|
@ -29,14 +30,43 @@ impl Exceptionate {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn set_channel(&self, channel: Arc<Channel>) {
|
||||
pub fn create_channel(&self) -> ZxResult<Arc<Channel>> {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.channel.replace(channel);
|
||||
if let Some(channel) = inner.channel.as_ref() {
|
||||
if channel.peer().is_ok() {
|
||||
// already has a valid channel
|
||||
return Err(ZxError::ALREADY_BOUND);
|
||||
}
|
||||
}
|
||||
let (sender, receiver) = Channel::create();
|
||||
inner.channel.replace(sender);
|
||||
Ok(receiver)
|
||||
}
|
||||
|
||||
pub fn get_channel(&self) -> Option<Arc<Channel>> {
|
||||
let inner = self.inner.lock();
|
||||
inner.channel.clone()
|
||||
fn send_exception(&self, exception: &Arc<Exception>) -> ZxResult<oneshot::Receiver<()>> {
|
||||
let mut inner = self.inner.lock();
|
||||
let channel = inner.channel.as_ref().ok_or(ZxError::NEXT)?;
|
||||
let info = ExceptionInfo {
|
||||
tid: exception.thread.id(),
|
||||
pid: exception.thread.proc().id(),
|
||||
type_: exception.type_,
|
||||
padding: Default::default(),
|
||||
};
|
||||
let (sender, receiver) = oneshot::channel::<()>();
|
||||
let object = ExceptionObject::create(exception.clone(), sender);
|
||||
let handle = Handle::new(object, Rights::DEFAULT_EXCEPTION);
|
||||
let msg = MessagePacket {
|
||||
data: info.pack(),
|
||||
handles: vec![handle],
|
||||
};
|
||||
channel.write(msg).map_err(|err| {
|
||||
if err == ZxError::PEER_CLOSED {
|
||||
inner.channel.take();
|
||||
return ZxError::NEXT;
|
||||
}
|
||||
err
|
||||
})?;
|
||||
Ok(receiver)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,20 +74,10 @@ impl Exceptionate {
|
|||
pub struct ExceptionInfo {
|
||||
pub tid: KoID,
|
||||
pub pid: KoID,
|
||||
pub type_: ExceptionChannelType,
|
||||
pub type_: ExceptionType,
|
||||
pub padding: u32,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum ExceptionChannelType {
|
||||
None = 0,
|
||||
Debugger = 1,
|
||||
Thread = 2,
|
||||
Process = 3,
|
||||
Job = 4,
|
||||
JobDebugger = 5,
|
||||
}
|
||||
|
||||
impl ExceptionInfo {
|
||||
#[allow(unsafe_code)]
|
||||
pub fn pack(&self) -> Vec<u8> {
|
||||
|
@ -65,3 +85,316 @@ impl ExceptionInfo {
|
|||
Vec::from(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct ExceptionHeader {
|
||||
pub size: u32,
|
||||
pub type_: ExceptionType,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ExceptionContext {
|
||||
pub vector: u64,
|
||||
pub err_code: u64,
|
||||
pub cr2: u64,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ExceptionContext {
|
||||
pub esr: u32,
|
||||
pub padding1: u32,
|
||||
pub far: u64,
|
||||
pub padding2: u64,
|
||||
}
|
||||
|
||||
impl ExceptionContext {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn from_user_context(cx: &UserContext) -> Self {
|
||||
ExceptionContext {
|
||||
vector: cx.trap_num as u64,
|
||||
err_code: cx.error_code as u64,
|
||||
cr2: kernel_hal::fetch_fault_vaddr() as u64,
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn from_user_context(_cx: &UserContext) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct ExceptionReport {
|
||||
pub header: ExceptionHeader,
|
||||
pub context: ExceptionContext,
|
||||
}
|
||||
|
||||
impl ExceptionReport {
|
||||
fn new(type_: ExceptionType, cx: Option<&UserContext>) -> Self {
|
||||
ExceptionReport {
|
||||
header: ExceptionHeader {
|
||||
type_,
|
||||
size: core::mem::size_of::<ExceptionReport>() as u32,
|
||||
},
|
||||
context: cx
|
||||
.map(ExceptionContext::from_user_context)
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ExceptionType {
|
||||
General = 0x008,
|
||||
FatalPageFault = 0x108,
|
||||
UndefinedInstruction = 0x208,
|
||||
SoftwareBreakpoint = 0x308,
|
||||
HardwareBreakpoint = 0x408,
|
||||
UnalignedAccess = 0x508,
|
||||
// exceptions generated by kernel instead of the hardware
|
||||
Synth = 0x8000,
|
||||
ThreadStarting = 0x8008,
|
||||
ThreadExiting = 0x8108,
|
||||
PolicyError = 0x8208,
|
||||
ProcessStarting = 0x8308,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ExceptionChannelType {
|
||||
None = 0,
|
||||
Debugger = 1,
|
||||
Thread = 2,
|
||||
Process = 3,
|
||||
Job = 4,
|
||||
JobDebugger = 5,
|
||||
}
|
||||
|
||||
/// This will be transmitted to registered exception handlers in userspace
|
||||
/// and provides them with exception state and control functionality.
|
||||
/// We do not send exception directly since it's hard to figure out
|
||||
/// when will the handle close.
|
||||
pub struct ExceptionObject {
|
||||
base: KObjectBase,
|
||||
exception: Arc<Exception>,
|
||||
close_signal: Option<oneshot::Sender<()>>,
|
||||
}
|
||||
|
||||
impl_kobject!(ExceptionObject);
|
||||
|
||||
impl ExceptionObject {
|
||||
fn create(exception: Arc<Exception>, close_signal: oneshot::Sender<()>) -> Arc<Self> {
|
||||
Arc::new(ExceptionObject {
|
||||
base: KObjectBase::new(),
|
||||
exception,
|
||||
close_signal: Some(close_signal),
|
||||
})
|
||||
}
|
||||
pub fn get_exception(&self) -> &Arc<Exception> {
|
||||
&self.exception
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ExceptionObject {
|
||||
fn drop(&mut self) {
|
||||
self.close_signal
|
||||
.take()
|
||||
.and_then(|signal| signal.send(()).ok());
|
||||
}
|
||||
}
|
||||
|
||||
/// An Exception represents a single currently-active exception.
|
||||
pub struct Exception {
|
||||
thread: Arc<Thread>,
|
||||
type_: ExceptionType,
|
||||
report: ExceptionReport,
|
||||
inner: Mutex<ExceptionInner>,
|
||||
}
|
||||
|
||||
struct ExceptionInner {
|
||||
current_channel_type: ExceptionChannelType,
|
||||
// Task rights copied from Exceptionate
|
||||
thread_rights: Rights,
|
||||
process_rights: Rights,
|
||||
handled: bool,
|
||||
second_chance: bool,
|
||||
}
|
||||
|
||||
impl Exception {
|
||||
pub fn create(
|
||||
thread: Arc<Thread>,
|
||||
type_: ExceptionType,
|
||||
cx: Option<&UserContext>,
|
||||
) -> Arc<Self> {
|
||||
Arc::new(Exception {
|
||||
thread,
|
||||
type_,
|
||||
report: ExceptionReport::new(type_, cx),
|
||||
inner: Mutex::new(ExceptionInner {
|
||||
current_channel_type: ExceptionChannelType::None,
|
||||
thread_rights: Rights::DEFAULT_THREAD,
|
||||
process_rights: Rights::DEFAULT_PROCESS,
|
||||
handled: false,
|
||||
second_chance: false,
|
||||
}),
|
||||
})
|
||||
}
|
||||
/// Handle the exception. The return value indicate if the thread is exited after this.
|
||||
/// Note that it's possible that this may returns before exception was send to any exception channel
|
||||
/// This happens only when the thread is killed before we send the exception
|
||||
pub async fn handle(self: &Arc<Self>) -> bool {
|
||||
self.thread.set_exception(Some(self.clone()));
|
||||
let future = self.handle_internal();
|
||||
pin_mut!(future);
|
||||
let result: ZxResult = self
|
||||
.thread
|
||||
.blocking_run(
|
||||
future,
|
||||
ThreadState::BlockedException,
|
||||
Duration::from_nanos(u64::max_value()),
|
||||
)
|
||||
.await;
|
||||
self.thread.set_exception(None);
|
||||
if let Err(err) = result {
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if err == ZxError::STOP {
|
||||
// We are killed
|
||||
self.thread.exit();
|
||||
return false;
|
||||
} else if err == ZxError::NEXT {
|
||||
// Nobody handled the exception, kill myself
|
||||
self.thread.exit();
|
||||
// TODO: In zircon the process is also killed, but for now don't do it
|
||||
// since this may break the core-test
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.thread.exit();
|
||||
false
|
||||
}
|
||||
async fn handle_internal(self: &Arc<Self>) -> ZxResult {
|
||||
for exceptionate in ExceptionateIterator::new(self) {
|
||||
let closed = match exceptionate.send_exception(self) {
|
||||
Ok(receiver) => receiver,
|
||||
// This channel is not available now!
|
||||
Err(ZxError::NEXT) => continue,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
self.inner.lock().current_channel_type = exceptionate.type_;
|
||||
// If this error, the sender is dropped, and the handle should also be closed.
|
||||
closed.await.ok();
|
||||
let handled = {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.current_channel_type = ExceptionChannelType::None;
|
||||
inner.handled
|
||||
};
|
||||
if handled {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(ZxError::NEXT)
|
||||
}
|
||||
|
||||
pub fn get_thread_and_rights(&self) -> (Arc<Thread>, Rights) {
|
||||
(self.thread.clone(), self.inner.lock().thread_rights)
|
||||
}
|
||||
|
||||
pub fn get_process_and_rights(&self) -> (Arc<Process>, Rights) {
|
||||
(self.thread.proc().clone(), self.inner.lock().process_rights)
|
||||
}
|
||||
|
||||
pub fn get_current_channel_type(&self) -> ExceptionChannelType {
|
||||
self.inner.lock().current_channel_type
|
||||
}
|
||||
|
||||
pub fn get_report(&self) -> ExceptionReport {
|
||||
self.report.clone()
|
||||
}
|
||||
|
||||
pub fn get_state(&self) -> u32 {
|
||||
self.inner.lock().handled as u32
|
||||
}
|
||||
|
||||
pub fn set_state(&self, state: u32) {
|
||||
self.inner.lock().handled = state == 1;
|
||||
}
|
||||
|
||||
pub fn get_strategy(&self) -> u32 {
|
||||
self.inner.lock().second_chance as u32
|
||||
}
|
||||
|
||||
pub fn set_strategy(&self, strategy: u32) -> ZxResult {
|
||||
let mut inner = self.inner.lock();
|
||||
match inner.current_channel_type {
|
||||
ExceptionChannelType::Debugger | ExceptionChannelType::JobDebugger => {
|
||||
inner.second_chance = strategy == 1;
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(ZxError::BAD_STATE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator used to find Exceptionates used while handling the exception
|
||||
/// We can use rust generator instead here but that is somehow not stable
|
||||
/// Exception handlers are tried in the following order:
|
||||
/// - debugger (first process, then job, then its parent job, and so on)
|
||||
/// - thread
|
||||
/// - process
|
||||
/// - debugger (in dealing with a second-chance exception)
|
||||
/// - job (first owning job, then its parent job, and so on up to root job)
|
||||
struct ExceptionateIterator<'a> {
|
||||
exception: &'a Exception,
|
||||
state: ExceptionateIteratorState,
|
||||
}
|
||||
|
||||
/// The state used in ExceptionateIterator.
|
||||
/// Name of optional is what to consider next
|
||||
enum ExceptionateIteratorState {
|
||||
Thread,
|
||||
Process,
|
||||
Job(Arc<Job>),
|
||||
Finished,
|
||||
}
|
||||
|
||||
impl<'a> ExceptionateIterator<'a> {
|
||||
fn new(exception: &'a Exception) -> Self {
|
||||
ExceptionateIterator {
|
||||
exception,
|
||||
state: ExceptionateIteratorState::Thread,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ExceptionateIterator<'a> {
|
||||
type Item = Arc<Exceptionate>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match &self.state {
|
||||
ExceptionateIteratorState::Thread => {
|
||||
self.state = ExceptionateIteratorState::Process;
|
||||
Some(self.exception.thread.get_exceptionate())
|
||||
}
|
||||
ExceptionateIteratorState::Process => {
|
||||
let proc = self.exception.thread.proc();
|
||||
self.state = ExceptionateIteratorState::Job(proc.job());
|
||||
Some(proc.get_exceptionate())
|
||||
}
|
||||
ExceptionateIteratorState::Job(job) => {
|
||||
let parent = job.parent();
|
||||
let result = job.get_exceptionate();
|
||||
self.state = parent.map_or(
|
||||
ExceptionateIteratorState::Finished,
|
||||
ExceptionateIteratorState::Job,
|
||||
);
|
||||
Some(result)
|
||||
}
|
||||
ExceptionateIteratorState::Finished => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,6 +171,10 @@ impl Job {
|
|||
self.exceptionate.clone()
|
||||
}
|
||||
|
||||
pub fn get_debug_exceptionate(&self) -> Arc<Exceptionate> {
|
||||
self.debug_exceptionate.clone()
|
||||
}
|
||||
|
||||
/// Get KoIDs of Processes.
|
||||
pub fn process_ids(&self) -> Vec<KoID> {
|
||||
self.inner.lock().processes.iter().map(|p| p.id()).collect()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Objects for Task Management.
|
||||
|
||||
use {super::*, crate::ipc::Channel, crate::signal::Port};
|
||||
use super::*;
|
||||
|
||||
mod exception;
|
||||
mod job;
|
||||
|
@ -10,7 +10,8 @@ mod suspend_token;
|
|||
mod thread;
|
||||
|
||||
pub use {
|
||||
self::job::*, self::job_policy::*, self::process::*, self::suspend_token::*, self::thread::*,
|
||||
self::exception::*, self::job::*, self::job_policy::*, self::process::*,
|
||||
self::suspend_token::*, self::thread::*,
|
||||
};
|
||||
|
||||
/// Task (Thread, Process, or Job)
|
||||
|
@ -23,12 +24,6 @@ pub trait Task: Sync + Send {
|
|||
|
||||
/// Resume the task
|
||||
fn resume(&self);
|
||||
|
||||
/// Create an exception channel on the task.
|
||||
fn create_exception_channel(&mut self, options: u32) -> ZxResult<Channel>;
|
||||
|
||||
/// Resume the task from a previously caught exception.
|
||||
fn resume_from_exception(&mut self, port: &Port, options: u32) -> ZxResult;
|
||||
}
|
||||
|
||||
pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1024;
|
||||
|
|
|
@ -56,6 +56,7 @@ pub struct Process {
|
|||
vmar: Arc<VmAddressRegion>,
|
||||
ext: Box<dyn Any + Send + Sync>,
|
||||
exceptionate: Arc<Exceptionate>,
|
||||
debug_exceptionate: Arc<Exceptionate>,
|
||||
inner: Mutex<ProcessInner>,
|
||||
}
|
||||
|
||||
|
@ -119,6 +120,7 @@ impl Process {
|
|||
vmar: VmAddressRegion::new_root(),
|
||||
ext: Box::new(ext),
|
||||
exceptionate: Exceptionate::new(ExceptionChannelType::Process),
|
||||
debug_exceptionate: Exceptionate::new(ExceptionChannelType::Debugger),
|
||||
inner: Mutex::new(ProcessInner::default()),
|
||||
});
|
||||
job.add_process(proc.clone())?;
|
||||
|
@ -465,6 +467,10 @@ impl Process {
|
|||
self.exceptionate.clone()
|
||||
}
|
||||
|
||||
pub fn get_debug_exceptionate(&self) -> Arc<Exceptionate> {
|
||||
self.debug_exceptionate.clone()
|
||||
}
|
||||
|
||||
/// Get KoIDs of Threads.
|
||||
pub fn thread_ids(&self) -> Vec<KoID> {
|
||||
self.inner.lock().threads.iter().map(|t| t.id()).collect()
|
||||
|
@ -490,14 +496,6 @@ impl Task for Process {
|
|||
thread.resume();
|
||||
}
|
||||
}
|
||||
|
||||
fn create_exception_channel(&mut self, _options: u32) -> ZxResult<Channel> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn resume_from_exception(&mut self, _port: &Port, _options: u32) -> ZxResult {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessInner {
|
||||
|
|
|
@ -119,6 +119,8 @@ struct ThreadInner {
|
|||
/// NOTE: This variable will never be `Suspended`. On suspended, the
|
||||
/// `suspend_count` is non-zero, and this represents the state before suspended.
|
||||
state: ThreadState,
|
||||
/// The currently processing exception
|
||||
exception: Option<Arc<Exception>>,
|
||||
/// The time this thread has run on cpu
|
||||
time: u128,
|
||||
flags: ThreadFlag,
|
||||
|
@ -293,11 +295,26 @@ impl Thread {
|
|||
let inner = self.inner.lock();
|
||||
ThreadInfo {
|
||||
state: inner.get_state() as u32,
|
||||
wait_exception_type: 0,
|
||||
wait_exception_channel_type: inner
|
||||
.exception
|
||||
.as_ref()
|
||||
.map_or(0, |exception| exception.get_current_channel_type() as u32),
|
||||
cpu_affnity_mask: [0u64; 8],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_thread_exception_info(&self) -> ZxResult<ExceptionReport> {
|
||||
let inner = self.inner.lock();
|
||||
if inner.get_state() != ThreadState::BlockedException {
|
||||
return Err(ZxError::BAD_STATE);
|
||||
}
|
||||
inner
|
||||
.exception
|
||||
.as_ref()
|
||||
.ok_or(ZxError::BAD_STATE)
|
||||
.map(|exception| exception.get_report())
|
||||
}
|
||||
|
||||
/// Run async future and change state while blocking.
|
||||
pub async fn blocking_run<F, T, FT>(
|
||||
&self,
|
||||
|
@ -385,18 +402,8 @@ impl Thread {
|
|||
pub fn get_time(&self) -> u64 {
|
||||
self.inner.lock().time as u64
|
||||
}
|
||||
|
||||
pub fn handle_exception(&self) -> impl Future<Output = bool> {
|
||||
//TODO: implement exception channel
|
||||
self.exit();
|
||||
struct ExceptionFuture;
|
||||
impl Future for ExceptionFuture {
|
||||
type Output = bool;
|
||||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Poll::Ready(false)
|
||||
}
|
||||
}
|
||||
ExceptionFuture
|
||||
pub fn set_exception(&self, exception: Option<Arc<Exception>>) {
|
||||
self.inner.lock().exception = exception;
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> ThreadFlag {
|
||||
|
@ -455,14 +462,6 @@ impl Task for Thread {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_exception_channel(&mut self, _options: u32) -> ZxResult<Channel> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn resume_from_exception(&mut self, _port: &Port, _options: u32) -> ZxResult {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoResult<T> {
|
||||
|
@ -524,7 +523,7 @@ impl Default for ThreadState {
|
|||
#[repr(C)]
|
||||
pub struct ThreadInfo {
|
||||
state: u32,
|
||||
wait_exception_type: u32,
|
||||
wait_exception_channel_type: u32,
|
||||
cpu_affnity_mask: [u64; 8],
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use {
|
||||
super::*, crate::object::*, alloc::sync::Arc, bitflags::bitflags, kernel_hal::user_io_vec::*,
|
||||
numeric_enum_macro::numeric_enum, spin::Mutex,
|
||||
};
|
||||
use {super::*, crate::object::*, alloc::sync::Arc, numeric_enum_macro::numeric_enum, spin::Mutex};
|
||||
|
||||
/// A readable, writable, seekable interface to some underlying storage
|
||||
///
|
||||
|
@ -11,27 +8,13 @@ use {
|
|||
/// storage, typically a VMO.
|
||||
pub struct Stream {
|
||||
base: KObjectBase,
|
||||
options: StreamOptions,
|
||||
options: u32,
|
||||
vmo: Arc<VmObject>,
|
||||
seek: Mutex<usize>,
|
||||
}
|
||||
|
||||
impl_kobject!(Stream);
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct StreamOptions: u32 {
|
||||
#[allow(clippy::identity_op)]
|
||||
// These can be passed to stream_create()
|
||||
const STREAM_MODE_READ = 1;
|
||||
const STREAM_MODE_WRITE = 1 << 1;
|
||||
const STREAM_CREATE_MASK = Self::STREAM_MODE_READ.bits | Self::STREAM_MODE_WRITE.bits;
|
||||
|
||||
// These can be passed to stream_writev()
|
||||
const STREAM_APPEND = 1;
|
||||
}
|
||||
}
|
||||
|
||||
numeric_enum! {
|
||||
#[repr(usize)]
|
||||
#[derive(Debug)]
|
||||
|
@ -44,40 +27,17 @@ numeric_enum! {
|
|||
|
||||
impl Stream {
|
||||
/// Create a stream from a VMO
|
||||
pub fn create(
|
||||
options: u32,
|
||||
vmo: Arc<VmObject>,
|
||||
vmo_rights: Rights,
|
||||
seek: usize,
|
||||
) -> ZxResult<(Arc<Self>, Rights)> {
|
||||
let options = StreamOptions::from_bits(options).ok_or(ZxError::INVALID_ARGS)?;
|
||||
if !(options - StreamOptions::STREAM_CREATE_MASK).is_empty() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let mut rights = Rights::DEFAULT_STREAM;
|
||||
if options.contains(StreamOptions::STREAM_MODE_READ) {
|
||||
rights |= Rights::READ;
|
||||
if !vmo_rights.contains(Rights::READ) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
}
|
||||
if options.contains(StreamOptions::STREAM_MODE_WRITE) {
|
||||
rights |= Rights::WRITE;
|
||||
if !vmo_rights.contains(Rights::WRITE) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
}
|
||||
let out = Arc::new(Stream {
|
||||
base: KObjectBase::with_signal(Signal::empty()), // it seems that stream don't care signals
|
||||
pub fn create(vmo: Arc<VmObject>, seek: usize, options: u32) -> Arc<Self> {
|
||||
Arc::new(Stream {
|
||||
base: KObjectBase::default(),
|
||||
options,
|
||||
vmo,
|
||||
seek: Mutex::new(seek),
|
||||
});
|
||||
Ok((out, rights))
|
||||
})
|
||||
}
|
||||
|
||||
/// Read data from the stream at the current seek offset
|
||||
pub fn read(&self, data: &OutIoVec<u8>) -> ZxResult<usize> {
|
||||
pub fn read(&self, data: &mut [u8]) -> ZxResult<usize> {
|
||||
let mut seek = self.seek.lock();
|
||||
let length = self.read_at(data, *seek)?;
|
||||
*seek += length;
|
||||
|
@ -85,20 +45,19 @@ impl Stream {
|
|||
}
|
||||
|
||||
/// Read data from the stream at a given offset
|
||||
pub fn read_at(&self, data: &OutIoVec<u8>, offset: usize) -> ZxResult<usize> {
|
||||
pub fn read_at(&self, data: &mut [u8], offset: usize) -> ZxResult<usize> {
|
||||
let count = data.len();
|
||||
let content_size = self.vmo.content_size();
|
||||
if offset >= content_size {
|
||||
return Ok(0);
|
||||
}
|
||||
let length = count.min(content_size - offset);
|
||||
let slice = data.as_mut_slice()?;
|
||||
self.vmo.read(offset, &mut slice[..length])?;
|
||||
self.vmo.read(offset, &mut data[..length])?;
|
||||
Ok(length)
|
||||
}
|
||||
|
||||
/// write data to the stream at the current seek offset or append data at the end of content
|
||||
pub fn write(&self, data: &InIoVec<u8>, append: bool) -> ZxResult<usize> {
|
||||
pub fn write(&self, data: &[u8], append: bool) -> ZxResult<usize> {
|
||||
let mut seek = self.seek.lock();
|
||||
if append {
|
||||
*seek = self.vmo.content_size();
|
||||
|
@ -109,7 +68,7 @@ impl Stream {
|
|||
}
|
||||
|
||||
/// Write data to the stream at a given offset
|
||||
pub fn write_at(&self, data: &InIoVec<u8>, offset: usize) -> ZxResult<usize> {
|
||||
pub fn write_at(&self, data: &[u8], offset: usize) -> ZxResult<usize> {
|
||||
let count = data.len();
|
||||
let mut content_size = self.vmo.content_size();
|
||||
let (target_size, overflow) = offset.overflowing_add(count);
|
||||
|
@ -123,15 +82,14 @@ impl Stream {
|
|||
return Err(ZxError::NO_SPACE);
|
||||
}
|
||||
let length = count.min(content_size - offset);
|
||||
let slice = data.as_slice()?;
|
||||
self.vmo.write(offset, &slice[..length])?;
|
||||
self.vmo.write(offset, &data[..length])?;
|
||||
Ok(length)
|
||||
}
|
||||
|
||||
/// Modify the current seek offset of the stream
|
||||
pub fn seek(&self, seek_origin: SeekOrigin, offset: isize) -> ZxResult<usize> {
|
||||
pub fn seek(&self, whence: SeekOrigin, offset: isize) -> ZxResult<usize> {
|
||||
let mut seek = self.seek.lock();
|
||||
let origin: usize = match seek_origin {
|
||||
let origin: usize = match whence {
|
||||
SeekOrigin::Start => 0,
|
||||
SeekOrigin::Current => *seek,
|
||||
SeekOrigin::End => self.vmo.content_size(),
|
||||
|
@ -156,7 +114,7 @@ impl Stream {
|
|||
pub fn get_info(&self) -> StreamInfo {
|
||||
let seek = self.seek.lock();
|
||||
StreamInfo {
|
||||
options: self.options.bits,
|
||||
options: self.options,
|
||||
padding1: 0,
|
||||
seek: *seek as u64,
|
||||
content_size: self.vmo.content_size() as u64,
|
||||
|
@ -167,20 +125,20 @@ impl Stream {
|
|||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct StreamInfo {
|
||||
// The options passed to zx_stream_create().
|
||||
/// The options passed to `Stream::create()`.
|
||||
options: u32,
|
||||
padding1: u32,
|
||||
// The current seek offset.
|
||||
//
|
||||
// Used by zx_stream_readv and zx_stream_writev to determine where to read
|
||||
// and write the stream.
|
||||
/// The current seek offset.
|
||||
///
|
||||
/// Used by stream_readv and stream_writev to determine where to read
|
||||
/// and write the stream.
|
||||
seek: u64,
|
||||
// The current size of the stream.
|
||||
//
|
||||
// The number of bytes in the stream that store data. The stream itself
|
||||
// might have a larger capacity to avoid reallocating the underlying storage
|
||||
// as the stream grows or shrinks.
|
||||
// NOTE: in fact, this value is store in the VmObject associated and can be
|
||||
// get/set through 'object_[get/set]_property(vmo_handle, ...)'
|
||||
/// The current size of the stream.
|
||||
///
|
||||
/// The number of bytes in the stream that store data. The stream itself
|
||||
/// might have a larger capacity to avoid reallocating the underlying storage
|
||||
/// as the stream grows or shrinks.
|
||||
/// NOTE: in fact, this value is store in the VmObject associated and can be
|
||||
/// get/set through 'object_[get/set]_property(vmo_handle, ...)'
|
||||
content_size: u64,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use {
|
||||
super::*,
|
||||
zircon_object::{ipc::Channel, task::*},
|
||||
};
|
||||
use {super::*, numeric_enum_macro::numeric_enum, zircon_object::task::*};
|
||||
|
||||
impl Syscall<'_> {
|
||||
pub fn sys_create_exception_channel(
|
||||
|
@ -15,29 +12,78 @@ impl Syscall<'_> {
|
|||
task, option, out
|
||||
);
|
||||
let proc = self.thread.proc();
|
||||
let task = proc.get_dyn_object_with_rights(
|
||||
task,
|
||||
let (task, rights) = proc.get_dyn_object_and_rights(task)?;
|
||||
if !rights.contains(
|
||||
Rights::INSPECT | Rights::DUPLICATE | Rights::TRANSFER | Rights::MANAGE_THREAD,
|
||||
)?;
|
||||
let exceptionate = task
|
||||
.clone()
|
||||
.downcast_arc::<Job>()
|
||||
.map(|x| x.get_exceptionate())
|
||||
.or_else(|_| {
|
||||
task.clone()
|
||||
.downcast_arc::<Process>()
|
||||
.map(|x| x.get_exceptionate())
|
||||
})
|
||||
.or_else(|_| {
|
||||
task.clone()
|
||||
.downcast_arc::<Thread>()
|
||||
.map(|x| x.get_exceptionate())
|
||||
})
|
||||
.map_err(|_| ZxError::WRONG_TYPE)?;
|
||||
let (end0, end1) = Channel::create();
|
||||
exceptionate.set_channel(end0);
|
||||
let user_end = proc.add_handle(Handle::new(end1, Rights::DEFAULT_CHANNEL));
|
||||
) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
let option = ExceptionChannelOption::try_from(option).map_err(|_| ZxError::INVALID_ARGS)?;
|
||||
let exceptionate = if let Ok(job) = task.clone().downcast_arc::<Job>() {
|
||||
if !rights.contains(Rights::ENUMERATE) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
match option {
|
||||
ExceptionChannelOption::None => job.get_exceptionate(),
|
||||
ExceptionChannelOption::Debugger => job.get_debug_exceptionate(),
|
||||
}
|
||||
} else if let Ok(process) = task.clone().downcast_arc::<Process>() {
|
||||
if !rights.contains(Rights::ENUMERATE) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
match option {
|
||||
ExceptionChannelOption::None => process.get_exceptionate(),
|
||||
ExceptionChannelOption::Debugger => process.get_debug_exceptionate(),
|
||||
}
|
||||
} else if let Ok(thread) = task.clone().downcast_arc::<Thread>() {
|
||||
match option {
|
||||
ExceptionChannelOption::None => thread.get_exceptionate(),
|
||||
ExceptionChannelOption::Debugger => return Err(ZxError::INVALID_ARGS),
|
||||
}
|
||||
} else {
|
||||
return Err(ZxError::WRONG_TYPE);
|
||||
};
|
||||
let user_end = proc.add_handle(Handle::new(
|
||||
exceptionate.create_channel()?,
|
||||
Rights::TRANSFER | Rights::WAIT | Rights::READ,
|
||||
));
|
||||
out.write(user_end)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sys_exception_get_thread(
|
||||
&self,
|
||||
exception: HandleValue,
|
||||
mut out: UserOutPtr<HandleValue>,
|
||||
) -> ZxResult {
|
||||
let proc = self.thread.proc();
|
||||
let exception =
|
||||
proc.get_object_with_rights::<ExceptionObject>(exception, Rights::default())?;
|
||||
let (object, right) = exception.get_exception().get_thread_and_rights();
|
||||
let handle = proc.add_handle(Handle::new(object, right));
|
||||
out.write(handle)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sys_exception_get_process(
|
||||
&self,
|
||||
exception: HandleValue,
|
||||
mut out: UserOutPtr<HandleValue>,
|
||||
) -> ZxResult {
|
||||
let proc = self.thread.proc();
|
||||
let exception =
|
||||
proc.get_object_with_rights::<ExceptionObject>(exception, Rights::default())?;
|
||||
let (object, right) = exception.get_exception().get_process_and_rights();
|
||||
let handle = proc.add_handle(Handle::new(object, right));
|
||||
out.write(handle)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
numeric_enum! {
|
||||
#[repr(u32)]
|
||||
pub enum ExceptionChannelOption {
|
||||
None = 0,
|
||||
Debugger = 1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use {
|
|||
sync::atomic::{AtomicI32, Ordering},
|
||||
},
|
||||
futures::pin_mut,
|
||||
kernel_hal::{user::*, user_io_vec::*, GeneralRegs},
|
||||
kernel_hal::{user::*, GeneralRegs},
|
||||
zircon_object::object::*,
|
||||
zircon_object::task::Thread,
|
||||
};
|
||||
|
@ -351,6 +351,8 @@ impl Syscall<'_> {
|
|||
Sys::INTERRUPT_ACK => self.sys_interrupt_ack(a0 as _),
|
||||
Sys::INTERRUPT_DESTROY => self.sys_interrupt_destroy(a0 as _),
|
||||
Sys::INTERRUPT_WAIT => self.sys_interrupt_wait(a0 as _, a1.into()).await,
|
||||
Sys::EXCEPTION_GET_THREAD => self.sys_exception_get_thread(a0 as _, a1.into()),
|
||||
Sys::EXCEPTION_GET_PROCESS => self.sys_exception_get_process(a0 as _, a1.into()),
|
||||
Sys::IOPORTS_REQUEST => {
|
||||
warn!("ioports.request: skip");
|
||||
Ok(())
|
||||
|
|
|
@ -79,6 +79,24 @@ impl Syscall<'_> {
|
|||
info_ptr.write(content_size)?;
|
||||
Ok(())
|
||||
}
|
||||
Property::ExceptionState => {
|
||||
let mut info_ptr = UserOutPtr::<u32>::from_addr_size(buffer, buffer_size)?;
|
||||
let state = proc
|
||||
.get_object_with_rights::<ExceptionObject>(handle_value, Rights::GET_PROPERTY)?
|
||||
.get_exception()
|
||||
.get_state();
|
||||
info_ptr.write(state)?;
|
||||
Ok(())
|
||||
}
|
||||
Property::ExceptionStrategy => {
|
||||
let mut info_ptr = UserOutPtr::<u32>::from_addr_size(buffer, buffer_size)?;
|
||||
let state = proc
|
||||
.get_object_with_rights::<ExceptionObject>(handle_value, Rights::GET_PROPERTY)?
|
||||
.get_exception()
|
||||
.get_strategy();
|
||||
info_ptr.write(state)?;
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
warn!("unknown property {:?}", property);
|
||||
Err(ZxError::INVALID_ARGS)
|
||||
|
@ -143,6 +161,20 @@ impl Syscall<'_> {
|
|||
proc.get_object::<VmObject>(handle_value)?
|
||||
.set_content_size(content_size)
|
||||
}
|
||||
Property::ExceptionState => {
|
||||
let state = UserInPtr::<u32>::from_addr_size(buffer, buffer_size)?.read()?;
|
||||
proc.get_object_with_rights::<ExceptionObject>(handle_value, Rights::SET_PROPERTY)?
|
||||
.get_exception()
|
||||
.set_state(state);
|
||||
Ok(())
|
||||
}
|
||||
Property::ExceptionStrategy => {
|
||||
let state = UserInPtr::<u32>::from_addr_size(buffer, buffer_size)?.read()?;
|
||||
proc.get_object_with_rights::<ExceptionObject>(handle_value, Rights::SET_PROPERTY)?
|
||||
.get_exception()
|
||||
.set_strategy(state)?;
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
warn!("unknown property");
|
||||
Err(ZxError::INVALID_ARGS)
|
||||
|
@ -228,6 +260,12 @@ impl Syscall<'_> {
|
|||
let thread = proc.get_object_with_rights::<Thread>(handle, Rights::INSPECT)?;
|
||||
info_ptr.write(thread.get_thread_info())?;
|
||||
}
|
||||
Topic::ThreadExceptionReport => {
|
||||
let mut info_ptr =
|
||||
UserOutPtr::<ExceptionReport>::from_addr_size(buffer, buffer_size)?;
|
||||
let thread = proc.get_object_with_rights::<Thread>(handle, Rights::INSPECT)?;
|
||||
info_ptr.write(thread.get_thread_exception_info()?)?;
|
||||
}
|
||||
Topic::HandleCount => {
|
||||
let mut info_ptr = UserOutPtr::<u32>::from_addr_size(buffer, buffer_size)?;
|
||||
let object = proc.get_dyn_object_with_rights(handle, Rights::INSPECT)?;
|
||||
|
@ -479,7 +517,9 @@ numeric_enum! {
|
|||
ProcessBreakOnLoad = 7,
|
||||
SocketRxThreshold = 12,
|
||||
SocketTxThreshold = 13,
|
||||
ExceptionState = 16,
|
||||
VmoContentSize = 17,
|
||||
ExceptionStrategy = 18,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use {super::*, zircon_object::vm::*};
|
||||
use {super::*, bitflags::bitflags, zircon_object::vm::*};
|
||||
|
||||
impl Syscall<'_> {
|
||||
pub fn sys_stream_create(
|
||||
|
@ -9,13 +9,30 @@ impl Syscall<'_> {
|
|||
mut out: UserOutPtr<HandleValue>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"stream.create: options={:#x?}, vmo_handle = {:#x?}, seek = {:#x?}",
|
||||
"stream.create: options={:#x?}, vmo_handle={:#x?}, seek={:#x?}",
|
||||
options, vmo_handle, seek
|
||||
);
|
||||
bitflags! {
|
||||
struct CreateOptions: u32 {
|
||||
#[allow(clippy::identity_op)]
|
||||
const MODE_READ = 1 << 0;
|
||||
const MODE_WRITE = 1 << 1;
|
||||
}
|
||||
}
|
||||
let options = CreateOptions::from_bits(options).ok_or(ZxError::INVALID_ARGS)?;
|
||||
let mut rights = Rights::DEFAULT_STREAM;
|
||||
let mut vmo_rights = Rights::empty();
|
||||
if options.contains(CreateOptions::MODE_READ) {
|
||||
rights |= Rights::READ;
|
||||
vmo_rights |= Rights::READ;
|
||||
}
|
||||
if options.contains(CreateOptions::MODE_WRITE) {
|
||||
rights |= Rights::WRITE;
|
||||
vmo_rights |= Rights::WRITE;
|
||||
}
|
||||
let proc = self.thread.proc();
|
||||
let (vmo, vmo_rights) = proc.get_object_and_rights::<VmObject>(vmo_handle)?;
|
||||
let (stream, rights) = Stream::create(options, vmo, vmo_rights, seek)?;
|
||||
let proc = self.thread.proc();
|
||||
let vmo = proc.get_object_with_rights::<VmObject>(vmo_handle, vmo_rights)?;
|
||||
let stream = Stream::create(vmo, seek, options.bits());
|
||||
let handle = proc.add_handle(Handle::new(stream, rights));
|
||||
out.write(handle)?;
|
||||
Ok(())
|
||||
|
@ -25,31 +42,27 @@ impl Syscall<'_> {
|
|||
&self,
|
||||
handle_value: HandleValue,
|
||||
options: u32,
|
||||
user_bytes: UserInPtr<InIoVec<u8>>,
|
||||
count: usize,
|
||||
vector: UserInPtr<IoVecIn>,
|
||||
vector_size: usize,
|
||||
mut actual_count_ptr: UserOutPtr<usize>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"stream.write: stream={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}",
|
||||
handle_value, options, user_bytes, count,
|
||||
"stream.write: stream={:#x?}, options={:#x?}, vector=({:#x?}; {:#x?})",
|
||||
handle_value, options, vector, vector_size,
|
||||
);
|
||||
let options = StreamOptions::from_bits(options).ok_or(ZxError::INVALID_ARGS)?;
|
||||
if !(options - StreamOptions::STREAM_APPEND).is_empty() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
if user_bytes.is_null() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
bitflags! {
|
||||
struct WriteOptions: u32 {
|
||||
const APPEND = 1;
|
||||
}
|
||||
}
|
||||
let data = vector.read_iovecs(vector_size)?;
|
||||
let options = WriteOptions::from_bits(options).ok_or(ZxError::INVALID_ARGS)?;
|
||||
let proc = self.thread.proc();
|
||||
let stream = proc.get_object_with_rights::<Stream>(handle_value, Rights::WRITE)?;
|
||||
let data = user_bytes.read_array(count)?;
|
||||
check_total_capacity(&data)?;
|
||||
let mut actual_count = 0;
|
||||
for io_vec in &data {
|
||||
if io_vec.is_null() {
|
||||
return Err(ZxError::NOT_FOUND);
|
||||
}
|
||||
actual_count += stream.write(io_vec, options.contains(StreamOptions::STREAM_APPEND))?;
|
||||
for io_vec in data.iter() {
|
||||
actual_count +=
|
||||
stream.write(io_vec.as_slice()?, options.contains(WriteOptions::APPEND))?;
|
||||
}
|
||||
actual_count_ptr.write_if_not_null(actual_count)?;
|
||||
Ok(())
|
||||
|
@ -59,33 +72,25 @@ impl Syscall<'_> {
|
|||
&self,
|
||||
handle_value: HandleValue,
|
||||
options: u32,
|
||||
offset: usize,
|
||||
user_bytes: UserInPtr<InIoVec<u8>>,
|
||||
count: usize,
|
||||
mut offset: usize,
|
||||
vector: UserInPtr<IoVecIn>,
|
||||
vector_size: usize,
|
||||
mut actual_count_ptr: UserOutPtr<usize>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"stream.write_at: stream={:#x?}, options={:#x?}, offset = {:#x?}, buffer={:#x?}, size={:#x?}",
|
||||
handle_value, options, offset, user_bytes, count,
|
||||
"stream.write_at: stream={:#x?}, options={:#x?}, offset={:#x?}, vector=({:#x?}; {:#x?})",
|
||||
handle_value, options, offset, vector, vector_size,
|
||||
);
|
||||
if options != 0 {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
if user_bytes.is_null() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let data = vector.read_iovecs(vector_size)?;
|
||||
let proc = self.thread.proc();
|
||||
let stream = proc.get_object_with_rights::<Stream>(handle_value, Rights::WRITE)?;
|
||||
let data = user_bytes.read_array(count)?;
|
||||
check_total_capacity(&data)?;
|
||||
let mut actual_count = 0;
|
||||
let mut off = offset;
|
||||
for io_vec in &data {
|
||||
if io_vec.is_null() {
|
||||
return Err(ZxError::NOT_FOUND);
|
||||
}
|
||||
actual_count += stream.write_at(io_vec, off)?;
|
||||
off += actual_count;
|
||||
for io_vec in data.iter() {
|
||||
actual_count += stream.write_at(io_vec.as_slice()?, offset)?;
|
||||
offset += actual_count;
|
||||
}
|
||||
actual_count_ptr.write_if_not_null(actual_count)?;
|
||||
Ok(())
|
||||
|
@ -95,30 +100,23 @@ impl Syscall<'_> {
|
|||
&self,
|
||||
handle_value: HandleValue,
|
||||
options: u32,
|
||||
user_bytes: UserInOutPtr<OutIoVec<u8>>,
|
||||
count: usize,
|
||||
vector: UserInPtr<IoVecOut>,
|
||||
vector_size: usize,
|
||||
mut actual_count_ptr: UserOutPtr<usize>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"stream.read: stream={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}",
|
||||
handle_value, options, user_bytes, count,
|
||||
"stream.read: stream={:#x?}, options={:#x?}, vector=({:#x?}; {:#x?})",
|
||||
handle_value, options, vector, vector_size,
|
||||
);
|
||||
if options != 0 {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
if user_bytes.is_null() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let mut data = user_bytes.read_array(count)?;
|
||||
let mut data = vector.read_iovecs(vector_size)?;
|
||||
let proc = self.thread.proc();
|
||||
let stream = proc.get_object_with_rights::<Stream>(handle_value, Rights::READ)?;
|
||||
check_total_capacity(&data)?;
|
||||
let mut actual_count = 0usize;
|
||||
for io_vec in &mut data {
|
||||
if io_vec.is_null() {
|
||||
return Err(ZxError::NOT_FOUND);
|
||||
}
|
||||
actual_count += stream.read(io_vec)?;
|
||||
for io_vec in data.iter_mut() {
|
||||
actual_count += stream.read(io_vec.as_mut_slice()?)?;
|
||||
}
|
||||
actual_count_ptr.write_if_not_null(actual_count)?;
|
||||
Ok(())
|
||||
|
@ -128,33 +126,25 @@ impl Syscall<'_> {
|
|||
&self,
|
||||
handle_value: HandleValue,
|
||||
options: u32,
|
||||
offset: usize,
|
||||
user_bytes: UserInOutPtr<OutIoVec<u8>>,
|
||||
count: usize,
|
||||
mut offset: usize,
|
||||
vector: UserInPtr<IoVecOut>,
|
||||
vector_size: usize,
|
||||
mut actual_count_ptr: UserOutPtr<usize>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"stream.read_at: stream={:#x?}, options={:#x?}, offset = {:#x?}, buffer={:#x?}, size={:#x?}",
|
||||
handle_value, options, offset, user_bytes, count,
|
||||
"stream.read_at: stream={:#x?}, options={:#x?}, offset={:#x?}, vector=({:#x?}; {:#x?})",
|
||||
handle_value, options, offset, vector, vector_size,
|
||||
);
|
||||
if options != 0 {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
if user_bytes.is_null() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let mut data = user_bytes.read_array(count)?;
|
||||
let mut data = vector.read_iovecs(vector_size)?;
|
||||
let proc = self.thread.proc();
|
||||
let stream = proc.get_object_with_rights::<Stream>(handle_value, Rights::READ)?;
|
||||
check_total_capacity(&data)?;
|
||||
let mut actual_count = 0usize;
|
||||
let mut off = offset;
|
||||
for io_vec in &mut data {
|
||||
if io_vec.is_null() {
|
||||
return Err(ZxError::NOT_FOUND);
|
||||
}
|
||||
actual_count += stream.read_at(io_vec, off)?;
|
||||
off += actual_count;
|
||||
for io_vec in data.iter_mut() {
|
||||
actual_count += stream.read_at(io_vec.as_mut_slice()?, offset)?;
|
||||
offset += actual_count;
|
||||
}
|
||||
actual_count_ptr.write_if_not_null(actual_count)?;
|
||||
Ok(())
|
||||
|
@ -163,34 +153,22 @@ impl Syscall<'_> {
|
|||
pub fn sys_stream_seek(
|
||||
&self,
|
||||
handle_value: HandleValue,
|
||||
seek_origin: usize,
|
||||
whence: usize,
|
||||
offset: isize,
|
||||
mut out_seek: UserOutPtr<usize>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"stream.seek: stream={:#x?}, seek_origin={:#x?}, offset = {:#x?}",
|
||||
handle_value, seek_origin, offset,
|
||||
"stream.seek: stream={:#x?}, whence={:#x?}, offset={:#x?}",
|
||||
handle_value, whence, offset,
|
||||
);
|
||||
let proc = self.thread.proc();
|
||||
let (stream, rights) = proc.get_object_and_rights::<Stream>(handle_value)?;
|
||||
if !rights.contains(Rights::READ) && !rights.contains(Rights::WRITE) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
let seek_origin = SeekOrigin::try_from(seek_origin).or(Err(ZxError::INVALID_ARGS))?;
|
||||
let new_seek = stream.seek(seek_origin, offset)?;
|
||||
let whence = SeekOrigin::try_from(whence).map_err(|_| ZxError::INVALID_ARGS)?;
|
||||
let new_seek = stream.seek(whence, offset)?;
|
||||
out_seek.write_if_not_null(new_seek)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_total_capacity<T, P: Policy>(data: &[IoVec<T, P>]) -> ZxResult {
|
||||
let mut total_count = 0usize;
|
||||
for io_vec in data {
|
||||
let (result, overflow) = total_count.overflowing_add(io_vec.len());
|
||||
if overflow {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
total_count = result;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue