mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-06-02 12:44:24 +02:00
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:
+3
-9
@@ -1,16 +1,10 @@
|
||||
include config.mk
|
||||
|
||||
# Nuke built-in rules and variables.
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
# 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)
|
||||
|
||||
# Default user QEMU flags. These are appended to the QEMU command calls.
|
||||
$(call USER_VARIABLE,QEMUFLAGS,-m 2G)
|
||||
|
||||
override QEMUFLAGS := -m $(MEMORY)
|
||||
override IMAGE_NAME := XunilOS-$(KARCH)
|
||||
|
||||
.PHONY: all
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export KARCH ?= aarch64
|
||||
export OUTPUT ?= kernel
|
||||
export MEMORY ?= 512M
|
||||
export TIMER_FREQUENCY_HZ ?= 1000
|
||||
Generated
+7
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,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",
|
||||
|
||||
@@ -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."),
|
||||
}
|
||||
}
|
||||
@@ -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) };
|
||||
}
|
||||
|
||||
@@ -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 +0,0 @@
|
||||
// TODO: add keyboard logic
|
||||
@@ -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;
|
||||
})
|
||||
}
|
||||
@@ -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 +0,0 @@
|
||||
// TODO: add mouse logic
|
||||
@@ -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
@@ -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")]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub const TIMER_FREQUENCY_HZ: usize = 1000;
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
@@ -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
@@ -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)")
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
+1
-1
Submodule user/libxunil updated: 695da84901...e134040a9f
Reference in New Issue
Block a user