diff --git a/osdk/src/base_crate/x86_64.ld.template b/osdk/src/base_crate/x86_64.ld.template index b1a1efeb..053d965e 100644 --- a/osdk/src/base_crate/x86_64.ld.template +++ b/osdk/src/base_crate/x86_64.ld.template @@ -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))) diff --git a/ostd/src/arch/x86/ex_table.rs b/ostd/src/arch/x86/ex_table.rs new file mode 100644 index 00000000..6d623e1f --- /dev/null +++ b/ostd/src/arch/x86/ex_table.rs @@ -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 { + let table_size = + (__ex_table_end as usize - __ex_table as usize) / core::mem::size_of::(); + // 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 + } +} diff --git a/ostd/src/arch/x86/mod.rs b/ostd/src/arch/x86/mod.rs index 82c2128c..4161c33b 100644 --- a/ostd/src/arch/x86/mod.rs +++ b/ostd/src/arch/x86/mod.rs @@ -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;