Add helper functions for UserContext to kernel-hal

This commit is contained in:
Yuekai Jia 2021-10-31 04:14:10 +08:00
parent d791c52700
commit 30831ed711
33 changed files with 772 additions and 834 deletions

View File

@ -33,13 +33,17 @@ bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev =
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
executor = { git = "https://github.com/rcore-os/executor.git", rev = "04b6b7b" }
naive-timer = "0.2.0"
# All mode on x86_64
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86 = "0.43"
x86_64 = "0.14"
# Bare-metal mode on x86_64
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
uefi = "0.11"
x86_64 = "0.14"
raw-cpuid = "9.0"
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" }

View File

@ -1,25 +0,0 @@
//! Context switch.
use riscv::register::scause::{Exception, Trap};
use riscv::register::{scause, stval};
use crate::{MMUFlags, VirtAddr};
hal_fn_impl! {
impl mod crate::hal_fn::context {
fn fetch_trap_num(_context: &UserContext) -> usize {
scause::read().bits()
}
fn fetch_page_fault_info(_scause: usize) -> (VirtAddr, MMUFlags) {
let fault_vaddr = stval::read() as _;
let flags = match scause::read().cause() {
Trap::Exception(Exception::LoadPageFault) => MMUFlags::READ,
Trap::Exception(Exception::StorePageFault) => MMUFlags::WRITE,
Trap::Exception(Exception::InstructionPageFault) => MMUFlags::EXECUTE,
_ => unreachable!(),
};
(fault_vaddr, flags)
}
}
}

View File

@ -3,7 +3,6 @@ mod sbi;
mod trap;
pub mod config;
pub mod context;
pub mod cpu;
pub mod interrupt;
pub mod mem;

View File

@ -1,8 +1,7 @@
use riscv::register::scause::{self, Exception, Trap};
use riscv::register::stval;
use riscv::register::scause;
use trapframe::TrapFrame;
use crate::MMUFlags;
use crate::context::TrapReason;
fn breakpoint(sepc: &mut usize) {
info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
@ -24,29 +23,13 @@ pub(super) fn super_soft() {
info!("Interrupt::SupervisorSoft!");
}
fn page_fault(access_flags: MMUFlags) {
crate::KHANDLER.handle_page_fault(stval::read(), access_flags);
}
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
let sepc = tf.sepc;
let scause = scause::read();
match scause.cause() {
Trap::Exception(Exception::Breakpoint) => breakpoint(&mut tf.sepc),
Trap::Exception(Exception::IllegalInstruction) => {
panic!("IllegalInstruction: {:#x}, sepc={:#x}", stval::read(), sepc)
}
Trap::Exception(Exception::LoadFault) => {
panic!("Load access fault: {:#x}, sepc={:#x}", stval::read(), sepc)
}
Trap::Exception(Exception::StoreFault) => {
panic!("Store access fault: {:#x}, sepc={:#x}", stval::read(), sepc)
}
Trap::Exception(Exception::LoadPageFault) => page_fault(MMUFlags::READ),
Trap::Exception(Exception::StorePageFault) => page_fault(MMUFlags::WRITE),
Trap::Exception(Exception::InstructionPageFault) => page_fault(MMUFlags::EXECUTE),
Trap::Interrupt(_) => crate::interrupt::handle_irq(scause.code()),
_ => panic!("Undefined Trap: {:?}", scause.cause()),
match TrapReason::from(scause) {
TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.sepc),
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
other => panic!("Undefined trap: {:x?} {:#x?}", other, tf),
}
}

View File

@ -1,41 +0,0 @@
//! Context switch.
use bitflags::bitflags;
use x86_64::registers::control::Cr2;
use crate::{MMUFlags, VirtAddr};
bitflags! {
struct PageFaultErrorCode: u32 {
const PRESENT = 1 << 0;
const WRITE = 1 << 1;
const USER = 1 << 2;
const RESERVED = 1 << 3;
const INST = 1 << 4;
}
}
hal_fn_impl! {
impl mod crate::hal_fn::context {
fn fetch_page_fault_info(error_code: usize) -> (VirtAddr, MMUFlags) {
let fault_vaddr = Cr2::read().as_u64() as _;
let mut flags = MMUFlags::empty();
let code = PageFaultErrorCode::from_bits_truncate(error_code as u32);
if code.contains(PageFaultErrorCode::WRITE) {
flags |= MMUFlags::WRITE
} else {
flags |= MMUFlags::READ
}
if code.contains(PageFaultErrorCode::USER) {
flags |= MMUFlags::USER
}
if code.contains(PageFaultErrorCode::INST) {
flags |= MMUFlags::EXECUTE
}
if code.contains(PageFaultErrorCode::RESERVED) {
error!("page table entry has reserved bits set!")
}
(fault_vaddr, flags)
}
}
}

View File

@ -2,7 +2,6 @@ mod drivers;
mod trap;
pub mod config;
pub mod context;
pub mod cpu;
pub mod interrupt;
pub mod mem;

View File

@ -3,32 +3,7 @@
use trapframe::TrapFrame;
// Reference: https://wiki.osdev.org/Exceptions
const DIVIDE_ERROR: usize = 0;
const DEBUG: usize = 1;
const NON_MASKABLE_INTERRUPT: usize = 2;
const BREAKPOINT: usize = 3;
const OVERFLOW: usize = 4;
const BOUND_RANGE_EXCEEDED: usize = 5;
const INVALID_OPCODE: usize = 6;
const DEVICE_NOT_AVAILABLE: usize = 7;
const DOUBLE_FAULT: usize = 8;
const COPROCESSOR_SEGMENT_OVERRUN: usize = 9;
const INVALID_TSS: usize = 10;
const SEGMENT_NOT_PRESENT: usize = 11;
const STACK_SEGMENT_FAULT: usize = 12;
const GENERAL_PROTECTION_FAULT: usize = 13;
const PAGE_FAULT: usize = 14;
const FLOATING_POINTEXCEPTION: usize = 16;
const ALIGNMENT_CHECK: usize = 17;
const MACHINE_CHECK: usize = 18;
const SIMD_FLOATING_POINT_EXCEPTION: usize = 19;
const VIRTUALIZATION_EXCEPTION: usize = 20;
const SECURITY_EXCEPTION: usize = 30;
// IRQ vectors
pub(super) const X86_INT_BASE: usize = 0x20;
pub(super) const X86_INT_MAX: usize = 0xff;
use crate::context::TrapReason;
pub(super) const X86_INT_LOCAL_APIC_BASE: usize = 0xf0;
pub(super) const X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE + 0x0;
@ -49,15 +24,6 @@ fn breakpoint() {
panic!("\nEXCEPTION: Breakpoint");
}
fn double_fault(tf: &TrapFrame) {
panic!("\nEXCEPTION: Double Fault\n{:#x?}", tf);
}
fn page_fault(tf: &mut TrapFrame) {
let (fault_vaddr, access_flags) = crate::context::fetch_page_fault_info(tf.error_code);
crate::KHANDLER.handle_page_fault(fault_vaddr, access_flags);
}
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
trace!(
@ -65,11 +31,10 @@ pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
tf.trap_num,
super::cpu::cpu_id()
);
match tf.trap_num {
BREAKPOINT => breakpoint(),
DOUBLE_FAULT => double_fault(tf),
PAGE_FAULT => page_fault(tf),
X86_INT_BASE..=X86_INT_MAX => crate::interrupt::handle_irq(tf.trap_num),
_ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf),
match TrapReason::from(tf.trap_num, tf.error_code) {
TrapReason::HardwareBreakpoint | TrapReason::SoftwareBreakpoint => breakpoint(),
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
other => panic!("Unhandled trap {:x?} {:#x?}", other, tf),
}
}

View File

@ -14,7 +14,7 @@ pub mod mem;
pub mod thread;
pub mod timer;
pub use self::arch::{config, context, cpu, interrupt, vm};
pub use self::arch::{config, cpu, interrupt, vm};
pub use super::hal_fn::{rand, vdso};
hal_fn_impl_default!(rand, vdso);

View File

