Tests: Exception restore sanity

pull/151/head
Andre Richter 2 years ago
parent 55548bf691
commit 7d374adad2
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -413,32 +413,31 @@ Minipush 1.0
[MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00
[ML] Loaded! Executing the payload now
[ 0.788994] mingo version 0.11.0
[ 0.789201] Booting on: Raspberry Pi 3
[ 0.789656] MMU online. Special regions:
[ 0.790133] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data
[ 0.791151] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO
[ 0.792040] Current privilege level: EL1
[ 0.792516] Exception handling state:
[ 0.792960] Debug: Masked
[ 0.793350] SError: Masked
[ 0.793740] IRQ: Masked
[ 0.794130] FIQ: Masked
[ 0.794520] Architectural timer resolution: 52 ns
[ 0.795094] Drivers loaded:
[ 0.795430] 1. BCM GPIO
[ 0.795788] 2. BCM PL011 UART
[ 0.796210] Timer test, spinning for 1 second
[ 1.796741]
[ 1.796745] Trying to read from address 8 GiB...
[ 1.797295] ************************************************
[ 1.797987] Whoa! We recovered from a synchronous exception!
[ 1.798680] ************************************************
[ 1.799373]
[ 1.799547] Let's try again
[ 1.799883] Trying to read from address 9 GiB...
Kernel panic:
[ 0.789853] mingo version 0.11.0
[ 0.790060] Booting on: Raspberry Pi 3
[ 0.790515] MMU online. Special regions:
[ 0.790992] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data
[ 0.792010] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO
[ 0.792899] Current privilege level: EL1
[ 0.793375] Exception handling state:
[ 0.793819] Debug: Masked
[ 0.794209] SError: Masked
[ 0.794599] IRQ: Masked
[ 0.794989] FIQ: Masked
[ 0.795379] Architectural timer resolution: 52 ns
[ 0.795954] Drivers loaded:
[ 0.796289] 1. BCM GPIO
[ 0.796647] 2. BCM PL011 UART
[ 0.797070] Timer test, spinning for 1 second
[ 1.797600]
[ 1.797604] Trying to read from address 8 GiB...
[ 1.798154] ************************************************
[ 1.798846] Whoa! We recovered from a synchronous exception!
[ 1.799539] ************************************************
[ 1.800233]
[ 1.800406] Let's try again
[ 1.800742] Trying to read from address 9 GiB...
[ 1.801306] Kernel panic:
CPU Exception!
ESR_EL1: 0x96000004
@ -457,25 +456,25 @@ SPSR_EL1: 0x600003c5
IRQ (I): Masked
FIQ (F): Masked
Illegal Execution State (IL): Not set
ELR_EL1: 0x0000000000082580
ELR_EL1: 0x0000000000082194
General purpose register:
x0 : 0x0000000000000000 x1 : 0x00000000000859b7
x2 : 0x0000000000000027 x3 : 0x0000000000084d3c
x4 : 0x0000000000000003 x5 : 0x3f26329c00000000
x6 : 0x0000000000000000 x7 : 0xd3d18800228d0241
x8 : 0x0000000240000000 x9 : 0x00000000000859b7
x0 : 0x0000000000000000 x1 : 0x000000000008555f
x2 : 0x0000000000000027 x3 : 0x000000000008435c
x4 : 0x0000000000000006 x5 : 0x3f27329c00000000
x6 : 0x0000000000000000 x7 : 0xd3d1b900228f0241
x8 : 0x0000000240000000 x9 : 0x000000000008555f
x10: 0x0000000000000443 x11: 0x000000003f201000
x12: 0x0000000000000019 x13: 0x0000000000000033
x14: 0x000000000007fd3d x15: 0x0000000000000058
x16: 0x0000000000000078 x17: 0xfd29f02255a847c0
x18: 0x9cd4788000000008 x19: 0x0000000000090008
x20: 0x00000000000857a0 x21: 0x000000003b9aca00
x22: 0x000000000008271c x23: 0x0000000000083314
x24: 0x00000000000003e8 x25: 0xffffffffc4653600
x26: 0x00000000000f4240 x27: 0x0000000000085880
x28: 0x0000000000085170 x29: 0x0000000000086c10
lr : 0x0000000000082574
x12: 0x0000000000000019 x13: 0x00000000ffffd8f0
x14: 0x000000000000147b x15: 0x00000000ffffff9c
x16: 0x000000000007fd38 x17: 0x0000000005f5e0ff
x18: 0x0000000000000034 x19: 0x0000000000090008
x20: 0x0000000000085398 x21: 0x000000003b9aca00
x22: 0x0000000000082e30 x23: 0x0000000000082308
x24: 0x0000000010624dd3 x25: 0xffffffffc4653600
x26: 0x00000000000866b8 x27: 0x0000000000085458
x28: 0x0000000000084fe0 x29: 0x0000000000086770
lr : 0x0000000000082188
```
## Diff to previous

@ -54,3 +54,7 @@ harness = false
[[test]]
name = "02_exception_sync_page_fault"
harness = false
[[test]]
name = "03_exception_restore_sanity"
harness = false

@ -648,6 +648,10 @@ harness = false
[[test]]
name = "02_exception_sync_page_fault"
harness = false
[[test]]
name = "03_exception_restore_sanity"
harness = false
```
#### Overriding Panic Behavior
@ -703,11 +707,11 @@ unsafe fn kernel_init() -> ! {
println!("Testing synchronous exception handling by causing a page fault");
if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() {
println!("MMU: {}", string);
info!("MMU: {}", string);
cpu::qemu_exit_failure()
}
println!("Writing beyond mapped area to address 9 GiB...");
info!("Writing beyond mapped area to address 9 GiB...");
let big_addr: u64 = 9 * 1024 * 1024 * 1024;
core::ptr::read_volatile(big_addr as *mut u64);
@ -761,7 +765,10 @@ The subtest first sends `"ABC"` over the console to the kernel, and then expects
#![no_main]
#![no_std]
use libkernel::{bsp, console, exception, print};
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use libkernel::{bsp, console, cpu, exception, print};
#[no_mangle]
unsafe fn kernel_init() -> ! {
@ -860,6 +867,24 @@ Compiling integration test(s) - rpi3
-------------------------------------------------------------------
✅ Success: 02_exception_sync_page_fault.rs
-------------------------------------------------------------------
Running tests/03_exception_restore_sanity.rs (target/aarch64-unknown-none-softfloat/release/deps/03_exception_restore_sanity-a56e14285bb26e0e)
-------------------------------------------------------------------
🦀 Running 1 console I/O tests
-------------------------------------------------------------------
1. Exception restore.........................................[ok]
Console log:
Testing exception restore
[ 0.130757] Making a dummy system call
[ 0.132592] Back from system call!
-------------------------------------------------------------------
✅ Success: 03_exception_restore_sanity.rs
-------------------------------------------------------------------
```
## Diff to previous
@ -883,7 +908,7 @@ diff -uNr 11_exceptions_part1_groundwork/Cargo.toml 12_integrated_testing/Cargo.
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
edition = "2021"
@@ -11,20 +11,46 @@
@@ -11,20 +11,50 @@
default = []
bsp_rpi3 = ["tock-registers"]
bsp_rpi4 = ["tock-registers"]
@ -934,6 +959,10 @@ diff -uNr 11_exceptions_part1_groundwork/Cargo.toml 12_integrated_testing/Cargo.
+[[test]]
+name = "02_exception_sync_page_fault"
+harness = false
+
+[[test]]
+name = "03_exception_restore_sanity"
+harness = false
diff -uNr 11_exceptions_part1_groundwork/Makefile 12_integrated_testing/Makefile
--- 11_exceptions_part1_groundwork/Makefile
@ -1070,7 +1099,7 @@ diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs 12_integrated_
diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs 12_integrated_testing/src/_arch/aarch64/exception.rs
--- 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs
+++ 12_integrated_testing/src/_arch/aarch64/exception.rs
@@ -87,18 +87,6 @@
@@ -87,15 +87,14 @@
#[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
@ -1083,12 +1112,30 @@ diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs 12_integ
- e.elr_el1 += 4;
-
- return;
- }
- }
-
default_exception_handler(e);
+ #[cfg(feature = "test_build")]
+ {
+ const TEST_SVC_ID: u64 = 0x1337;
+
+ if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() {
+ if e.esr_el1.iss() == TEST_SVC_ID {
+ return;
+ }
}
}
@@ -192,6 +191,12 @@
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
+
+ #[cfg(feature = "test_build")]
+ #[inline(always)]
+ fn iss(&self) -> u64 {
+ self.0.read(ESR_EL1::ISS)
+ }
}
/// Human readable ESR_EL1.
diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs 12_integrated_testing/src/_arch/aarch64/memory/mmu/translation_table.rs
--- 11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs
@ -1814,7 +1861,7 @@ diff -uNr 11_exceptions_part1_groundwork/tests/00_console_sanity.rb 12_integrate
diff -uNr 11_exceptions_part1_groundwork/tests/00_console_sanity.rs 12_integrated_testing/tests/00_console_sanity.rs
--- 11_exceptions_part1_groundwork/tests/00_console_sanity.rs
+++ 12_integrated_testing/tests/00_console_sanity.rs
@@ -0,0 +1,35 @@
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2019-2022 Andre Richter <andre.o.richter@gmail.com>
@ -1825,6 +1872,9 @@ diff -uNr 11_exceptions_part1_groundwork/tests/00_console_sanity.rs 12_integrate
+#![no_main]
+#![no_std]
+
+/// Console tests should time out on the I/O harness in case of panic.
+mod panic_wait_forever;
+
+use libkernel::{bsp, console, cpu, exception, print};
+
+#[no_mangle]
@ -1953,6 +2003,96 @@ diff -uNr 11_exceptions_part1_groundwork/tests/02_exception_sync_page_fault.rs 1
+ cpu::qemu_exit_failure()
+}
diff -uNr 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rb 12_integrated_testing/tests/03_exception_restore_sanity.rb
--- 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rb
+++ 12_integrated_testing/tests/03_exception_restore_sanity.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+# SPDX-License-Identifier: MIT OR Apache-2.0
+#
+# Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
+
+require_relative '../../common/tests/console_io_test'
+
+# Verify that exception restore works.
+class ExceptionRestoreTest < SubtestBase
+ def name
+ 'Exception restore'
+ end
+
+ def run(qemu_out, _qemu_in)
+ expect_or_raise(qemu_out, 'Back from system call!')
+ end
+end
+
+##--------------------------------------------------------------------------------------------------
+## Test registration
+##--------------------------------------------------------------------------------------------------
+def subtest_collection
+ [ExceptionRestoreTest.new]
+end
diff -uNr 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rs 12_integrated_testing/tests/03_exception_restore_sanity.rs
--- 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rs
+++ 12_integrated_testing/tests/03_exception_restore_sanity.rs
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! A simple sanity test to see if exception restore code works.
+
+#![feature(format_args_nl)]
+#![no_main]
+#![no_std]
+
+/// Console tests should time out on the I/O harness in case of panic.
+mod panic_wait_forever;
+
+use core::arch::asm;
+use libkernel::{bsp, cpu, exception, info, memory, println};
+
+#[inline(never)]
+fn nested_system_call() {
+ #[cfg(target_arch = "aarch64")]
+ unsafe {
+ asm!("svc #0x1337", options(nomem, nostack, preserves_flags));
+ }
+
+ #[cfg(not(target_arch = "aarch64"))]
+ {
+ info!("Not supported yet");
+ cpu::wait_forever();
+ }
+}
+
+#[no_mangle]
+unsafe fn kernel_init() -> ! {
+ use memory::mmu::interface::MMU;
+
+ exception::handling_init();
+ bsp::console::qemu_bring_up_console();
+
+ // This line will be printed as the test header.
+ println!("Testing exception restore");
+
+ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() {
+ info!("MMU: {}", string);
+ cpu::qemu_exit_failure()
+ }
+
+ info!("Making a dummy system call");
+
+ // Calling this inside a function indirectly tests if the link register is restored properly.
+ nested_system_call();
+
+ info!("Back from system call!");
+
+ // The QEMU process running this test will be closed by the I/O test harness.
+ cpu::wait_forever();
+}
diff -uNr 11_exceptions_part1_groundwork/tests/boot_test_string.rb 12_integrated_testing/tests/boot_test_string.rb
--- 11_exceptions_part1_groundwork/tests/boot_test_string.rb
+++ 12_integrated_testing/tests/boot_test_string.rb
@ -1976,6 +2116,20 @@ diff -uNr 11_exceptions_part1_groundwork/tests/panic_exit_success/mod.rs 12_inte
+ libkernel::cpu::qemu_exit_success()
+}
diff -uNr 11_exceptions_part1_groundwork/tests/panic_wait_forever/mod.rs 12_integrated_testing/tests/panic_wait_forever/mod.rs
--- 11_exceptions_part1_groundwork/tests/panic_wait_forever/mod.rs
+++ 12_integrated_testing/tests/panic_wait_forever/mod.rs
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
+
+/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever.
+#[no_mangle]
+fn _panic_exit() -> ! {
+ libkernel::cpu::wait_forever()
+}
diff -uNr 11_exceptions_part1_groundwork/test-types/Cargo.toml 12_integrated_testing/test-types/Cargo.toml
--- 11_exceptions_part1_groundwork/test-types/Cargo.toml
+++ 12_integrated_testing/test-types/Cargo.toml

@ -87,6 +87,17 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
#[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
#[cfg(feature = "test_build")]
{
const TEST_SVC_ID: u64 = 0x1337;
if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() {
if e.esr_el1.iss() == TEST_SVC_ID {
return;
}
}
}
default_exception_handler(e);
}
@ -180,6 +191,12 @@ impl EsrEL1 {
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
#[cfg(feature = "test_build")]
#[inline(always)]
fn iss(&self) -> u64 {
self.0.read(ESR_EL1::ISS)
}
}
/// Human readable ESR_EL1.

@ -8,6 +8,9 @@
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use libkernel::{bsp, console, cpu, exception, print};
#[no_mangle]

@ -0,0 +1,25 @@
# frozen_string_literal: true
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
require_relative '../../common/tests/console_io_test'
# Verify that exception restore works.
class ExceptionRestoreTest < SubtestBase
def name
'Exception restore'
end
def run(qemu_out, _qemu_in)
expect_or_raise(qemu_out, 'Back from system call!')
end
end
##--------------------------------------------------------------------------------------------------
## Test registration
##--------------------------------------------------------------------------------------------------
def subtest_collection
[ExceptionRestoreTest.new]
end

@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
//! A simple sanity test to see if exception restore code works.
#![feature(format_args_nl)]
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use core::arch::asm;
use libkernel::{bsp, cpu, exception, info, memory, println};
#[inline(never)]
fn nested_system_call() {
#[cfg(target_arch = "aarch64")]
unsafe {
asm!("svc #0x1337", options(nomem, nostack, preserves_flags));
}
#[cfg(not(target_arch = "aarch64"))]
{
info!("Not supported yet");
cpu::wait_forever();
}
}
#[no_mangle]
unsafe fn kernel_init() -> ! {
use memory::mmu::interface::MMU;
exception::handling_init();
bsp::console::qemu_bring_up_console();
// This line will be printed as the test header.
println!("Testing exception restore");
if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() {
info!("MMU: {}", string);
cpu::qemu_exit_failure()
}
info!("Making a dummy system call");
// Calling this inside a function indirectly tests if the link register is restored properly.
nested_system_call();
info!("Back from system call!");
// The QEMU process running this test will be closed by the I/O test harness.
cpu::wait_forever();
}

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever.
#[no_mangle]
fn _panic_exit() -> ! {
libkernel::cpu::wait_forever()
}

@ -54,3 +54,7 @@ harness = false
[[test]]
name = "02_exception_sync_page_fault"
harness = false
[[test]]
name = "03_exception_restore_sanity"
harness = false

@ -913,7 +913,7 @@ diff -uNr 12_integrated_testing/src/_arch/aarch64/exception.rs 13_exceptions_par
use core::{arch::global_asm, cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*};
use tock_registers::{
@@ -91,8 +92,11 @@
@@ -102,8 +103,11 @@
}
#[no_mangle]
@ -2753,9 +2753,9 @@ diff -uNr 12_integrated_testing/src/synchronization.rs 13_exceptions_part2_perip
+ }
}
diff -uNr 12_integrated_testing/tests/03_exception_irq_sanity.rs 13_exceptions_part2_peripheral_IRQs/tests/03_exception_irq_sanity.rs
--- 12_integrated_testing/tests/03_exception_irq_sanity.rs
+++ 13_exceptions_part2_peripheral_IRQs/tests/03_exception_irq_sanity.rs
diff -uNr 12_integrated_testing/tests/04_exception_irq_sanity.rs 13_exceptions_part2_peripheral_IRQs/tests/04_exception_irq_sanity.rs
--- 12_integrated_testing/tests/04_exception_irq_sanity.rs
+++ 13_exceptions_part2_peripheral_IRQs/tests/04_exception_irq_sanity.rs
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//

@ -88,6 +88,17 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
#[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
#[cfg(feature = "test_build")]
{
const TEST_SVC_ID: u64 = 0x1337;
if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() {
if e.esr_el1.iss() == TEST_SVC_ID {
return;
}
}
}
default_exception_handler(e);
}
@ -184,6 +195,12 @@ impl EsrEL1 {
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
#[cfg(feature = "test_build")]
#[inline(always)]
fn iss(&self) -> u64 {
self.0.read(ESR_EL1::ISS)
}
}
/// Human readable ESR_EL1.

@ -8,6 +8,9 @@
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use libkernel::{bsp, console, cpu, exception, print};
#[no_mangle]

@ -0,0 +1,25 @@
# frozen_string_literal: true
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
require_relative '../../common/tests/console_io_test'
# Verify that exception restore works.
class ExceptionRestoreTest < SubtestBase
def name
'Exception restore'
end
def run(qemu_out, _qemu_in)
expect_or_raise(qemu_out, 'Back from system call!')
end
end
##--------------------------------------------------------------------------------------------------
## Test registration
##--------------------------------------------------------------------------------------------------
def subtest_collection
[ExceptionRestoreTest.new]
end

@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
//! A simple sanity test to see if exception restore code works.
#![feature(format_args_nl)]
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use core::arch::asm;
use libkernel::{bsp, cpu, exception, info, memory, println};
#[inline(never)]
fn nested_system_call() {
#[cfg(target_arch = "aarch64")]
unsafe {
asm!("svc #0x1337", options(nomem, nostack, preserves_flags));
}
#[cfg(not(target_arch = "aarch64"))]
{
info!("Not supported yet");
cpu::wait_forever();
}
}
#[no_mangle]
unsafe fn kernel_init() -> ! {
use memory::mmu::interface::MMU;
exception::handling_init();
bsp::console::qemu_bring_up_console();
// This line will be printed as the test header.
println!("Testing exception restore");
if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() {
info!("MMU: {}", string);
cpu::qemu_exit_failure()
}
info!("Making a dummy system call");
// Calling this inside a function indirectly tests if the link register is restored properly.
nested_system_call();
info!("Back from system call!");
// The QEMU process running this test will be closed by the I/O test harness.
cpu::wait_forever();
}

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever.
#[no_mangle]
fn _panic_exit() -> ! {
libkernel::cpu::wait_forever()
}

@ -54,3 +54,7 @@ harness = false
[[test]]
name = "02_exception_sync_page_fault"
harness = false
[[test]]
name = "03_exception_restore_sanity"
harness = false

@ -3641,4 +3641,52 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/tests/02_exception_sync_page_fault
info!("Writing beyond mapped area to address 9 GiB...");
let big_addr: u64 = 9 * 1024 * 1024 * 1024;
diff -uNr 13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rs 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs
--- 13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rs
+++ 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs
@@ -30,18 +30,40 @@
#[no_mangle]
unsafe fn kernel_init() -> ! {
- use memory::mmu::interface::MMU;
+ use libkernel::driver::interface::DriverManager;
exception::handling_init();
- bsp::console::qemu_bring_up_console();
// This line will be printed as the test header.
println!("Testing exception restore");
- if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() {
- info!("MMU: {}", string);
+ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() {
+ Err(string) => {
+ info!("Error mapping kernel binary: {}", string);
+ cpu::qemu_exit_failure()
+ }
+ Ok(addr) => addr,
+ };
+
+ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) {
+ info!("Enabling MMU failed: {}", e);
cpu::qemu_exit_failure()
}
+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet.
+
+ memory::mmu::post_enable_init();
+ bsp::console::qemu_bring_up_console();
+
+ // Bring up the drivers needed for printing first.
+ for i in bsp::driver::driver_manager()
+ .early_print_device_drivers()
+ .iter()
+ {
+ // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU.
+ i.init().unwrap_or_else(|_| cpu::qemu_exit_failure());
+ }
+ bsp::driver::driver_manager().post_early_print_device_driver_init();
+ // Printing available again from here on.
info!("Making a dummy system call");
```

@ -88,6 +88,17 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
#[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
#[cfg(feature = "test_build")]
{
const TEST_SVC_ID: u64 = 0x1337;
if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() {
if e.esr_el1.iss() == TEST_SVC_ID {
return;
}
}
}
default_exception_handler(e);
}
@ -184,6 +195,12 @@ impl EsrEL1 {
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
#[cfg(feature = "test_build")]
#[inline(always)]
fn iss(&self) -> u64 {
self.0.read(ESR_EL1::ISS)
}
}
/// Human readable ESR_EL1.

@ -8,6 +8,9 @@
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use libkernel::{bsp, console, cpu, exception, print};
#[no_mangle]

@ -0,0 +1,25 @@
# frozen_string_literal: true
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
require_relative '../../common/tests/console_io_test'
# Verify that exception restore works.
class ExceptionRestoreTest < SubtestBase
def name
'Exception restore'
end
def run(qemu_out, _qemu_in)
expect_or_raise(qemu_out, 'Back from system call!')
end
end
##--------------------------------------------------------------------------------------------------
## Test registration
##--------------------------------------------------------------------------------------------------
def subtest_collection
[ExceptionRestoreTest.new]
end

@ -0,0 +1,77 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
//! A simple sanity test to see if exception restore code works.
#![feature(format_args_nl)]
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use core::arch::asm;
use libkernel::{bsp, cpu, exception, info, memory, println};
#[inline(never)]
fn nested_system_call() {
#[cfg(target_arch = "aarch64")]
unsafe {
asm!("svc #0x1337", options(nomem, nostack, preserves_flags));
}
#[cfg(not(target_arch = "aarch64"))]
{
info!("Not supported yet");
cpu::wait_forever();
}
}
#[no_mangle]
unsafe fn kernel_init() -> ! {
use libkernel::driver::interface::DriverManager;
exception::handling_init();
// This line will be printed as the test header.
println!("Testing exception restore");
let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() {
Err(string) => {
info!("Error mapping kernel binary: {}", string);
cpu::qemu_exit_failure()
}
Ok(addr) => addr,
};
if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) {
info!("Enabling MMU failed: {}", e);
cpu::qemu_exit_failure()
}
// Printing will silently fail from here on, because the driver's MMIO is not remapped yet.
memory::mmu::post_enable_init();
bsp::console::qemu_bring_up_console();
// Bring up the drivers needed for printing first.
for i in bsp::driver::driver_manager()
.early_print_device_drivers()
.iter()
{
// Any encountered errors cannot be printed yet, obviously, so just safely park the CPU.
i.init().unwrap_or_else(|_| cpu::qemu_exit_failure());
}
bsp::driver::driver_manager().post_early_print_device_driver_init();
// Printing available again from here on.
info!("Making a dummy system call");
// Calling this inside a function indirectly tests if the link register is restored properly.
nested_system_call();
info!("Back from system call!");
// The QEMU process running this test will be closed by the I/O test harness.
cpu::wait_forever();
}

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever.
#[no_mangle]
fn _panic_exit() -> ! {
libkernel::cpu::wait_forever()
}

@ -54,3 +54,7 @@ harness = false
[[test]]
name = "02_exception_sync_page_fault"
harness = false
[[test]]
name = "03_exception_restore_sanity"
harness = false

@ -1686,16 +1686,16 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs 15_virtual_mem_part3
diff -uNr 14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rs
--- 14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rs
+++ 15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rs
@@ -8,7 +8,7 @@
#![no_main]
#![no_std]
@@ -11,7 +11,7 @@
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
-use libkernel::{bsp, console, cpu, exception, print};
+use libkernel::{bsp, console, cpu, exception, memory, print};
#[no_mangle]
unsafe fn kernel_init() -> ! {
@@ -16,6 +16,7 @@
@@ -19,6 +19,7 @@
use console::interface::*;
exception::handling_init();
@ -1770,9 +1770,56 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs
info!("Writing beyond mapped area to address 9 GiB...");
let big_addr: u64 = 9 * 1024 * 1024 * 1024;
diff -uNr 14_virtual_mem_part2_mmio_remap/tests/03_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/03_exception_irq_sanity.rs
--- 14_virtual_mem_part2_mmio_remap/tests/03_exception_irq_sanity.rs
+++ 15_virtual_mem_part3_precomputed_tables/tests/03_exception_irq_sanity.rs
diff -uNr 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rs
--- 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs
+++ 15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rs
@@ -30,40 +30,12 @@
#[no_mangle]
unsafe fn kernel_init() -> ! {
- use libkernel::driver::interface::DriverManager;
-
exception::handling_init();
-
- // This line will be printed as the test header.
- println!("Testing exception restore");
-
- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() {
- Err(string) => {
- info!("Error mapping kernel binary: {}", string);
- cpu::qemu_exit_failure()
- }
- Ok(addr) => addr,
- };
-
- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) {
- info!("Enabling MMU failed: {}", e);
- cpu::qemu_exit_failure()
- }
- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet.
-
memory::mmu::post_enable_init();
bsp::console::qemu_bring_up_console();
- // Bring up the drivers needed for printing first.
- for i in bsp::driver::driver_manager()
- .early_print_device_drivers()
- .iter()
- {
- // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU.
- i.init().unwrap_or_else(|_| cpu::qemu_exit_failure());
- }
- bsp::driver::driver_manager().post_early_print_device_driver_init();
- // Printing available again from here on.
+ // This line will be printed as the test header.
+ println!("Testing exception restore");
info!("Making a dummy system call");
diff -uNr 14_virtual_mem_part2_mmio_remap/tests/04_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/04_exception_irq_sanity.rs
--- 14_virtual_mem_part2_mmio_remap/tests/04_exception_irq_sanity.rs
+++ 15_virtual_mem_part3_precomputed_tables/tests/04_exception_irq_sanity.rs
@@ -10,11 +10,12 @@
#![reexport_test_harness_main = "test_main"]
#![test_runner(libkernel::test_runner)]

@ -88,6 +88,17 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
#[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
#[cfg(feature = "test_build")]
{
const TEST_SVC_ID: u64 = 0x1337;
if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() {
if e.esr_el1.iss() == TEST_SVC_ID {
return;
}
}
}
default_exception_handler(e);
}
@ -184,6 +195,12 @@ impl EsrEL1 {
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
#[cfg(feature = "test_build")]
#[inline(always)]
fn iss(&self) -> u64 {
self.0.read(ESR_EL1::ISS)
}
}
/// Human readable ESR_EL1.

@ -8,6 +8,9 @@
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use libkernel::{bsp, console, cpu, exception, memory, print};
#[no_mangle]

@ -0,0 +1,25 @@
# frozen_string_literal: true
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
require_relative '../../common/tests/console_io_test'
# Verify that exception restore works.
class ExceptionRestoreTest < SubtestBase
def name
'Exception restore'
end
def run(qemu_out, _qemu_in)
expect_or_raise(qemu_out, 'Back from system call!')
end
end
##--------------------------------------------------------------------------------------------------
## Test registration
##--------------------------------------------------------------------------------------------------
def subtest_collection
[ExceptionRestoreTest.new]
end

@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
//! A simple sanity test to see if exception restore code works.
#![feature(format_args_nl)]
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use core::arch::asm;
use libkernel::{bsp, cpu, exception, info, memory, println};
#[inline(never)]
fn nested_system_call() {
#[cfg(target_arch = "aarch64")]
unsafe {
asm!("svc #0x1337", options(nomem, nostack, preserves_flags));
}
#[cfg(not(target_arch = "aarch64"))]
{
info!("Not supported yet");
cpu::wait_forever();
}
}
#[no_mangle]
unsafe fn kernel_init() -> ! {
exception::handling_init();
memory::mmu::post_enable_init();
bsp::console::qemu_bring_up_console();
// This line will be printed as the test header.
println!("Testing exception restore");
info!("Making a dummy system call");
// Calling this inside a function indirectly tests if the link register is restored properly.
nested_system_call();
info!("Back from system call!");
// The QEMU process running this test will be closed by the I/O test harness.
cpu::wait_forever();
}

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever.
#[no_mangle]
fn _panic_exit() -> ! {
libkernel::cpu::wait_forever()
}

@ -54,3 +54,7 @@ harness = false
[[test]]
name = "02_exception_sync_page_fault"
harness = false
[[test]]
name = "03_exception_restore_sanity"
harness = false

@ -88,6 +88,17 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
#[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
#[cfg(feature = "test_build")]
{
const TEST_SVC_ID: u64 = 0x1337;
if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() {
if e.esr_el1.iss() == TEST_SVC_ID {
return;
}
}
}
default_exception_handler(e);
}
@ -184,6 +195,12 @@ impl EsrEL1 {
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
#[cfg(feature = "test_build")]
#[inline(always)]
fn iss(&self) -> u64 {
self.0.read(ESR_EL1::ISS)
}
}
/// Human readable ESR_EL1.

