mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-06-02 11:44:24 +02:00
Add virtio driver for aarch64 with only input for now, move keyboard,
mouse and other io logic to an io folder, make ps2 convert to linux event codes like virtio, force modern mmio and gic version 2 on aarch64
This commit is contained in:
+4
-2
@@ -4,7 +4,7 @@ include config.mk
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
override QEMUFLAGS := -m $(MEMORY)
|
||||
override QEMUFLAGS := -m $(MEMORY) -global virtio-mmio.force-legacy=false
|
||||
override IMAGE_NAME := XunilOS-$(KARCH)
|
||||
|
||||
.PHONY: all
|
||||
@@ -39,12 +39,14 @@ run-hdd-x86_64: edk2-ovmf $(IMAGE_NAME).hdd
|
||||
.PHONY: run-aarch64
|
||||
run-aarch64: edk2-ovmf $(IMAGE_NAME).iso
|
||||
qemu-system-$(KARCH) \
|
||||
-M virt \
|
||||
-M virt,gic-version=2,secure=off \
|
||||
-cpu cortex-a72 \
|
||||
-device ramfb \
|
||||
-device qemu-xhci \
|
||||
-device usb-kbd \
|
||||
-device usb-mouse \
|
||||
-device virtio-keyboard-device \
|
||||
-device virtio-mouse-device \
|
||||
-serial stdio \
|
||||
-drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||
-cdrom $(IMAGE_NAME).iso \
|
||||
|
||||
+2
-1
@@ -6,11 +6,12 @@ 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 karch = env::var("KARCH").unwrap_or_else(|_| "x86_64".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};"#),
|
||||
format!("pub const TIMER_FREQUENCY_HZ: usize = {timer_frequency_hz};\npub const KARCH: &str = \"{karch}\";"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ use crate::{
|
||||
arch::aarch64::{
|
||||
heap::init_heap,
|
||||
interrupts::init_interrupts,
|
||||
kmi::setup_kmi,
|
||||
paging::{AArchPageTable, initialize_paging_aarch64},
|
||||
},
|
||||
config::TIMER_FREQUENCY_HZ,
|
||||
driver::io::virtio::scan_devices,
|
||||
};
|
||||
use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse};
|
||||
|
||||
@@ -17,7 +17,7 @@ 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);
|
||||
core::arch::asm!("mrs {}, cntp_tval_el0", "isb", in(reg) freq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) {
|
||||
pub extern "C" fn init_aarch64(mapper: &mut AArchPageTable) {
|
||||
init_heap(mapper);
|
||||
set_timer_freq(TIMER_FREQUENCY_HZ);
|
||||
scan_devices();
|
||||
init_interrupts();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ use core::{arch::global_asm, sync::atomic::Ordering};
|
||||
|
||||
use crate::{
|
||||
arch::syscall::syscall_dispatch,
|
||||
config::TIMER_FREQUENCY_HZ,
|
||||
driver::{
|
||||
graphics::framebuffer::with_framebuffer,
|
||||
keyboard::push_scancode,
|
||||
kmi::{keyboard_interrupt, mouse_interrupt},
|
||||
io::virtio::{KEYBOARD_SLOT, MOUSE_SLOT, input::input_interrupt},
|
||||
serial::with_serial_console,
|
||||
timer::TIMER,
|
||||
},
|
||||
@@ -161,8 +161,13 @@ pub fn init_interrupts() {
|
||||
pub fn enable_interrupts() {
|
||||
unsafe {
|
||||
gic_enable_interrupt(30); // timer IRQ
|
||||
gic_enable_interrupt(17); // keyboard IRQ
|
||||
gic_enable_interrupt(18); // mouse IRQ
|
||||
|
||||
let keyboard_irq = 32 + 0x10 + KEYBOARD_SLOT.load(Ordering::Relaxed);
|
||||
let mouse_irq = 32 + 0x10 + MOUSE_SLOT.load(Ordering::Relaxed);
|
||||
|
||||
gic_enable_interrupt(keyboard_irq as u32);
|
||||
gic_enable_interrupt(mouse_irq as u32);
|
||||
|
||||
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);
|
||||
@@ -183,6 +188,10 @@ unsafe extern "C" fn no_operation(ctx: *mut UserContext) {
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe extern "C" fn irq_handler(ctx: *mut UserContext) {
|
||||
let interrupt_id = unsafe { gic_acknowledge() };
|
||||
|
||||
let keyboard_irq = 32 + 0x10 + KEYBOARD_SLOT.load(Ordering::Relaxed);
|
||||
let mouse_irq = 32 + 0x10 + MOUSE_SLOT.load(Ordering::Relaxed);
|
||||
|
||||
match interrupt_id {
|
||||
30 => {
|
||||
TIMER.interrupt();
|
||||
@@ -198,14 +207,14 @@ unsafe extern "C" fn irq_handler(ctx: *mut UserContext) {
|
||||
fb.present();
|
||||
});
|
||||
}
|
||||
|
||||
unsafe { core::arch::asm!("msr cntp_tval_el0, {}", in(reg) TIMER_FREQUENCY_HZ) };
|
||||
}
|
||||
17 => {
|
||||
if let Some(scancode) = keyboard_interrupt() {
|
||||
push_scancode(scancode);
|
||||
}
|
||||
interrupt_id if keyboard_irq == interrupt_id as u64 => {
|
||||
input_interrupt("kbd");
|
||||
}
|
||||
18 => {
|
||||
mouse_interrupt();
|
||||
interrupt_id if mouse_irq == interrupt_id as u64 => {
|
||||
input_interrupt("mouse");
|
||||
}
|
||||
|
||||
_ => {}
|
||||
@@ -288,6 +297,6 @@ 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_irq, irq_handler);
|
||||
exception_handler!(lower_el_aarch64_fiq, no_operation);
|
||||
exception_handler!(lower_el_aarch64_serror, no_operation);
|
||||
|
||||
@@ -184,9 +184,7 @@ pub fn initialize_paging_aarch64<'a>(
|
||||
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();
|
||||
page_table.map_range(0xFFFF_0000_0a00_0000, 0x0a00_0000, 0x8000, device_flags()); // Virtio setup_mair();
|
||||
setup_tcr();
|
||||
|
||||
let stack_phys = KERNEL_STACK.0.as_ptr() as u64 - k_virt_base + k_phys_base;
|
||||
|
||||
@@ -13,13 +13,19 @@ use x86_64::{
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::paging::AArchPageTable;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::driver::io::ps2::process_scancodes;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::driver::io::virtio::input::process_keycodes;
|
||||
use crate::{
|
||||
arch::arch::{FRAME_ALLOCATOR, sleep},
|
||||
driver::{
|
||||
elf::loader::run_elf,
|
||||
fs::vfs::{vfs_close, vfs_lseek, vfs_open, vfs_read},
|
||||
graphics::framebuffer::{FRAMEBUFFER, USER_FB_BASE, with_framebuffer},
|
||||
keyboard::{KeyboardEvent, process_scancodes},
|
||||
io::{
|
||||
fs::vfs::{vfs_close, vfs_lseek, vfs_open, vfs_read},
|
||||
keyboard::KeyboardEvent,
|
||||
},
|
||||
timer::TIMER,
|
||||
},
|
||||
print,
|
||||
@@ -192,7 +198,11 @@ fn close(fd: isize) -> isize {
|
||||
}
|
||||
|
||||
fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
process_scancodes();
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
process_keycodes();
|
||||
|
||||
if max_events <= 0 || user_ptr.is_null() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{
|
||||
syscall::init_syscalls,
|
||||
},
|
||||
config::TIMER_FREQUENCY_HZ,
|
||||
driver::kmi::MOUSE,
|
||||
driver::io::mouse::MOUSE,
|
||||
};
|
||||
|
||||
use x86_64::{
|
||||
|
||||
@@ -4,8 +4,7 @@ use crate::{
|
||||
arch::x86_64::gdt,
|
||||
driver::{
|
||||
graphics::framebuffer::with_framebuffer,
|
||||
keyboard::push_scancode,
|
||||
kmi::{keyboard_interrupt, mouse_interrupt},
|
||||
io::ps2::{keyboard_interrupt, mouse_interrupt, push_scancode},
|
||||
serial::with_serial_console,
|
||||
timer::TIMER,
|
||||
},
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
pub const TIMER_FREQUENCY_HZ: usize = 1000;
|
||||
pub const TIMER_FREQUENCY_HZ: usize = 1000;
|
||||
pub const KARCH: &str = "aarch64";
|
||||
@@ -38,9 +38,9 @@ fn fd_ok(fd: Fd) -> bool {
|
||||
fd >= 0 && (fd as usize) < MAX_FD
|
||||
}
|
||||
|
||||
static DOOM_WAD: &[u8] = include_bytes!("../../../../assets/doom1.wad");
|
||||
static DOOM_ELF: &[u8] = include_bytes!("../../../../assets/doomgeneric");
|
||||
static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../assets/helloworld.elf");
|
||||
static DOOM_WAD: &[u8] = include_bytes!("../../../../../assets/doom1.wad");
|
||||
static DOOM_ELF: &[u8] = include_bytes!("../../../../../assets/doomgeneric");
|
||||
static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../../assets/helloworld.elf");
|
||||
|
||||
static FILES: &[FakeFileEntry] = &[
|
||||
FakeFileEntry {
|
||||
@@ -0,0 +1,192 @@
|
||||
pub const KEY_RESERVED: u8 = 0;
|
||||
pub const KEY_ESC: u8 = 1;
|
||||
pub const KEY_1: u8 = 2;
|
||||
pub const KEY_2: u8 = 3;
|
||||
pub const KEY_3: u8 = 4;
|
||||
pub const KEY_4: u8 = 5;
|
||||
pub const KEY_5: u8 = 6;
|
||||
pub const KEY_6: u8 = 7;
|
||||
pub const KEY_7: u8 = 8;
|
||||
pub const KEY_8: u8 = 9;
|
||||
pub const KEY_9: u8 = 10;
|
||||
pub const KEY_0: u8 = 11;
|
||||
pub const KEY_MINUS: u8 = 12;
|
||||
pub const KEY_EQUAL: u8 = 13;
|
||||
pub const KEY_BACKSPACE: u8 = 14;
|
||||
pub const KEY_TAB: u8 = 15;
|
||||
pub const KEY_Q: u8 = 16;
|
||||
pub const KEY_W: u8 = 17;
|
||||
pub const KEY_E: u8 = 18;
|
||||
pub const KEY_R: u8 = 19;
|
||||
pub const KEY_T: u8 = 20;
|
||||
pub const KEY_Y: u8 = 21;
|
||||
pub const KEY_U: u8 = 22;
|
||||
pub const KEY_I: u8 = 23;
|
||||
pub const KEY_O: u8 = 24;
|
||||
pub const KEY_P: u8 = 25;
|
||||
pub const KEY_LEFTBRACE: u8 = 26;
|
||||
pub const KEY_RIGHTBRACE: u8 = 27;
|
||||
pub const KEY_ENTER: u8 = 28;
|
||||
pub const KEY_LEFTCTRL: u8 = 29;
|
||||
pub const KEY_A: u8 = 30;
|
||||
pub const KEY_S: u8 = 31;
|
||||
pub const KEY_D: u8 = 32;
|
||||
pub const KEY_F: u8 = 33;
|
||||
pub const KEY_G: u8 = 34;
|
||||
pub const KEY_H: u8 = 35;
|
||||
pub const KEY_J: u8 = 36;
|
||||
pub const KEY_K: u8 = 37;
|
||||
pub const KEY_L: u8 = 38;
|
||||
pub const KEY_SEMICOLON: u8 = 39;
|
||||
pub const KEY_APOSTROPHE: u8 = 40;
|
||||
pub const KEY_GRAVE: u8 = 41;
|
||||
pub const KEY_LEFTSHIFT: u8 = 42;
|
||||
pub const KEY_BACKSLASH: u8 = 43;
|
||||
pub const KEY_Z: u8 = 44;
|
||||
pub const KEY_X: u8 = 45;
|
||||
pub const KEY_C: u8 = 46;
|
||||
pub const KEY_V: u8 = 47;
|
||||
pub const KEY_B: u8 = 48;
|
||||
pub const KEY_N: u8 = 49;
|
||||
pub const KEY_M: u8 = 50;
|
||||
pub const KEY_COMMA: u8 = 51;
|
||||
pub const KEY_DOT: u8 = 52;
|
||||
pub const KEY_SLASH: u8 = 53;
|
||||
pub const KEY_RIGHTSHIFT: u8 = 54;
|
||||
pub const KEY_KPASTERISK: u8 = 55;
|
||||
pub const KEY_LEFTALT: u8 = 56;
|
||||
pub const KEY_SPACE: u8 = 57;
|
||||
pub const KEY_CAPSLOCK: u8 = 58;
|
||||
pub const KEY_F1: u8 = 59;
|
||||
pub const KEY_F2: u8 = 60;
|
||||
pub const KEY_F3: u8 = 61;
|
||||
pub const KEY_F4: u8 = 62;
|
||||
pub const KEY_F5: u8 = 63;
|
||||
pub const KEY_F6: u8 = 64;
|
||||
pub const KEY_F7: u8 = 65;
|
||||
pub const KEY_F8: u8 = 66;
|
||||
pub const KEY_F9: u8 = 67;
|
||||
pub const KEY_F10: u8 = 68;
|
||||
pub const KEY_NUMLOCK: u8 = 69;
|
||||
pub const KEY_SCROLLLOCK: u8 = 70;
|
||||
pub const KEY_KP7: u8 = 71;
|
||||
pub const KEY_KP8: u8 = 72;
|
||||
pub const KEY_KP9: u8 = 73;
|
||||
pub const KEY_KPMINUS: u8 = 74;
|
||||
pub const KEY_KP4: u8 = 75;
|
||||
pub const KEY_KP5: u8 = 76;
|
||||
pub const KEY_KP6: u8 = 77;
|
||||
pub const KEY_KPPLUS: u8 = 78;
|
||||
pub const KEY_KP1: u8 = 79;
|
||||
pub const KEY_KP2: u8 = 80;
|
||||
pub const KEY_KP3: u8 = 81;
|
||||
pub const KEY_KP0: u8 = 82;
|
||||
pub const KEY_KPDOT: u8 = 83;
|
||||
pub const KEY_RIGHTCTRL: u8 = 97;
|
||||
pub const KEY_UP: u8 = 103;
|
||||
pub const KEY_LEFT: u8 = 105;
|
||||
pub const KEY_RIGHT: u8 = 106;
|
||||
pub const KEY_DOWN: u8 = 108;
|
||||
|
||||
pub const KEY_TO_CHAR: [Option<(char, char)>; 84] = [
|
||||
None, // 0 KEY_RESERVED
|
||||
Some(('\x1b', '\x1b')), // 1 KEY_ESC
|
||||
Some(('1', '!')), // 2 KEY_1
|
||||
Some(('2', '@')), // 3 KEY_2
|
||||
Some(('3', '#')), // 4 KEY_3
|
||||
Some(('4', '$')), // 5 KEY_4
|
||||
Some(('5', '%')), // 6 KEY_5
|
||||
Some(('6', '^')), // 7 KEY_6
|
||||
Some(('7', '&')), // 8 KEY_7
|
||||
Some(('8', '*')), // 9 KEY_8
|
||||
Some(('9', '(')), // 10 KEY_9
|
||||
Some(('0', ')')), // 11 KEY_0
|
||||
Some(('-', '_')), // 12 KEY_MINUS
|
||||
Some(('=', '+')), // 13 KEY_EQUAL
|
||||
Some(('\x08', '\x08')), // 14 KEY_BACKSPACE
|
||||
Some(('\t', '\t')), // 15 KEY_TAB
|
||||
Some(('q', 'Q')), // 16 KEY_Q
|
||||
Some(('w', 'W')), // 17 KEY_W
|
||||
Some(('e', 'E')), // 18 KEY_E
|
||||
Some(('r', 'R')), // 19 KEY_R
|
||||
Some(('t', 'T')), // 20 KEY_T
|
||||
Some(('y', 'Y')), // 21 KEY_Y
|
||||
Some(('u', 'U')), // 22 KEY_U
|
||||
Some(('i', 'I')), // 23 KEY_I
|
||||
Some(('o', 'O')), // 24 KEY_O
|
||||
Some(('p', 'P')), // 25 KEY_P
|
||||
Some(('[', '{')), // 26 KEY_LEFTBRACE
|
||||
Some((']', '}')), // 27 KEY_RIGHTBRACE
|
||||
Some(('\n', '\n')), // 28 KEY_ENTER
|
||||
None, // 29 KEY_LEFTCTRL
|
||||
Some(('a', 'A')), // 30 KEY_A
|
||||
Some(('s', 'S')), // 31 KEY_S
|
||||
Some(('d', 'D')), // 32 KEY_D
|
||||
Some(('f', 'F')), // 33 KEY_F
|
||||
Some(('g', 'G')), // 34 KEY_G
|
||||
Some(('h', 'H')), // 35 KEY_H
|
||||
Some(('j', 'J')), // 36 KEY_J
|
||||
Some(('k', 'K')), // 37 KEY_K
|
||||
Some(('l', 'L')), // 38 KEY_L
|
||||
Some((';', ':')), // 39 KEY_SEMICOLON
|
||||
Some(('\'', '"')), // 40 KEY_APOSTROPHE
|
||||
Some(('`', '~')), // 41 KEY_GRAVE
|
||||
None, // 42 KEY_LEFTSHIFT
|
||||
Some(('\\', '|')), // 43 KEY_BACKSLASH
|
||||
Some(('z', 'Z')), // 44 KEY_Z
|
||||
Some(('x', 'X')), // 45 KEY_X
|
||||
Some(('c', 'C')), // 46 KEY_C
|
||||
Some(('v', 'V')), // 47 KEY_V
|
||||
Some(('b', 'B')), // 48 KEY_B
|
||||
Some(('n', 'N')), // 49 KEY_N
|
||||
Some(('m', 'M')), // 50 KEY_M
|
||||
Some((',', '<')), // 51 KEY_COMMA
|
||||
Some(('.', '>')), // 52 KEY_DOT
|
||||
Some(('/', '?')), // 53 KEY_SLASH
|
||||
None, // 54 KEY_RIGHTSHIFT
|
||||
Some(('*', '*')), // 55 KEY_KPASTERISK
|
||||
None, // 56 KEY_LEFTALT
|
||||
Some((' ', ' ')), // 57 KEY_SPACE
|
||||
None, // 58 KEY_CAPSLOCK
|
||||
None, // 59 KEY_F1
|
||||
None, // 60 KEY_F2
|
||||
None, // 61 KEY_F3
|
||||
None, // 62 KEY_F4
|
||||
None, // 63 KEY_F5
|
||||
None, // 64 KEY_F6
|
||||
None, // 65 KEY_F7
|
||||
None, // 66 KEY_F8
|
||||
None, // 67 KEY_F9
|
||||
None, // 68 KEY_F10
|
||||
None, // 69 KEY_NUMLOCK
|
||||
None, // 70 KEY_SCROLLLOCK
|
||||
Some(('7', '7')), // 71 KEY_KP7
|
||||
Some(('8', '8')), // 72 KEY_KP8
|
||||
Some(('9', '9')), // 73 KEY_KP9
|
||||
Some(('-', '-')), // 74 KEY_KPMINUS
|
||||
Some(('4', '4')), // 75 KEY_KP4
|
||||
Some(('5', '5')), // 76 KEY_KP5
|
||||
Some(('6', '6')), // 77 KEY_KP6
|
||||
Some((('+'), '+')), // 78 KEY_KPPLUS
|
||||
Some(('1', '1')), // 79 KEY_KP1
|
||||
Some(('2', '2')), // 80 KEY_KP2
|
||||
Some(('3', '3')), // 81 KEY_KP3
|
||||
Some(('0', '0')), // 82 KEY_KP0
|
||||
Some(('.', '.')), // 83 KEY_KPDOT
|
||||
];
|
||||
|
||||
pub fn keycode_to_char(keycode: u8, shift: bool) -> Option<char> {
|
||||
let entry = KEY_TO_CHAR.get(keycode as usize)?.as_ref()?;
|
||||
Some(if shift { entry.1 } else { entry.0 })
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy, Default)]
|
||||
pub struct KeyboardEvent {
|
||||
pub state: u8,
|
||||
pub _pad1: u8,
|
||||
pub key: u16,
|
||||
pub mods: u16,
|
||||
pub _pad2: u16,
|
||||
pub unicode: u32,
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
pub mod fs;
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod ps2;
|
||||
pub mod virtio;
|
||||
@@ -0,0 +1,45 @@
|
||||
use core::sync::atomic::{AtomicBool, AtomicI16, AtomicU8, Ordering};
|
||||
|
||||
pub struct Mouse {
|
||||
pub left_button_pressed: AtomicBool,
|
||||
pub right_button_pressed: AtomicBool,
|
||||
pub middle_button_pressed: AtomicBool,
|
||||
pub x_delta: AtomicI16,
|
||||
pub y_delta: AtomicI16,
|
||||
pub status: AtomicU8,
|
||||
}
|
||||
|
||||
impl Mouse {
|
||||
const fn new() -> Mouse {
|
||||
Mouse {
|
||||
left_button_pressed: AtomicBool::new(false),
|
||||
right_button_pressed: AtomicBool::new(false),
|
||||
middle_button_pressed: AtomicBool::new(false),
|
||||
x_delta: AtomicI16::new(0),
|
||||
y_delta: AtomicI16::new(0),
|
||||
status: AtomicU8::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_state(&self) -> (bool, bool, bool) {
|
||||
(
|
||||
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();
|
||||
@@ -0,0 +1,325 @@
|
||||
use core::sync::atomic::{AtomicU8, AtomicU64, Ordering};
|
||||
use heapless::spsc::{Consumer, Producer, Queue};
|
||||
use pc_keyboard::{DecodedKey, HandleControl, KeyCode, KeyState, Keyboard, ScancodeSet2, layouts};
|
||||
|
||||
use static_cell::StaticCell;
|
||||
|
||||
#[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,
|
||||
};
|
||||
use crate::{
|
||||
driver::io::{keyboard::*, mouse::MOUSE},
|
||||
task::scheduler::SCHEDULER,
|
||||
util::get_bit,
|
||||
};
|
||||
|
||||
pub fn keycode_to_linux(kc: KeyCode) -> Option<u8> {
|
||||
let code = match kc {
|
||||
KeyCode::Escape => KEY_ESC,
|
||||
KeyCode::Key1 => KEY_1,
|
||||
KeyCode::Key2 => KEY_2,
|
||||
KeyCode::Key3 => KEY_3,
|
||||
KeyCode::Key4 => KEY_4,
|
||||
KeyCode::Key5 => KEY_5,
|
||||
KeyCode::Key6 => KEY_6,
|
||||
KeyCode::Key7 => KEY_7,
|
||||
KeyCode::Key8 => KEY_8,
|
||||
KeyCode::Key9 => KEY_9,
|
||||
KeyCode::Key0 => KEY_0,
|
||||
KeyCode::OemMinus => KEY_MINUS,
|
||||
KeyCode::OemPlus => KEY_EQUAL,
|
||||
KeyCode::Backspace => KEY_BACKSPACE,
|
||||
KeyCode::Tab => KEY_TAB,
|
||||
KeyCode::Q => KEY_Q,
|
||||
KeyCode::W => KEY_W,
|
||||
KeyCode::E => KEY_E,
|
||||
KeyCode::R => KEY_R,
|
||||
KeyCode::T => KEY_T,
|
||||
KeyCode::Y => KEY_Y,
|
||||
KeyCode::U => KEY_U,
|
||||
KeyCode::I => KEY_I,
|
||||
KeyCode::O => KEY_O,
|
||||
KeyCode::P => KEY_P,
|
||||
KeyCode::Oem4 => KEY_LEFTBRACE,
|
||||
KeyCode::Oem6 => KEY_RIGHTBRACE,
|
||||
KeyCode::Return => KEY_ENTER,
|
||||
KeyCode::LControl => KEY_LEFTCTRL,
|
||||
KeyCode::A => KEY_A,
|
||||
KeyCode::S => KEY_S,
|
||||
KeyCode::D => KEY_D,
|
||||
KeyCode::F => KEY_F,
|
||||
KeyCode::G => KEY_G,
|
||||
KeyCode::H => KEY_H,
|
||||
KeyCode::J => KEY_J,
|
||||
KeyCode::K => KEY_K,
|
||||
KeyCode::L => KEY_L,
|
||||
KeyCode::Oem1 => KEY_SEMICOLON,
|
||||
KeyCode::Oem7 => KEY_APOSTROPHE,
|
||||
KeyCode::LShift => KEY_LEFTSHIFT,
|
||||
KeyCode::Oem5 => KEY_BACKSLASH,
|
||||
KeyCode::Z => KEY_Z,
|
||||
KeyCode::X => KEY_X,
|
||||
KeyCode::C => KEY_C,
|
||||
KeyCode::V => KEY_V,
|
||||
KeyCode::B => KEY_B,
|
||||
KeyCode::N => KEY_N,
|
||||
KeyCode::M => KEY_M,
|
||||
KeyCode::OemComma => KEY_COMMA,
|
||||
KeyCode::OemPeriod => KEY_DOT,
|
||||
KeyCode::Oem2 => KEY_SLASH,
|
||||
KeyCode::RShift => KEY_RIGHTSHIFT,
|
||||
KeyCode::NumpadMultiply => KEY_KPASTERISK,
|
||||
KeyCode::LAlt => KEY_LEFTALT,
|
||||
KeyCode::Spacebar => KEY_SPACE,
|
||||
KeyCode::CapsLock => KEY_CAPSLOCK,
|
||||
KeyCode::F1 => KEY_F1,
|
||||
KeyCode::F2 => KEY_F2,
|
||||
KeyCode::F3 => KEY_F3,
|
||||
KeyCode::F4 => KEY_F4,
|
||||
KeyCode::F5 => KEY_F5,
|
||||
KeyCode::F6 => KEY_F6,
|
||||
KeyCode::F7 => KEY_F7,
|
||||
KeyCode::F8 => KEY_F8,
|
||||
KeyCode::F9 => KEY_F9,
|
||||
KeyCode::F10 => KEY_F10,
|
||||
KeyCode::NumpadLock => KEY_NUMLOCK,
|
||||
KeyCode::ScrollLock => KEY_SCROLLLOCK,
|
||||
KeyCode::Numpad7 => KEY_KP7,
|
||||
KeyCode::Numpad8 => KEY_KP8,
|
||||
KeyCode::Numpad9 => KEY_KP9,
|
||||
KeyCode::NumpadSubtract => KEY_KPMINUS,
|
||||
KeyCode::Numpad4 => KEY_KP4,
|
||||
KeyCode::Numpad5 => KEY_KP5,
|
||||
KeyCode::Numpad6 => KEY_KP6,
|
||||
KeyCode::NumpadAdd => KEY_KPPLUS,
|
||||
KeyCode::Numpad1 => KEY_KP1,
|
||||
KeyCode::Numpad2 => KEY_KP2,
|
||||
KeyCode::Numpad3 => KEY_KP3,
|
||||
KeyCode::Numpad0 => KEY_KP0,
|
||||
KeyCode::NumpadPeriod => KEY_KPDOT,
|
||||
KeyCode::RControl => KEY_RIGHTCTRL,
|
||||
KeyCode::ArrowUp => KEY_UP,
|
||||
KeyCode::ArrowLeft => KEY_LEFT,
|
||||
KeyCode::ArrowRight => KEY_RIGHT,
|
||||
KeyCode::ArrowDown => KEY_DOWN,
|
||||
_ => return None,
|
||||
};
|
||||
Some(code)
|
||||
}
|
||||
|
||||
static SCANCODE_QUEUE: StaticCell<Queue<u8, 256>> = StaticCell::new();
|
||||
static mut SCANCODE_PROD: Option<Producer<'static, u8>> = None;
|
||||
static mut SCANCODE_CONS: Option<Consumer<'static, u8>> = None;
|
||||
static mut KEYBOARD: Option<Keyboard<layouts::Us104Key, ScancodeSet2>> = None;
|
||||
|
||||
static DROPPED_SCANCODES: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
pub fn init_keyboard() {
|
||||
let q = SCANCODE_QUEUE.init(Queue::new());
|
||||
let (p, c) = q.split();
|
||||
|
||||
unsafe {
|
||||
SCANCODE_PROD = Some(p);
|
||||
SCANCODE_CONS = Some(c);
|
||||
KEYBOARD = Some(Keyboard::new(
|
||||
ScancodeSet2::new(),
|
||||
layouts::Us104Key,
|
||||
HandleControl::Ignore,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_scancode(scancode: u8) {
|
||||
let pushed = unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
match SCANCODE_PROD.as_mut() {
|
||||
Some(prod) => prod.enqueue(scancode).is_ok(),
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
if !pushed {
|
||||
DROPPED_SCANCODES.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_scancodes() {
|
||||
loop {
|
||||
let scancode = unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
match SCANCODE_CONS.as_mut() {
|
||||
Some(cons) => match cons.dequeue() {
|
||||
Some(b) => b,
|
||||
None => break,
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(kbd_event) = process_scancode(scancode) {
|
||||
let mut scheduler = SCHEDULER.lock();
|
||||
for process in scheduler.processes.values_mut() {
|
||||
process.kbd_buffer.push(kbd_event);
|
||||
}
|
||||
drop(scheduler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_scancode(scancode: u8) -> Option<KeyboardEvent> {
|
||||
#[allow(static_mut_refs)]
|
||||
let kbd = unsafe { KEYBOARD.as_mut().expect("keyboard not initialized") };
|
||||
if let Ok(Some(key_event)) = kbd.add_byte(scancode) {
|
||||
let keycode = key_event.code;
|
||||
let keystate = key_event.state;
|
||||
let (unicode, state) = match (kbd.process_keyevent(key_event), keystate) {
|
||||
(Some(DecodedKey::Unicode(ch)), st) => (ch as u32, st),
|
||||
_ => (0, keystate),
|
||||
};
|
||||
|
||||
if let Some(linux_keycode) = keycode_to_linux(keycode) {
|
||||
return Some(KeyboardEvent {
|
||||
state: if state == KeyState::Down { 1 } else { 0 },
|
||||
_pad1: 0,
|
||||
key: linux_keycode as u16,
|
||||
mods: 0,
|
||||
_pad2: 0,
|
||||
unicode,
|
||||
});
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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<(bool, bool, bool, 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 == 1,
|
||||
right_button_pressed == 1,
|
||||
middle_button_pressed == 1,
|
||||
x_delta,
|
||||
y_delta,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_interrupt() {
|
||||
if let Some(interrupt_result) = process_mouse_interrupt() {
|
||||
MOUSE
|
||||
.left_button_pressed
|
||||
.store(interrupt_result.0, Ordering::Relaxed);
|
||||
MOUSE
|
||||
.right_button_pressed
|
||||
.store(interrupt_result.1, Ordering::Relaxed);
|
||||
MOUSE
|
||||
.middle_button_pressed
|
||||
.store(interrupt_result.2, Ordering::Relaxed);
|
||||
MOUSE
|
||||
.x_delta
|
||||
.fetch_add(interrupt_result.3, Ordering::Relaxed);
|
||||
MOUSE
|
||||
.y_delta
|
||||
.fetch_add(interrupt_result.4, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
use heapless::spsc::{Consumer, Producer, Queue};
|
||||
use static_cell::StaticCell;
|
||||
|
||||
use crate::{
|
||||
arch::arch::serial_print,
|
||||
driver::io::{
|
||||
keyboard::{
|
||||
KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, KeyboardEvent,
|
||||
keycode_to_char,
|
||||
},
|
||||
mouse::MOUSE,
|
||||
virtio::{
|
||||
KEYBOARD_SLOT, MOUSE_SLOT, VIRTIO_MMIO_BASE, VIRTIO_MMIO_STRIDE,
|
||||
queue::{QUEUE_SIZE, VirtqueueMem},
|
||||
transport::{VirtioMmio, VirtioMmioReg},
|
||||
},
|
||||
},
|
||||
task::scheduler::SCHEDULER,
|
||||
};
|
||||
|
||||
const BTN_LEFT: u16 = 0x110;
|
||||
const BTN_RIGHT: u16 = 0x111;
|
||||
const BTN_MIDDLE: u16 = 0x112;
|
||||
|
||||
const REL_X: u16 = 0x00;
|
||||
const REL_Y: u16 = 0x01;
|
||||
const REL_WHEEL: u16 = 0x08;
|
||||
|
||||
const EVENT_KEY: u16 = 0x01;
|
||||
const EVENT_REL: u16 = 0x02;
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum VirtioInputCfgSelect {
|
||||
Unset = 0x00,
|
||||
IdName = 0x01,
|
||||
IdSerial = 0x02,
|
||||
IdDevids = 0x03,
|
||||
PropBits = 0x10,
|
||||
EvBits = 0x11,
|
||||
AbsInfo = 0x12,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VirtioInputEvent {
|
||||
event_type: u16,
|
||||
code: u16,
|
||||
value: u32,
|
||||
}
|
||||
|
||||
pub struct ModState {
|
||||
shift: bool,
|
||||
caps_lock: bool,
|
||||
ctrl: bool,
|
||||
alt: bool,
|
||||
}
|
||||
|
||||
impl ModState {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
shift: false,
|
||||
caps_lock: false,
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
}
|
||||
}
|
||||
pub fn update(&mut self, code: u8, value: u32) {
|
||||
match code {
|
||||
KEY_LEFTSHIFT | KEY_RIGHTSHIFT => self.shift = value != 0,
|
||||
KEY_LEFTCTRL => self.ctrl = value != 0,
|
||||
KEY_CAPSLOCK => self.caps_lock = value != 0,
|
||||
KEY_LEFTALT => self.alt = value != 0,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn effective_shift(&self) -> bool {
|
||||
self.shift ^ self.caps_lock
|
||||
}
|
||||
}
|
||||
|
||||
pub static mut VIRTIO_KEYBOARD_QUEUE: VirtqueueMem = unsafe { core::mem::zeroed() };
|
||||
pub static mut VIRTIO_MOUSE_QUEUE: VirtqueueMem = unsafe { core::mem::zeroed() };
|
||||
pub static mut MODIFIERS: ModState = ModState::new();
|
||||
|
||||
static KEYCODE_QUEUE: StaticCell<Queue<(u8, u8, bool), 256>> = StaticCell::new();
|
||||
static mut KEYCODE_PROD: Option<Producer<'static, (u8, u8, bool)>> = None;
|
||||
static mut KEYCODE_CONS: Option<Consumer<'static, (u8, u8, bool)>> = None;
|
||||
|
||||
pub fn init_keyboard() {
|
||||
let q = KEYCODE_QUEUE.init(Queue::new());
|
||||
let (p, c) = q.split();
|
||||
|
||||
unsafe {
|
||||
KEYCODE_PROD = Some(p);
|
||||
KEYCODE_CONS = Some(c);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_keycodes() {
|
||||
let mut scheduler = SCHEDULER.lock();
|
||||
|
||||
loop {
|
||||
let keycode_data = unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
match KEYCODE_CONS.as_mut() {
|
||||
Some(cons) => match cons.dequeue() {
|
||||
Some(b) => b,
|
||||
None => break,
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
};
|
||||
|
||||
for process in scheduler.processes.values_mut() {
|
||||
process.kbd_buffer.push(KeyboardEvent {
|
||||
state: keycode_data.1,
|
||||
_pad1: 0,
|
||||
key: keycode_data.0 as u16,
|
||||
mods: 0,
|
||||
_pad2: 0,
|
||||
unicode: keycode_to_char(keycode_data.0, keycode_data.2).unwrap_or('\0') as u32,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
drop(scheduler);
|
||||
}
|
||||
|
||||
pub fn read_device_name(device: &VirtioMmio) -> &str {
|
||||
return unsafe {
|
||||
let select_ptr = (device.base + 0x100) as *mut u8;
|
||||
let subsel_ptr = (device.base + 0x101) as *mut u8;
|
||||
let size_ptr = (device.base + 0x102) as *mut u8;
|
||||
let name_ptr = (device.base + 0x108) as *mut u8;
|
||||
|
||||
select_ptr.write_volatile(VirtioInputCfgSelect::IdName as u8);
|
||||
subsel_ptr.write_volatile(0x00);
|
||||
|
||||
let size = size_ptr.read_volatile() as usize;
|
||||
|
||||
if size == 0 || size > 128 {
|
||||
return "Error";
|
||||
}
|
||||
|
||||
let slice = core::slice::from_raw_parts(name_ptr, size);
|
||||
core::str::from_utf8(slice).unwrap_or("Error")
|
||||
};
|
||||
}
|
||||
|
||||
pub fn input_interrupt(device_type: &str) {
|
||||
#[allow(static_mut_refs)]
|
||||
let queue: Option<&mut VirtqueueMem> = {
|
||||
if device_type == "kbd" {
|
||||
Some(unsafe { &mut VIRTIO_KEYBOARD_QUEUE })
|
||||
} else if device_type == "mouse" {
|
||||
Some(unsafe { &mut VIRTIO_MOUSE_QUEUE })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let device = VirtioMmio::new(
|
||||
VIRTIO_MMIO_BASE + {
|
||||
if device_type == "kbd" {
|
||||
KEYBOARD_SLOT.load(core::sync::atomic::Ordering::Relaxed)
|
||||
} else if device_type == "mouse" {
|
||||
MOUSE_SLOT.load(core::sync::atomic::Ordering::Relaxed)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} * VIRTIO_MMIO_STRIDE,
|
||||
);
|
||||
|
||||
if queue.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let queue = queue.unwrap();
|
||||
|
||||
let status = device.read(VirtioMmioReg::InterruptStatus);
|
||||
device.write(VirtioMmioReg::InterruptAck, status);
|
||||
|
||||
loop {
|
||||
let used_idx = unsafe { core::ptr::read_volatile(&queue.used.idx) };
|
||||
let last_idx = queue.last_used_idx;
|
||||
|
||||
if last_idx == used_idx {
|
||||
return;
|
||||
}
|
||||
|
||||
let used_element = &queue.used.ring[last_idx as usize % QUEUE_SIZE];
|
||||
let desc_idx = used_element.id;
|
||||
|
||||
queue.last_used_idx = last_idx.wrapping_add(1);
|
||||
|
||||
let event = unsafe { core::ptr::read_volatile(&queue.buffers[desc_idx as usize]) };
|
||||
|
||||
let avail_idx = unsafe { core::ptr::read_volatile(&queue.avail.idx) };
|
||||
queue.avail.ring[(avail_idx as usize) % QUEUE_SIZE] = desc_idx as u16;
|
||||
|
||||
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
unsafe {
|
||||
core::ptr::write_volatile(&mut queue.avail.idx, avail_idx.wrapping_add(1));
|
||||
}
|
||||
|
||||
device.write(VirtioMmioReg::QueueNotify, 0);
|
||||
|
||||
handle_event(&event);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn handle_event(event: &VirtioInputEvent) {
|
||||
if event.event_type == 0 || event.code == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
match event.event_type {
|
||||
EVENT_KEY => {
|
||||
unsafe { MODIFIERS.update(event.code as u8, event.value) };
|
||||
match event.code {
|
||||
BTN_LEFT => {
|
||||
MOUSE
|
||||
.left_button_pressed
|
||||
.store(event.value == 1, core::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
BTN_RIGHT => {
|
||||
MOUSE
|
||||
.right_button_pressed
|
||||
.store(event.value == 1, core::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
BTN_MIDDLE => {
|
||||
MOUSE
|
||||
.middle_button_pressed
|
||||
.store(event.value == 1, core::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
_ => {
|
||||
let state = match event.value {
|
||||
1 => 1,
|
||||
0 => 0,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let _ = match unsafe { KEYCODE_PROD.as_mut() } {
|
||||
Some(prod) => prod
|
||||
.enqueue(unsafe {
|
||||
(event.code as u8, state, MODIFIERS.effective_shift())
|
||||
})
|
||||
.is_ok(),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
EVENT_REL => match event.code {
|
||||
REL_X => {
|
||||
MOUSE.x_delta.fetch_add(
|
||||
event.value as i32 as i16,
|
||||
core::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
REL_Y => {
|
||||
MOUSE.y_delta.fetch_add(
|
||||
event.value as i32 as i16,
|
||||
core::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
REL_WHEEL => {}
|
||||
_ => {}
|
||||
},
|
||||
_ => serial_print("Could not recognize virtio input event from interrupt\n"),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
use core::sync::atomic::AtomicU64;
|
||||
|
||||
use crate::{
|
||||
arch::arch::serial_print,
|
||||
driver::io::virtio::{
|
||||
input::read_device_name,
|
||||
queue::setup_queue,
|
||||
transport::{VirtioMmio, VirtioMmioReg},
|
||||
},
|
||||
util::U64Buf,
|
||||
};
|
||||
|
||||
pub mod input;
|
||||
pub mod queue;
|
||||
pub mod transport;
|
||||
|
||||
pub const VIRTIO_MMIO_BASE: u64 = 0xFFFF_0000_0a00_0000;
|
||||
pub const VIRTIO_MMIO_STRIDE: u64 = 0x200;
|
||||
pub const VIRTIO_MMIO_COUNT: u64 = 32;
|
||||
|
||||
const VIRTIO_MAGIC: u32 = 0x74726976;
|
||||
|
||||
const VIRTIO_DEVICE_INPUT: u32 = 0x12;
|
||||
const VIRTIO_DEVICE_BLOCK: u32 = 0x02;
|
||||
|
||||
const DEVICE_ACKNOWLEDGE: u32 = 0x01;
|
||||
const DEVICE_DRIVER: u32 = 0x02;
|
||||
const DEVICE_FEATURES_OK: u32 = 0x08;
|
||||
const DEVICE_DRIVER_OK: u32 = 0x04;
|
||||
const DEVICE_FAILED: u32 = 0x80;
|
||||
|
||||
pub static KEYBOARD_SLOT: AtomicU64 = AtomicU64::new(u64::MAX);
|
||||
pub static MOUSE_SLOT: AtomicU64 = AtomicU64::new(u64::MAX);
|
||||
|
||||
pub fn get_device(slot: u64) -> Option<VirtioMmio> {
|
||||
let base = VIRTIO_MMIO_BASE + slot * VIRTIO_MMIO_STRIDE;
|
||||
let device = VirtioMmio::new(base);
|
||||
|
||||
if device.read(VirtioMmioReg::MagicValue) != VIRTIO_MAGIC {
|
||||
return None;
|
||||
}
|
||||
|
||||
if device.read(VirtioMmioReg::Version) != 0x02 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let device_id = device.read(VirtioMmioReg::DeviceID);
|
||||
|
||||
if device_id == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(device)
|
||||
}
|
||||
|
||||
pub fn scan_devices() {
|
||||
for i in 0..VIRTIO_MMIO_COUNT {
|
||||
let base = VIRTIO_MMIO_BASE + i * VIRTIO_MMIO_STRIDE;
|
||||
let device = VirtioMmio::new(base);
|
||||
|
||||
if device.read(VirtioMmioReg::MagicValue) != VIRTIO_MAGIC {
|
||||
continue;
|
||||
}
|
||||
|
||||
if device.read(VirtioMmioReg::Version) != 0x02 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let device_id = device.read(VirtioMmioReg::DeviceID);
|
||||
|
||||
if device_id == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
serial_print("Slot #");
|
||||
serial_print(U64Buf::new(i).as_str());
|
||||
serial_print(" device_id=");
|
||||
serial_print(U64Buf::new(device.read(VirtioMmioReg::DeviceID) as u64).as_str());
|
||||
serial_print("\n");
|
||||
|
||||
match device_id {
|
||||
VIRTIO_DEVICE_INPUT => {
|
||||
serial_print("Input device found!");
|
||||
serial_print("\n");
|
||||
if init_device(&device) {
|
||||
serial_print("Successfully initialized device!\n");
|
||||
} else {
|
||||
serial_print("Device initialization failed.\n");
|
||||
}
|
||||
|
||||
let device_name = read_device_name(&device);
|
||||
|
||||
serial_print("Found name of device: ");
|
||||
serial_print(device_name);
|
||||
serial_print("\n");
|
||||
|
||||
serial_print("Setting up queue for device...\n");
|
||||
|
||||
if read_device_name(&device).contains("QEMU Virtio Keyboard") {
|
||||
KEYBOARD_SLOT.store(i, core::sync::atomic::Ordering::Relaxed);
|
||||
setup_queue(&device, "kbd");
|
||||
} else if read_device_name(&device).contains("QEMU Virtio Mouse") {
|
||||
MOUSE_SLOT.store(i, core::sync::atomic::Ordering::Relaxed);
|
||||
setup_queue(&device, "mouse");
|
||||
} else {
|
||||
serial_print("Could not recognize device.");
|
||||
continue;
|
||||
}
|
||||
|
||||
device.write(
|
||||
VirtioMmioReg::Status,
|
||||
DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_FEATURES_OK | DEVICE_DRIVER_OK,
|
||||
);
|
||||
|
||||
serial_print("Successfully set up queue for device and notified it.\n");
|
||||
}
|
||||
VIRTIO_DEVICE_BLOCK => {
|
||||
// TODO: add block device support
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_device(device: &VirtioMmio) -> bool {
|
||||
device.write(VirtioMmioReg::Status, 0); // reset
|
||||
device.write(VirtioMmioReg::Status, DEVICE_ACKNOWLEDGE);
|
||||
device.write(VirtioMmioReg::Status, DEVICE_ACKNOWLEDGE | DEVICE_DRIVER);
|
||||
device.write(VirtioMmioReg::DriverFeatures, 0); // no features for now
|
||||
device.write(
|
||||
VirtioMmioReg::Status,
|
||||
DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_FEATURES_OK,
|
||||
);
|
||||
|
||||
if device.read(VirtioMmioReg::Status) & DEVICE_FEATURES_OK == 0 {
|
||||
device.write(VirtioMmioReg::Status, DEVICE_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
use core::{mem::offset_of, sync::atomic::Ordering};
|
||||
|
||||
use crate::{
|
||||
KERNEL_PHYS_BASE, KERNEL_VIRT_BASE,
|
||||
driver::io::virtio::{
|
||||
input::{VIRTIO_KEYBOARD_QUEUE, VIRTIO_MOUSE_QUEUE, VirtioInputEvent},
|
||||
transport::{VirtioMmio, VirtioMmioReg},
|
||||
},
|
||||
};
|
||||
|
||||
const VIRTQ_DESC_F_WRITE: u16 = 0x02;
|
||||
pub const QUEUE_SIZE: usize = 64;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VirtQDesc {
|
||||
pub addr: u64,
|
||||
pub len: u32,
|
||||
pub flags: u16,
|
||||
pub next: u16,
|
||||
}
|
||||
|
||||
impl VirtQDesc {
|
||||
pub const fn writable() -> Self {
|
||||
Self {
|
||||
addr: 0,
|
||||
len: 0,
|
||||
flags: VIRTQ_DESC_F_WRITE,
|
||||
next: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct VirtQAvail {
|
||||
pub flags: u16,
|
||||
pub idx: u16,
|
||||
pub ring: [u16; QUEUE_SIZE],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct VirtQUsedElem {
|
||||
pub id: u32,
|
||||
pub len: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct VirtQUsed {
|
||||
pub flags: u16,
|
||||
pub idx: u16,
|
||||
pub ring: [VirtQUsedElem; QUEUE_SIZE],
|
||||
}
|
||||
|
||||
#[repr(C, align(16))]
|
||||
pub struct VirtqueueMem {
|
||||
pub desc: [VirtQDesc; QUEUE_SIZE],
|
||||
pub avail: VirtQAvail,
|
||||
pub used: VirtQUsed,
|
||||
pub buffers: [VirtioInputEvent; QUEUE_SIZE],
|
||||
pub last_used_idx: u16,
|
||||
}
|
||||
|
||||
pub fn fill_descriptors(queue: &mut VirtqueueMem) {
|
||||
let kernel_virt_base = KERNEL_VIRT_BASE.load(core::sync::atomic::Ordering::Relaxed);
|
||||
let kernel_phys_base = KERNEL_PHYS_BASE.load(core::sync::atomic::Ordering::Relaxed);
|
||||
for i in 0..QUEUE_SIZE {
|
||||
let virt_addr = &queue.buffers[i] as *const VirtioInputEvent as u64;
|
||||
let phys_addr = virt_addr - kernel_virt_base + kernel_phys_base;
|
||||
queue.desc[i].addr = phys_addr;
|
||||
queue.desc[i].len = size_of::<VirtioInputEvent>() as u32;
|
||||
queue.desc[i].flags = VIRTQ_DESC_F_WRITE;
|
||||
queue.avail.ring[i] = i as u16;
|
||||
}
|
||||
queue.avail.idx = QUEUE_SIZE as u16;
|
||||
}
|
||||
pub fn setup_queue(device: &VirtioMmio, device_type: &str) {
|
||||
#[allow(static_mut_refs)]
|
||||
let queue: Option<&mut VirtqueueMem> = {
|
||||
if device_type == "kbd" {
|
||||
Some(unsafe { &mut VIRTIO_KEYBOARD_QUEUE })
|
||||
} else if device_type == "mouse" {
|
||||
Some(unsafe { &mut VIRTIO_MOUSE_QUEUE })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if queue.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let queue = queue.unwrap();
|
||||
|
||||
let phys_base: u64 = queue as *const VirtqueueMem as u64
|
||||
- KERNEL_VIRT_BASE.load(Ordering::Relaxed)
|
||||
+ KERNEL_PHYS_BASE.load(Ordering::Relaxed);
|
||||
|
||||
device.write(VirtioMmioReg::QueueSel, 0);
|
||||
device.write(VirtioMmioReg::QueueNum, QUEUE_SIZE as u32);
|
||||
|
||||
let desc_phys = phys_base + offset_of!(VirtqueueMem, desc) as u64;
|
||||
device.write(VirtioMmioReg::QueueDescLow, (desc_phys & 0xFFFFFFFF) as u32);
|
||||
device.write(VirtioMmioReg::QueueDescHigh, (desc_phys >> 32) as u32);
|
||||
|
||||
let avail_phys = phys_base + offset_of!(VirtqueueMem, avail) as u64;
|
||||
device.write(
|
||||
VirtioMmioReg::QueueDriverLow,
|
||||
(avail_phys & 0xFFFFFFFF) as u32,
|
||||
);
|
||||
device.write(VirtioMmioReg::QueueDriverHigh, (avail_phys >> 32) as u32);
|
||||
|
||||
let used_phys = phys_base + offset_of!(VirtqueueMem, used) as u64;
|
||||
device.write(
|
||||
VirtioMmioReg::QueueDeviceLow,
|
||||
(used_phys & 0xFFFFFFFF) as u32,
|
||||
);
|
||||
device.write(VirtioMmioReg::QueueDeviceHigh, (used_phys >> 32) as u32);
|
||||
|
||||
fill_descriptors(queue);
|
||||
|
||||
core::sync::atomic::fence(Ordering::SeqCst);
|
||||
device.write(VirtioMmioReg::QueueReady, 1);
|
||||
device.write(VirtioMmioReg::QueueNotify, 0);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#[repr(u64)]
|
||||
pub enum VirtioMmioReg {
|
||||
MagicValue = 0x000,
|
||||
Version = 0x004,
|
||||
DeviceID = 0x008,
|
||||
VendorID = 0x00c,
|
||||
DeviceFeatures = 0x010,
|
||||
DriverFeatures = 0x020,
|
||||
QueueSel = 0x030,
|
||||
QueueNumMax = 0x034,
|
||||
QueueNum = 0x038,
|
||||
QueueReady = 0x044,
|
||||
QueueNotify = 0x050,
|
||||
InterruptStatus = 0x060,
|
||||
InterruptAck = 0x064,
|
||||
Status = 0x070,
|
||||
QueueDescLow = 0x080,
|
||||
QueueDescHigh = 0x084,
|
||||
QueueDriverLow = 0x090,
|
||||
QueueDriverHigh = 0x094,
|
||||
QueueDeviceLow = 0x0a0,
|
||||
QueueDeviceHigh = 0x0a4,
|
||||
ConfigGeneration = 0x0fc,
|
||||
Config = 0x100,
|
||||
}
|
||||
|
||||
pub struct VirtioMmio {
|
||||
pub base: u64,
|
||||
}
|
||||
|
||||
impl VirtioMmio {
|
||||
pub fn new(base: u64) -> Self {
|
||||
Self { base }
|
||||
}
|
||||
|
||||
pub fn read(&self, reg: VirtioMmioReg) -> u32 {
|
||||
unsafe {
|
||||
let ptr = (self.base + reg as u64) as *const u32;
|
||||
ptr.read_volatile()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, reg: VirtioMmioReg, value: u32) {
|
||||
unsafe {
|
||||
let ptr = (self.base + reg as u64) as *mut u32;
|
||||
ptr.write_volatile(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
use heapless::spsc::{Consumer, Producer, Queue};
|
||||
use pc_keyboard::{DecodedKey, HandleControl, KeyState, Keyboard, ScancodeSet2, layouts};
|
||||
use static_cell::StaticCell;
|
||||
|
||||
use crate::task::scheduler::SCHEDULER;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy, Default)]
|
||||
pub struct KeyboardEvent {
|
||||
pub state: u8,
|
||||
pub _pad1: u8,
|
||||
pub key: u16,
|
||||
pub mods: u16,
|
||||
pub _pad2: u16,
|
||||
pub unicode: u32,
|
||||
}
|
||||
|
||||
static SCANCODE_QUEUE: StaticCell<Queue<u8, 256>> = StaticCell::new();
|
||||
static mut SCANCODE_PROD: Option<Producer<'static, u8>> = None;
|
||||
static mut SCANCODE_CONS: Option<Consumer<'static, u8>> = None;
|
||||
static mut KEYBOARD: Option<Keyboard<layouts::Us104Key, ScancodeSet2>> = None;
|
||||
|
||||
static DROPPED_SCANCODES: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
pub fn init_keyboard() {
|
||||
let q = SCANCODE_QUEUE.init(Queue::new());
|
||||
let (p, c) = q.split();
|
||||
|
||||
unsafe {
|
||||
SCANCODE_PROD = Some(p);
|
||||
SCANCODE_CONS = Some(c);
|
||||
KEYBOARD = Some(Keyboard::new(
|
||||
ScancodeSet2::new(),
|
||||
layouts::Us104Key,
|
||||
HandleControl::Ignore,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_scancode(scancode: u8) {
|
||||
let pushed = unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
match SCANCODE_PROD.as_mut() {
|
||||
Some(prod) => prod.enqueue(scancode).is_ok(),
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
if !pushed {
|
||||
DROPPED_SCANCODES.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_scancodes() {
|
||||
loop {
|
||||
let scancode = unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
match SCANCODE_CONS.as_mut() {
|
||||
Some(cons) => match cons.dequeue() {
|
||||
Some(b) => b,
|
||||
None => break,
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(kbd_event) = process_scancode(scancode) {
|
||||
let mut scheduler = SCHEDULER.lock();
|
||||
for process in scheduler.processes.values_mut() {
|
||||
process.kbd_buffer.push(kbd_event);
|
||||
}
|
||||
drop(scheduler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_scancode(scancode: u8) -> Option<KeyboardEvent> {
|
||||
#[allow(static_mut_refs)]
|
||||
let kbd = unsafe { KEYBOARD.as_mut().expect("keyboard not initialized") };
|
||||
if let Ok(Some(key_event)) = kbd.add_byte(scancode) {
|
||||
let keycode = key_event.code;
|
||||
let keystate = key_event.state;
|
||||
let (unicode, state) = match (kbd.process_keyevent(key_event), keystate) {
|
||||
(Some(DecodedKey::Unicode(ch)), st) => (ch as u32, st),
|
||||
_ => (0, keystate),
|
||||
};
|
||||
|
||||
return Some(KeyboardEvent {
|
||||
state: if state == KeyState::Down { 1 } else { 0 },
|
||||
_pad1: 0,
|
||||
key: keycode as u16,
|
||||
mods: 0,
|
||||
_pad2: 0,
|
||||
unicode,
|
||||
});
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
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,7 +1,5 @@
|
||||
pub mod elf;
|
||||
pub mod fs;
|
||||
pub mod graphics;
|
||||
pub mod keyboard;
|
||||
pub mod kmi;
|
||||
pub mod io;
|
||||
pub mod serial;
|
||||
pub mod timer;
|
||||
|
||||
+44
-21
@@ -4,9 +4,33 @@
|
||||
#![feature(naked_functions_rustic_abi)]
|
||||
extern crate alloc;
|
||||
use core::fmt::Write;
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::interrupts::enable_interrupts;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::paging::AArchPageTable;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::driver::graphics::primitives::rectangle_filled;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use aarch64_cpu::registers::{DAIF, Writeable};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::driver::io::virtio::input::init_keyboard;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::driver::elf::loader::run_elf;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::driver::io::ps2::init_keyboard;
|
||||
|
||||
use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_print};
|
||||
|
||||
use crate::driver::graphics::base::rgb;
|
||||
use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer};
|
||||
|
||||
use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console};
|
||||
use crate::driver::timer::TIMER;
|
||||
|
||||
use limine::BaseRevision;
|
||||
use limine::request::{
|
||||
DateAtBootRequest, ExecutableAddressRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest,
|
||||
@@ -19,21 +43,6 @@ 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;
|
||||
use crate::driver::graphics::base::rgb;
|
||||
use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::driver::graphics::primitives::rectangle_filled;
|
||||
use crate::driver::keyboard::init_keyboard;
|
||||
use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console};
|
||||
use crate::driver::timer::TIMER;
|
||||
|
||||
#[repr(C, align(16))]
|
||||
#[allow(dead_code)]
|
||||
struct AlignedElf([u8; include_bytes!("../../assets/init").len()]);
|
||||
@@ -78,6 +87,9 @@ static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
|
||||
#[unsafe(link_section = ".requests_end_marker")]
|
||||
static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
|
||||
|
||||
pub static KERNEL_PHYS_BASE: AtomicU64 = AtomicU64::new(0);
|
||||
pub static KERNEL_VIRT_BASE: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => {
|
||||
@@ -124,24 +136,35 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
);
|
||||
#[allow(unused_variables)]
|
||||
if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
if let Some(executable_address_response) = EXECUTABLE_ADDRESS_REQUEST.get_response() {
|
||||
KERNEL_PHYS_BASE.store(
|
||||
executable_address_response.physical_base(),
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
|
||||
KERNEL_VIRT_BASE.store(
|
||||
executable_address_response.virtual_base(),
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use crate::arch::aarch64::init::preinit_aarch64;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
preinit_aarch64(
|
||||
hhdm_response,
|
||||
memory_map_response,
|
||||
executable_address_response,
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe {
|
||||
kernel_main_x86_64()
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
driver::keyboard::KeyboardEvent, mm::address_space::AddressSpace, task::context::UserContext,
|
||||
driver::io::keyboard::KeyboardEvent, mm::address_space::AddressSpace,
|
||||
task::context::UserContext,
|
||||
};
|
||||
|
||||
pub enum ProcessState {
|
||||
|
||||
+1
-1
Submodule user/apps/doomgeneric updated: 703b2e6e21...2c34740743
+1
-1
Submodule user/init updated: 4690716227...601d2cab7f
+1
-1
Submodule user/libxunil updated: e134040a9f...7ddebd6df5
Reference in New Issue
Block a user