@ -1,7 +1,281 @@
//! User context.
use crate::{MMUFlags, VirtAddr};
use core::fmt;
use trapframe::UserContext as UserContextInner;
pub use trapframe::{GeneralRegs, UserContext};
pub use trapframe::GeneralRegs;
cfg_if! {
if #[cfg(feature = "libos")] {
pub use trapframe::syscall_fn_entry as syscall_entry;
} else {
pub use dummpy_syscall_entry as syscall_entry;
pub fn dummpy_syscall_entry() {
unreachable!("dummpy_syscall_entry")
}
}
}
/// For reading and writing fields in [`UserContext`].
#[derive(Debug)]
pub enum UserContextField {
InstrPointer,
StackPointer,
ThreadPointer,
ReturnValue,
}
/// Reason of the trap.
#[derive(Debug)]
pub enum TrapReason {
Syscall,
Interrupt(usize),
PageFault(VirtAddr, MMUFlags),
UndefinedInstruction,
SoftwareBreakpoint,
HardwareBreakpoint,
UnalignedAccess,
GernelFault(usize),
}
impl TrapReason {
/// Get [`TrapReason`] from `trap_num` and `error_code` in trap frame for x86.
#[cfg(target_arch = "x86_64")]
pub fn from(trap_num: usize, error_code: usize) -> Self {
use x86::irq::*;
const X86_INT_BASE: u8 = 0x20;
const X86_INT_MAX: u8 = 0xff;
// See https://github.com/rcore-os/trapframe-rs/blob/25cb5282aca8ceb4f7fc4dcd61e7e73b67d9ae00/src/arch/x86_64/syscall.S#L117
if trap_num == 0x100 {
return Self::Syscall;
}
match trap_num as u8 {
DEBUG_VECTOR => Self::HardwareBreakpoint,
BREAKPOINT_VECTOR => Self::SoftwareBreakpoint,
INVALID_OPCODE_VECTOR => Self::UndefinedInstruction,
ALIGNMENT_CHECK_VECTOR => Self::UnalignedAccess,
PAGE_FAULT_VECTOR => {
bitflags::bitflags! {
struct PageFaultErrorCode: u32 {
const PRESENT = 1 << 0;
const WRITE = 1 << 1;
const USER = 1 << 2;
const RESERVED = 1 << 3;
const INST = 1 << 4;
}
}
let fault_vaddr = x86_64::registers::control::Cr2::read().as_u64() as _;
let code = PageFaultErrorCode::from_bits_truncate(error_code as u32);
let mut flags = MMUFlags::empty();
if code.contains(PageFaultErrorCode::WRITE) {
flags |= MMUFlags::WRITE
} else {
flags |= MMUFlags::READ
}
if code.contains(PageFaultErrorCode::USER) {
flags |= MMUFlags::USER
}
if code.contains(PageFaultErrorCode::INST) {
flags |= MMUFlags::EXECUTE
}
if code.contains(PageFaultErrorCode::RESERVED) {
error!("page table entry has reserved bits set!");
}
Self::PageFault(fault_vaddr, flags)
}
vec @ X86_INT_BASE..=X86_INT_MAX => Self::Interrupt(vec as usize),
_ => Self::GernelFault(trap_num),
}
}
#[cfg(target_arch = "riscv64")]
pub fn from(scause: riscv::register::scause::Scause) -> Self {
use riscv::register::scause::{Exception, Trap};
let stval = riscv::register::stval::read();
match scause.cause() {
Trap::Exception(Exception::UserEnvCall) => Self::Syscall,
Trap::Exception(Exception::Breakpoint) => Self::SoftwareBreakpoint,
Trap::Exception(Exception::IllegalInstruction) => Self::UndefinedInstruction,
Trap::Exception(Exception::InstructionMisaligned)
| Trap::Exception(Exception::StoreMisaligned) => Self::UnalignedAccess,
Trap::Exception(Exception::LoadPageFault) => Self::PageFault(stval, MMUFlags::READ),
Trap::Exception(Exception::StorePageFault) => Self::PageFault(stval, MMUFlags::WRITE),
Trap::Exception(Exception::InstructionPageFault) => {
Self::PageFault(stval, MMUFlags::EXECUTE)
}
Trap::Interrupt(_) => Self::Interrupt(scause.code()),
_ => Self::GernelFault(scause.code()),
}
}
}
/// User context saved on trap.
#[repr(transparent)]
#[derive(Clone)]
pub struct UserContext(UserContextInner);
impl UserContext {
/// Create an empty user context.
pub fn new() -> Self {
let context = UserContextInner::default();
Self(context)
}
/// Initialize the context for entry into userspace.
pub fn setup_uspace(&mut self, pc: usize, sp: usize, arg1: usize, arg2: usize) {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
self.0.general.rip = pc;
self.0.general.rsp = sp;
self.0.general.rdi = arg1;
self.0.general.rsi = arg2;
// IOPL = 3, IF = 1
// FIXME: set IOPL = 0 when IO port bitmap is supporte
self.0.general.rflags = 0x3000 | 0x200 | 0x2;
} else if #[cfg(target_arch = "aarch64")] {
self.0.elr = pc;
self.0.sp = sp;
self.0.general.x0 = arg1;
self.0.general.x1 = arg2;
// Mask SError exceptions (currently unhandled).
// TODO
self.0.spsr = 1 << 8;
} else if #[cfg(target_arch = "riscv64")] {
self.0.sepc = pc;
self.0.general.sp = sp;
self.0.general.a0 = arg1;
self.0.general.a1 = arg2;
// SUM = 1, FS = 0b11, SPIE = 1
self.0.sstatus = 1 << 18 | 0b11 << 13 | 1 << 5;
}
}
}
/// Switch to user mode.
pub fn enter_uspace(&mut self) {
cfg_if! {
if #[cfg(feature = "libos")] {
self.0.run_fncall()
} else {
self.0.run()
}
}
}
/// Returns the `error_code` field of the context.
#[cfg(any(target_arch = "x86_64", doc))]
#[doc(cfg(target_arch = "x86_64"))]
pub fn error_code(&self) -> usize {
self.0.error_code
}
/// Returns [`TrapReason`] according to the context.
pub fn trap_reason(&self) -> TrapReason {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
TrapReason::from(self.0.trap_num, self.0.error_code)
} else if #[cfg(target_arch = "aarch64")] {
unimplemented!() // ESR_EL1
} else if #[cfg(target_arch = "riscv64")] {
TrapReason::from(riscv::register::scause::read())
} else {
unimplemented!()
}
}
}
/// Returns a `usize` representing the trap reason. (i.e., IDT vector for x86, `scause` for RISC-V)
pub fn raw_trap_reason(&self) -> usize {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
self.0.trap_num
} else if #[cfg(target_arch = "aarch64")] {
unimplemented!() // ESR_EL1
} else if #[cfg(target_arch = "riscv64")] {
riscv::register::scause::read().bits()
} else {
unimplemented!()
}
}
}
/// Returns the reference of general registers.
pub fn general(&self) -> &GeneralRegs {
&self.0.general
}
/// Returns the mutable reference of general registers.
pub fn general_mut(&mut self) -> &mut GeneralRegs {
&mut self.0.general
}
fn field_ref(&mut self, which: UserContextField) -> &mut usize {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
match which {
UserContextField::InstrPointer => &mut self.0.general.rip,
UserContextField::StackPointer => &mut self.0.general.rsp,
UserContextField::ThreadPointer => &mut self.0.general.fsbase,
UserContextField::ReturnValue => &mut self.0.general.rax,
}
} else if #[cfg(target_arch = "aarch64")] {
match which {
UserContextField::InstrPointer => &mut self.0.elr,
UserContextField::StackPointer => &mut self.0.sp,
UserContextField::ThreadPointer => &mut self.0.tpidr,
UserContextField::ReturnValue => &mut self.0.general.x0,
}
} else if #[cfg(target_arch = "riscv64")] {
match which {
UserContextField::InstrPointer => &mut self.0.sepc,
UserContextField::StackPointer => &mut self.0.general.sp,
UserContextField::ThreadPointer => &mut self.0.general.tp,
UserContextField::ReturnValue => &mut self.0.general.a0,
}
} else {
unimplemented!()
}
}
}
/// Read a field of the context.
pub fn get_field(&mut self, which: UserContextField) -> usize {
*self.field_ref(which)
}
/// Write a field of the context.
pub fn set_field(&mut self, which: UserContextField, value: usize) {
*self.field_ref(which) = value;
}
/// Advance the instruction pointer in trap handler on some architecture.
pub fn advance_pc(&mut self, reason: TrapReason) {
cfg_if! {
if #[cfg(target_arch = "riscv64")] {
if let TrapReason::Syscall = reason { self.0.sepc += 4 }
} else {
let _ = reason;
}
}
}
}
impl Default for UserContext {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for UserContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
/// X86 vector registers.
#[repr(C, align(16))]
#[derive(Debug, Copy, Clone)]
pub struct VectorRegs {
@ -43,18 +317,9 @@ impl Default for VectorRegs {
pub struct U128(pub [u64; 2]);
impl fmt::Debug for U128 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:#016x}_{:016x}", self.0[1], self.0[0])
}
}
cfg_if! {
if #[cfg(feature = "libos")] {
pub use trapframe::syscall_fn_entry as syscall_entry;
} else {
pub use dummpy_syscall_entry as syscall_entry;
pub fn dummpy_syscall_entry() {
unreachable!("dummpy_syscall_entry")
}
}
}

View File

@ -1,4 +1,3 @@
pub(super) mod context;
pub(super) mod defs;
pub(super) mod future;
pub(super) mod mem;
@ -8,4 +7,5 @@ pub(super) mod vm;
pub mod addr;
pub mod console;
pub mod context;
pub mod user;

View File

