Add a config.mk file where global variables can be modified, add aarch64

interrupts with IRQ and syscalls, make phys_to_virt checked, recreate
stack on aarch64, make serial console finally line wrap and have max
height correctly, add U64Buf for when i need number debug, rename mouse
and keyboard files to kmi and merge them, add non-working pl050 support
This commit is contained in:
csd4ni3l
2026-05-16 23:43:13 +02:00
parent 812d4cf6d4
commit 2a73c3aeb4
30 changed files with 979 additions and 278 deletions
+7
View File
@@ -7,6 +7,7 @@ name = "XunilOS"
version = "0.1.0"
dependencies = [
"aarch64-cpu",
"fdt",
"font8x8",
"heapless",
"lazy_static",
@@ -51,6 +52,12 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413d67b29ef1021b4d60f4aa1e925ca031751e213832b4b1d588fae623c05c60"
[[package]]
name = "fdt"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "font8x8"
version = "0.3.1"
+1
View File
@@ -23,6 +23,7 @@ x86_64 = "0.15.4"
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64-cpu = "11.2.0"
fdt = "0.1.5"
[profile.dev]
panic = "abort"
+1 -9
View File
@@ -2,15 +2,7 @@
MAKEFLAGS += -rR
.SUFFIXES:
# This is the name that our final executable will have.
# Change as needed.
override OUTPUT := kernel
# Convenience macro to reliably declare user overridable variables.
override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2)))
# Target architecture to build for. Default to x86_64.
$(call USER_VARIABLE,KARCH,x86_64)
include ../config.mk
ifeq ($(RUST_TARGET),)
override RUST_TARGET := $(KARCH)-unknown-none
+18
View File
@@ -1,5 +1,23 @@
use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let timer_frequency_hz = env::var("TIMER_FREQUENCY_HZ").unwrap_or_else(|_| "1000".to_string());
let out_dir = PathBuf::from("src");
fs::write(
out_dir.join("config.rs"),
format!(r#"pub const TIMER_FREQUENCY_HZ: usize = {timer_frequency_hz};"#),
)
.unwrap();
println!("cargo:rerun-if-env-changed=KARCH");
println!("cargo:rerun-if-env-changed=TIMER_FREQUENCY_HZ");
println!("cargo:rerun-if-env-changed=OUTPUT");
// Tell cargo to pass the linker script to the linker..
println!("cargo:rustc-link-arg=-Tlinker-{arch}.ld");
// ..and to re-run if it changes.
+6 -1
View File
@@ -23,8 +23,13 @@ SECTIONS
. = 0xffffffff80000000;
__kernel_start = .;
__text_start = .;
.text : { *(.text .text.*) } :text
.text : ALIGN(0x1000) {
*(.text.vectors)
*(.text .text.*)
} :text
. = ALIGN(CONSTANT(MAXPAGESIZE));
__text_end = .;
+1 -1
View File
@@ -1,7 +1,7 @@
[toolchain]
channel = "nightly"
targets = [
# "x86_64-unknown-none",
"x86_64-unknown-none",
"aarch64-unknown-none",
# "riscv64gc-unknown-none-elf",
# "loongarch64-unknown-none",
+33
View File
@@ -0,0 +1,33 @@
// TODO: actually use this?
use fdt::Fdt;
fn get_midr() -> u64 {
let midr: u64;
unsafe { core::arch::asm!("mrs {}, MIDR_EL1", out(reg) midr, options(nomem, nostack)) };
midr
}
pub fn is_qemu() -> bool {
let midr = get_midr();
let implementer = (midr >> 24) & 0xFF;
implementer == 0x00
}
pub unsafe fn read_dtb<'a>() -> Fdt<'a> {
match is_qemu() {
true => {
let ptr: *mut u32 = 0x4000_0000 as *mut u32;
let magic = u32::from_be(unsafe { ptr.read_volatile() });
assert_eq!(magic, 0xd00dfeed);
let size = u32::from_be(unsafe { ptr.add(1).read_volatile() }) as usize;
let bytes = unsafe { core::slice::from_raw_parts(ptr as *const u8, size) };
return Fdt::new(bytes).unwrap();
}
false => panic!("Can't read DTB of non-qemu device. Unimplemented."),
}
}
+45 -9
View File
@@ -1,21 +1,57 @@
use crate::arch::aarch64::{
heap::init_heap,
paging::{AArchPageTable, initialize_paging_aarch64},
use crate::{
arch::aarch64::{
heap::init_heap,
interrupts::init_interrupts,
kmi::setup_kmi,
paging::{AArchPageTable, initialize_paging_aarch64},
},
config::TIMER_FREQUENCY_HZ,
};
use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse};
pub fn init_aarch64<'a>(
// needs to be page aligned since we map it into the page table
#[repr(align(4096))]
pub struct Stack(pub [u8; 64 * 1024]);
pub static KERNEL_STACK: Stack = Stack([0; 64 * 1024]);
pub fn set_timer_freq(freq: usize) {
unsafe {
core::arch::asm!("mrs {}, cntp_tval_el0", in(reg) freq);
}
}
#[unsafe(naked)]
pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) {
// fix stack, since limine's bootloader stack is not mapped
core::arch::naked_asm!(
"msr spsel, #1",
"adrp x1, {stack}",
"add x1, x1, :lo12:{stack}",
"add sp, x1, {size}",
"b kernel_main_aarch64",
stack = sym KERNEL_STACK,
size = const 64 * 1024,
);
}
#[unsafe(no_mangle)]
pub extern "C" fn init_aarch64(mapper: &mut AArchPageTable) {
init_heap(mapper);
set_timer_freq(TIMER_FREQUENCY_HZ);
init_interrupts();
unsafe { setup_kmi() };
}
pub fn preinit_aarch64<'a>(
hhdm_response: &HhdmResponse,
memory_map_response: &'a MemoryMapResponse,
executable_address_response: &ExecutableAddressResponse,
) -> AArchPageTable {
) {
let mut mapper = initialize_paging_aarch64(
hhdm_response,
memory_map_response,
executable_address_response,
);
init_heap(&mut mapper);
return mapper;
unsafe { init_aarch64_trampoline(&mut mapper) };
}
+293 -1
View File
@@ -1 +1,293 @@
// TODO: add interrupts
use core::{arch::global_asm, sync::atomic::Ordering};
use crate::{
arch::syscall::syscall_dispatch,
driver::{
graphics::framebuffer::with_framebuffer,
keyboard::push_scancode,
kmi::{keyboard_interrupt, mouse_interrupt},
serial::with_serial_console,
timer::TIMER,
},
task::context::UserContext,
};
use aarch64_cpu::registers::{DAIF, Writeable};
global_asm!(
r#"
.section .text.vectors
.global __exception_vectors
.balign 0x800
__exception_vectors:
.balign 0x80; ldr x16, =current_el_sp0_sync; br x16
.balign 0x80; ldr x16, =current_el_sp0_irq; br x16
.balign 0x80; ldr x16, =current_el_sp0_fiq; br x16
.balign 0x80; ldr x16, =current_el_sp0_serror; br x16
.balign 0x80; ldr x16, =current_el_spx_sync; br x16
.balign 0x80; ldr x16, =current_el_spx_irq; br x16
.balign 0x80; ldr x16, =current_el_spx_fiq; br x16
.balign 0x80; ldr x16, =current_el_spx_serror; br x16
.balign 0x80; ldr x16, =lower_el_aarch64_sync; br x16
.balign 0x80; ldr x16, =lower_el_aarch64_irq; br x16
.balign 0x80; ldr x16, =lower_el_aarch64_fiq; br x16
.balign 0x80; ldr x16, =lower_el_aarch64_serror; br x16
.balign 0x80; ldr x16, =lower_el_aarch32_sync; br x16
.balign 0x80; ldr x16, =lower_el_aarch32_irq; br x16
.balign 0x80; ldr x16, =lower_el_aarch32_fiq; br x16
.balign 0x80; ldr x16, =lower_el_aarch32_serror; br x16
"#
);
// stp allows storing in pairs, ldp loads in pairs
macro_rules! exception_handler {
($name:ident, $rust_handler:ident) => {
#[unsafe(naked)]
#[unsafe(no_mangle)]
unsafe extern "C" fn $name() {
core::arch::naked_asm!(
"sub sp, sp, #288",
"stp x0, x1, [sp, #0]",
"stp x2, x3, [sp, #16]",
"stp x4, x5, [sp, #32]",
"stp x6, x7, [sp, #48]",
"stp x8, x9, [sp, #64]",
"stp x10, x11, [sp, #80]",
"stp x12, x13, [sp, #96]",
"stp x14, x15, [sp, #112]",
"stp x16, x17, [sp, #128]",
"stp x18, x19, [sp, #144]",
"stp x20, x21, [sp, #160]",
"stp x22, x23, [sp, #176]",
"stp x24, x25, [sp, #192]",
"stp x26, x27, [sp, #208]",
"stp x28, x29, [sp, #224]",
"mrs x0, elr_el1",
"mrs x1, spsr_el1",
"stp x30, x0, [sp, #240]",
"str x1, [sp, #256]",
"mrs x2, esr_el1",
"mrs x3, far_el1",
"stp x2, x3, [sp, #264]",
"mov x0, sp",
concat!("bl ", stringify!($rust_handler)),
"ldr x1, [sp, #256]",
"ldp x30, x0, [sp, #240]",
"msr spsr_el1, x1",
"msr elr_el1, x0",
"ldp x0, x1, [sp, #0]",
"ldp x2, x3, [sp, #16]",
"ldp x4, x5, [sp, #32]",
"ldp x6, x7, [sp, #48]",
"ldp x8, x9, [sp, #64]",
"ldp x10, x11, [sp, #80]",
"ldp x12, x13, [sp, #96]",
"ldp x14, x15, [sp, #112]",
"ldp x16, x17, [sp, #128]",
"ldp x18, x19, [sp, #144]",
"ldp x20, x21, [sp, #160]",
"ldp x22, x23, [sp, #176]",
"ldp x24, x25, [sp, #192]",
"ldp x26, x27, [sp, #208]",
"ldp x28, x29, [sp, #224]",
"add sp, sp, #288",
"eret"
);
}
};
}
unsafe fn use_exception_vectors() {
unsafe {
core::arch::asm!(
"adrp x0, __exception_vectors",
"add x0, x0, :lo12:__exception_vectors",
"msr vbar_el1, x0",
"isb"
);
}
}
const GICD_BASE: u64 = 0xFFFF_0000_0800_0000;
const GICC_BASE: u64 = 0xFFFF_0000_0801_0000;
const ESR_EC_SHIFT: u64 = 26;
const ESR_EC_MASK: u64 = 0x3F;
const EC_SVC_AA64: u64 = 0x15;
unsafe fn gic_init() {
let gicd_ctrl = GICD_BASE as *mut u32;
unsafe {
gicd_ctrl.write_volatile(1);
}
let gicc_ctrl = GICC_BASE as *mut u32;
unsafe {
gicc_ctrl.write_volatile(1);
}
let gicc_pmr = (GICC_BASE + 0x4) as *mut u32;
unsafe {
gicc_pmr.write_volatile(0xFF); // allow all priorities
}
}
unsafe fn gic_enable_interrupt(id: u32) {
let reg = (GICD_BASE + 0x100 + (id as u64 / 32 * 4)) as *mut u32;
unsafe { reg.write_volatile(1 << (id % 32)) };
}
unsafe fn gic_acknowledge() -> u32 {
let gicc_air = (GICC_BASE + 0xC) as *mut u32;
unsafe { gicc_air.read_volatile() & 0x3FF } // interrupt id
}
unsafe fn gic_eoi(id: u32) {
let gicc_eoir = (GICC_BASE + 0x10) as *mut u32;
unsafe {
gicc_eoir.write_volatile(id);
}
}
pub fn init_interrupts() {
unsafe { use_exception_vectors() };
unsafe { gic_init() };
unsafe { core::arch::asm!("isb") };
}
pub fn enable_interrupts() {
unsafe {
gic_enable_interrupt(30); // timer IRQ
gic_enable_interrupt(17); // keyboard IRQ
gic_enable_interrupt(18); // mouse IRQ
core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) 1u64); // enable timer
}
DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked);
}
#[allow(unused_variables, dead_code)]
#[unsafe(no_mangle)]
unsafe extern "C" fn no_operation(ctx: *mut UserContext) {
let interrupt_id = unsafe { gic_acknowledge() };
unsafe {
gic_eoi(interrupt_id);
}
}
#[allow(unused_variables, dead_code)]
#[unsafe(no_mangle)]
unsafe extern "C" fn irq_handler(ctx: *mut UserContext) {
let interrupt_id = unsafe { gic_acknowledge() };
match interrupt_id {
30 => {
TIMER.interrupt();
let t = TIMER.interrupt_count.load(Ordering::Relaxed);
if t % 60 == 0 {
with_framebuffer(|fb| {
with_serial_console(|serial_console| {
serial_console.print(".", fb);
serial_console.render(fb)
});
fb.present();
});
}
}
17 => {
if let Some(scancode) = keyboard_interrupt() {
push_scancode(scancode);
}
}
18 => {
mouse_interrupt();
}
_ => {}
}
unsafe {
gic_eoi(interrupt_id);
}
}
fn handle_aborts(ec: u64, ctx: &UserContext) {
match ec {
0x25 => {
panic!(
"Data abort at VA={:#x} ELR={:#x} ESR={:#x}",
ctx.far_el1, ctx.elr_el1, ctx.esr_el1
);
}
0x21 => {
panic!(
"Instruction abort at VA={:#x} ELR={:#x}",
ctx.far_el1, ctx.elr_el1
);
}
_ => {
panic!(
"Unhandled sync abort VA={:#x} ELR={:#x} ESR={:#x}",
ctx.far_el1, ctx.elr_el1, ctx.esr_el1
);
}
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn sync_handler_user(ctx: *mut UserContext) {
let mut ctx = unsafe { *ctx };
let ec = (ctx.esr_el1 >> ESR_EC_SHIFT) & ESR_EC_MASK;
#[allow(unused_assignments)]
match ec {
EC_SVC_AA64 => {
ctx.x0 = unsafe {
syscall_dispatch(
ctx.x8 as usize,
ctx.x0 as isize,
ctx.x1 as isize,
ctx.x2 as isize,
ctx.x3 as isize,
ctx.x4 as isize,
ctx.x5 as isize,
)
} as u64;
}
_ => handle_aborts(ec, &ctx),
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn sync_handler_kernel(ctx: *mut UserContext) {
let ctx = unsafe { *ctx };
let ec = (ctx.esr_el1 >> ESR_EC_SHIFT) & ESR_EC_MASK;
handle_aborts(ec, &ctx)
}
// these are UB and should not happen
exception_handler!(current_el_sp0_sync, no_operation);
exception_handler!(current_el_sp0_irq, no_operation);
exception_handler!(current_el_sp0_fiq, no_operation);
exception_handler!(current_el_sp0_serror, no_operation);
exception_handler!(lower_el_aarch32_sync, no_operation);
exception_handler!(lower_el_aarch32_irq, no_operation);
exception_handler!(lower_el_aarch32_fiq, no_operation);
exception_handler!(lower_el_aarch32_serror, no_operation);
// kernel
exception_handler!(current_el_spx_sync, sync_handler_kernel);
exception_handler!(current_el_spx_irq, irq_handler);
exception_handler!(current_el_spx_fiq, no_operation);
exception_handler!(current_el_spx_serror, no_operation);
// usermode
exception_handler!(lower_el_aarch64_sync, sync_handler_user);
exception_handler!(lower_el_aarch64_irq, no_operation);
exception_handler!(lower_el_aarch64_fiq, no_operation);
exception_handler!(lower_el_aarch64_serror, no_operation);
-1
View File
@@ -1 +0,0 @@
// TODO: add keyboard logic
+87
View File
@@ -0,0 +1,87 @@
use crate::arch::arch::safe_lock;
const KMI0_BASE: u64 = 0xFFFF_0000_0905_0000;
const KMI1_BASE: u64 = 0xFFFF_0000_0906_0000;
const KMI_CR: u64 = 0x00;
const KMI_STAT: u64 = 0x04;
const KMI_DATA: u64 = 0x08;
pub unsafe fn kmi_write(base: u64, kmi_type: u64, val: u8) {
let data = (base + kmi_type) as *mut u32;
unsafe { data.write_volatile(val as u32) };
}
pub fn kmi_read(base: u64, kmi_type: u64) -> u8 {
let data = (base + kmi_type) as *const u32;
unsafe { data.read_volatile() as u8 }
}
pub unsafe fn read_mouse_control() -> u8 {
kmi_read(KMI1_BASE, KMI_STAT)
}
pub unsafe fn read_mouse_data() -> u8 {
kmi_read(KMI1_BASE, KMI_DATA)
}
pub unsafe fn read_keyboard_control() -> u8 {
kmi_read(KMI0_BASE, KMI_STAT)
}
pub unsafe fn read_keyboard_data() -> u8 {
kmi_read(KMI0_BASE, KMI_DATA)
}
pub unsafe fn setup_kmi() -> u8 {
safe_lock(|| unsafe {
let cr0 = (KMI0_BASE + KMI_CR) as *mut u32;
cr0.write_volatile(0x14); // enable keyboard
kmi_write(KMI0_BASE, KMI_DATA, 0xFF); // reset keyboard
if kmi_read(KMI0_BASE, KMI_DATA) != 0xFA {
// ACK
return 2;
}
if kmi_read(KMI0_BASE, KMI_DATA) != 0xAA {
// self-test passed
return 3;
}
kmi_write(KMI0_BASE, KMI_DATA, 0xF4); // enable keyboard data reporting
if kmi_read(KMI0_BASE, KMI_DATA) != 0xFA {
// ACK
return 4;
}
let cr1 = (KMI1_BASE + KMI_CR) as *mut u32;
cr1.write_volatile(0x14); // enable mouse
kmi_write(KMI1_BASE, KMI_DATA, 0xFF); // reset mouse
if kmi_read(KMI1_BASE, KMI_DATA) != 0xFA {
// ACK
return 5;
}
if kmi_read(KMI1_BASE, KMI_DATA) != 0xAA {
// self-test passed
return 6;
}
if kmi_read(KMI1_BASE, KMI_DATA) != 0x00 {
// mouse ID
return 7;
}
kmi_write(KMI1_BASE, KMI_DATA, 0xF4); // enable mouse data reporting
if kmi_read(KMI1_BASE, KMI_DATA) != 0xFA {
// ACK
return 8;
}
return 9;
})
}
+2 -1
View File
@@ -1,7 +1,8 @@
pub mod dtb;
pub mod heap;
pub mod init;
pub mod interrupts;
pub mod mouse;
pub mod kmi;
pub mod paging;
pub mod syscall;
pub mod usermode;
-1
View File
@@ -1 +0,0 @@
// TODO: add mouse logic
+51 -12
View File
@@ -1,4 +1,12 @@
use crate::arch::arch::{HHDM_OFFSET, XunilFrameAllocator, safe_lock};
use core::sync::atomic::{AtomicBool, Ordering};
use crate::{
arch::{
aarch64::init::KERNEL_STACK,
arch::{HHDM_OFFSET, XunilFrameAllocator, safe_lock, serial_print},
},
util::U64Buf,
};
use limine::{
memory_map::EntryType,
response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse},
@@ -48,9 +56,24 @@ pub fn device_flags() -> u64 {
// no SH bits for device memory
}
static HHDM_OVERFLOW_REPORTED: AtomicBool = AtomicBool::new(false);
fn phys_to_virt(phys: u64) -> *mut u64 {
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
(phys + hhdm_offset) as *mut u64
let hhdm_offset = HHDM_OFFSET.load(Ordering::Relaxed);
match phys.checked_add(hhdm_offset) {
Some(virt) => virt as *mut u64,
None => {
if !HHDM_OVERFLOW_REPORTED.swap(true, Ordering::Relaxed) {
serial_print("HHDM overflow phys=");
serial_print(U64Buf::new(phys).as_str());
serial_print(", hhdm_offset=");
serial_print(U64Buf::new(hhdm_offset).as_str());
serial_print("\n");
}
panic!("phys_to_virt overflow");
}
}
}
pub fn tlb_flush() {
@@ -73,6 +96,11 @@ pub fn set_page_table(root_phys: u64) {
}
}
pub fn setup_mair() {
let mair: u64 = (0xFF << 0) | (0x00 << 8);
unsafe { core::arch::asm!("msr mair_el1, {0}", "isb", in(reg) mair) }
}
// translation control register: handles addresses
fn setup_tcr() {
unsafe {
@@ -85,8 +113,10 @@ fn setup_tcr() {
(0b01 << 10)| // ORGN0: normal WB RAWA
(0b01 << 26)| // ORGN1
(0b01 << 8) | // IRGN0
(0b01 << 24); // IRGN1
core::arch::asm!("msr tcr_el1, {0}", in(reg) tcr);
(0b01 << 24) | // IRGN1
(0b101 << 32); // IPS: 48-bit PA (256GB)
core::arch::asm!("msr tcr_el1, {0}", "isb", in(reg) tcr);
}
}
@@ -151,9 +181,19 @@ pub fn initialize_paging_aarch64<'a>(
);
}
page_table.map_page(0xFFFF_0000_0900_0000, 0x0900_0000, device_flags()); // the UART
page_table.map_range(0xFFFF_0000_0900_0000, 0x0900_0000, 0x1000, device_flags()); // the UART
page_table.map_range(0xFFFF_0000_0800_0000, 0x0800_0000, 0x10000, device_flags()); // the GICD
page_table.map_range(0xFFFF_0000_0801_0000, 0x0801_0000, 0x10000, device_flags()); // the GICC
page_table.map_page(0xFFFF_0000_0905_0000, 0x0905_0000, device_flags()); // KMI0 (keyboard)
page_table.map_page(0xFFFF_0000_0906_0000, 0x0906_0000, device_flags()); // KMI1 (mouse)
setup_mair();
setup_tcr();
let stack_phys = KERNEL_STACK.0.as_ptr() as u64 - k_virt_base + k_phys_base;
let stack_virt = KERNEL_STACK.0.as_ptr() as u64;
page_table.map_range(stack_virt, stack_phys, 64 * 1024, kernel_data_flags());
set_page_table(page_table.root_phys);
tlb_flush();
@@ -166,9 +206,9 @@ pub struct AArchPageTable {
pub fn alloc_frame() -> Option<u64> {
let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR_AARCH64.lock());
let frame = frame_allocator.allocate_frame();
let frame_opt = frame_allocator.allocate_frame();
drop(frame_allocator);
return frame;
return frame_opt;
}
impl AArchPageTable {
@@ -179,7 +219,7 @@ impl AArchPageTable {
.expect("Could not allocate frame for page table");
unsafe {
core::ptr::write_bytes(phys_to_virt(root_phys), 0, 512);
core::ptr::write_bytes(phys_to_virt(root_phys), 0, 4096);
}
AArchPageTable { root_phys }
@@ -200,7 +240,7 @@ impl AArchPageTable {
} else {
let child = alloc_frame().expect("Could not allocate frame when creating page table");
unsafe {
core::ptr::write_bytes(phys_to_virt(child), 0, 512);
core::ptr::write_bytes(phys_to_virt(child), 0, 4096);
entry_ptr.write_volatile(child | VALID | TABLE);
}
return child;
@@ -216,7 +256,6 @@ impl AArchPageTable {
let l1_phys = self.get_or_create_table(self.root_phys, l0);
let l2_phys = self.get_or_create_table(l1_phys, l1);
let l3_phys = self.get_or_create_table(l2_phys, l2);
let entry_ptr = self.table_ptr(l3_phys, l3);
unsafe {
+4 -15
View File
@@ -91,24 +91,13 @@ impl XunilFrameAllocator {
}
#[cfg(target_arch = "x86_64")]
pub fn init<'a>(
hhdm_response: &HhdmResponse,
memory_map_response: &'a MemoryMapResponse,
) -> OffsetPageTable<'static> {
return init_x86_64(hhdm_response, memory_map_response);
pub fn init<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {
init_x86_64(hhdm_response, memory_map_response);
}
#[cfg(target_arch = "aarch64")]
pub fn init<'a>(
hhdm_response: &HhdmResponse,
memory_map_response: &'a MemoryMapResponse,
executable_address_response: &ExecutableAddressResponse,
) -> AArchPageTable {
return init_aarch64(
hhdm_response,
memory_map_response,
executable_address_response,
);
pub fn init(mapper: &mut AArchPageTable) {
init_aarch64(mapper);
}
#[cfg(target_arch = "x86_64")]
+7 -12
View File
@@ -3,11 +3,12 @@ use crate::{
gdt::load_gdt_x86_64,
heap::init_heap,
interrupts::{PICS, init_idt_x86_64},
mouse::setup_mouse,
kmi::setup_kmi,
paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64},
syscall::init_syscalls,
},
driver::mouse::MOUSE,
config::TIMER_FREQUENCY_HZ,
driver::kmi::MOUSE,
};
use x86_64::{
@@ -19,8 +20,7 @@ use x86_64::{
use limine::response::{HhdmResponse, MemoryMapResponse};
const TIMER_PRECISION_HZ: u32 = 1000;
const PIT_DIVISOR: u16 = (1_193_182_u32 / TIMER_PRECISION_HZ) as u16;
const PIT_DIVISOR: u16 = (1_193_182_u32 / TIMER_FREQUENCY_HZ as u32) as u16;
pub fn memory_management_init(
hhdm_response: &HhdmResponse,
@@ -47,10 +47,7 @@ pub fn set_pit_interval() {
});
}
pub fn init_x86_64<'a>(
hhdm_response: &HhdmResponse,
memory_map_response: &'a MemoryMapResponse,
) -> OffsetPageTable<'static> {
pub fn init_x86_64<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {
load_gdt_x86_64();
unsafe {
@@ -78,7 +75,7 @@ pub fn init_x86_64<'a>(
pics.write_masks(master_mask, slave_mask);
}
let mouse_status = setup_mouse();
let kmi_status = setup_kmi();
set_pit_interval();
interrupts::enable();
@@ -89,7 +86,5 @@ pub fn init_x86_64<'a>(
.ok()
.expect("Failed to initalize heap");
MOUSE.set_status(mouse_status);
return mapper;
MOUSE.set_status(kmi_status);
}
+10 -19
View File
@@ -1,10 +1,13 @@
use core::sync::atomic::Ordering;
use crate::{
arch::x86_64::{gdt, mouse::mouse_interrupt},
arch::x86_64::gdt,
driver::{
graphics::framebuffer::with_framebuffer, keyboard::push_scancode, mouse::MOUSE,
serial::with_serial_console, timer::TIMER,
graphics::framebuffer::with_framebuffer,
keyboard::push_scancode,
kmi::{keyboard_interrupt, mouse_interrupt},
serial::with_serial_console,
timer::TIMER,
},
println,
};
@@ -12,7 +15,6 @@ use lazy_static::lazy_static;
use pic8259::ChainedPics;
use spin::Mutex;
use x86_64::{
instructions::port::Port,
registers::control::Cr2,
structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
};
@@ -115,17 +117,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
}
extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: InterruptStackFrame) {
let interrupt_result = mouse_interrupt();
if let Some(interrupt_result) = interrupt_result {
MOUSE.interrupt(
interrupt_result.0,
interrupt_result.1,
interrupt_result.2,
interrupt_result.3,
interrupt_result.4,
);
}
mouse_interrupt();
unsafe {
PICS.lock()
@@ -134,10 +126,9 @@ extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: InterruptStackFr
}
pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
let mut port = Port::new(0x60);
let scancode: u8 = unsafe { port.read() };
push_scancode(scancode);
if let Some(scancode) = keyboard_interrupt() {
push_scancode(scancode);
}
unsafe {
PICS.lock()
@@ -1,14 +1,5 @@
// Comment to self: WHY IS THIS SOO HARD
use crate::util::get_bit;
use core::sync::atomic::{AtomicU8, Ordering};
use x86_64::instructions::{interrupts::without_interrupts, port::Port};
static CURRENTLY_RECEIVING_STATE: AtomicU8 = AtomicU8::new(0);
static FLAGS_BYTE: AtomicU8 = AtomicU8::new(0);
static X_DELTA_BYTE: AtomicU8 = AtomicU8::new(0);
static Y_DELTA_BYTE: AtomicU8 = AtomicU8::new(0);
use crate::arch::arch::safe_lock;
use x86_64::instructions::port::Port;
fn wait_input_buffer_clear(command_port: &mut Port<u8>) {
unsafe {
@@ -83,8 +74,8 @@ fn clear_and_expect_output(
}
}
pub fn setup_mouse() -> u8 {
without_interrupts(|| {
pub fn setup_kmi() -> u8 {
safe_lock(|| {
let mut command_port: Port<u8> = Port::new(0x64);
let mut data_port: Port<u8> = Port::new(0x60);
@@ -143,88 +134,29 @@ pub fn setup_mouse() -> u8 {
})
}
fn reset_state() {
CURRENTLY_RECEIVING_STATE.store(0, Ordering::Relaxed);
FLAGS_BYTE.store(0, Ordering::Relaxed);
X_DELTA_BYTE.store(0, Ordering::Relaxed);
Y_DELTA_BYTE.store(0, Ordering::Relaxed);
}
pub fn mouse_interrupt() -> Option<(u8, u8, u8, i16, i16)> {
pub unsafe fn read_mouse_control() -> u8 {
let mut command_port: Port<u8> = Port::new(0x64);
let mut data_port: Port<u8> = Port::new(0x60);
unsafe {
if (command_port.read() & 0x20) == 0 {
// if this interrupt is not for the mouse, return
return None;
}
let byte = data_port.read();
let state_idx = CURRENTLY_RECEIVING_STATE.fetch_add(1, Ordering::Relaxed);
if state_idx == 0 {
if (byte & 0x08) == 0 {
// if sync bit unset, return
reset_state();
return None;
}
if (byte & 0b0100_0000) != 0 {
// if x overflow set, return
reset_state();
return None;
}
if (byte & 0b1000_0000) != 0 {
// if y overflow set, return
reset_state();
return None;
}
FLAGS_BYTE.store(byte, Ordering::Relaxed);
None
} else if state_idx == 1 {
X_DELTA_BYTE.store(byte, Ordering::Relaxed);
None
} else if state_idx == 2 {
Y_DELTA_BYTE.store(byte, Ordering::Relaxed);
let flags = FLAGS_BYTE.load(Ordering::Relaxed);
let left_button_pressed = get_bit(flags, 0);
let right_button_pressed = get_bit(flags, 1);
let middle_button_pressed = get_bit(flags, 2);
let x_delta_sign = get_bit(flags, 4);
let y_delta_sign = get_bit(flags, 5);
let x_delta: i16 = {
let x_delta = X_DELTA_BYTE.load(Ordering::Relaxed);
if x_delta_sign == 1 {
(x_delta as i16) - 256
} else {
x_delta as i16
}
};
let y_delta: i16 = -{
let y_delta = Y_DELTA_BYTE.load(Ordering::Relaxed);
if y_delta_sign == 1 {
(y_delta as i16) - 256
} else {
y_delta as i16
}
};
reset_state();
Some((
left_button_pressed,
right_button_pressed,
middle_button_pressed,
x_delta,
y_delta,
))
} else {
None
}
}
unsafe { command_port.read() }
}
pub unsafe fn read_mouse_data() -> u8 {
let mut data: Port<u8> = Port::new(0x60);
unsafe { data.read() }
}
pub unsafe fn write_mouse_control(byte: u8) {
let mut command_port: Port<u8> = Port::new(0x64);
unsafe { command_port.write(byte) }
}
pub unsafe fn write_mouse_data(byte: u8) {
let mut command_port: Port<u8> = Port::new(0x60);
unsafe { command_port.write(byte) }
}
pub unsafe fn read_keyboard_data() -> u8 {
unsafe { read_mouse_data() }
}
pub unsafe fn read_keyboard_control() -> u8 {
unsafe { read_mouse_control() }
}
+1 -1
View File
@@ -2,7 +2,7 @@ pub mod gdt;
pub mod heap;
pub mod init;
pub mod interrupts;
pub mod mouse;
pub mod kmi;
pub mod paging;
pub mod syscall;
pub mod usermode;
+1
View File
@@ -0,0 +1 @@
pub const TIMER_FREQUENCY_HZ: usize = 1000;
+190
View File
@@ -0,0 +1,190 @@
use crate::util::get_bit;
use core::sync::atomic::{AtomicI16, AtomicU8, Ordering};
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::kmi::{
read_keyboard_control, read_keyboard_data, read_mouse_control, read_mouse_data,
};
#[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::kmi::{
read_keyboard_control, read_keyboard_data, read_mouse_control, read_mouse_data,
};
static CURRENTLY_RECEIVING_STATE: AtomicU8 = AtomicU8::new(0);
static FLAGS_BYTE: AtomicU8 = AtomicU8::new(0);
static X_DELTA_BYTE: AtomicU8 = AtomicU8::new(0);
static Y_DELTA_BYTE: AtomicU8 = AtomicU8::new(0);
pub struct Mouse {
left_button_pressed: AtomicU8,
right_button_pressed: AtomicU8,
middle_button_pressed: AtomicU8,
x_delta: AtomicI16,
y_delta: AtomicI16,
status: AtomicU8,
}
impl Mouse {
const fn new() -> Mouse {
Mouse {
left_button_pressed: AtomicU8::new(0),
right_button_pressed: AtomicU8::new(0),
middle_button_pressed: AtomicU8::new(0),
x_delta: AtomicI16::new(0),
y_delta: AtomicI16::new(0),
status: AtomicU8::new(0),
}
}
pub fn interrupt(
&self,
left_button_pressed: u8,
right_button_pressed: u8,
middle_button_pressed: u8,
x_delta: i16,
y_delta: i16,
) {
self.left_button_pressed
.store(left_button_pressed, Ordering::Relaxed);
self.right_button_pressed
.store(right_button_pressed, Ordering::Relaxed);
self.middle_button_pressed
.store(middle_button_pressed, Ordering::Relaxed);
self.x_delta.fetch_add(x_delta, Ordering::Relaxed);
self.y_delta.fetch_add(y_delta, Ordering::Relaxed);
}
pub fn button_state(&self) -> (u8, u8, u8) {
(
self.left_button_pressed.load(Ordering::Relaxed),
self.right_button_pressed.load(Ordering::Relaxed),
self.middle_button_pressed.load(Ordering::Relaxed),
)
}
pub fn take_motion(&self) -> (i16, i16) {
(
self.x_delta.swap(0, Ordering::Relaxed),
self.y_delta.swap(0, Ordering::Relaxed),
)
}
pub fn set_status(&self, status: u8) {
self.status.store(status, Ordering::Relaxed);
}
pub fn get_status(&self) -> u8 {
self.status.load(Ordering::Relaxed)
}
}
fn reset_state() {
CURRENTLY_RECEIVING_STATE.store(0, Ordering::Relaxed);
FLAGS_BYTE.store(0, Ordering::Relaxed);
X_DELTA_BYTE.store(0, Ordering::Relaxed);
Y_DELTA_BYTE.store(0, Ordering::Relaxed);
}
pub fn process_mouse_interrupt() -> Option<(u8, u8, u8, i16, i16)> {
#[cfg(target_arch = "x86_64")]
if (unsafe { read_mouse_control() } & 0x20) == 0 {
return None;
}
#[cfg(target_arch = "aarch64")]
if (unsafe { read_mouse_control() } & 0x10) == 0 {
return None;
}
let byte = unsafe { read_mouse_data() };
let state_idx = CURRENTLY_RECEIVING_STATE.fetch_add(1, Ordering::Relaxed);
if state_idx == 0 {
if (byte & 0x08) == 0 {
// if sync bit unset, return
reset_state();
return None;
}
if (byte & 0b0100_0000) != 0 {
// if x overflow set, return
reset_state();
return None;
}
if (byte & 0b1000_0000) != 0 {
// if y overflow set, return
reset_state();
return None;
}
FLAGS_BYTE.store(byte, Ordering::Relaxed);
None
} else if state_idx == 1 {
X_DELTA_BYTE.store(byte, Ordering::Relaxed);
None
} else if state_idx == 2 {
Y_DELTA_BYTE.store(byte, Ordering::Relaxed);
let flags = FLAGS_BYTE.load(Ordering::Relaxed);
let left_button_pressed = get_bit(flags, 0);
let right_button_pressed = get_bit(flags, 1);
let middle_button_pressed = get_bit(flags, 2);
let x_delta_sign = get_bit(flags, 4);
let y_delta_sign = get_bit(flags, 5);
let x_delta: i16 = {
let x_delta = X_DELTA_BYTE.load(Ordering::Relaxed);
if x_delta_sign == 1 {
(x_delta as i16) - 256
} else {
x_delta as i16
}
};
let y_delta: i16 = -{
let y_delta = Y_DELTA_BYTE.load(Ordering::Relaxed);
if y_delta_sign == 1 {
(y_delta as i16) - 256
} else {
y_delta as i16
}
};
reset_state();
Some((
left_button_pressed,
right_button_pressed,
middle_button_pressed,
x_delta,
y_delta,
))
} else {
None
}
}
pub fn mouse_interrupt() {
if let Some(interrupt_result) = process_mouse_interrupt() {
MOUSE.interrupt(
interrupt_result.0,
interrupt_result.1,
interrupt_result.2,
interrupt_result.3,
interrupt_result.4,
);
}
}
pub fn keyboard_interrupt() -> Option<u8> {
#[cfg(target_arch = "x86_64")]
if (unsafe { read_keyboard_control() } & 0x01) == 0 {
return None; // OBF clear, no data
}
#[cfg(target_arch = "aarch64")]
if (unsafe { read_keyboard_control() } & 0x10) == 0 {
return None; // RXFULL clear, no data
}
let scancode = unsafe { read_keyboard_data() };
Some(scancode)
}
pub static MOUSE: Mouse = Mouse::new();
+1 -1
View File
@@ -2,6 +2,6 @@ pub mod elf;
pub mod fs;
pub mod graphics;
pub mod keyboard;
pub mod mouse;
pub mod kmi;
pub mod serial;
pub mod timer;
-63
View File
@@ -1,63 +0,0 @@
use core::sync::atomic::{AtomicI16, AtomicU8, Ordering};
pub struct Mouse {
left_button_pressed: AtomicU8,
right_button_pressed: AtomicU8,
middle_button_pressed: AtomicU8,
x_delta: AtomicI16,
y_delta: AtomicI16,
status: AtomicU8,
}
impl Mouse {
const fn new() -> Mouse {
Mouse {
left_button_pressed: AtomicU8::new(0),
right_button_pressed: AtomicU8::new(0),
middle_button_pressed: AtomicU8::new(0),
x_delta: AtomicI16::new(0),
y_delta: AtomicI16::new(0),
status: AtomicU8::new(0),
}
}
pub fn interrupt(
&self,
left_button_pressed: u8,
right_button_pressed: u8,
middle_button_pressed: u8,
x_delta: i16,
y_delta: i16,
) {
self.left_button_pressed
.store(left_button_pressed, Ordering::Relaxed);
self.right_button_pressed
.store(right_button_pressed, Ordering::Relaxed);
self.middle_button_pressed
.store(middle_button_pressed, Ordering::Relaxed);
self.x_delta.fetch_add(x_delta, Ordering::Relaxed);
self.y_delta.fetch_add(y_delta, Ordering::Relaxed);
}
pub fn button_state(&self) -> (u8, u8, u8) {
(
self.left_button_pressed.load(Ordering::Relaxed),
self.right_button_pressed.load(Ordering::Relaxed),
self.middle_button_pressed.load(Ordering::Relaxed),
)
}
pub fn take_motion(&self) -> (i16, i16) {
(
self.x_delta.swap(0, Ordering::Relaxed),
self.y_delta.swap(0, Ordering::Relaxed),
)
}
pub fn set_status(&self, status: u8) {
self.status.store(status, Ordering::Relaxed);
}
pub fn get_status(&self) -> u8 {
self.status.load(Ordering::Relaxed)
}
}
pub static MOUSE: Mouse = Mouse::new();
+40 -4
View File
@@ -1,3 +1,4 @@
use crate::alloc::string::ToString;
use crate::driver::graphics::font_render::render_text;
use crate::driver::graphics::framebuffer::Framebuffer;
use crate::{arch::arch::safe_lock, driver::graphics::base::rgb};
@@ -20,7 +21,7 @@ impl Write for ConsoleWriter<'_> {
pub struct SerialConsole {
text: String,
font_size: usize,
pub font_size: usize,
dirty: bool,
}
@@ -35,10 +36,45 @@ impl SerialConsole {
pub fn print(&mut self, text: &str, fb: &mut Framebuffer) {
let max_height = fb.height / (12 * self.font_size);
if self.text.split('\n').count() > max_height {
self.clear();
let max_width = fb.width / (8 * self.font_size);
for ch in text.chars() {
if ch == '\n' {
self.text.push('\n');
continue;
}
let line_len = self
.text
.rsplit('\n')
.next()
.map(|l| l.chars().count())
.unwrap_or(0);
if line_len >= max_width {
self.text.push('\n');
}
self.text.push(ch);
}
self.text.push_str(text);
let lines = self.text.lines().count();
if lines > max_height {
let remove = lines - max_height;
let mut split = 0;
for (i, c) in self.text.char_indices() {
if c == '\n' {
split += 1;
if split == remove {
self.text = self.text[i + 1..].to_string();
break;
}
}
}
}
self.dirty = true;
}
+76 -20
View File
@@ -5,17 +5,24 @@
extern crate alloc;
use core::fmt::Write;
#[cfg(target_arch = "aarch64")]
use aarch64_cpu::registers::{DAIF, Writeable};
use limine::BaseRevision;
use limine::request::{
DateAtBootRequest, ExecutableAddressRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest,
RequestsEndMarker, RequestsStartMarker,
};
pub mod arch;
pub mod config;
pub mod driver;
pub mod mm;
pub mod task;
pub mod util;
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::interrupts::enable_interrupts;
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::paging::AArchPageTable;
use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_print};
#[cfg(target_arch = "x86_64")]
use crate::driver::elf::loader::run_elf;
@@ -104,42 +111,56 @@ pub fn _print(args: core::fmt::Arguments) {
#[unsafe(no_mangle)]
unsafe extern "C" fn kmain() -> ! {
// All limine requests must also be referenced in a called function, otherwise they may be
// removed by the linker.
assert!(BASE_REVISION.is_supported());
// mask everything early to prevent stack corruption and other undefined behavior
#[cfg(target_arch = "aarch64")]
{
DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Masked + DAIF::F::Masked);
}
if let Some(hhdm_response) = HHDM_REQUEST.get_response() {
HHDM_OFFSET.store(
hhdm_response.offset(),
core::sync::atomic::Ordering::Relaxed,
);
#[allow(unused_variables)]
if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() {
#[cfg(target_arch = "x86_64")]
init(hhdm_response, memory_map_response);
#[cfg(target_arch = "aarch64")]
if let Some(executable_address_response) = EXECUTABLE_ADDRESS_REQUEST.get_response() {
init(
use crate::arch::aarch64::init::preinit_aarch64;
preinit_aarch64(
hhdm_response,
memory_map_response,
executable_address_response,
);
loop {}
} else {
kernel_crash()
}
#[cfg(target_arch = "x86_64")]
unsafe {
kernel_main_x86_64()
}
} else {
kernel_crash(); // Could not get required info from Limine's memory map.
}
} else {
kernel_crash(); // Could not get required info from Limine's higher-half direct mapping.
}
}
#[cfg(target_arch = "aarch64")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kernel_main_aarch64(mapper: &mut AArchPageTable) -> ! {
// All limine requests must also be referenced in a called function, otherwise they may be
// removed by the linker.
assert!(BASE_REVISION.is_supported());
init(mapper);
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() {
init_framebuffer(&limine_framebuffer);
#[cfg(target_arch = "x86_64")]
with_framebuffer(|fb| fb.setup_x86_64());
#[cfg(target_arch = "aarch64")]
with_framebuffer(|fb| fb.setup_aarch64());
} else {
serial_print("no framebuffers found");
@@ -156,17 +177,52 @@ unsafe extern "C" fn kmain() -> ! {
println!("Could not get date at boot. Will default to 0.")
}
#[cfg(target_arch = "aarch64")]
{
println!("Hello from Aarch64!");
with_framebuffer(|fb| {
with_serial_console(|sc| sc.render(fb));
rectangle_filled(fb, 100, 100, 20, 20, rgb(255, 255, 255));
fb.present();
});
println!("Hello from Aarch64!");
with_framebuffer(|fb| {
with_serial_console(|sc| sc.render(fb));
rectangle_filled(fb, 100, 100, 20, 20, rgb(255, 255, 255));
});
enable_interrupts();
loop {}
}
#[cfg(target_arch = "x86_64")]
pub unsafe fn kernel_main_x86_64() -> ! {
// All limine requests must also be referenced in a called function, otherwise they may be
// removed by the linker.
assert!(BASE_REVISION.is_supported());
if let Some(hhdm_response) = HHDM_REQUEST.get_response() {
if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() {
init(hhdm_response, memory_map_response);
} else {
kernel_crash(); // Could not get required info from Limine's memory map.
}
} else {
kernel_crash(); // Could not get required info from Limine's higher-half direct mapping.
}
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() {
init_framebuffer(&limine_framebuffer);
with_framebuffer(|fb| fb.setup_x86_64());
} else {
serial_print("no framebuffers found");
}
}
init_serial_console();
init_keyboard();
if let Some(date_at_boot_response) = DATE_AT_BOOT_REQUEST.get_response() {
TIMER.set_date_at_boot(date_at_boot_response.timestamp().as_secs());
} else {
println!("Could not get date at boot. Will default to 0.")
}
#[cfg(target_arch = "x86_64")]
run_elf(INIT_ELF_BYTES, false);
loop {}
@@ -200,7 +256,7 @@ fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
let mut buf = [0u8; 512];
let msg = {
let mut w = BufWriter::new(&mut buf);
let _ = core::fmt::write(&mut w, core::format_args!("{}", _info.message()));
let _ = core::fmt::write(&mut w, core::format_args!("{}", _info));
let len = w.pos;
core::str::from_utf8(&buf[..len]).unwrap_or("(utf8 error)")
};
+38 -1
View File
@@ -26,7 +26,44 @@ pub struct UserContext {
#[cfg(target_arch = "aarch64")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct UserContext {}
pub struct UserContext {
pub x0: u64,
pub x1: u64,
pub x2: u64,
pub x3: u64,
pub x4: u64,
pub x5: u64,
pub x6: u64,
pub x7: u64,
pub x8: u64,
pub x9: u64,
pub x10: u64,
pub x11: u64,
pub x12: u64,
pub x13: u64,
pub x14: u64,
pub x15: u64,
pub x16: u64,
pub x17: u64,
pub x18: u64,
pub x19: u64,
pub x20: u64,
pub x21: u64,
pub x22: u64,
pub x23: u64,
pub x24: u64,
pub x25: u64,
pub x26: u64,
pub x27: u64,
pub x28: u64,
pub x29: u64,
pub x30: u64,
pub elr_el1: u64,
pub spsr_el1: u64,
pub esr_el1: u64, // exception type
pub far_el1: u64, // fault type
_pad: u64,
}
#[unsafe(no_mangle)]
pub extern "C" fn ctx_save(regs: *const UserContext) {
+30
View File
@@ -1,6 +1,36 @@
use crate::{driver::timer::TIMER, println};
use spin::{Mutex, MutexGuard};
pub struct U64Buf {
buf: [u8; 20],
start: usize,
}
impl U64Buf {
pub fn new(n: u64) -> Self {
let mut buf = [0u8; 20];
let mut pos = 20;
let mut val = n;
if val == 0 {
buf[19] = b'0';
return Self { buf, start: 19 };
}
while val > 0 {
pos -= 1;
buf[pos] = b'0' + (val % 10) as u8;
val /= 10;
}
Self { buf, start: pos }
}
pub fn as_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(&self.buf[self.start..]) }
}
}
pub struct Locked<A> {
inner: Mutex<A>,
}