Added kinda working key input checking
This commit is contained in:
parent
1d61f97abb
commit
2dfd253f34
118
Cargo.lock
generated
118
Cargo.lock
generated
|
@ -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",
|
||||||
|
]
|
||||||
|
|
29
boot/boot.s
29
boot/boot.s
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
39
build.sh
39
build.sh
|
@ -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'"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
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;
|
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!(
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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!");
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
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::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user