@ -145,7 +145,7 @@ pub trait GenericPageTable: Sync + Send {
fn unmap_cont(&mut self, start_vaddr: VirtAddr, size: usize) -> PagingResult {
assert!(is_aligned(start_vaddr));
assert!(is_aligned(size));
debug!("unmap_cont: {:#x?}", start_vaddr..start_vaddr + size,);
debug!("unmap_cont: {:#x?}", start_vaddr..start_vaddr + size);
let mut vaddr = start_vaddr;
let end_vaddr = vaddr + size;
while vaddr < end_vaddr {

View File

@ -2,7 +2,7 @@ use alloc::{boxed::Box, string::String, vec::Vec};
use core::{future::Future, ops::Range, time::Duration};
use crate::drivers::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::{common, HalResult, KernelConfig, KernelHandler, MMUFlags, PhysAddr, VirtAddr};
use crate::{common, HalResult, KernelConfig, KernelHandler, PhysAddr, VirtAddr};
hal_fn_def! {
/// Bootstrap and initialization.
@ -126,27 +126,6 @@ hal_fn_def! {
pub(crate) fn console_write_early(_s: &str) {}
}
/// User context.
pub mod context: common::context {
/// Enter user mode.
pub fn context_run(context: &mut UserContext) {
cfg_if! {
if #[cfg(feature = "libos")] {
context.run_fncall()
} else {
context.run()
}
}
}
/// Get the trap number when trap.
pub fn fetch_trap_num(context: &UserContext) -> usize;
/// Get the fault virtual address and access type of the last page fault by `info_reg`
/// (`error_code` for x86, `scause` for riscv).
pub fn fetch_page_fault_info(info_reg: usize) -> (VirtAddr, MMUFlags);
}
/// Thread spawning.
pub mod thread: common::thread {
/// Spawn a new thread.

View File

@ -38,7 +38,7 @@ cfg_if! {
pub(crate) use config::KCONFIG;
pub(crate) use kernel_handler::KHANDLER;
pub use common::{addr, console, defs::*, user};
pub use common::{addr, console, context, defs::*, user};
pub use config::KernelConfig;
pub use imp::*;
pub use kernel_handler::KernelHandler;

View File

@ -1,3 +1,5 @@
//! CPU information.
hal_fn_impl! {
impl mod crate::hal_fn::cpu {
fn cpu_id() -> u8 {

View File

@ -15,9 +15,9 @@ pub mod vm;
#[doc(cfg(feature = "libos"))]
pub mod libos;
pub use super::hal_fn::{context, interrupt, rand};
pub use super::hal_fn::{interrupt, rand};
hal_fn_impl_default!(context, interrupt, rand, super::hal_fn::console);
hal_fn_impl_default!(interrupt, rand, super::hal_fn::console);
#[cfg(target_os = "macos")]
mod macos;

View File

@ -25,17 +25,18 @@ extern crate alloc;
#[macro_use]
extern crate log;
use {
self::consts::SyscallType as Sys,
alloc::sync::Arc,
core::convert::TryFrom,
kernel_hal::{context::GeneralRegs, user::*},
linux_object::{error::*, fs::FileDesc, process::*},
zircon_object::{object::*, task::*, vm::VirtAddr},
};
use alloc::sync::Arc;
use core::convert::TryFrom;
#[cfg(target_arch = "riscv64")]
use kernel_hal::context::UserContext;
use kernel_hal::user::{IoVecIn, IoVecOut, UserInOutPtr, UserInPtr, UserOutPtr};
use linux_object::error::{LxError, SysResult};
use linux_object::fs::FileDesc;
use linux_object::process::{wait_child, wait_child_any, LinuxProcess, ProcessExt, RLimit};
use zircon_object::object::{KernelObject, KoID, Signal};
use zircon_object::task::{CurrentThread, Process, Thread, ThreadFn};
use zircon_object::{vm::VirtAddr, ZxError};
use self::consts::SyscallType as Sys;
mod consts {
// generated from syscall.h.in
@ -53,16 +54,10 @@ mod vm;
pub struct Syscall<'a> {
/// the thread making a syscall
pub thread: &'a CurrentThread,
/// the entry of current syscall
pub syscall_entry: VirtAddr,
/// store the regs statues
#[cfg(not(target_arch = "riscv64"))]
pub regs: &'a mut GeneralRegs,
/// riscv GeneralRegs does not have Entry register
#[cfg(target_arch = "riscv64")]
pub context: &'a mut UserContext,
/// new thread function
pub thread_fn: ThreadFn,
/// the entry of current syscall
pub syscall_entry: VirtAddr,
}
impl Syscall<'_> {

View File

@ -11,7 +11,9 @@ impl Syscall<'_> {
match code {
ARCH_SET_FS => {
info!("sys_arch_prctl: set FSBASE to {:#x}", addr);
self.regs.fsbase = addr;
self.thread.with_context(|ctx| {
ctx.set_field(kernel_hal::context::UserContextField::ThreadPointer, addr)
})?;
Ok(0)
}
_ => Err(LxError::EINVAL),
@ -28,10 +30,15 @@ impl Syscall<'_> {
let vdso_const = kernel_hal::vdso::vdso_constants();
#[cfg(target_arch = "x86_64")]
let arch = "x86_64";
#[cfg(target_arch = "riscv64")]
let arch = "riscv64";
let arch = if cfg!(target_arch = "x86_64") {
"x86_64"
} else if cfg!(target_arch = "aarch64") {
"aarch64"
} else if cfg!(target_arch = "riscv64") {
"riscv64"
} else {
"unknown"
};
let strings = [
"Linux", // sysname

View File

@ -10,12 +10,14 @@
//! - getppid
use super::*;
use bitflags::bitflags;
use core::fmt::Debug;
use linux_object::fs::INodeExt;
use linux_object::loader::LinuxElfLoader;
use bitflags::bitflags;
use kernel_hal::context::UserContextField;
use linux_object::thread::{CurrentThreadExt, ThreadExt};
use linux_object::time::*;
use linux_object::time::TimeSpec;
use linux_object::{fs::INodeExt, loader::LinuxElfLoader};
impl Syscall<'_> {
/// Fork the current process. Return the child's PID.
@ -23,12 +25,10 @@ impl Syscall<'_> {
info!("fork:");
let new_proc = Process::fork_from(self.zircon_process(), false)?; // old pt NULL here
let new_thread = Thread::create_linux(&new_proc)?;
#[cfg(not(target_arch = "riscv64"))]
new_thread.start_with_regs(GeneralRegs::new_fork(self.regs), self.thread_fn)?;
#[cfg(target_arch = "riscv64")]
new_thread.start_with_context(self.context, self.thread_fn)?;
let mut new_ctx = self.thread.context_cloned()?;
new_ctx.set_field(UserContextField::ReturnValue, 0);
new_thread.with_context(|ctx| *ctx = new_ctx)?;
new_thread.start(self.thread_fn)?;
info!("fork: {} -> {}", self.zircon_process().id(), new_proc.id());
Ok(new_proc.id() as usize)
@ -39,11 +39,10 @@ impl Syscall<'_> {
info!("vfork:");
let new_proc = Process::fork_from(self.zircon_process(), true)?;
let new_thread = Thread::create_linux(&new_proc)?;
#[cfg(not(target_arch = "riscv64"))]
new_thread.start_with_regs(GeneralRegs::new_fork(self.regs), self.thread_fn)?;
#[cfg(target_arch = "riscv64")]
new_thread.start_with_context(self.context, self.thread_fn)?;
let mut new_ctx = self.thread.context_cloned()?;
new_ctx.set_field(UserContextField::ReturnValue, 0);
new_thread.with_context(|ctx| *ctx = new_ctx)?;
new_thread.start(self.thread_fn)?;
let new_proc: Arc<dyn KernelObject> = new_proc;
info!(
@ -85,14 +84,12 @@ impl Syscall<'_> {
panic!("unsupported sys_clone flags: {:#x}", flags);
}
let new_thread = Thread::create_linux(self.zircon_process())?;
#[cfg(not(target_arch = "riscv64"))]
{
let regs = GeneralRegs::new_clone(self.regs, newsp, newtls);
new_thread.start_with_regs(regs, self.thread_fn)?;
}
#[cfg(target_arch = "riscv64")]
new_thread.start_with_context(self.context, self.thread_fn)?;
let mut new_ctx = self.thread.context_cloned()?;
new_ctx.set_field(UserContextField::StackPointer, newsp);
new_ctx.set_field(UserContextField::ThreadPointer, newtls);
new_ctx.set_field(UserContextField::ReturnValue, 0);
new_thread.with_context(|ctx| *ctx = new_ctx)?;
new_thread.start(self.thread_fn)?;
let tid = new_thread.id();
info!("clone: {} -> {}", self.thread.id(), tid);
@ -196,9 +193,6 @@ impl Syscall<'_> {
};
let (entry, sp) = loader.load(&vmar, &data, args, envs, path.clone())?;
// Activate page table
// vmar.activate();
// Modify exec path
proc.set_execute_path(&path);
@ -206,26 +200,11 @@ impl Syscall<'_> {
// self.zircon_process().signal_set(Signal::SIGNALED);
// Workaround, the child process could NOT exit correctly
#[cfg(not(target_arch = "riscv64"))]
{
*self.regs = GeneralRegs::new_fn(entry, sp, 0, 0);
}
#[cfg(target_arch = "riscv64")]
{
self.context.general = GeneralRegs::new_fn(entry, sp, 0, 0);
self.context.sepc = entry;
info!(
"execve: PageTable: {:#x}, entry: {:#x}, sp: {:#x}",
self.zircon_process().vmar().table_phys(),
self.context.sepc,
self.context.general.sp
);
}
self.thread
.with_context(|ctx| ctx.setup_uspace(entry, sp, 0, 0))?;
Ok(0)
}
//
// pub fn sys_yield(&self) -> SysResult {
// thread::yield_now();
// Ok(0)
@ -370,66 +349,3 @@ bitflags! {
const IO = 1 << 31;
}
}
trait RegExt {
fn new_fn(entry: usize, sp: usize, arg1: usize, arg2: usize) -> Self;
fn new_clone(regs: &Self, newsp: usize, newtls: usize) -> Self;
fn new_fork(regs: &Self) -> Self;
}
#[cfg(target_arch = "x86_64")]
impl RegExt for GeneralRegs {
fn new_fn(entry: usize, sp: usize, arg1: usize, arg2: usize) -> Self {
GeneralRegs {
rip: entry,
rsp: sp,
rdi: arg1,
rsi: arg2,
// FIXME: set IOPL = 0 when IO port bitmap is supported
rflags: 0x3202, // IOPL = 3, enable interrupt
..Default::default()
}
}
fn new_clone(regs: &Self, newsp: usize, newtls: usize) -> Self {
GeneralRegs {
rax: 0,
rsp: newsp,
fsbase: newtls,
..*regs
}
}
fn new_fork(regs: &Self) -> Self {
GeneralRegs { rax: 0, ..*regs }
}
}
#[cfg(target_arch = "riscv64")]
impl RegExt for GeneralRegs {
fn new_fn(entry: usize, sp: usize, arg1: usize, arg2: usize) -> Self {
info!(
"new_fn(), Did NOT save ip:{:#x} register! x_x Saved sp: {:#x}",
entry, sp
);
GeneralRegs {
sp,
a0: arg1,
a1: arg2,
..Default::default()
}
}
fn new_clone(regs: &Self, newsp: usize, newtls: usize) -> Self {
GeneralRegs {
a0: 0,
sp: newsp,
tp: newtls,
..*regs
}
}
//设置了返回值为0
fn new_fork(regs: &Self) -> Self {
GeneralRegs { a0: 0, ..*regs }
}
}

View File

@ -6,7 +6,7 @@ use {
/// Create kcounter VMOs from kernel memory.
/// Return (KCOUNTER_NAMES_VMO, KCOUNTER_VMO).
#[cfg(target_os = "none")]
#[cfg(not(feature = "libos"))]
pub fn create_kcounter_vmo() -> (Arc<VmObject>, Arc<VmObject>) {
const HEADER_SIZE: usize = size_of::<KCounterVmoHeader>();
const DESC_SIZE: usize = size_of::<KCounterDescItem>();
@ -50,7 +50,7 @@ pub fn create_kcounter_vmo() -> (Arc<VmObject>, Arc<VmObject>) {
/// Create kcounter VMOs.
/// NOTE: kcounter is not supported in libos.
#[cfg(not(target_os = "none"))]
#[cfg(feature = "libos")]
pub fn create_kcounter_vmo() -> (Arc<VmObject>, Arc<VmObject>) {
const HEADER_SIZE: usize = size_of::<KCounterVmoHeader>();
let counter_name_vmo = VmObject::new_paged(1);

View File

@ -8,15 +8,17 @@
extern crate alloc;
#[macro_use]
extern crate log;
#[macro_use]
extern crate cfg_if;
cfg_if::cfg_if! {
cfg_if! {
if #[cfg(any(feature = "linux", doc))] {
#[doc(cfg(feature = "linux"))]
pub mod linux;
}
}
cfg_if::cfg_if! {
cfg_if! {
if #[cfg(any(feature = "zircon", doc))] {
mod kcounter;

View File

@ -1,23 +1,14 @@
//! Run Linux process and manage trap/interrupt/syscall.
use {
alloc::{boxed::Box, string::String, sync::Arc, vec::Vec},
core::{future::Future, pin::Pin},
linux_object::{
fs::{vfs::FileSystem, INodeExt},
loader::LinuxElfLoader,
process::ProcessExt,
thread::{CurrentThreadExt, ThreadExt},
},
linux_syscall::Syscall,
zircon_object::task::*,
zircon_object::{object::KernelObject, ZxError, ZxResult},
};
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use core::{future::Future, pin::Pin};
use kernel_hal::context::UserContext;
#[cfg(target_arch = "x86_64")]
use kernel_hal::context::GeneralRegs;
use kernel_hal::context::{TrapReason, UserContext, UserContextField};
use linux_object::fs::{vfs::FileSystem, INodeExt};
use linux_object::thread::{CurrentThreadExt, ThreadExt};
use linux_object::{loader::LinuxElfLoader, process::ProcessExt};
use zircon_object::task::{CurrentThread, Job, Process, Thread, ThreadState};
use zircon_object::{object::KernelObject, ZxError, ZxResult};
/// Create and run main Linux process
pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) -> Arc<Process> {
@ -42,7 +33,7 @@ pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) ->
let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs, path).unwrap();
thread
.start(entry, sp, 0, 0, thread_fn)
.start_with_entry(entry, sp, 0, 0, thread_fn)
.expect("failed to start main thread");
proc
}
@ -63,143 +54,99 @@ async fn run_user(thread: CurrentThread) {
kernel_hal::thread::set_tid(thread.id(), thread.proc().id());
loop {
// wait
let mut cx = thread.wait_for_run().await;
let mut ctx = thread.wait_for_run().await;
if thread.state() == ThreadState::Dying {
break;
}
// run
trace!("go to user: {:#x?}", cx);
kernel_hal::context::context_run(&mut cx);
trace!("back from user: {:#x?}", cx);
// handle trap/interrupt/syscall
trace!("go to user: {:#x?}", ctx);
ctx.enter_uspace();
trace!("back from user: {:#x?}", ctx);
if let Err(err) = handle_user_trap(&thread, &mut cx).await {
// handle trap/interrupt/syscall
if let Err(err) = handle_user_trap(&thread, ctx).await {
thread.exit_linux(err as i32);
}
thread.end_running(cx);
}
}
async fn handle_user_trap(thread: &CurrentThread, cx: &mut UserContext) -> ZxResult {
let pid = thread.proc().id();
async fn handle_user_trap(thread: &CurrentThread, mut ctx: Box<UserContext>) -> ZxResult {
let reason = ctx.trap_reason();
#[cfg(target_arch = "x86_64")]
match cx.trap_num {
0x100 => handle_syscall(thread, &mut cx.general).await,
0x20..=0xff => {
kernel_hal::interrupt::handle_irq(cx.trap_num);
// TODO: configurable
if cx.trap_num == 0xf1 {
if let TrapReason::Syscall = reason {
let num = syscall_num(&ctx);
let args = syscall_args(&ctx);
ctx.advance_pc(reason);
thread.put_context(ctx);
let mut syscall = linux_syscall::Syscall {
thread,
thread_fn,
syscall_entry: kernel_hal::context::syscall_entry as usize,
};
let ret = syscall.syscall(num as u32, args).await as usize;
thread.with_context(|ctx| ctx.set_field(UserContextField::ReturnValue, ret))?;
return Ok(());
}
thread.put_context(ctx);
match reason {
TrapReason::Interrupt(vector) => {
kernel_hal::interrupt::handle_irq(vector);
kernel_hal::thread::yield_now().await;
}
}
0xe => {
let (vaddr, flags) = kernel_hal::context::fetch_page_fault_info(cx.error_code);
warn!(
"page fault from user mode @ {:#x}({:?}), pid={}",
vaddr, flags, pid
);
let vmar = thread.proc().vmar();
if let Err(err) = vmar.handle_page_fault(vaddr, flags) {
error!(
"Failed to handle page Fault from user mode @ {:#x}({:?}): {:?}\n{:#x?}",
vaddr, flags, err, cx
);
return Err(err);
}
}
_ => {
error!("not supported interrupt from user mode. {:#x?}", cx);
return Err(ZxError::NOT_SUPPORTED);
}
}
// UserContext
#[cfg(target_arch = "riscv64")]
{
let trap_num = kernel_hal::context::fetch_trap_num(cx);
let is_interrupt = ((trap_num >> (core::mem::size_of::<usize>() * 8 - 1)) & 1) == 1;
let trap_num = trap_num & 0xfff;
if is_interrupt {
kernel_hal::interrupt::handle_irq(trap_num);
// Timer
if trap_num == 5 {
kernel_hal::thread::yield_now().await;
}
} else {
match trap_num {
// syscall
8 => handle_syscall(thread, cx).await,
// PageFault
12 | 13 | 15 => {
let (vaddr, flags) = kernel_hal::context::fetch_page_fault_info(trap_num);
warn!(
"page fault from user mode @ {:#x}({:?}), pid={}",
vaddr, flags, pid
);
let vmar = thread.proc().vmar();
if let Err(err) = vmar.handle_page_fault(vaddr, flags) {
error!(
"Failed to handle page Fault from user mode @ {:#x}({:?}): {:?}\n{:#x?}",
vaddr, flags, err, cx
);
return Err(err);
}
}
_ => {
error!(
"not supported pid: {} exception {} from user mode. {:#x?}",
pid, trap_num, cx
);
return Err(ZxError::NOT_SUPPORTED);
}
}
}
}
Ok(())
}
/// syscall handler entry
#[cfg(target_arch = "x86_64")]
async fn handle_syscall(thread: &CurrentThread, regs: &mut GeneralRegs) {
trace!("syscall: {:#x?}", regs);
let num = regs.rax as u32;
let args = [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9];
let mut syscall = Syscall {
thread,
syscall_entry: kernel_hal::context::syscall_entry as usize,
thread_fn,
regs,
};
regs.rax = syscall.syscall(num, args).await as usize;
TrapReason::PageFault(vaddr, flags) => {
info!("page fault from user mode @ {:#x}({:?})", vaddr, flags);
let vmar = thread.proc().vmar();
vmar.handle_page_fault(vaddr, flags).map_err(|err| {
error!(
"failed to handle page fault from user mode @ {:#x}({:?}): {:?}\n{:#x?}",
vaddr,
flags,
err,
thread.context_cloned(),
);
err
})
}
_ => {
error!(
"unsupported trap from user mode: {:x?} {:#x?}",
reason,
thread.context_cloned(),
);
Err(ZxError::NOT_SUPPORTED)
}
}
}
#[cfg(target_arch = "riscv64")]
async fn handle_syscall(thread: &CurrentThread, cx: &mut UserContext) {
trace!("syscall: {:#x?}", cx.general);
let num = cx.general.a7 as u32;
let args = [
cx.general.a0,
cx.general.a1,
cx.general.a2,
cx.general.a3,
cx.general.a4,
cx.general.a5,
];
// add before fork
cx.sepc += 4;
//注意, 此时的regs没有原context所有权故无法通过此regs修改寄存器
//let regs = &mut (cx.general as GeneralRegs);
let mut syscall = Syscall {
thread,
syscall_entry: kernel_hal::context::syscall_entry as usize,
context: cx,
thread_fn,
};
cx.general.a0 = syscall.syscall(num, args).await as usize;
fn syscall_num(ctx: &UserContext) -> usize {
let regs = ctx.general();
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
regs.rax
} else if #[cfg(target_arch = "aarch64")] {
regs.x8
} else if #[cfg(target_arch = "riscv64")] {
regs.a7
} else {
unimplemented!()
}
}
}
fn syscall_args(ctx: &UserContext) -> [usize; 6] {
let regs = ctx.general();
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
[regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9]
} else if #[cfg(target_arch = "aarch64")] {
[regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5]
} else if #[cfg(target_arch = "riscv64")] {
[regs.a0, regs.a1, regs.a2, regs.a3, regs.a4, regs.a5]
} else {
unimplemented!()
}
}
}

View File

@ -1,12 +1,19 @@
//! Run Zircon user program (userboot) and manage trap/interrupt/syscall.
use {
alloc::{boxed::Box, sync::Arc, vec::Vec},
core::{future::Future, pin::Pin},
xmas_elf::ElfFile,
zircon_object::{dev::*, ipc::*, object::*, task::*, util::elf_loader::*, vm::*},
zircon_syscall::Syscall,
};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use core::{future::Future, pin::Pin};
use xmas_elf::ElfFile;
use kernel_hal::context::{TrapReason, UserContext, UserContextField};
use kernel_hal::{MMUFlags, PAGE_SIZE};
use zircon_object::dev::{Resource, ResourceFlags, ResourceKind};
use zircon_object::ipc::{Channel, MessagePacket};
use zircon_object::kcounter;
use zircon_object::object::{Handle, KernelObject, Rights};
use zircon_object::task::{CurrentThread, ExceptionType, Job, Process, Thread, ThreadState};
use zircon_object::util::elf_loader::{ElfExt, VmarExt};
use zircon_object::vm::{VmObject, VmarFlags};
// These describe userboot itself
const K_PROC_SELF: usize = 0;
@ -119,11 +126,12 @@ pub fn run_userboot(zbi: impl AsRef<[u8]>, cmdline: &str) -> Arc<Process> {
let stack_bottom = vmar
.map(None, stack_vmo.clone(), 0, stack_vmo.len(), flags)
.unwrap();
#[cfg(target_arch = "x86_64")]
let sp = if cfg!(target_arch = "x86_64") {
// WARN: align stack to 16B, then emulate a 'call' (push rip)
let sp = stack_bottom + stack_vmo.len() - 8;
#[cfg(target_arch = "aarch64")]
let sp = stack_bottom + stack_vmo.len();
stack_bottom + stack_vmo.len() - 8
} else {
stack_bottom + stack_vmo.len()
};
// channel
let (user_channel, kernel_channel) = Channel::create();
@ -180,7 +188,7 @@ pub fn run_userboot(zbi: impl AsRef<[u8]>, cmdline: &str) -> Arc<Process> {
}
kcounter!(EXCEPTIONS_USER, "exceptions.user");
kcounter!(EXCEPTIONS_TIMER, "exceptions.timer");
kcounter!(EXCEPTIONS_IRQ, "exceptions.irq");
kcounter!(EXCEPTIONS_PGFAULT, "exceptions.pgfault");
fn thread_fn(thread: CurrentThread) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
@ -197,125 +205,123 @@ async fn run_user(thread: CurrentThread) {
thread.handle_exception(ExceptionType::ThreadStarting).await;
loop {
let mut cx = thread.wait_for_run().await;
// wait
let mut ctx = thread.wait_for_run().await;
if thread.state() == ThreadState::Dying {
break;
}
trace!("go to user: {:#x?}", cx);
// run
trace!("go to user: {:#x?}", ctx);
debug!("switch to {}|{}", thread.proc().name(), thread.name());
let tmp_time = kernel_hal::timer::timer_now().as_nanos();
// * Attention
// The code will enter a magic zone from here.
// `context run` will be executed into a wrapped library where context switching takes place.
// The details are available in the trapframe crate on crates.io.
kernel_hal::context::context_run(&mut cx);
// `enter_uspace` will be executed into a wrapped library where context switching takes place.
// The details are available in the `trapframe` crate on crates.io.
ctx.enter_uspace();
// Back from the userspace
let time = kernel_hal::timer::timer_now().as_nanos() - tmp_time;
thread.time_add(time);
trace!("back from user: {:#x?}", cx);
trace!("back from user: {:#x?}", ctx);
EXCEPTIONS_USER.add(1);
let trap_num = cx.trap_num;
thread.end_running(cx);
if let Err(e) = handler_user_trap(&thread, trap_num).await {
// handle trap/interrupt/syscall
if let Err(e) = handler_user_trap(&thread, ctx).await {
if let ExceptionType::ThreadExiting = e {
break;
}
thread.handle_exception(e).await;
}
}
thread.handle_exception(ExceptionType::ThreadExiting).await;
}
async fn handler_user_trap(thread: &CurrentThread, trap_num: usize) -> Result<(), ExceptionType> {
#[cfg(target_arch = "aarch64")]
match trap_num {
0 => handle_syscall(&thread).await,
_ => unimplemented!(),
}
#[cfg(target_arch = "x86_64")]
match trap_num {
0x100 => handle_syscall(thread).await,
0x20..=0xff => {
kernel_hal::interrupt::handle_irq(trap_num);
// TODO: configurable
if trap_num == 0xf1 {
EXCEPTIONS_TIMER.add(1);
kernel_hal::thread::yield_now().await;
}
}
0xe => {
EXCEPTIONS_PGFAULT.add(1);
let error_code = thread.with_context(|cx| cx.error_code);
let (vaddr, flags) = kernel_hal::context::fetch_page_fault_info(error_code);
info!(
"page fault from user mode {:#x} {:#x?} {:?}",
vaddr, error_code, flags
);
let vmar = thread.proc().vmar();
if let Err(err) = vmar.handle_page_fault(vaddr, flags) {
error!("handle_page_fault error: {:?}", err);
return Err(ExceptionType::FatalPageFault);
}
}
0x8 => thread.with_context(|cx| {
panic!("Double fault from user mode! {:#x?}", cx);
}),
num => {
return Err(match num {
0x1 => ExceptionType::HardwareBreakpoint,
0x3 => ExceptionType::SoftwareBreakpoint,
0x6 => ExceptionType::UndefinedInstruction,
0x17 => ExceptionType::UnalignedAccess,
_ => ExceptionType::General,
})
}
}
Ok(())
async fn handler_user_trap(
thread: &CurrentThread,
mut ctx: Box<UserContext>,
) -> Result<(), ExceptionType> {
let reason = ctx.trap_reason();
if let TrapReason::Syscall = reason {
let num = syscall_num(&ctx);
let args = syscall_args(&ctx);
ctx.advance_pc(reason);
thread.put_context(ctx);
let mut syscall = zircon_syscall::Syscall { thread, thread_fn };
let ret = syscall.syscall(num as u32, args).await as usize;
thread
.with_context(|ctx| ctx.set_field(UserContextField::ReturnValue, ret))
.map_err(|_| ExceptionType::ThreadExiting)?;
return Ok(());
}
async fn handle_syscall(thread: &CurrentThread) {
let (num, args) = thread.with_context(|cx| {
let regs = cx.general;
#[cfg(target_arch = "x86_64")]
let num = regs.rax as u32;
#[cfg(target_arch = "aarch64")]
let num = regs.x16 as u32;
// LibOS: Function call ABI
#[cfg(feature = "libos")]
#[cfg(target_arch = "x86_64")]
let args = unsafe {
let a6 = (regs.rsp as *const usize).read();
let a7 = (regs.rsp as *const usize).add(1).read();
[
regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9, a6, a7,
]
};
// RealOS: Zircon syscall ABI
#[cfg(not(feature = "libos"))]
#[cfg(target_arch = "x86_64")]
let args = [
regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9, regs.r12, regs.r13,
];
// ARM64
#[cfg(target_arch = "aarch64")]
let args = [
regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5, regs.x6, regs.x7,
];
(num, args)
});
let mut syscall = Syscall { thread, thread_fn };
let ret = syscall.syscall(num, args).await as usize;
thread.with_context(|cx| {
#[cfg(target_arch = "x86_64")]
{
cx.general.rax = ret;
thread.put_context(ctx);
match reason {
TrapReason::Interrupt(vector) => {
kernel_hal::interrupt::handle_irq(vector);
kernel_hal::thread::yield_now().await;
EXCEPTIONS_IRQ.add(1); // FIXME
Ok(())
}
TrapReason::PageFault(vaddr, flags) => {
EXCEPTIONS_PGFAULT.add(1);
info!("page fault from user mode @ {:#x}({:?})", vaddr, flags);
let vmar = thread.proc().vmar();
vmar.handle_page_fault(vaddr, flags).map_err(|err| {
error!(
"failed to handle page fault from user mode @ {:#x}({:?}): {:?}\n{:#x?}",
vaddr,
flags,
err,
thread.context_cloned()
);
ExceptionType::FatalPageFault
})
}
TrapReason::UndefinedInstruction => Err(ExceptionType::UndefinedInstruction),
TrapReason::SoftwareBreakpoint => Err(ExceptionType::SoftwareBreakpoint),
TrapReason::HardwareBreakpoint => Err(ExceptionType::HardwareBreakpoint),
TrapReason::UnalignedAccess => Err(ExceptionType::UnalignedAccess),
TrapReason::GernelFault(_) => Err(ExceptionType::General),
_ => unreachable!(),
}
}
fn syscall_num(ctx: &UserContext) -> usize {
let regs = ctx.general();
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
regs.rax
} else if #[cfg(target_arch = "aarch64")] {
regs.x16
} else if #[cfg(target_arch = "riscv64")] {
regs.a7
} else {
unimplemented!()
}
}
}
fn syscall_args(ctx: &UserContext) -> [usize; 8] {
let regs = ctx.general();
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
if cfg!(feature = "libos") {
let arg7 = unsafe{ (regs.rsp as *const usize).read() };
let arg8 = unsafe{ (regs.rsp as *const usize).add(1).read() };
[regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9, arg7, arg8]
} else {
[regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9, regs.r12, regs.r13]
}
} else if #[cfg(target_arch = "aarch64")] {
[regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5, regs.x6, regs.x7]
} else if #[cfg(target_arch = "riscv64")] {
[regs.a0, regs.a1, regs.a2, regs.a3, regs.a4, regs.a5, regs.a6, regs.a7]
} else {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
{
cx.general.x0 = ret;
}
});
}

View File

@ -50,7 +50,7 @@ rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
buddy_system_allocator = "0.7"
executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
executor = { git = "https://github.com/rcore-os/executor.git", rev = "04b6b7b" }
# Bare-metal mode on x86_64
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]

View File

@ -432,7 +432,7 @@ pub fn wait_signal_many(
#[macro_export]
macro_rules! impl_kobject {
($class:ident $( $fn:tt )*) => {
impl KernelObject for $class {
impl $crate::object::KernelObject for $class {
fn id(&self) -> KoID {
self.base.id
}
@ -457,7 +457,7 @@ macro_rules! impl_kobject {
fn signal_change(&self, clear: Signal, set: Signal) {
self.base.signal_change(clear, set);
}
fn add_signal_callback(&self, callback: SignalHandler) {
fn add_signal_callback(&self, callback: $crate::object::SignalHandler) {
self.base.add_signal_callback(callback);
}
$( $fn )*
@ -467,6 +467,7 @@ macro_rules! impl_kobject {
&self,
f: &mut core::fmt::Formatter<'_>,
) -> core::result::Result<(), core::fmt::Error> {
use $crate::object::KernelObject;
f.debug_tuple(&stringify!($class))
.field(&self.id())
.field(&self.name())
@ -484,14 +485,14 @@ macro_rules! define_count_helper {
struct CountHelper(());
impl CountHelper {
fn new() -> Self {
kcounter!(CREATE_COUNT, concat!(stringify!($class), ".create"));
$crate::kcounter!(CREATE_COUNT, concat!(stringify!($class), ".create"));
CREATE_COUNT.add(1);
CountHelper(())
}
}
impl Drop for CountHelper {
fn drop(&mut self) {
kcounter!(DESTROY_COUNT, concat!(stringify!($class), ".destroy"));
$crate::kcounter!(DESTROY_COUNT, concat!(stringify!($class), ".destroy"));
DESTROY_COUNT.add(1);
}
}

View File

@ -1,7 +1,14 @@
use {
super::*, crate::ipc::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec,
core::mem::size_of, futures::channel::oneshot, kernel_hal::context::UserContext, spin::Mutex,
};
use alloc::{sync::Arc, vec::Vec};
use core::mem::size_of;
use futures::channel::oneshot;
use kernel_hal::context::{TrapReason, UserContext};
use spin::Mutex;
use super::{Job, Task, Thread};
use crate::ipc::{Channel, MessagePacket};
use crate::object::{Handle, KObjectBase, KernelObject, KoID, Rights, Signal};
use crate::{impl_kobject, ZxError, ZxResult};
/// Kernel-owned exception channel endpoint.
pub struct Exceptionate {
@ -77,7 +84,7 @@ impl Exceptionate {
let (object, closed) = ExceptionObject::create(exception.clone(), rights);
let msg = MessagePacket {
data: info.pack(),
handles: vec![Handle::new(object, Rights::DEFAULT_EXCEPTION)],
handles: alloc::vec![Handle::new(object, Rights::DEFAULT_EXCEPTION)],
};
channel.write(msg).map_err(|err| {
if err == ZxError::PEER_CLOSED {
@ -120,53 +127,67 @@ struct ExceptionHeader {
/// Data associated with an exception (siginfo in linux parlance)
/// Things available from regsets (e.g., pc) are not included here.
/// For an example list of things one might add, see linux siginfo.
#[cfg(target_arch = "x86_64")]
#[repr(transparent)]
#[derive(Debug, Default, Clone)]
struct ExceptionContext(ExceptionContextInner);
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
#[repr(C)]
#[derive(Debug, Default, Clone)]
struct ExceptionContext {
struct ExceptionContextInner {
vector: u64,
err_code: u64,
cr2: u64,
}
/// Data associated with an exception (siginfo in linux parlance)
/// Things available from regsets (e.g., pc) are not included here.
/// For an example list of things one might add, see linux siginfo.
#[cfg(target_arch = "aarch64")]
} else if #[cfg(target_arch = "aarch64")] {
#[repr(C)]
#[derive(Debug, Default, Clone)]
struct ExceptionContext {
struct ExceptionContextInner {
esr: u32,
padding1: u32,
_padding1: u32,
far: u64,
padding2: u64,
_padding2: u64,
}
#[cfg(target_arch = "riscv64")]
} else if #[cfg(target_arch = "riscv64")] {
#[repr(C)]
#[derive(Debug, Default, Clone)]
struct ExceptionContext {
padding1: u64,
padding2: u64,
padding3: u64,
struct ExceptionContextInner {
scause: u64,
stval: u64,
_padding: 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::context::fetch_page_fault_info(cx.error_code).0 as u64,
fn from_user_context(ctx: &UserContext) -> Self {
let fault_vaddr = if let TrapReason::PageFault(vaddr, _) = ctx.trap_reason() {
vaddr as u64
} else {
return Default::default();
};
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
Self(ExceptionContextInner {
vector: ctx.raw_trap_reason() as _,
err_code: ctx.error_code() as _,
cr2: fault_vaddr,
})
} else if #[cfg(target_arch = "aarch64")] {
Self(ExceptionContextInner {
esr: ctx.raw_trap_reason() as _,
far: fault_vaddr,
..Default::default()
})
} else if #[cfg(target_arch = "riscv64")] {
Self(ExceptionContextInner {
scause: ctx.raw_trap_reason() as _,
stval: fault_vaddr,
..Default::default()
})
}
}
#[cfg(target_arch = "aarch64")]
fn from_user_context(_cx: &UserContext) -> Self {
unimplemented!()
}
#[cfg(target_arch = "riscv64")]
fn from_user_context(_cx: &UserContext) -> Self {
unimplemented!()
}
}
@ -377,7 +398,7 @@ impl Exception {
};
if result == Err(ZxError::NEXT) && !self.type_.is_synth() {
// Nobody handled the exception, kill myself
self.thread.proc().exit(TASK_RETCODE_SYSCALL_KILL);
self.thread.proc().exit(super::TASK_RETCODE_SYSCALL_KILL);
}
}
@ -522,6 +543,7 @@ impl Iterator for JobDebuggerIterator {
#[cfg(test)]
mod tests {
use super::*;
use crate::task::*;
#[test]
fn exceptionate_iterator() {

View File

@ -447,7 +447,7 @@ mod tests {
let proc = Process::create(&root_job, "proc").expect("failed to create process");
let thread = Thread::create(&proc, "thread").expect("failed to create thread");
thread
.start(0, 0, 0, 0, |thread| {
.start(|thread| {
std::boxed::Box::pin(async {
println!("should not be killed");
async_std::task::sleep(Duration::from_millis(1000)).await;

View File

@ -1,12 +1,17 @@
use {
super::{exception::*, job::Job, job_policy::*, thread::Thread, *},
crate::{object::*, signal::Futex, vm::*},
alloc::{boxed::Box, sync::Arc, vec::Vec},
core::{any::Any, sync::atomic::AtomicI32},
futures::channel::oneshot::{self, Receiver, Sender},
hashbrown::HashMap,
spin::Mutex,
};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use core::{any::Any, sync::atomic::AtomicI32};
use futures::channel::oneshot::{self, Receiver, Sender};
use hashbrown::HashMap;
use spin::Mutex;
use super::exception::{ExceptionChannelType, Exceptionate};
use super::job_policy::{JobPolicy, PolicyAction, PolicyCondition};
use super::{Job, Task, Thread, ThreadFn};
use crate::object::{Handle, HandleBasicInfo, HandleValue, INVALID_HANDLE};
use crate::object::{KObjectBase, KernelObject, KoID, Rights, Signal};
use crate::{define_count_helper, impl_kobject};
use crate::{signal::Futex, vm::VmAddressRegion, ZxError, ZxResult};
/// Process abstraction
///
@ -153,11 +158,11 @@ impl Process {
/// // start the new thread
/// proc.start(&thread, 1, 4, Some(handle), 2, |thread| Box::pin(async move {
/// let cx = thread.wait_for_run().await;
/// assert_eq!(cx.general.rip, 1); // entry
/// assert_eq!(cx.general.rsp, 4); // stack_top
/// assert_eq!(cx.general.rdi, 3); // arg0 (handle)
/// assert_eq!(cx.general.rsi, 2); // arg1
/// thread.end_running(cx);
/// assert_eq!(cx.general().rip, 1); // entry
/// assert_eq!(cx.general().rsp, 4); // stack_top
/// assert_eq!(cx.general().rdi, 3); // arg0 (handle)
/// assert_eq!(cx.general().rsi, 2); // arg1
/// thread.put_context(cx);
/// })).unwrap();
///
/// # let object: Arc<dyn KernelObject> = thread.clone();
@ -186,16 +191,11 @@ impl Process {
handle_value = arg1.map_or(INVALID_HANDLE, |handle| inner.add_handle(handle));
}
thread.set_first_thread();
match thread.start(entry, stack, handle_value as usize, arg2, thread_fn) {
Ok(_) => Ok(()),
Err(err) => {
let mut inner = self.inner.lock();
if handle_value != INVALID_HANDLE {
inner.remove_handle(handle_value).ok();
}
Err(err)
}
let res = thread.start_with_entry(entry, stack, handle_value as usize, arg2, thread_fn);
if res.is_err() && handle_value != INVALID_HANDLE {
self.inner.lock().remove_handle(handle_value).ok();
}
res
}
/// Exit current process with `retcode`.
@ -551,7 +551,7 @@ impl Process {
impl Task for Process {
fn kill(&self) {
self.exit(TASK_RETCODE_SYSCALL_KILL);
self.exit(super::TASK_RETCODE_SYSCALL_KILL);
}
fn suspend(&self) {
@ -635,6 +635,8 @@ pub struct ProcessInfo {
#[cfg(test)]
mod tests {
use super::*;
use crate::object::KernelObject;
use crate::task::*;
#[test]
fn create() {

View File

@ -19,7 +19,7 @@ use {
/// let thread = Thread::create(&proc, "thread").unwrap();
///
/// // start the thread and never terminate
/// thread.start(0, 0, 0, 0, |thread| Box::pin(async move {
/// thread.start(|thread| Box::pin(async move {
/// loop { async_std::task::yield_now().await }
/// let _ = thread;
/// })).unwrap();

View File

@ -1,27 +1,22 @@
use {
super::exception::*,
super::process::Process,
super::*,
crate::object::*,
alloc::{boxed::Box, sync::Arc},
bitflags::bitflags,
core::{
any::Any,
future::Future,
ops::Deref,
pin::Pin,
task::{Context, Poll, Waker},
time::Duration,
},
futures::{channel::oneshot::*, future::FutureExt, pin_mut, select_biased},
kernel_hal::context::{GeneralRegs, UserContext},
spin::Mutex,
};
pub use self::thread_state::*;
mod thread_state;
pub use self::thread_state::ThreadStateKind;
use alloc::{boxed::Box, sync::Arc};
use core::task::{Context, Poll, Waker};
use core::time::Duration;
use core::{any::Any, future::Future, pin::Pin};
use bitflags::bitflags;
use futures::{channel::oneshot::*, future::FutureExt, pin_mut, select_biased};
use kernel_hal::context::UserContext;
use spin::Mutex;
use self::thread_state::ContextAccessState;
use super::{exception::*, Process, Task};
use crate::object::{KObjectBase, KoID, Signal};
use crate::{define_count_helper, impl_kobject, ZxError, ZxResult};
/// Runnable / computation entity
///
/// ## SYNOPSIS
@ -217,7 +212,7 @@ impl Thread {
ext: Box::new(ext),
exceptionate: Exceptionate::new(ExceptionChannelType::Thread),
inner: Mutex::new(ThreadInner {
context: Some(Box::new(UserContext::default())),
context: Some(Box::new(UserContext::new())),
..Default::default()
}),
});
@ -235,8 +230,39 @@ impl Thread {
&self.ext
}
/// Returns a copy of saved context of current thread, or `Err(ZxError::BAD_STATE)`
/// if the thread is running.
pub fn context_cloned(&self) -> ZxResult<UserContext> {
self.with_context(|ctx| ctx.clone())
}
/// Access saved context of current thread, or `Err(ZxError::BAD_STATE)` if
/// the thread is running.
pub fn with_context<T, F>(&self, f: F) -> ZxResult<T>
where
F: FnOnce(&mut UserContext) -> T,
{
let mut inner = self.inner.lock();
if let Some(ctx) = inner.context.as_mut() {
Ok(f(ctx))
} else {
Err(ZxError::BAD_STATE)
}
}
/// Start execution on the thread.
pub fn start(
pub fn start(self: &Arc<Self>, thread_fn: ThreadFn) -> ZxResult {
self.inner
.lock()
.change_state(ThreadState::Running, &self.base);
let current = CurrentThread(self.clone());
let future = thread_fn(current);
kernel_hal::thread::spawn(ThreadSwitchFuture::new(self.clone(), future));
Ok(())
}
/// Setup the instruction and stack pointer, then tart execution on the thread
pub fn start_with_entry(
self: &Arc<Self>,
entry: usize,
stack: usize,
@ -244,74 +270,8 @@ impl Thread {
arg2: usize,
thread_fn: ThreadFn,
) -> ZxResult {
{
let mut inner = self.inner.lock();
let context = inner.context.as_mut().ok_or(ZxError::BAD_STATE)?;
#[cfg(target_arch = "x86_64")]
{
context.general.rip = entry;
context.general.rsp = stack;
context.general.rdi = arg1;
context.general.rsi = arg2;
// FIXME: set IOPL = 0 when IO port bitmap is supported
context.general.rflags = 0x3202; // IOPL = 3, enable interrupt
}
#[cfg(target_arch = "aarch64")]
{
context.elr = entry;
context.sp = stack;
context.general.x0 = arg1;
context.general.x1 = arg2;
}
#[cfg(target_arch = "riscv64")]
{
context.sepc = entry;
context.general.sp = stack;
context.general.a0 = arg1;
context.general.a1 = arg2;
context.sstatus = 1 << 18 | 3 << 13 | 1 << 5; // SUM | FS | SPIE
}
inner.change_state(ThreadState::Running, &self.base);
}
self.spawn(thread_fn);
Ok(())
}
/// Start execution with given registers.
pub fn start_with_regs(self: &Arc<Self>, regs: GeneralRegs, thread_fn: ThreadFn) -> ZxResult {
{
let mut inner = self.inner.lock();
let context = inner.context.as_mut().ok_or(ZxError::BAD_STATE)?;
context.general = regs;
#[cfg(target_arch = "x86_64")]
{
// FIXME: set IOPL = 0 when IO port bitmap is supported
context.general.rflags |= 0x3202; // IOPL = 3, enable interrupt
}
inner.change_state(ThreadState::Running, &self.base);
}
self.spawn(thread_fn);
Ok(())
}
/// Similar to start_with_regs(), but change a parameter: context
pub fn start_with_context(self: &Arc<Self>, cx: &UserContext, thread_fn: ThreadFn) -> ZxResult {
{
let mut inner = self.inner.lock();
let context = inner.context.as_mut().ok_or(ZxError::BAD_STATE)?;
context.general = cx.general;
context.set_syscall_ret(0);
#[cfg(target_arch = "riscv64")]
{
context.sepc = cx.sepc;
context.sstatus = 1 << 18 | 3 << 13 | 1 << 5; // SUM | FS | SPIE
debug!("start_with_regs_pc(), sepc: {:#x}", context.sepc);
}
inner.change_state(ThreadState::Running, &self.base);
}
self.spawn(thread_fn);
Ok(())
self.with_context(|ctx| ctx.setup_uspace(entry, stack, arg1, arg2))?;
self.start(thread_fn)
}
/// Stop the thread. Internal implementation of `exit` and `kill`.
@ -432,31 +392,6 @@ impl Thread {
f(&mut self.inner.lock().flags)
}
/// Set the thread local fsbase register on x86_64.
#[cfg(target_arch = "x86_64")]
pub fn set_fsbase(&self, fsbase: usize) -> ZxResult {
let mut inner = self.inner.lock();
let context = inner.context.as_mut().ok_or(ZxError::BAD_STATE)?;
context.general.fsbase = fsbase;
Ok(())
}
/// Set the thread local gsbase register on x86_64.
#[cfg(target_arch = "x86_64")]
pub fn set_gsbase(&self, gsbase: usize) -> ZxResult {
let mut inner = self.inner.lock();
let context = inner.context.as_mut().ok_or(ZxError::BAD_STATE)?;
context.general.gsbase = gsbase;
Ok(())
}
/// Spawn the future returned by `thread_fn` in this thread.
fn spawn(self: &Arc<Self>, thread_fn: ThreadFn) {
let current = CurrentThread(self.clone());
let future = thread_fn(current);
kernel_hal::thread::spawn(ThreadSwitchFuture::new(self.clone(), future));
}
/// Terminate the current running thread.
fn terminate(&self) {
let mut inner = self.inner.lock();
@ -555,25 +490,13 @@ impl CurrentThread {
}
/// The thread ends running and takes back the context.
pub fn end_running(&self, context: Box<UserContext>) {
pub fn put_context(&self, context: Box<UserContext>) {
let mut inner = self.inner.lock();
inner.context = Some(context);
let state = inner.state;
inner.change_state(state, &self.base);
}
/// Access saved context of current thread.
///
/// Will panic if the context is not availiable.
pub fn with_context<T, F>(&self, f: F) -> T
where
F: FnOnce(&mut UserContext) -> T,
{
let mut inner = self.inner.lock();
let mut cx = inner.context.as_mut().unwrap();
f(&mut cx)
}
/// Run async future and change state while blocking.
pub async fn blocking_run<F, T, FT>(
&self,
@ -689,9 +612,8 @@ impl CurrentThread {
}
}
impl Deref for CurrentThread {
impl core::ops::Deref for CurrentThread {
type Target = Arc<Thread>;
fn deref(&self) -> &Self::Target {
&self.0
}
@ -798,8 +720,9 @@ impl Future for ThreadSwitchFuture {
#[cfg(test)]
mod tests {
use super::job::Job;
use super::*;
use crate::object::*;
use crate::task::*;
use kernel_hal::timer::timer_now;
#[test]
@ -825,12 +748,12 @@ mod tests {
// function for new thread
async fn new_thread(thread: CurrentThread) {
let cx = thread.wait_for_run().await;
assert_eq!(cx.general.rip, 1);
assert_eq!(cx.general.rsp, 4);
assert_eq!(cx.general.rdi, 3);
assert_eq!(cx.general.rsi, 2);
assert_eq!(cx.general().rip, 1);
assert_eq!(cx.general().rsp, 4);
assert_eq!(cx.general().rdi, 3);
assert_eq!(cx.general().rsi, 2);
async_std::task::sleep(Duration::from_millis(10)).await;
thread.end_running(cx);
thread.put_context(cx);
}
// start a new thread
@ -937,7 +860,7 @@ mod tests {
let proc = Process::create(&root_job, "proc").expect("failed to create process");
let thread = Thread::create(&proc, "thread").expect("failed to create thread");
const SIZE: usize = core::mem::size_of::<GeneralRegs>();
const SIZE: usize = core::mem::size_of::<kernel_hal::context::GeneralRegs>();
let mut buf = [0; 10];
assert_eq!(
thread.read_state(ThreadStateKind::General, &mut buf).err(),
@ -985,15 +908,13 @@ mod tests {
assert_eq!(thread.state(), ThreadState::New);
thread
.start(0, 0, 0, 0, |thread| Box::pin(new_thread(thread)))
.unwrap();
thread.start(|thread| Box::pin(new_thread(thread))).unwrap();
async fn new_thread(thread: CurrentThread) {
assert_eq!(thread.state(), ThreadState::Running);
// without suspend
let context = thread.wait_for_run().await;
thread.end_running(context);
thread.put_context(context);
// with suspend
thread.suspend();

View File

@ -13,35 +13,25 @@ numeric_enum! {
Vector = 2,
Debug = 4,
SingleStep = 5,
FS = 6,
GS = 7,
}
}
pub(super) trait ContextExt {
pub(super) trait ContextAccessState {
fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult<usize>;
fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult;
}
impl ContextExt for UserContext {
impl ContextAccessState for UserContext {
fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult<usize> {
match kind {
ThreadStateKind::General => buf.write_struct(&self.general),
#[cfg(target_arch = "x86_64")]
ThreadStateKind::FS => buf.write_struct(&self.general.fsbase),
#[cfg(target_arch = "x86_64")]
ThreadStateKind::GS => buf.write_struct(&self.general.gsbase),
ThreadStateKind::General => buf.write_struct(self.general()),
_ => Err(ZxError::NOT_SUPPORTED),
}
}
fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult {
match kind {
ThreadStateKind::General => self.general = buf.read_struct()?,
#[cfg(target_arch = "x86_64")]
ThreadStateKind::FS => self.general.fsbase = buf.read_struct()?,
#[cfg(target_arch = "x86_64")]
ThreadStateKind::GS => self.general.gsbase = buf.read_struct()?,
ThreadStateKind::General => *self.general_mut() = buf.read_struct()?,
_ => return Err(ZxError::NOT_SUPPORTED),
}
Ok(())

View File

@ -9,18 +9,19 @@ extern crate alloc;
#[macro_use]
extern crate log;
use {
self::time::Deadline,
alloc::sync::Arc,
core::{
convert::TryFrom,
sync::atomic::{AtomicI32, Ordering},
},
futures::pin_mut,
kernel_hal::user::*,
zircon_object::object::*,
zircon_object::task::{CurrentThread, ThreadFn},
};
use alloc::sync::Arc;
use core::convert::TryFrom;
use core::sync::atomic::{AtomicI32, Ordering};
use futures::pin_mut;
use kernel_hal::user::{IoVecIn, IoVecOut, UserInOutPtr, UserInPtr, UserOutPtr};
use zircon_object::object::{wait_signal_many, KernelObject, KoID, Rights, Signal};
use zircon_object::object::{Handle, HandleBasicInfo, HandleValue, INVALID_HANDLE};
use zircon_object::task::{CurrentThread, ThreadFn};
use zircon_object::{ZxError, ZxResult};
use self::consts::SyscallType as Sys;
use self::time::Deadline;
mod channel;
mod consts;
@ -47,8 +48,6 @@ mod time;
mod vmar;
mod vmo;
use consts::SyscallType as Sys;
pub struct Syscall<'a> {
pub thread: &'a CurrentThread,
pub thread_fn: ThreadFn,

View File

@ -139,14 +139,14 @@ impl Syscall<'_> {
Property::RegisterFs => {
let thread = proc.get_object::<Thread>(handle_value)?;
let fsbase = UserInPtr::<usize>::from_addr_size(buffer, buffer_size)?.read()?;
thread.set_fsbase(fsbase)?;
thread.with_context(|ctx| ctx.general_mut().fsbase = fsbase)?;
Ok(())
}
#[cfg(target_arch = "x86_64")]
Property::RegisterGs => {
let thread = proc.get_object::<Thread>(handle_value)?;
let gsbase = UserInPtr::<usize>::from_addr_size(buffer, buffer_size)?.read()?;
thread.set_gsbase(gsbase)?;
thread.with_context(|ctx| ctx.general_mut().gsbase = gsbase)?;
Ok(())
}
Property::ProcessBreakOnLoad => {
@ -184,7 +184,7 @@ impl Syscall<'_> {
Ok(())
}
_ => {
warn!("unknown property");
warn!("unknown property {:?}", property);
Err(ZxError::INVALID_ARGS)
}
}

View File

@ -198,7 +198,7 @@ impl Syscall<'_> {
if thread.proc().status() != Status::Running {
return Err(ZxError::BAD_STATE);
}
thread.start(entry, stack, arg1, arg2, self.thread_fn)?;
thread.start_with_entry(entry, stack, arg1, arg2, self.thread_fn)?;
Ok(())
}