Added kinda working key input checking
This commit is contained in:
@@ -10,8 +10,13 @@ test=false
|
||||
crate-type=["staticlib"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[profile.release]
|
||||
strip = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.5.0"
|
||||
crossbeam = { version = "0.8.4", default-features = false, features = ["alloc"] }
|
||||
hashbrown = "0.14.5"
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
log = "0.4.21"
|
||||
multiboot2 = "0.20.2"
|
||||
|
||||
0
kernel/src/drivers/mod.rs
Normal file
0
kernel/src/drivers/mod.rs
Normal file
@@ -7,7 +7,6 @@ mod types;
|
||||
use spin::Mutex;
|
||||
pub use types::*;
|
||||
|
||||
|
||||
const MAX_EVENT_LISTENERS: usize = 255;
|
||||
|
||||
lazy_static!(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use pc_keyboard::DecodedKey;
|
||||
use pc_keyboard::KeyEvent;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
TimerInterrupt(Option<usize>), // trash unused value
|
||||
Ps2KeyPress(Option<DecodedKey>)
|
||||
Ps2KeyEvent(Option<KeyEvent>),
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
@@ -1,50 +1,90 @@
|
||||
use core::ptr::addr_of;
|
||||
|
||||
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
|
||||
use x86_64::instructions::segmentation::{CS, DS, Segment};
|
||||
use x86_64::structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable, SegmentSelector};
|
||||
use x86_64::VirtAddr;
|
||||
use x86_64::structures::tss::TaskStateSegment;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
|
||||
pub const STACK_SIZE: usize = 4096 * 5;
|
||||
pub static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||
pub static mut PRIV_TSS_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||
|
||||
|
||||
|
||||
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
|
||||
|
||||
lazy_static! {
|
||||
static ref TSS: TaskStateSegment = {
|
||||
let mut tss = TaskStateSegment::new();
|
||||
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
|
||||
const STACK_SIZE: usize = 4096 * 5;
|
||||
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
let stack_start = VirtAddr::from_ptr(unsafe { addr_of!(STACK) });
|
||||
let stack_end = stack_start + STACK_SIZE as u64;
|
||||
stack_end
|
||||
};
|
||||
tss.privilege_stack_table[0] = {
|
||||
#[allow(unused_unsafe)]
|
||||
let stack_start = VirtAddr::from_ptr(unsafe { addr_of!(PRIV_TSS_STACK) });
|
||||
let stack_end = stack_start + STACK_SIZE as u64;
|
||||
stack_end
|
||||
};
|
||||
tss
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
lazy_static! {
|
||||
static ref GDT: (GlobalDescriptorTable, Selectors) = {
|
||||
pub static ref GDT: (GlobalDescriptorTable, Selectors) = {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let code_selector = gdt.append(Descriptor::kernel_code_segment());
|
||||
let tss_selector = gdt.append(Descriptor::tss_segment(&TSS));
|
||||
(gdt, Selectors { code_selector, tss_selector })
|
||||
let kernel_data_flags = DescriptorFlags::USER_SEGMENT | DescriptorFlags::PRESENT | DescriptorFlags::WRITABLE;
|
||||
|
||||
let code_sel = gdt.append(Descriptor::kernel_code_segment());
|
||||
let data_sel = gdt.append(Descriptor::UserSegment(kernel_data_flags.bits()));
|
||||
|
||||
let tss_sel = gdt.append(Descriptor::tss_segment(&TSS));
|
||||
let user_data_sel = gdt.append(Descriptor::user_data_segment()); // user data segment
|
||||
let user_code_sel = gdt.append(Descriptor::user_code_segment()); // user code segment
|
||||
(gdt, Selectors {code_sel, data_sel, tss_sel, user_data_sel, user_code_sel })
|
||||
};
|
||||
}
|
||||
|
||||
struct Selectors {
|
||||
code_selector: SegmentSelector,
|
||||
tss_selector: SegmentSelector,
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct Selectors {
|
||||
pub code_sel: SegmentSelector,
|
||||
pub data_sel: SegmentSelector,
|
||||
pub tss_sel: SegmentSelector,
|
||||
pub user_data_sel: SegmentSelector,
|
||||
pub user_code_sel: SegmentSelector
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
log::info!("GDT init");
|
||||
use x86_64::instructions::tables::load_tss;
|
||||
use x86_64::instructions::segmentation::{CS, Segment};
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
let stack = unsafe { addr_of!(STACK) as *const _ };
|
||||
#[allow(unused_unsafe)]
|
||||
let user_stack = unsafe { addr_of!(PRIV_TSS_STACK) as *const _ };
|
||||
log::info!("gdt init");
|
||||
log::debug!("gdt = {:?}", &GDT.0 as *const _ );
|
||||
log::debug!("tss = {:?}", &*TSS as *const _ );
|
||||
log::debug!("kernel_stack = {:?}", stack);
|
||||
log::debug!("user_stack = {:?}", user_stack);
|
||||
log::debug!("kernel_code_sel = {:?}", GDT.1.code_sel);
|
||||
log::debug!("kernel_data_sel = {:?}", GDT.1.data_sel);
|
||||
log::debug!("tss_sel = {:?}", GDT.1.tss_sel);
|
||||
log::debug!("user_code_sel = {:?}", GDT.1.user_code_sel);
|
||||
log::debug!("user_code_sel = {:?}", GDT.1.user_data_sel);
|
||||
|
||||
|
||||
GDT.0.load();
|
||||
unsafe {
|
||||
CS::set_reg(GDT.1.code_selector);
|
||||
load_tss(GDT.1.tss_selector);
|
||||
DS::set_reg(GDT.1.data_sel);
|
||||
CS::set_reg(GDT.1.code_sel);
|
||||
load_tss(GDT.1.tss_sel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ pub extern "x86-interrupt" fn breakpoint(sf: InterruptStackFrame){
|
||||
pub extern "x86-interrupt" fn timer_interrupt(_: InterruptStackFrame){
|
||||
//log::debug!("INT: TIMER\n{:#?}", sf);
|
||||
// print!(".");
|
||||
EVENTMAN.lock().dispatch(&crate::events::Event::TimerInterrupt(None));
|
||||
// EVENTMAN.lock().dispatch(&crate::events::Event::TimerInterrupt(None));
|
||||
unsafe {
|
||||
super::PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Timer as u8);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use pc_keyboard::DecodedKey;
|
||||
use hashbrown::HashSet;
|
||||
use pc_keyboard::{DecodedKey, KeyState};
|
||||
use spin::Mutex;
|
||||
use x86_64::structures::idt::InterruptStackFrame;
|
||||
|
||||
use crate::{events::EVENTMAN, interrupts::PICS};
|
||||
@@ -16,15 +18,13 @@ pub extern "x86-interrupt" fn ps2_kb_int(_sf: InterruptStackFrame){
|
||||
layouts::Us104Key, HandleControl::Ignore)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
let mut keyboard = KEYBOARD.lock();
|
||||
let mut port = Port::new(0x60);
|
||||
|
||||
let scancode: u8 = unsafe { port.read() };
|
||||
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
|
||||
if let Some(key) = keyboard.process_keyevent(key_event) {
|
||||
EVENTMAN.lock().dispatch(&crate::events::Event::Ps2KeyPress(Some(key)));
|
||||
}
|
||||
EVENTMAN.lock().dispatch(&crate::events::Event::Ps2KeyEvent(Some(key_event)));
|
||||
}
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
|
||||
@@ -14,7 +14,6 @@ lazy_static::lazy_static! {
|
||||
|
||||
idt.breakpoint.set_handler_fn(handlers::breakpoint);
|
||||
idt.page_fault.set_handler_fn(handlers::page_fault);
|
||||
|
||||
idt[InterruptIndex::Timer as u8]
|
||||
.set_handler_fn(handlers::timer_interrupt);
|
||||
idt[InterruptIndex::Keyboard as u8]
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(allocator_api)]
|
||||
|
||||
use core::ptr::addr_of;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use pc_keyboard::{DecodedKey, KeyCode};
|
||||
use x86_64::instructions::nop;
|
||||
|
||||
use crate::{gdt::PRIV_TSS_STACK, scheduler::{executor::Executor, Task}, utils::jmp_to_usermode};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
@@ -18,7 +24,8 @@ mod utils;
|
||||
#[macro_use]
|
||||
mod events;
|
||||
mod mem;
|
||||
|
||||
mod scheduler;
|
||||
mod std;
|
||||
|
||||
|
||||
|
||||
@@ -30,19 +37,28 @@ extern "C" fn kmain(mb2_info_addr: usize) -> ! {
|
||||
interrupts::init_idt();
|
||||
utils::enable_nxe_bit();
|
||||
utils::enable_write_protect_bit();
|
||||
std::init();
|
||||
|
||||
mem::init(mb2_info_addr);
|
||||
let active_table = mem::init(mb2_info_addr);
|
||||
|
||||
//unsafe {
|
||||
// jmp_to_usermode(active_table, usermode_code as *const () as usize, addr_of!(PRIV_TSS_STACK) as *const () as usize);
|
||||
//}
|
||||
|
||||
let mut a = Vec::new();
|
||||
//let mut executor = Executor::new();
|
||||
//executor.spawn(Task::new(usermode_code()));
|
||||
//executor.run();
|
||||
|
||||
//let mut a = Vec::new();
|
||||
|
||||
|
||||
a.push(6);
|
||||
a.push(9);
|
||||
a.push(4);
|
||||
a.push(2);
|
||||
a.push(0);
|
||||
//a.push(6);
|
||||
//a.push(9);
|
||||
//a.push(4);
|
||||
//a.push(2);
|
||||
//a.push(0);
|
||||
|
||||
log::error!("{:?}", a);
|
||||
//log::error!("{:?}", a);
|
||||
|
||||
|
||||
|
||||
@@ -56,8 +72,12 @@ extern "C" fn kmain(mb2_info_addr: usize) -> ! {
|
||||
// let (level_4_page_table, _) = Cr3::read();
|
||||
// println!("Level 4 page table at: {:?}", level_4_page_table.start_address());
|
||||
log::info!("end of work");
|
||||
|
||||
utils::hcf();
|
||||
loop {
|
||||
if std::input::is_key_down(KeyCode::A) {
|
||||
log::info!(":3");
|
||||
}
|
||||
}
|
||||
// utils::hcf();
|
||||
}
|
||||
|
||||
|
||||
@@ -68,3 +88,6 @@ fn panic(pi: &core::panic::PanicInfo) -> ! {
|
||||
}
|
||||
|
||||
|
||||
async fn usermode_code() {
|
||||
log::info!("Hello from usermode!");
|
||||
}
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
use core::{alloc::{AllocError, GlobalAlloc, Layout}, sync::atomic::{AtomicUsize, Ordering}};
|
||||
//use core::{alloc::{AllocError, GlobalAlloc, Layout}, sync::atomic::{AtomicUsize, Ordering}};
|
||||
|
||||
use x86_64::align_up;
|
||||
//use x86_64::align_up;
|
||||
|
||||
pub const HEAP_START: usize = 0o_000_001_000_000_0000;
|
||||
pub const HEAP_START: usize = 0o_000_001_000_000_0000; // 0x40000000 - 0x40019000
|
||||
pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB
|
||||
|
||||
/// A simple allocator that allocates memory linearly and ignores freed memory.
|
||||
#[derive(Debug)]
|
||||
pub struct BumpAllocator {
|
||||
heap_start: usize,
|
||||
heap_end: usize,
|
||||
next: AtomicUsize,
|
||||
}
|
||||
// A simple allocator that allocates memory linearly and ignores freed memory.
|
||||
//#[derive(Debug)]
|
||||
//pub struct BumpAllocator {
|
||||
// heap_start: usize,
|
||||
// heap_end: usize,
|
||||
// next: AtomicUsize,
|
||||
//}
|
||||
|
||||
impl BumpAllocator {
|
||||
pub const fn new(heap_start: usize, heap_end: usize) -> Self {
|
||||
Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) }
|
||||
}
|
||||
}
|
||||
//impl BumpAllocator {
|
||||
// pub const fn new(heap_start: usize, heap_end: usize) -> Self {
|
||||
// Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) }
|
||||
// }
|
||||
//}
|
||||
|
||||
unsafe impl GlobalAlloc for BumpAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
loop {
|
||||
// load current state of the `next` field
|
||||
let current_next = self.next.load(Ordering::Relaxed);
|
||||
let alloc_start = align_up(current_next as u64, layout.align() as u64);
|
||||
let alloc_end = alloc_start.saturating_add(layout.size() as u64);
|
||||
//unsafe impl GlobalAlloc for BumpAllocator {
|
||||
// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
// loop {
|
||||
// // load current state of the `next` field
|
||||
// let current_next = self.next.load(Ordering::Relaxed);
|
||||
// let alloc_start = align_up(current_next as u64, layout.align() as u64);
|
||||
// let alloc_end = alloc_start.saturating_add(layout.size() as u64);
|
||||
//
|
||||
// if alloc_end <= self.heap_end as u64 {
|
||||
// // update the `next` pointer if it still has the value `current_next`
|
||||
// let next_now = self.next.compare_exchange(current_next, alloc_end as usize, Ordering::Relaxed, Ordering::Relaxed).unwrap();
|
||||
// if next_now == current_next {
|
||||
// // next address was successfully updated, allocation succeeded
|
||||
// return alloc_start as *mut u8;
|
||||
// }
|
||||
// } else {
|
||||
// panic!("OUT OF MEMORY");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if alloc_end <= self.heap_end as u64 {
|
||||
// update the `next` pointer if it still has the value `current_next`
|
||||
let next_now = self.next.compare_exchange(current_next, alloc_end as usize, Ordering::Relaxed, Ordering::Relaxed).unwrap();
|
||||
if next_now == current_next {
|
||||
// next address was successfully updated, allocation succeeded
|
||||
return alloc_start as *mut u8;
|
||||
}
|
||||
} else {
|
||||
panic!("OUT OF MEMORY");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
// do nothing, leak memory
|
||||
}
|
||||
}
|
||||
// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
// // do nothing, leak memory
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -161,7 +161,7 @@ impl MemInfo<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(mb_ptr: usize) {
|
||||
pub fn init(mb_ptr: usize) -> paging::ActivePageTable {
|
||||
once::assert_has_not_been_called!("mem::init must be called only once");
|
||||
let mem_info = MemInfo::load(mb_ptr);
|
||||
let mut frame_alloc = area_frame_alloc::AreaFrameAllocator::new(&mem_info);
|
||||
@@ -179,4 +179,5 @@ pub fn init(mb_ptr: usize) {
|
||||
unsafe {
|
||||
GLOBAL_ALLOCATOR.lock().claim(Span::from_base_size(HEAP_START as *mut u8, HEAP_SIZE)).unwrap();
|
||||
}
|
||||
active_table
|
||||
}
|
||||
|
||||
@@ -189,7 +189,9 @@ pub fn remap_the_kernel<A>(allocator: &mut A, mem_info: &MemInfo) -> ActivePageT
|
||||
continue;
|
||||
}
|
||||
|
||||
log::debug!("mapping section '{}' at addr: {:#x}, size: {:#x}", section.name().unwrap_or("NONE"), section.start_address(), section.size());
|
||||
//log::debug!("mapping section '{}' at addr: {:#x}, size: {:#x}",
|
||||
// section.name().unwrap_or("NONE"), section.start_address(), section.size());
|
||||
|
||||
assert!(section.start_address() as usize % PAGE_SIZE == 0,
|
||||
"sections need to be page aligned");
|
||||
|
||||
|
||||
98
kernel/src/scheduler/executor.rs
Normal file
98
kernel/src/scheduler/executor.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use core::task::{Context, Poll, Waker};
|
||||
|
||||
use super::{Task, TaskId};
|
||||
use alloc::{collections::BTreeMap, sync::Arc, task::Wake};
|
||||
use crossbeam::queue::ArrayQueue;
|
||||
|
||||
pub struct Executor {
|
||||
tasks: BTreeMap<TaskId, Task>,
|
||||
task_queue: Arc<ArrayQueue<TaskId>>,
|
||||
waker_cache: BTreeMap<TaskId, Waker>,
|
||||
}
|
||||
|
||||
impl Executor {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tasks: BTreeMap::new(),
|
||||
task_queue: Arc::new(ArrayQueue::new(100)),
|
||||
waker_cache: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn(&mut self, task: Task) {
|
||||
let task_id = task.id;
|
||||
if self.tasks.insert(task.id, task).is_some() {
|
||||
panic!("task with same ID already in tasks");
|
||||
}
|
||||
self.task_queue.push(task_id).expect("queue full");
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn run(&mut self) {
|
||||
loop {
|
||||
if self.task_queue.len() == 0 {
|
||||
log::debug!("Task queue is empty, scheduler exiting");
|
||||
break;
|
||||
}
|
||||
self.run_ready_tasks();
|
||||
}
|
||||
}
|
||||
fn run_ready_tasks(&mut self) {
|
||||
// destructure `self` to avoid borrow checker errors
|
||||
let Self {
|
||||
tasks,
|
||||
task_queue,
|
||||
waker_cache,
|
||||
} = self;
|
||||
|
||||
while let Some(task_id) = task_queue.pop() {
|
||||
let task = match tasks.get_mut(&task_id) {
|
||||
Some(task) => task,
|
||||
None => continue, // task no longer exists
|
||||
};
|
||||
let waker = waker_cache
|
||||
.entry(task_id)
|
||||
.or_insert_with(|| TaskWaker::new(task_id, task_queue.clone()));
|
||||
let mut context = Context::from_waker(waker);
|
||||
match task.poll(&mut context) {
|
||||
Poll::Ready(()) => {
|
||||
// task done -> remove it and its cached waker
|
||||
tasks.remove(&task_id);
|
||||
waker_cache.remove(&task_id);
|
||||
}
|
||||
Poll::Pending => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct TaskWaker {
|
||||
task_id: TaskId,
|
||||
task_queue: Arc<ArrayQueue<TaskId>>,
|
||||
}
|
||||
|
||||
impl TaskWaker {
|
||||
fn wake_task(&self) {
|
||||
self.task_queue.push(self.task_id).expect("task_queue full");
|
||||
}
|
||||
fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>) -> Waker {
|
||||
Waker::from(Arc::new(TaskWaker {
|
||||
task_id,
|
||||
task_queue,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Wake for TaskWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
self.wake_task();
|
||||
}
|
||||
|
||||
fn wake_by_ref(self: &Arc<Self>) {
|
||||
self.wake_task();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
32
kernel/src/scheduler/mod.rs
Normal file
32
kernel/src/scheduler/mod.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use core::{future::Future, pin::Pin, sync::atomic::{AtomicU64, Ordering}, task::{Context, Poll}};
|
||||
use alloc::boxed::Box;
|
||||
|
||||
pub mod executor;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct TaskId(u64);
|
||||
|
||||
pub struct Task {
|
||||
id: TaskId,
|
||||
future: Pin<Box<dyn Future<Output = ()>>>,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub fn new(f: impl Future<Output = ()> + 'static) -> Self {
|
||||
Self {
|
||||
id: TaskId::new(),
|
||||
future: Box::pin(f)
|
||||
}
|
||||
}
|
||||
fn poll(&mut self, context: &mut Context) -> Poll<()> {
|
||||
self.future.as_mut().poll(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskId {
|
||||
fn new() -> Self {
|
||||
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
|
||||
TaskId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
50
kernel/src/std/input.rs
Normal file
50
kernel/src/std/input.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use alloc::{boxed::Box, collections::{btree_set::BTreeSet, vec_deque::VecDeque}, sync::Arc, vec::Vec};
|
||||
use hashbrown::HashSet;
|
||||
use lazy_static::lazy_static;
|
||||
use pc_keyboard::{DecodedKey, KeyCode, KeyEvent, KeyState};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::nop;
|
||||
|
||||
use crate::events::{Event, EVENTMAN};
|
||||
static mut KEYS_PRESSED: Mutex<BTreeSet<KeyCode>> = Mutex::new(BTreeSet::new());
|
||||
static mut KEY_BUF: VecDeque<KeyEvent> = VecDeque::new();
|
||||
const KEY_BUF_MAX_LEN: usize = 32;
|
||||
|
||||
pub(super) unsafe fn init() {
|
||||
EVENTMAN.lock().add_listener(crate::events::Event::Ps2KeyEvent(None), |e| {
|
||||
let Event::Ps2KeyEvent(ke) = e else {panic!()};
|
||||
if let Some(ke) = ke {
|
||||
if KEY_BUF.len() > KEY_BUF_MAX_LEN {
|
||||
KEY_BUF.pop_front();
|
||||
}
|
||||
KEY_BUF.push_back(ke.clone());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: It is possible for `KEY_BUF` to get overfilled and lose data and make keys stuck.
|
||||
// Possibly run this every now an again somehow
|
||||
unsafe fn process_events() {
|
||||
while !KEY_BUF.is_empty() {
|
||||
if let Some(ke) = KEY_BUF.pop_front() {
|
||||
match ke.state {
|
||||
KeyState::Down => {
|
||||
KEYS_PRESSED.lock().insert(ke.code);
|
||||
}
|
||||
KeyState::Up => {
|
||||
KEYS_PRESSED.lock().remove(&ke.code);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_key_down(key: KeyCode) -> bool {
|
||||
unsafe {
|
||||
process_events();
|
||||
return KEYS_PRESSED.lock().contains(&key);
|
||||
}
|
||||
}
|
||||
8
kernel/src/std/mod.rs
Normal file
8
kernel/src/std/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
pub mod input;
|
||||
|
||||
|
||||
|
||||
|
||||
pub fn init() {
|
||||
unsafe { input::init(); };
|
||||
}
|
||||
13
kernel/src/syscalls/mod.rs
Normal file
13
kernel/src/syscalls/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
// register for address of syscall handler
|
||||
const MSR_STAR: usize = 0xC0000081;
|
||||
|
||||
|
||||
pub fn init() {
|
||||
asm!("\
|
||||
xor rax, rax
|
||||
mov rdx, 0x230008 // use seg selectors 8, 16 for syscall and 43, 51 for sysret
|
||||
wrmsr" :: "{rcx}"(MSR_STAR) : "rax", "rdx" : "intel", "volatile");
|
||||
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use x86::msr::{rdmsr, wrmsr, IA32_EFER};
|
||||
use x86_64::{instructions, registers::control::{Cr0, Cr0Flags}};
|
||||
use x86_64::{instructions, registers::{control::{Cr0, Cr0Flags}, segmentation::{Segment, DS}}, PrivilegeLevel};
|
||||
|
||||
use crate::mem::paging::{ActivePageTable, VirtualAddress};
|
||||
|
||||
|
||||
|
||||
@@ -22,3 +26,31 @@ pub fn enable_write_protect_bit() {
|
||||
|
||||
unsafe { Cr0::write(Cr0::read() | Cr0Flags::WRITE_PROTECT) };
|
||||
}
|
||||
|
||||
|
||||
pub unsafe fn set_usermode_segments() -> (u16, u16) {
|
||||
// set ds and tss, return cs and ds
|
||||
let (mut cs, mut ds) = (crate::gdt::GDT.1.user_code_sel, crate::gdt::GDT.1.user_data_sel);
|
||||
cs.0 |= PrivilegeLevel::Ring3 as u16;
|
||||
ds.0 |= PrivilegeLevel::Ring3 as u16;
|
||||
DS::set_reg(ds);
|
||||
(cs.0, ds.0)
|
||||
}
|
||||
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn jmp_to_usermode(apt: ActivePageTable, code: VirtualAddress, stack_end: VirtualAddress) {
|
||||
let (cs_idx, ds_idx) = set_usermode_segments();
|
||||
x86_64::instructions::tlb::flush_all(); // flush the TLB after address-space switch
|
||||
let code_addr = apt.translate(code).expect("Invalid virt addr");
|
||||
let sa_addr = apt.translate(stack_end).expect("Invalid virt addr");
|
||||
|
||||
asm!("push {ds:x}", // stack segment
|
||||
"push {sa}", // rsp
|
||||
"push 0x200", // rflags (only interrupt bit set)
|
||||
"push {cs:x}", // code segment
|
||||
"push {code}", // ret to virtual addr
|
||||
"iretq",
|
||||
code = in(reg) code_addr, sa = in(reg) sa_addr, cs = in(reg) cs_idx, ds = in(reg) ds_idx);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user