From 4d36dd541f3ea4ec6ac72681feb6d587f87bab6d Mon Sep 17 00:00:00 2001 From: YanWQ-monad Date: Fri, 19 Jul 2024 15:42:53 +0800 Subject: [PATCH] Extract x86-specific exception handling in aster-nix --- kernel/src/arch/x86/cpu.rs | 4 +- kernel/src/arch/x86/signal.rs | 33 +++++++- kernel/src/process/process/timer_manager.rs | 2 +- kernel/src/process/signal/signals/fault.rs | 34 +-------- kernel/src/thread/exception.rs | 62 +++------------ ostd/src/arch/x86/cpu/mod.rs | 85 +++++++++------------ ostd/src/arch/x86/trap/mod.rs | 8 +- 7 files changed, 86 insertions(+), 142 deletions(-) diff --git a/kernel/src/arch/x86/cpu.rs b/kernel/src/arch/x86/cpu.rs index f90067df2..7b7aaa1c5 100644 --- a/kernel/src/arch/x86/cpu.rs +++ b/kernel/src/arch/x86/cpu.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 use ostd::{ - cpu::{CpuExceptionInfo, RawGeneralRegs, UserContext, PAGE_FAULT}, + cpu::{CpuException, CpuExceptionInfo, RawGeneralRegs, UserContext}, Pod, }; @@ -107,7 +107,7 @@ impl TryFrom<&CpuExceptionInfo> for PageFaultInfo { type Error = (); fn try_from(value: &CpuExceptionInfo) -> Result { - if value.cpu_exception() != PAGE_FAULT { + if value.cpu_exception() != CpuException::PAGE_FAULT { return Err(()); } diff --git a/kernel/src/arch/x86/signal.rs b/kernel/src/arch/x86/signal.rs index ec5070ec6..aac24ffda 100644 --- a/kernel/src/arch/x86/signal.rs +++ b/kernel/src/arch/x86/signal.rs @@ -1,8 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 -use ostd::cpu::UserContext; +use ostd::cpu::{CpuException, CpuExceptionInfo, UserContext}; -use crate::process::signal::{sig_num::SigNum, SignalContext}; +use crate::process::signal::{ + constants::*, sig_num::SigNum, signals::fault::FaultSignal, SignalContext, +}; impl SignalContext for UserContext { fn set_arguments(&mut self, sig_num: SigNum, siginfo_addr: usize, ucontext_addr: usize) { @@ -11,3 +13,30 @@ impl SignalContext for UserContext { self.set_rdx(ucontext_addr); } } + +impl From<&CpuExceptionInfo> for FaultSignal { + fn from(trap_info: &CpuExceptionInfo) -> Self { + let exception = CpuException::to_cpu_exception(trap_info.id as u16).unwrap(); + let (num, code, addr) = match exception { + CpuException::DIVIDE_BY_ZERO => (SIGFPE, FPE_INTDIV, None), + CpuException::X87_FLOATING_POINT_EXCEPTION + | CpuException::SIMD_FLOATING_POINT_EXCEPTION => (SIGFPE, FPE_FLTDIV, None), + CpuException::BOUND_RANGE_EXCEEDED => (SIGSEGV, SEGV_BNDERR, None), + CpuException::ALIGNMENT_CHECK => (SIGBUS, BUS_ADRALN, None), + CpuException::INVALID_OPCODE => (SIGILL, ILL_ILLOPC, None), + CpuException::GENERAL_PROTECTION_FAULT => (SIGBUS, BUS_ADRERR, None), + CpuException::PAGE_FAULT => { + const PF_ERR_FLAG_PRESENT: usize = 1usize << 0; + let code = if trap_info.error_code & PF_ERR_FLAG_PRESENT != 0 { + SEGV_ACCERR + } else { + SEGV_MAPERR + }; + let addr = Some(trap_info.page_fault_addr as u64); + (SIGSEGV, code, addr) + } + _ => panic!("Exception cannot be a signal"), + }; + FaultSignal::new(num, code, addr) + } +} diff --git a/kernel/src/process/process/timer_manager.rs b/kernel/src/process/process/timer_manager.rs index c0a934359..0a31aabdf 100644 --- a/kernel/src/process/process/timer_manager.rs +++ b/kernel/src/process/process/timer_manager.rs @@ -11,7 +11,7 @@ use id_alloc::IdAlloc; use ostd::{ arch::{ timer::{self, TIMER_FREQ}, - x86::trap::is_kernel_interrupted, + trap::is_kernel_interrupted, }, sync::Mutex, }; diff --git a/kernel/src/process/signal/signals/fault.rs b/kernel/src/process/signal/signals/fault.rs index faeab0810..cb73e06fb 100644 --- a/kernel/src/process/signal/signals/fault.rs +++ b/kernel/src/process/signal/signals/fault.rs @@ -1,16 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 -use ostd::cpu::{ - CpuException, CpuExceptionInfo, ALIGNMENT_CHECK, BOUND_RANGE_EXCEEDED, DIVIDE_BY_ZERO, - GENERAL_PROTECTION_FAULT, INVALID_OPCODE, PAGE_FAULT, SIMD_FLOATING_POINT_EXCEPTION, - X87_FLOATING_POINT_EXCEPTION, -}; - use super::Signal; use crate::{ prelude::*, - process::signal::{c_types::siginfo_t, constants::*, sig_num::SigNum}, + process::signal::{c_types::siginfo_t, sig_num::SigNum}, }; + #[derive(Debug, Clone, Copy, PartialEq)] pub struct FaultSignal { num: SigNum, @@ -19,30 +14,7 @@ pub struct FaultSignal { } impl FaultSignal { - pub fn new(trap_info: &CpuExceptionInfo) -> FaultSignal { - debug!("Trap id: {}", trap_info.id); - let exception = CpuException::to_cpu_exception(trap_info.id as u16).unwrap(); - let (num, code, addr) = match *exception { - DIVIDE_BY_ZERO => (SIGFPE, FPE_INTDIV, None), - X87_FLOATING_POINT_EXCEPTION | SIMD_FLOATING_POINT_EXCEPTION => { - (SIGFPE, FPE_FLTDIV, None) - } - BOUND_RANGE_EXCEEDED => (SIGSEGV, SEGV_BNDERR, None), - ALIGNMENT_CHECK => (SIGBUS, BUS_ADRALN, None), - INVALID_OPCODE => (SIGILL, ILL_ILLOPC, None), - GENERAL_PROTECTION_FAULT => (SIGBUS, BUS_ADRERR, None), - PAGE_FAULT => { - const PF_ERR_FLAG_PRESENT: usize = 1usize << 0; - let code = if trap_info.error_code & PF_ERR_FLAG_PRESENT != 0 { - SEGV_ACCERR - } else { - SEGV_MAPERR - }; - let addr = Some(trap_info.page_fault_addr as u64); - (SIGSEGV, code, addr) - } - _ => panic!("Exception cannot be a signal"), - }; + pub fn new(num: SigNum, code: i32, addr: Option) -> FaultSignal { FaultSignal { num, code, addr } } } diff --git a/kernel/src/thread/exception.rs b/kernel/src/thread/exception.rs index cb899d5ae..465eb8691 100644 --- a/kernel/src/thread/exception.rs +++ b/kernel/src/thread/exception.rs @@ -73,61 +73,19 @@ pub(crate) fn handle_page_fault_from_vmar( /// generate a fault signal for current process. fn generate_fault_signal(trap_info: &CpuExceptionInfo, ctx: &Context) { - let signal = FaultSignal::new(trap_info); + let signal = FaultSignal::from(trap_info); ctx.posix_thread.enqueue_signal(Box::new(signal)); } -macro_rules! log_trap_common { - ($exception_name: ident, $trap_info: ident) => { - trace!( - "[Trap][{}][err = {}]", - stringify!($exception_name), - $trap_info.error_code - ) - }; -} - fn log_trap_info(trap_info: &CpuExceptionInfo) { - match trap_info.cpu_exception() { - DIVIDE_BY_ZERO => log_trap_common!(DIVIDE_BY_ZERO, trap_info), - DEBUG => log_trap_common!(DEBUG, trap_info), - NON_MASKABLE_INTERRUPT => log_trap_common!(NON_MASKABLE_INTERRUPT, trap_info), - BREAKPOINT => log_trap_common!(BREAKPOINT, trap_info), - OVERFLOW => log_trap_common!(OVERFLOW, trap_info), - BOUND_RANGE_EXCEEDED => log_trap_common!(BOUND_RANGE_EXCEEDED, trap_info), - INVALID_OPCODE => log_trap_common!(INVALID_OPCODE, trap_info), - DEVICE_NOT_AVAILABLE => log_trap_common!(DEVICE_NOT_AVAILABLE, trap_info), - DOUBLE_FAULT => log_trap_common!(DOUBLE_FAULT, trap_info), - COPROCESSOR_SEGMENT_OVERRUN => log_trap_common!(COPROCESSOR_SEGMENT_OVERRUN, trap_info), - INVALID_TSS => log_trap_common!(INVALID_TSS, trap_info), - SEGMENT_NOT_PRESENT => log_trap_common!(SEGMENT_NOT_PRESENT, trap_info), - STACK_SEGMENT_FAULT => log_trap_common!(STACK_SEGMENT_FAULT, trap_info), - GENERAL_PROTECTION_FAULT => log_trap_common!(GENERAL_PROTECTION_FAULT, trap_info), - PAGE_FAULT => { - trace!( - "[Trap][{}][page fault addr = 0x{:x}, err = {}]", - stringify!(PAGE_FAULT), - trap_info.page_fault_addr, - trap_info.error_code - ); - } - // 15 reserved - X87_FLOATING_POINT_EXCEPTION => log_trap_common!(X87_FLOATING_POINT_EXCEPTION, trap_info), - ALIGNMENT_CHECK => log_trap_common!(ALIGNMENT_CHECK, trap_info), - MACHINE_CHECK => log_trap_common!(MACHINE_CHECK, trap_info), - SIMD_FLOATING_POINT_EXCEPTION => log_trap_common!(SIMD_FLOATING_POINT_EXCEPTION, trap_info), - VIRTUALIZATION_EXCEPTION => log_trap_common!(VIRTUALIZATION_EXCEPTION, trap_info), - CONTROL_PROTECTION_EXCEPTION => log_trap_common!(CONTROL_PROTECTION_EXCEPTION, trap_info), - HYPERVISOR_INJECTION_EXCEPTION => { - log_trap_common!(HYPERVISOR_INJECTION_EXCEPTION, trap_info) - } - VMM_COMMUNICATION_EXCEPTION => log_trap_common!(VMM_COMMUNICATION_EXCEPTION, trap_info), - SECURITY_EXCEPTION => log_trap_common!(SECURITY_EXCEPTION, trap_info), - _ => { - info!( - "[Trap][Unknown trap type][id = {}, err = {}]", - trap_info.id, trap_info.error_code - ); - } + if let Ok(page_fault_info) = PageFaultInfo::try_from(trap_info) { + trace!( + "[Trap][PAGE_FAULT][page fault addr = 0x{:x}, err = {}]", + trap_info.page_fault_addr, + trap_info.error_code + ); + } else { + let exception = trap_info.cpu_exception(); + trace!("[Trap][{exception:?}][err = {}]", trap_info.error_code) } } diff --git a/ostd/src/arch/x86/cpu/mod.rs b/ostd/src/arch/x86/cpu/mod.rs index 5eccb68ae..cb5cbe7f7 100644 --- a/ostd/src/arch/x86/cpu/mod.rs +++ b/ostd/src/arch/x86/cpu/mod.rs @@ -12,6 +12,8 @@ use core::{ use bitflags::bitflags; use cfg_if::cfg_if; use log::debug; +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; use x86::bits64::segmentation::wrfsbase; use x86_64::registers::rflags::RFlags; @@ -109,41 +111,37 @@ impl UserContextApiInternal for UserContext { // set ID flag which means cpu support CPUID instruction self.user_context.general.rflags |= (RFlags::INTERRUPT_FLAG | RFlags::ID).bits() as usize; - let return_reason: ReturnReason; const SYSCALL_TRAPNUM: u16 = 0x100; // return when it is syscall or cpu exception type is Fault or Trap. - loop { + let return_reason = loop { scheduler::might_preempt(); self.user_context.run(); match CpuException::to_cpu_exception(self.user_context.trap_num as u16) { Some(exception) => { #[cfg(feature = "cvm_guest")] - if *exception == VIRTUALIZATION_EXCEPTION { + if exception == CpuException::VIRTUALIZATION_EXCEPTION { handle_virtualization_exception(self); continue; } - if exception.typ == CpuExceptionType::FaultOrTrap - || exception.typ == CpuExceptionType::Fault - || exception.typ == CpuExceptionType::Trap - { - return_reason = ReturnReason::UserException; - break; + match exception.typ() { + CpuExceptionType::FaultOrTrap + | CpuExceptionType::Trap + | CpuExceptionType::Fault => break ReturnReason::UserException, + _ => (), } } None => { if self.user_context.trap_num as u16 == SYSCALL_TRAPNUM { - return_reason = ReturnReason::UserSyscall; - break; + break ReturnReason::UserSyscall; } } }; call_irq_callback_functions(&self.as_trap_frame(), self.as_trap_frame().trap_num); if has_kernel_event() { - return_reason = ReturnReason::KernelEvent; - break; + break ReturnReason::KernelEvent; } - } + }; crate::arch::irq::enable_local(); if return_reason == ReturnReason::UserException { @@ -212,39 +210,26 @@ pub enum CpuExceptionType { Reserved, } -/// CPU exception. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct CpuException { - /// The ID of the CPU exception. - pub number: u16, - /// The type of the CPU exception. - pub typ: CpuExceptionType, -} - -/// Copy from: https://veykril.github.io/tlborm/decl-macros/building-blocks/counting.html#slice-length -macro_rules! replace_expr { - ($_t:tt $sub:expr) => { - $sub - }; -} - -/// Copy from: https://veykril.github.io/tlborm/decl-macros/building-blocks/counting.html#slice-length -macro_rules! count_tts { - ($($tts:tt)*) => {<[()]>::len(&[$(replace_expr!($tts ())),*])}; -} - macro_rules! define_cpu_exception { - ( $([ $name: ident = $exception_num:tt, $exception_type:tt]),* ) => { - const EXCEPTION_LIST : [CpuException;count_tts!($($name)*)] = [ - $($name,)* - ]; - $( - #[doc = concat!("The ", stringify!($name), " exception")] - pub const $name : CpuException = CpuException{ - number: $exception_num, - typ: CpuExceptionType::$exception_type, - }; - )* + ( $([ $name: ident = $exception_id:tt, $exception_type:tt]),* ) => { + /// CPU exception. + #[allow(non_camel_case_types)] + #[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive)] + pub enum CpuException { + $( + #[doc = concat!("The ", stringify!($name), " exception")] + $name = $exception_id, + )* + } + + impl CpuException { + /// The type of the CPU exception. + pub fn typ(&self) -> CpuExceptionType { + match self { + $( CpuException::$name => CpuExceptionType::$exception_type, )* + } + } + } } } @@ -314,19 +299,19 @@ bitflags! { impl CpuException { /// Checks if the given `trap_num` is a valid CPU exception. pub fn is_cpu_exception(trap_num: u16) -> bool { - trap_num < EXCEPTION_LIST.len() as u16 + Self::to_cpu_exception(trap_num).is_some() } /// Maps a `trap_num` to its corresponding CPU exception. - pub fn to_cpu_exception(trap_num: u16) -> Option<&'static CpuException> { - EXCEPTION_LIST.get(trap_num as usize) + pub fn to_cpu_exception(trap_num: u16) -> Option { + FromPrimitive::from_u16(trap_num) } } impl CpuExceptionInfo { /// Get corresponding CPU exception pub fn cpu_exception(&self) -> CpuException { - EXCEPTION_LIST[self.id] + CpuException::to_cpu_exception(self.id as u16).unwrap() } } diff --git a/ostd/src/arch/x86/trap/mod.rs b/ostd/src/arch/x86/trap/mod.rs index 45484578d..b9d847405 100644 --- a/ostd/src/arch/x86/trap/mod.rs +++ b/ostd/src/arch/x86/trap/mod.rs @@ -26,7 +26,7 @@ use log::debug; use super::ex_table::ExTable; use crate::{ - cpu::{CpuException, CpuExceptionInfo, PageFaultErrorCode, PAGE_FAULT}, + cpu::{CpuException, CpuExceptionInfo, PageFaultErrorCode}, cpu_local_cell, mm::{ kspace::{KERNEL_PAGE_TABLE, LINEAR_MAPPING_BASE_VADDR, LINEAR_MAPPING_VADDR_RANGE}, @@ -40,7 +40,7 @@ use crate::{ cfg_if! { if #[cfg(feature = "cvm_guest")] { use tdx_guest::{tdcall, tdx_is_enabled, handle_virtual_exception}; - use crate::arch::{cpu::VIRTUALIZATION_EXCEPTION, tdx_guest::TrapFrameWrapper}; + use crate::arch::tdx_guest::TrapFrameWrapper; } } @@ -223,13 +223,13 @@ extern "sysv64" fn trap_handler(f: &mut TrapFrame) { if CpuException::is_cpu_exception(f.trap_num as u16) { match CpuException::to_cpu_exception(f.trap_num as u16).unwrap() { #[cfg(feature = "cvm_guest")] - &VIRTUALIZATION_EXCEPTION => { + CpuException::VIRTUALIZATION_EXCEPTION => { let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n"); let mut trapframe_wrapper = TrapFrameWrapper(&mut *f); handle_virtual_exception(&mut trapframe_wrapper, &ve_info); *f = *trapframe_wrapper.0; } - &PAGE_FAULT => { + CpuException::PAGE_FAULT => { let page_fault_addr = x86_64::registers::control::Cr2::read_raw(); // The actual user space implementation should be responsible // for providing mechanism to treat the 0 virtual address.