@ -8,6 +8,9 @@
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use libkernel::{bsp, console, cpu, exception, memory, print};
#[no_mangle]

@ -0,0 +1,25 @@
# frozen_string_literal: true
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
require_relative '../../common/tests/console_io_test'
# Verify that exception restore works.
class ExceptionRestoreTest < SubtestBase
def name
'Exception restore'
end
def run(qemu_out, _qemu_in)
expect_or_raise(qemu_out, 'Back from system call!')
end
end
##--------------------------------------------------------------------------------------------------
## Test registration
##--------------------------------------------------------------------------------------------------
def subtest_collection
[ExceptionRestoreTest.new]
end

@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
//! A simple sanity test to see if exception restore code works.
#![feature(format_args_nl)]
#![no_main]
#![no_std]
/// Console tests should time out on the I/O harness in case of panic.
mod panic_wait_forever;
use core::arch::asm;
use libkernel::{bsp, cpu, exception, info, memory, println};
#[inline(never)]
fn nested_system_call() {
#[cfg(target_arch = "aarch64")]
unsafe {
asm!("svc #0x1337", options(nomem, nostack, preserves_flags));
}
#[cfg(not(target_arch = "aarch64"))]
{
info!("Not supported yet");
cpu::wait_forever();
}
}
#[no_mangle]
unsafe fn kernel_init() -> ! {
exception::handling_init();
memory::mmu::post_enable_init();
bsp::console::qemu_bring_up_console();
// This line will be printed as the test header.
println!("Testing exception restore");
info!("Making a dummy system call");
// Calling this inside a function indirectly tests if the link register is restored properly.
nested_system_call();
info!("Back from system call!");
// The QEMU process running this test will be closed by the I/O test harness.
cpu::wait_forever();
}

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever.
#[no_mangle]
fn _panic_exit() -> ! {
libkernel::cpu::wait_forever()
}
Loading…
Cancel
Save