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;
53pub mod thread_id;
54
55#[cfg(target_arch = "x86")]
56mod start;
57
58/// Performs low-level CPU initialization.
59///
60/// This function installs new segmentation and interrupt handling regimes which the rest of this
61/// crate needs to function properly.
62///
63/// ## Safety
64///
65/// This function must never be executed more than once.
66///
67/// Before calling, memory must be identity mapped. Otherwise the introduction of flat segmentation
68/// will cause the kernel's code/data to move unexpectedly.
69///
70/// After this function returns, it is safe to enable interrupts. However, interrupts below number
71/// 32 must **never** be generated except by the CPU itself (i.e. exceptions), as doing so would
72/// interfere with the internal handler stubs. This means that before enabling interrupts, the
73/// caller must ensure that any hardware delivering external interrupts (such as the PIC/APIC) is
74/// configured to use interrupt number 32 or above.
75pub unsafe fn init() {
76    unsafe {
77        segmentation::init();
78        interrupts::init();
79    }
80}
81
82/// Stops instruction execution and places the processor in a HALT state.
83///
84/// An enabled interrupt (including NMI and SMI), a debug exception, the BINIT#
85/// signal, the INIT# signal, or the RESET# signal will resume execution. If an
86/// interrupt (including NMI) is used to resume execution after a HLT instruction,
87/// the saved instruction pointer (CS:EIP) points to the instruction following
88/// the HLT instruction.
89///
90/// # Safety
91/// Will cause a general protection fault if used outside of ring 0.
92#[cfg(target_arch = "x86")]
93#[inline(always)]
94pub unsafe fn halt() {
95    use core::arch::asm;
96
97    unsafe {
98        asm!("hlt", options(att_syntax, nomem, nostack)); // check if preserves_flags
99    }
100}