Enable exception table mechanism

This commit is contained in:
Chen Chengjun 2024-06-27 21:09:44 +08:00 committed by Tate, Hongliang Tian
parent 5b9dd2fee8
commit 5f7cf245ac
3 changed files with 88 additions and 0 deletions

View File

@ -58,6 +58,16 @@ SECTIONS
__bss_end = .;
}
# The section to store exception table (ExTable).
# This table is used for recovering from specific exception handling faults
# occurring at known points in the code.
# Ref: /aster-frame/src/arch/x86/ex_table.rs
.ex_table : AT(ADDR(.ex_table) - KERNEL_VMA) {
__ex_table = .;
KEEP(*(SORT(.ex_table)))
__ex_table_end = .;
}
.ktest_array : AT(ADDR(.ktest_array) - KERNEL_VMA) {
__ktest_array = .;
KEEP(*(SORT(.ktest_array)))

View File

@ -0,0 +1,77 @@
// SPDX-License-Identifier: MPL-2.0
use crate::prelude::Vaddr;
#[repr(C)]
struct ExTableItem {
inst_addr: Vaddr,
recovery_inst_addr: Vaddr,
}
extern "C" {
fn __ex_table();
fn __ex_table_end();
}
/// A structure representing the usage of exception table (ExTable).
/// This table is used for recovering from specific exception handling faults
/// occurring at known points in the code.
///
/// To add a recovery instruction for a target assembly instruction, one should add
/// the following statements:
///
/// ```
/// .pushsection .ex_table, "a"
/// .align 8
/// .quad [.target_label],
/// .quad [.recovery_label],
/// .popsection
/// ```
///
/// where the `target_label` and `recovery_label` are the labels of the target instruction
/// and the label of recovery instruction respectively.
///
/// For example, we have the following assembly code snippets in an input file:
/// ```
/// .label1:
/// rep movsb
/// mov rax, rcx
/// .label2:
/// ret
/// ```
///
/// We can add the following statements in the same file (`label1` and `label2` are local
/// labels):
///
/// ```
/// .pushsection .ex_table, "a"
/// .align 8
/// .quad [.label1],
/// .quad [.label2],
/// .popsection
/// ```
///
/// After that, we can use the API of `ExTable` to resume execution when handling
/// exceptions caused by `rep movsb` (which `label1` point to) failing.
pub(crate) struct ExTable;
impl ExTable {
/// Finds the recovery instruction address for a given instruction address.
///
/// This function is generally used when an exception (such as a page fault) occurs.
/// if the exception handling fails and there is a predefined recovery action,
/// then the found recovery action will be taken.
pub fn find_recovery_inst_addr(inst_addr: Vaddr) -> Option<Vaddr> {
let table_size =
(__ex_table_end as usize - __ex_table as usize) / core::mem::size_of::<ExTableItem>();
// SAFETY: `__ex_table` is a static section consisting of `ExTableItem`.
let ex_table =
unsafe { core::slice::from_raw_parts(__ex_table as *const ExTableItem, table_size) };
for item in ex_table {
if item.inst_addr == inst_addr {
return Some(item.recovery_inst_addr);
}
}
None
}
}

View File

@ -6,6 +6,7 @@ pub mod boot;
pub mod console;
pub(crate) mod cpu;
pub mod device;
pub(crate) mod ex_table;
pub mod iommu;
pub(crate) mod irq;
pub(crate) mod kernel;