//! Stage 22: the arm64 (aarch64) side of the `arch` interface (see //! src/arch/mod.rs). This is a *bring-up*: enough to boot on QEMU's `virt` //! board with a Cortex-A53, print, take exceptions, turn on the MMU, and //! get a timer interrupt through the GIC. No processes, no scheduler yet. //! //! | File | Part | //! |------|------| //! | `boot.rs` | entry: `_start`, EL2 -> EL1, stack, .bss, then `kmain` | //! | `console.rs` | text out through the board's UART, `print!`/`println!` | //! | `exceptions.rs` | the vector table, ESR decoding, IRQ dispatch | //! | `gic.rs` | the GICv2 interrupt controller (virt) | //! | `timer.rs` | the generic timer (CNTV), the tick count | //! | `paging.rs` | MMU: identity map + the same memory again in the higher half | //! | `dtb.rs` | a small device tree (DTB) reader | //! | `mmio.rs` | device register access (through the higher half once the MMU is on) | //! | `board/` | what differs between boards: `virt` (works), `raspi3` (a skeleton) | //! | `main.rs` | the kernel binary `rustbelt-aarch64` (`kmain`) | //! | `link.ld` | where the kernel goes in memory (0x4020_0000 on virt) | pub mod board; pub mod boot; pub mod console; pub mod dtb; pub mod exceptions; pub mod gic; pub mod mmio; pub mod paging; pub mod timer; /// The `arch` interface's `interrupts` (vector table + IRQ mask); the /// controller itself is the board's (`board::current().irq()`). pub use exceptions as interrupts; use core::arch::asm; /// The banner, the first line the arm64 kernel prints. pub const BANNER: &str = concat!("Rustbelt ", env!("CARGO_PKG_VERSION"), " (stage 22: arm64 bring-up)"); /// The exception level we're running at now (1 = kernel, 2 = hypervisor). pub fn current_el() -> u64 { let el: u64; unsafe { asm!("mrs {}, CurrentEL", out(reg) el) }; (el >> 2) & 3 } /// End the QEMU run with `code` as QEMU's exit status, through Arm /// **semihosting** (QEMU must be started with `-semihosting`): `HLT #0xF000` /// with operation 0x18 (`SYS_EXIT`) in w0 and, in x1, the address of two /// words: the reason `ADP_Stopped_ApplicationExit` (0x20026) and the code. /// /// (PSCI `SYSTEM_OFF` would also stop QEMU, but it can't carry a status.) /// Without `-semihosting` the HLT is an undefined instruction; on a real /// board there's no semihosting, so this is a QEMU-only way out. pub fn exit(code: u32) -> ! { let block: [u64; 2] = [0x20026, code as u64]; unsafe { asm!("hlt #0xf000", in("w0") 0x18u32, in("x1") block.as_ptr(), options(nostack)); } halt() } /// Stop this CPU for good: mask interrupts and wait forever. pub fn halt() -> ! { loop { unsafe { asm!("msr daifset, #0xf", "wfe", options(nomem, nostack)) }; } }