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