forked from rcore-os/zCore
Add helper functions for UserContext to kernel-hal
This commit is contained in:
parent
d791c52700
commit
30831ed711
|
@ -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" }
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ mod sbi;
|
|||
mod trap;
|
||||
|
||||
pub mod config;
|
||||
pub mod context;
|
||||
pub mod cpu;
|
||||
pub mod interrupt;
|
||||
pub mod mem;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ mod drivers;
|
|||
mod trap;
|
||||
|
||||
pub mod config;
|
||||
pub mod context;
|
||||
pub mod cpu;
|
||||
pub mod interrupt;
|
||||
pub mod mem;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,52 +1,10 @@
|
|||
//! User context.
|
||||
|
||||
use crate::{MMUFlags, VirtAddr};
|
||||
use core::fmt;
|
||||
use trapframe::UserContext as UserContextInner;
|
||||
|
||||
pub use trapframe::{GeneralRegs, UserContext};
|
||||
|
||||
#[repr(C, align(16))]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct VectorRegs {
|
||||
pub fcw: u16,
|
||||
pub fsw: u16,
|
||||
pub ftw: u8,
|
||||
pub _pad0: u8,
|
||||
pub fop: u16,
|
||||
pub fip: u32,
|
||||
pub fcs: u16,
|
||||
pub _pad1: u16,
|
||||
|
||||
pub fdp: u32,
|
||||
pub fds: u16,
|
||||
pub _pad2: u16,
|
||||
pub mxcsr: u32,
|
||||
pub mxcsr_mask: u32,
|
||||
|
||||
pub mm: [U128; 8],
|
||||
pub xmm: [U128; 16],
|
||||
pub reserved: [U128; 3],
|
||||
pub available: [U128; 3],
|
||||
}
|
||||
|
||||
// https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol1/o_7281d5ea06a5b67a-274.html
|
||||
impl Default for VectorRegs {
|
||||
fn default() -> Self {
|
||||
VectorRegs {
|
||||
fcw: 0x37f,
|
||||
mxcsr: 0x1f80,
|
||||
..unsafe { core::mem::zeroed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// workaround: libcore has bug on Debug print u128 ??
|
||||
#[derive(Default, Clone, Copy)]
|
||||
#[repr(C, align(16))]
|
||||
pub struct U128(pub [u64; 2]);
|
||||
|
||||
impl fmt::Debug for U128 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:#016x}_{:016x}", self.0[1], self.0[0])
|
||||
}
|
||||
}
|
||||
pub use trapframe::GeneralRegs;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "libos")] {
|
||||
|
@ -58,3 +16,310 @@ cfg_if! {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
pub fcw: u16,
|
||||
pub fsw: u16,
|
||||
pub ftw: u8,
|
||||
pub _pad0: u8,
|
||||
pub fop: u16,
|
||||
pub fip: u32,
|
||||
pub fcs: u16,
|
||||
pub _pad1: u16,
|
||||
|
||||
pub fdp: u32,
|
||||
pub fds: u16,
|
||||
pub _pad2: u16,
|
||||
pub mxcsr: u32,
|
||||
pub mxcsr_mask: u32,
|
||||
|
||||
pub mm: [U128; 8],
|
||||
pub xmm: [U128; 16],
|
||||
pub reserved: [U128; 3],
|
||||
pub available: [U128; 3],
|
||||
}
|
||||
|
||||
// https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol1/o_7281d5ea06a5b67a-274.html
|
||||
impl Default for VectorRegs {
|
||||
fn default() -> Self {
|
||||
VectorRegs {
|
||||
fcw: 0x37f,
|
||||
mxcsr: 0x1f80,
|
||||
..unsafe { core::mem::zeroed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// workaround: libcore has bug on Debug print u128 ??
|
||||
#[derive(Default, Clone, Copy)]
|
||||
#[repr(C, align(16))]
|
||||
pub struct U128(pub [u64; 2]);
|
||||
|
||||
impl fmt::Debug for U128 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:#016x}_{:016x}", self.0[1], self.0[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! CPU information.
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::hal_fn::cpu {
|
||||
fn cpu_id() -> u8 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<'_> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,36 +193,18 @@ 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);
|
||||
|
||||
// TODO: use right signal
|
||||
//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.zircon_process().signal_set(Signal::SIGNALED);
|
||||
// Workaround, the child process could NOT exit correctly
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
kernel_hal::thread::yield_now().await;
|
||||
}
|
||||
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;
|
||||
Ok(())
|
||||
}
|
||||
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
|
||||
);
|
||||
TrapReason::PageFault(vaddr, flags) => {
|
||||
info!("page fault from user mode @ {:#x}({:?})", vaddr, flags);
|
||||
let vmar = thread.proc().vmar();
|
||||
if let Err(err) = vmar.handle_page_fault(vaddr, flags) {
|
||||
vmar.handle_page_fault(vaddr, flags).map_err(|err| {
|
||||
error!(
|
||||
"Failed to handle page Fault from user mode @ {:#x}({:?}): {:?}\n{:#x?}",
|
||||
vaddr, flags, err, cx
|
||||
"failed to handle page fault from user mode @ {:#x}({:?}): {:?}\n{:#x?}",
|
||||
vaddr,
|
||||
flags,
|
||||
err,
|
||||
thread.context_cloned(),
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
err
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
error!("not supported interrupt from user mode. {:#x?}", cx);
|
||||
return Err(ZxError::NOT_SUPPORTED);
|
||||
error!(
|
||||
"unsupported trap from user mode: {:x?} {:#x?}",
|
||||
reason,
|
||||
thread.context_cloned(),
|
||||
);
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#[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_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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")]
|
||||
// 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();
|
||||
let sp = if cfg!(target_arch = "x86_64") {
|
||||
// WARN: align stack to 16B, then emulate a 'call' (push rip)
|
||||
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!(),
|
||||
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(());
|
||||
}
|
||||
#[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;
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
0xe => {
|
||||
TrapReason::PageFault(vaddr, flags) => {
|
||||
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
|
||||
);
|
||||
info!("page fault from user mode @ {:#x}({:?})", vaddr, 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,
|
||||
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!(),
|
||||
}
|
||||
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;
|
||||
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!()
|
||||
}
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
cx.general.x0 = ret;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,54 +127,68 @@ 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(C)]
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct ExceptionContext {
|
||||
vector: u64,
|
||||
err_code: u64,
|
||||
cr2: u64,
|
||||
}
|
||||
struct ExceptionContext(ExceptionContextInner);
|
||||
|
||||
/// 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")]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct ExceptionContext {
|
||||
esr: u32,
|
||||
padding1: u32,
|
||||
far: u64,
|
||||
padding2: u64,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct ExceptionContext {
|
||||
padding1: u64,
|
||||
padding2: u64,
|
||||
padding3: u64,
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct ExceptionContextInner {
|
||||
vector: u64,
|
||||
err_code: u64,
|
||||
cr2: u64,
|
||||
}
|
||||
} else if #[cfg(target_arch = "aarch64")] {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct ExceptionContextInner {
|
||||
esr: u32,
|
||||
_padding1: u32,
|
||||
far: u64,
|
||||
_padding2: u64,
|
||||
}
|
||||
} else if #[cfg(target_arch = "riscv64")] {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Data reported to an exception handler for most exceptions.
|
||||
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue