Added kinda working key input checking

This commit is contained in:
Gvidas Juknevičius 2024-09-01 23:42:39 +03:00
parent 1d61f97abb
commit 2dfd253f34
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
24 changed files with 566 additions and 90 deletions

2
.gdbinit Normal file
View File

@ -0,0 +1,2 @@
target remote localhost:1234

118
Cargo.lock generated
View File

@ -2,6 +2,24 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "allocator-api2"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.3.0" version = "1.3.0"
@ -26,6 +44,47 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
dependencies = [
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "0.99.17" version = "0.99.17"
@ -34,7 +93,17 @@ checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
"allocator-api2",
] ]
[[package]] [[package]]
@ -42,6 +111,8 @@ name = "kernel"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.5.0",
"crossbeam",
"hashbrown",
"lazy_static", "lazy_static",
"log", "log",
"multiboot2", "multiboot2",
@ -99,6 +170,12 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60bfe75a40f755f162b794140436c57845cb106fd1467598631c76c6fff08e28" checksum = "60bfe75a40f755f162b794140436c57845cb106fd1467598631c76c6fff08e28"
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "pc-keyboard" name = "pc-keyboard"
version = "0.7.0" version = "0.7.0"
@ -140,7 +217,7 @@ checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -199,6 +276,17 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "syn"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "talc" name = "talc"
version = "4.4.1" version = "4.4.1"
@ -242,6 +330,12 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "volatile" name = "volatile"
version = "0.4.6" version = "0.4.6"
@ -270,3 +364,23 @@ dependencies = [
"rustversion", "rustversion",
"volatile", "volatile",
] ]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
]

View File

@ -1,6 +1,11 @@
global _start global _start
extern long_mode_start extern long_mode_start
%define ERR_NO_MB "0"
%define ERR_NO_CPUID "1"
%define ERR_NO_LONG_MODE "2"
%define ERR_NO_V86 "3"
section .text section .text
bits 32 bits 32
_start: _start:
@ -19,6 +24,7 @@ _start:
call set_up_page_tables call set_up_page_tables
call enable_paging call enable_paging
call enable_sce
; load the 64-bit GDT ; load the 64-bit GDT
lgdt [gdt64.pointer] lgdt [gdt64.pointer]
@ -32,12 +38,29 @@ _start:
mov dword [0xb8000], 0x2f4b2f4f mov dword [0xb8000], 0x2f4b2f4f
hlt hlt
detect_v86:
smsw ax
and eax,1 ;CR0.PE bit
cmp eax, 1
je .no_v86
ret
.no_v86:
mov al, ERR_NO_V86
jmp error
enable_sce: ; System Call Extensions
mov ecx, 0xC0000080
rdmsr
or eax, 1
wrmsr
ret
check_multiboot: check_multiboot:
cmp eax, 0x36d76289 cmp eax, 0x36d76289
jne .no_multiboot jne .no_multiboot
ret ret
.no_multiboot: .no_multiboot:
mov al, "0" mov al, ERR_NO_MB
jmp error jmp error
check_cpuid: check_cpuid:
@ -73,7 +96,7 @@ check_cpuid:
je .no_cpuid je .no_cpuid
ret ret
.no_cpuid: .no_cpuid:
mov al, "1" mov al, ERR_NO_CPUID
jmp error jmp error
check_long_mode: check_long_mode:
@ -90,7 +113,7 @@ check_long_mode:
jz .no_long_mode ; If it's not set, there is no long mode jz .no_long_mode ; If it's not set, there is no long mode
ret ret
.no_long_mode: .no_long_mode:
mov al, "2" mov al, ERR_NO_LONG_MODE
jmp error jmp error
set_up_page_tables: set_up_page_tables:

View File

@ -1,7 +1,9 @@
set timeout=0 set timeout=0
set default=0 set default=0
insmod all_video
menuentry "poppin" { menuentry "poppin" {
multiboot2 /boot/poppin.bin multiboot2 /boot/poppin.bin
set gfxpayload=1024x768x32
boot
} }

View File

@ -24,7 +24,14 @@ function pre_build() {
function build_kernel() { function build_kernel() {
echo "INFO: Building poppin-kernel" echo "INFO: Building poppin-kernel"
pushd kernel > /dev/null pushd kernel > /dev/null
cargo build --release --target-dir ../${BUILD_DIR} case $1 in
dev)
cargo build --target-dir ../${BUILD_DIR}
;;
*)
cargo build --release --target-dir ../${BUILD_DIR}
;;
esac
popd > /dev/null popd > /dev/null
} }
@ -46,7 +53,7 @@ function link(){
${BUILD_DIR}/multiboot.o \ ${BUILD_DIR}/multiboot.o \
${BUILD_DIR}/boot.o \ ${BUILD_DIR}/boot.o \
${BUILD_DIR}/long_mode.o \ ${BUILD_DIR}/long_mode.o \
${BUILD_DIR}/x86_64-unknown-none/release/libkernel.a $1 # kernel path
} }
function check_mb() { function check_mb() {
@ -71,6 +78,15 @@ function run_qemu() {
-cdrom $ISO \ -cdrom $ISO \
-serial stdio \ -serial stdio \
-device VGA -device VGA
# -d int \
}
function run_qemu_gdb {
qemu-system-x86_64 \
-cdrom $ISO \
-device VGA \
-d int \
-s -S -monitor stdio
} }
function print_help() { function print_help() {
@ -84,11 +100,21 @@ function build() {
pre_build pre_build
build_kernel build_kernel
build_boot build_boot
link link ${BUILD_DIR}/x86_64-unknown-none/release/libkernel.a
check_mb check_mb
make_iso make_iso
} }
function build_dev() {
pre_build
build_kernel dev
build_boot
link ${BUILD_DIR}/x86_64-unknown-none/debug/libkernel.a
check_mb
make_iso
}
case $1 in case $1 in
run-qemu) run-qemu)
@ -98,6 +124,13 @@ case $1 in
build) build)
build build
;; ;;
build-dev)
build_dev
;;
run-qemu-gdb)
build
run_qemu_gdb
;;
*) *)
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
echo "ERROR: Unknown option '$1'" echo "ERROR: Unknown option '$1'"

View File

