Skip to main content

starnix_core/arch/x64/
task.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::signals::{SignalDetail, SignalInfo};
6use crate::task::{CurrentTask, ExceptionResult, PageFaultExceptionReport};
7use starnix_uapi::signals::{SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP};
8
9pub fn handle_hardware_exception(
10    current_task: &CurrentTask,
11    report: &zx::ExceptionReport,
12) -> Option<ExceptionResult> {
13    let ip = current_task.thread_state.registers.instruction_pointer_register();
14    match report.ty {
15        // See IntelĀ® 64 and IA-32 Architectures Software Developer's Manual, Volume 3, Chapter 6
16        // (Interrupt and exception handling).
17        zx::ExceptionType::General => match report.arch.vector {
18            // 0: Division by 0.
19            0 => Some(ExceptionResult::Signal(SignalInfo::with_detail(
20                SIGFPE,
21                linux_uapi::FPE_INTDIV as i32,
22                SignalDetail::SigFault { addr: ip },
23            ))),
24
25            // 16: FPU exception.
26            // 19: SSE exception.
27            16 | 19 => Some(ExceptionResult::Signal(SignalInfo::with_detail(
28                SIGFPE,
29                linux_uapi::FPE_FLTINV as i32,
30                SignalDetail::SigFault { addr: ip },
31            ))),
32
33            // 13: General Protection Fault, e.g. `hlt` instruction.
34            13 => Some(ExceptionResult::Signal(SignalInfo::kernel(SIGSEGV))),
35
36            _ => None,
37        },
38        zx::ExceptionType::FatalPageFault { status } => {
39            let decoded = decode_page_fault_exception_report(&report.arch);
40            Some(current_task.handle_page_fault(decoded, status))
41        }
42        zx::ExceptionType::UndefinedInstruction => {
43            Some(ExceptionResult::Signal(SignalInfo::with_detail(
44                SIGILL,
45                linux_uapi::ILL_ILLOPC as i32,
46                SignalDetail::SigFault { addr: ip },
47            )))
48        }
49        zx::ExceptionType::UnalignedAccess => {
50            Some(ExceptionResult::Signal(SignalInfo::with_detail(
51                SIGBUS,
52                linux_uapi::BUS_ADRALN as i32,
53                SignalDetail::SigFault { addr: report.arch.cr2 },
54            )))
55        }
56        zx::ExceptionType::SoftwareBreakpoint => {
57            // When generating a software breakpoint, x86 deviates from other
58            // architectures, returns SI_KERNEL and does not populate si_addr.
59            Some(ExceptionResult::Signal(SignalInfo::kernel(SIGTRAP)))
60        }
61        zx::ExceptionType::HardwareBreakpoint => {
62            Some(ExceptionResult::Signal(SignalInfo::with_detail(
63                SIGTRAP,
64                linux_uapi::TRAP_HWBKPT as i32,
65                SignalDetail::SigFault { addr: ip },
66            )))
67        }
68        _ => None,
69    }
70}
71
72pub fn decode_page_fault_exception_report(
73    data: &zx::ExceptionArchData,
74) -> PageFaultExceptionReport {
75    // [intel/vol3]: 6.15: Interrupt 14--Page-Fault Exception (#PF)
76    let faulting_address = data.cr2;
77    let not_present = data.err_code & 0x01 == 0; // Low bit means "present"
78    let is_write = data.err_code & 0x02 != 0;
79    let is_execute = data.err_code & 0xF0 != 0;
80
81    PageFaultExceptionReport { faulting_address, not_present, is_write, is_execute }
82}