Skip to content

Commit

Permalink
Merge pull request #164 from arceos-org/new-trap-handler
Browse files Browse the repository at this point in the history
Refactor trap handler with linkme::distributed_slice
  • Loading branch information
equation314 committed Jul 30, 2024
2 parents 0d42139 + 1f97a03 commit 25d75ce
Show file tree
Hide file tree
Showing 17 changed files with 275 additions and 104 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on: [push, pull_request]
env:
qemu-version: 8.2.0
rust-toolchain: nightly-2024-05-02
arceos-apps: b36b9d5
arceos-apps: c01cd92

jobs:
unit-test:
Expand Down
25 changes: 24 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions api/arceos_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ default = []

irq = ["axfeat/irq"]
alloc = ["dep:axalloc", "axfeat/alloc"]
multitask = ["axtask/multitask", "axfeat/multitask"]
fs = ["dep:axfs", "axfeat/fs"]
net = ["dep:axnet", "axfeat/net"]
display = ["dep:axdisplay", "axfeat/display"]
paging = ["dep:axmm", "axfeat/paging"]
multitask = ["axtask/multitask", "axsync/multitask", "axfeat/multitask"]
fs = ["dep:axfs", "dep:axdriver", "axfeat/fs"]
net = ["dep:axnet", "dep:axdriver", "axfeat/net"]
display = ["dep:axdisplay", "dep:axdriver", "axfeat/display"]

myfs = ["axfeat/myfs"]

Expand All @@ -32,8 +33,11 @@ axruntime = { workspace = true }
axconfig = { workspace = true }
axlog = { workspace = true }
axhal = { workspace = true }
axsync = { workspace = true }
axalloc = { workspace = true, optional = true }
axmm = { workspace = true, optional = true }
axtask = { workspace = true, optional = true }
axdriver = { workspace = true, optional = true }
axfs = { workspace = true, optional = true }
axnet = { workspace = true, optional = true }
axdisplay = { workspace = true, optional = true }
28 changes: 27 additions & 1 deletion api/arceos_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
feature = "dummy-if-not-enabled"
))]
extern crate alloc;
extern crate axruntime;

#[macro_use]
mod macros;
Expand Down Expand Up @@ -339,3 +338,30 @@ pub mod io {
pub type AxPollState;
}
}

/// Re-exports of ArceOS modules.
///
/// You should prefer to use other APIs rather than these modules. The modules
/// here should only be used if other APIs do not meet your requirements.
pub mod modules {
pub use axconfig;
pub use axhal;
pub use axlog;
pub use axruntime;
pub use axsync;

#[cfg(feature = "alloc")]
pub use axalloc;
#[cfg(feature = "display")]
pub use axdisplay;
#[cfg(any(feature = "fs", feature = "net", feature = "display"))]
pub use axdriver;
#[cfg(feature = "fs")]
pub use axfs;
#[cfg(feature = "paging")]
pub use axmm;
#[cfg(feature = "net")]
pub use axnet;
#[cfg(feature = "multitask")]
pub use axtask;
}
2 changes: 1 addition & 1 deletion modules/axhal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ default = []
[dependencies]
log = "0.4"
cfg-if = "1.0"
linkme = "0.3"
bitflags = "2.6"
static_assertions = "1.1.0"
kernel_guard = "0.1"
Expand All @@ -31,7 +32,6 @@ lazyinit = "0.2"
percpu = "0.1"
memory_addr = "0.2"
handler_table = "0.1"
crate_interface = "0.1"
page_table_entry = "0.3"
page_table_multiarch = { version = "0.3", optional = true }
axlog = { workspace = true }
Expand Down
17 changes: 11 additions & 6 deletions modules/axhal/linker.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,14 @@ SECTIONS

. = ALIGN(4K);
_percpu_start = .;
_percpu_end = _percpu_start + SIZEOF(.percpu);
.percpu 0x0 : AT(_percpu_start) {
_percpu_load_start = .;
*(.percpu .percpu.*)
_percpu_load_end = .;
. = ALIGN(64);
_percpu_size_aligned = .;

. = _percpu_load_start + _percpu_size_aligned * %SMP%;
. = _percpu_load_start + ALIGN(64) * %SMP%;
}
. = _percpu_start + SIZEOF(.percpu);
_percpu_end = .;
. = _percpu_end;

. = ALIGN(4K);
_edata = .;
Expand All @@ -84,3 +81,11 @@ SECTIONS
*(.comment) *(.gnu*) *(.note*) *(.eh_frame*)
}
}

SECTIONS {
linkme_IRQ : { *(linkme_IRQ) }
linkm2_IRQ : { *(linkm2_IRQ) }
linkme_PAGE_FAULT : { *(linkme_PAGE_FAULT) }
linkm2_PAGE_FAULT : { *(linkm2_PAGE_FAULT) }
}
INSERT AFTER .tbss;
97 changes: 67 additions & 30 deletions modules/axhal/src/arch/aarch64/trap.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use core::arch::global_asm;

use aarch64_cpu::registers::{ESR_EL1, FAR_EL1};
use memory_addr::VirtAddr;
use page_table_entry::MappingFlags;
use tock_registers::interfaces::Readable;

use super::TrapFrame;
Expand Down Expand Up @@ -35,39 +37,79 @@ fn invalid_exception(tf: &TrapFrame, kind: TrapKind, source: TrapSource) {
);
}