@ -10,8 +10,13 @@ test=false
crate-type=["staticlib"] crate-type=["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[profile.release]
strip = false
[dependencies] [dependencies]
bitflags = "2.5.0" 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"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
log = "0.4.21" log = "0.4.21"
multiboot2 = "0.20.2" multiboot2 = "0.20.2"

View File

View File

@ -7,7 +7,6 @@ mod types;
use spin::Mutex; use spin::Mutex;
pub use types::*; pub use types::*;
const MAX_EVENT_LISTENERS: usize = 255; const MAX_EVENT_LISTENERS: usize = 255;
lazy_static!( lazy_static!(

View File

@ -1,10 +1,10 @@
use pc_keyboard::DecodedKey; use pc_keyboard::KeyEvent;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub enum Event { pub enum Event {
TimerInterrupt(Option<usize>), // trash unused value TimerInterrupt(Option<usize>), // trash unused value
Ps2KeyPress(Option<DecodedKey>) Ps2KeyEvent(Option<KeyEvent>),
} }
#[macro_export] #[macro_export]

View File

@ -1,50 +1,90 @@
use core::ptr::addr_of; use core::ptr::addr_of;
use x86_64::instructions::segmentation::{CS, DS, Segment};
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector}; use x86_64::structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable, SegmentSelector};
use x86_64::VirtAddr; use x86_64::VirtAddr;
use x86_64::structures::tss::TaskStateSegment; use x86_64::structures::tss::TaskStateSegment;
use lazy_static::lazy_static; 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; pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
lazy_static! { lazy_static! {
static ref TSS: TaskStateSegment = { static ref TSS: TaskStateSegment = {
let mut tss = TaskStateSegment::new(); let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { 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_start = VirtAddr::from_ptr(unsafe { addr_of!(STACK) });
let stack_end = stack_start + STACK_SIZE as u64; let stack_end = stack_start + STACK_SIZE as u64;
stack_end 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 tss
}; };
} }
lazy_static! { lazy_static! {
static ref GDT: (GlobalDescriptorTable, Selectors) = { pub static ref GDT: (GlobalDescriptorTable, Selectors) = {
let mut gdt = GlobalDescriptorTable::new(); let mut gdt = GlobalDescriptorTable::new();
let code_selector = gdt.append(Descriptor::kernel_code_segment()); let kernel_data_flags = DescriptorFlags::USER_SEGMENT | DescriptorFlags::PRESENT | DescriptorFlags::WRITABLE;
let tss_selector = gdt.append(Descriptor::tss_segment(&TSS));
(gdt, Selectors { code_selector, tss_selector }) 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 { #[allow(dead_code)]
code_selector: SegmentSelector, #[derive(Debug)]
tss_selector: SegmentSelector, 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() { pub fn init() {
log::info!("GDT init");
use x86_64::instructions::tables::load_tss; 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(); GDT.0.load();
unsafe { unsafe {
CS::set_reg(GDT.1.code_selector); DS::set_reg(GDT.1.data_sel);
load_tss(GDT.1.tss_selector); CS::set_reg(GDT.1.code_sel);
load_tss(GDT.1.tss_sel);
} }
} }

View File

@ -12,7 +12,7 @@ pub extern "x86-interrupt" fn breakpoint(sf: InterruptStackFrame){
pub extern "x86-interrupt" fn timer_interrupt(_: InterruptStackFrame){ pub extern "x86-interrupt" fn timer_interrupt(_: InterruptStackFrame){
//log::debug!("INT: TIMER\n{:#?}", sf); //log::debug!("INT: TIMER\n{:#?}", sf);
// print!("."); // print!(".");
EVENTMAN.lock().dispatch(&crate::events::Event::TimerInterrupt(None)); // EVENTMAN.lock().dispatch(&crate::events::Event::TimerInterrupt(None));
unsafe { unsafe {
super::PICS.lock() super::PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Timer as u8); .notify_end_of_interrupt(InterruptIndex::Timer as u8);

View File

@ -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 x86_64::structures::idt::InterruptStackFrame;
use crate::{events::EVENTMAN, interrupts::PICS}; use crate::{events::EVENTMAN, interrupts::PICS};
@ -22,9 +24,7 @@ pub extern "x86-interrupt" fn ps2_kb_int(_sf: InterruptStackFrame){
let scancode: u8 = unsafe { port.read() }; let scancode: u8 = unsafe { port.read() };
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { 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::Ps2KeyEvent(Some(key_event)));
EVENTMAN.lock().dispatch(&crate::events::Event::Ps2KeyPress(Some(key)));
}
} }
unsafe { unsafe {
PICS.lock() PICS.lock()

View File

@ -14,7 +14,6 @@ lazy_static::lazy_static! {
idt.breakpoint.set_handler_fn(handlers::breakpoint); idt.breakpoint.set_handler_fn(handlers::breakpoint);
idt.page_fault.set_handler_fn(handlers::page_fault); idt.page_fault.set_handler_fn(handlers::page_fault);
idt[InterruptIndex::Timer as u8] idt[InterruptIndex::Timer as u8]
.set_handler_fn(handlers::timer_interrupt); .set_handler_fn(handlers::timer_interrupt);
idt[InterruptIndex::Keyboard as u8] idt[InterruptIndex::Keyboard as u8]

View File

@ -6,7 +6,13 @@
#![feature(ptr_internals)] #![feature(ptr_internals)]
#![feature(allocator_api)] #![feature(allocator_api)]
use core::ptr::addr_of;
use alloc::vec::Vec; 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; extern crate alloc;
@ -18,7 +24,8 @@ mod utils;
#[macro_use] #[macro_use]
mod events; mod events;
mod mem; mod mem;
mod scheduler;
mod std;
@ -30,19 +37,28 @@ extern "C" fn kmain(mb2_info_addr: usize) -> ! {
interrupts::init_idt(); interrupts::init_idt();
utils::enable_nxe_bit(); utils::enable_nxe_bit();
utils::enable_write_protect_bit(); utils::enable_write_protect_bit();
std::init();
mem::init(mb2_info_addr); let active_table = mem::init(mb2_info_addr);
let mut a = Vec::new(); //unsafe {
// jmp_to_usermode(active_table, usermode_code as *const () as usize, addr_of!(PRIV_TSS_STACK) as *const () as usize);
//}
//let mut executor = Executor::new();
//executor.spawn(Task::new(usermode_code()));
//executor.run();
//let mut a = Vec::new();
a.push(6); //a.push(6);
a.push(9); //a.push(9);
a.push(4); //a.push(4);
a.push(2); //a.push(2);
a.push(0); //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(); // let (level_4_page_table, _) = Cr3::read();
// println!("Level 4 page table at: {:?}", level_4_page_table.start_address()); // println!("Level 4 page table at: {:?}", level_4_page_table.start_address());
log::info!("end of work"); log::info!("end of work");
loop {
utils::hcf(); 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!");
}

View File

@ -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 pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB
/// A simple allocator that allocates memory linearly and ignores freed memory. // A simple allocator that allocates memory linearly and ignores freed memory.
#[derive(Debug)] //#[derive(Debug)]
pub struct BumpAllocator { //pub struct BumpAllocator {
heap_start: usize, // heap_start: usize,
heap_end: usize, // heap_end: usize,
next: AtomicUsize, // next: AtomicUsize,
} //}
impl BumpAllocator { //impl BumpAllocator {
pub const fn new(heap_start: usize, heap_end: usize) -> Self { // pub const fn new(heap_start: usize, heap_end: usize) -> Self {
Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) } // Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) }
} // }
} //}
unsafe impl GlobalAlloc for BumpAllocator { //unsafe impl GlobalAlloc for BumpAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { // unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
loop { // loop {
// load current state of the `next` field // // load current state of the `next` field
let current_next = self.next.load(Ordering::Relaxed); // let current_next = self.next.load(Ordering::Relaxed);
let alloc_start = align_up(current_next as u64, layout.align() as u64); // let alloc_start = align_up(current_next as u64, layout.align() as u64);
let alloc_end = alloc_start.saturating_add(layout.size() 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 { // unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
// update the `next` pointer if it still has the value `current_next` // // do nothing, leak memory
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
}
}

View File

@ -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"); once::assert_has_not_been_called!("mem::init must be called only once");
let mem_info = MemInfo::load(mb_ptr); let mem_info = MemInfo::load(mb_ptr);
let mut frame_alloc = area_frame_alloc::AreaFrameAllocator::new(&mem_info); let mut frame_alloc = area_frame_alloc::AreaFrameAllocator::new(&mem_info);
@ -179,4 +179,5 @@ pub fn init(mb_ptr: usize) {
unsafe { unsafe {
GLOBAL_ALLOCATOR.lock().claim(Span::from_base_size(HEAP_START as *mut u8, HEAP_SIZE)).unwrap(); GLOBAL_ALLOCATOR.lock().claim(Span::from_base_size(HEAP_START as *mut u8, HEAP_SIZE)).unwrap();
} }
active_table
} }

View File

@ -189,7 +189,9 @@ pub fn remap_the_kernel<A>(allocator: &mut A, mem_info: &MemInfo) -> ActivePageT
continue; 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, assert!(section.start_address() as usize % PAGE_SIZE == 0,
"sections need to be page aligned"); "sections need to be page aligned");

View 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();
}
}

View 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
View 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
View File

@ -0,0 +1,8 @@
pub mod input;
pub fn init() {
unsafe { input::init(); };
}

View 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");
}

View File

@ -1,5 +1,9 @@
use core::arch::asm;
use x86::msr::{rdmsr, wrmsr, IA32_EFER}; 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) }; 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);
}

View File

@ -56,5 +56,5 @@ SECTIONS {
.gcc_except_table : ALIGN(4K) { .gcc_except_table : ALIGN(4K) {
*(.gcc_except_table) *(.gcc_except_table)
. = ALIGN(4K); . = ALIGN(4K);
}` }
} }