x86/
lib.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2024.
4
5//! Generic support for 32-bit Intel/AMD CPUs.
6//!
7//! ## Interrupt Handling
8//!
9//! Once initialized, this crate assumes ownership of the CPU's interrupt handling facilities.
10//!
11//! Interrupts from external devices are handled by calling an extern function named
12//! `_handle_external_interrupt`, which must be defined by the chip or board crate. This function
13//! must have a `cdecl` ABI and must accept a single `u32` argument which is the number of the
14//! external interrupt.
15//!
16//! The `_handle_external_interrupt` function should typically perform the following tasks:
17//!
18//! 1. Call [`InterruptPoller::set_pending`] to mark the given interrupt as pending
19//! 2. Send an EOI signal to any relevant interrupt controllers
20//!
21//! Any other logic needed to service the interrupt (for instance, reading from buffers or re-arming
22//! hardware) should typically be performed within the current chip's `service_pending_interrupts`
23//! method.
24//!
25//! Apart from external interrupts, all other interrupt categories such as CPU exceptions or system
26//! calls are handled internally by this crate.
27//!
28//! ## Safety
29//!
30//! Some of the `unsafe` code in this crate relies on the blanket assumption that this code is being
31//! compiled into a Tock kernel for an x86 system. When calling code from this crate, the following
32//! statements must always be true:
33//!
34//! * The CPU is executing at ring 0
35//! * The CPU has I/O privileges
36
37#![deny(unsafe_op_in_unsafe_fn)]
38#![no_std]
39mod boundary;
40pub use boundary::Boundary;
41
42mod interrupts;
43pub use interrupts::InterruptPoller;
44pub use interrupts::IDT_RESERVED_EXCEPTIONS;
45
46mod segmentation;
47
48pub mod support;
49
50pub mod mpu;
51
52pub mod registers;
53
54#[cfg(target_arch = "x86")]
55mod start;
56
57/// Performs low-level CPU initialization.
58///
59/// This function installs new segmentation and interrupt handling regimes which the rest of this
60/// crate needs to function properly.
61///
62/// ## Safety
63///
64/// This function must never be executed more than once.
65///
66/// Before calling, memory must be identity mapped. Otherwise the introduction of flat segmentation
67/// will cause the kernel's code/data to move unexpectedly.
68///
69/// After this function returns, it is safe to enable interrupts. However, interrupts below number
70/// 32 must **never** be generated except by the CPU itself (i.e. exceptions), as doing so would
71/// interfere with the internal handler stubs. This means that before enabling interrupts, the
72/// caller must ensure that any hardware delivering external interrupts (such as the PIC/APIC) is
73/// configured to use interrupt number 32 or above.
74pub unsafe fn init() {
75    unsafe {
76        segmentation::init();
77        interrupts::init();
78    }
79}
80
81/// Stops instruction execution and places the processor in a HALT state.
82///
83/// An enabled interrupt (including NMI and SMI), a debug exception, the BINIT#
84/// signal, the INIT# signal, or the RESET# signal will resume execution. If an
85/// interrupt (including NMI) is used to resume execution after a HLT instruction,
86/// the saved instruction pointer (CS:EIP) points to the instruction following
87/// the HLT instruction.
88///
89/// # Safety
90/// Will cause a general protection fault if used outside of ring 0.
91#[cfg(target_arch = "x86")]
92#[inline(always)]
93pub unsafe fn halt() {
94    use core::arch::asm;
95
96    unsafe {
97        asm!("hlt", options(att_syntax, nomem, nostack)); // check if preserves_flags
98    }
99}