#[no_mangle]
fn handle_irq_exception(_tf: &TrapFrame) {
handle_trap!(IRQ, 0);
}

fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) {
let mut access_flags = MappingFlags::EXECUTE;
if is_user {
access_flags |= MappingFlags::USER;
}
let vaddr = VirtAddr::from(FAR_EL1.get() as usize);

// Only handle Translation fault and Permission fault
if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits
|| !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user)
{
panic!(
"Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ISS={:#x} ({:?}):\n{:#x?}",
if is_user { "EL0" } else { "EL1" },
tf.elr,
vaddr,
iss,
access_flags,
tf,
);
}
}

fn handle_data_abort(tf: &TrapFrame, iss: u64, is_user: bool) {
let wnr = (iss & (1 << 6)) != 0; // WnR: Write not Read
let cm = (iss & (1 << 8)) != 0; // CM: Cache maintenance
let mut access_flags = if wnr & !cm {
MappingFlags::WRITE
} else {
MappingFlags::READ
};
if is_user {
access_flags |= MappingFlags::USER;
}
let vaddr = VirtAddr::from(FAR_EL1.get() as usize);

// Only handle Translation fault and Permission fault
if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits
|| !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user)
{
panic!(
"Unhandled {} Data Abort @ {:#x}, fault_vaddr={:#x}, ISS=0b{:08b} ({:?}):\n{:#x?}",
if is_user { "EL0" } else { "EL1" },
tf.elr,
vaddr,
iss,
access_flags,
tf,
);
}
}

#[no_mangle]
fn handle_sync_exception(tf: &mut TrapFrame) {
let esr = ESR_EL1.extract();
let iss = esr.read(ESR_EL1::ISS);
match esr.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::SVC64) => {
warn!("No syscall is supported currently!");
}
Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => handle_instruction_abort(tf, iss, true),
Some(ESR_EL1::EC::Value::InstrAbortCurrentEL) => handle_instruction_abort(tf, iss, false),
Some(ESR_EL1::EC::Value::DataAbortLowerEL) => handle_data_abort(tf, iss, true),
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => handle_data_abort(tf, iss, false),
Some(ESR_EL1::EC::Value::Brk64) => {
let iss = esr.read(ESR_EL1::ISS);
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
tf.elr += 4;
}
Some(ESR_EL1::EC::Value::SVC64) => {
warn!("No supervisor call is supported currently!");
}
Some(ESR_EL1::EC::Value::DataAbortLowerEL)
| Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => {
let iss = esr.read(ESR_EL1::ISS);
warn!(
"EL0 Page Fault @ {:#x}, FAR={:#x}, ISS={:#x}",
tf.elr,
FAR_EL1.get(),
iss
);
}
Some(ESR_EL1::EC::Value::DataAbortCurrentEL)
| Some(ESR_EL1::EC::Value::InstrAbortCurrentEL) => {
let iss = esr.read(ESR_EL1::ISS);
panic!(
"EL1 Page Fault @ {:#x}, FAR={:#x}, ISS={:#x}:\n{:#x?}",
tf.elr,
FAR_EL1.get(),
iss,
tf,
);
}
_ => {
panic!(
"Unhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})",
Expand All @@ -79,8 +121,3 @@ fn handle_sync_exception(tf: &mut TrapFrame) {
}
}
}

#[no_mangle]
fn handle_irq_exception(_tf: &TrapFrame) {
crate::trap::handle_irq_extern(0)
}
31 changes: 29 additions & 2 deletions modules/axhal/src/arch/riscv/trap.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use memory_addr::VirtAddr;
use page_table_entry::MappingFlags;
use riscv::register::scause::{self, Exception as E, Trap};
use riscv::register::stval;

use super::TrapFrame;

Expand All @@ -14,12 +17,36 @@ fn handle_breakpoint(sepc: &mut usize) {
*sepc += 2
}

fn handle_page_fault(tf: &TrapFrame, mut access_flags: MappingFlags, is_user: bool) {
if is_user {
access_flags |= MappingFlags::USER;
}
let vaddr = VirtAddr::from(stval::read());
if !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user) {
panic!(
"Unhandled {} Page Fault @ {:#x}, fault_vaddr={:#x} ({:?}):\n{:#x?}",
if is_user { "User" } else { "Supervisor" },
tf.sepc,
vaddr,
access_flags,
tf,
);
}
}

#[no_mangle]
fn riscv_trap_handler(tf: &mut TrapFrame, _from_user: bool) {
fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool) {
let scause = scause::read();
match scause.cause() {
Trap::Exception(E::LoadPageFault) => handle_page_fault(tf, MappingFlags::READ, from_user),
Trap::Exception(E::StorePageFault) => handle_page_fault(tf, MappingFlags::WRITE, from_user),
Trap::Exception(E::InstructionPageFault) => {
handle_page_fault(tf, MappingFlags::EXECUTE, from_user)
}
Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc),
Trap::Interrupt(_) => crate::trap::handle_irq_extern(scause.bits()),
Trap::Interrupt(_) => {
handle_trap!(IRQ, scause.bits());
}
_ => {
panic!(
"Unhandled trap {:?} @ {:#x}:\n{:#x?}",
Expand Down
Loading

0 comments on commit 25d75ce

Please sign in to comment.