uwu
This commit is contained in:
parent
6de42c3dba
commit
1b2dd2bfbe
|
@ -1,6 +1,6 @@
|
||||||
[unstable]
|
[unstable]
|
||||||
bindeps = true
|
bindeps = true
|
||||||
build-std = ["core", "compiler_builtins"]
|
build-std = ["core", "compiler_builtins", "alloc"]
|
||||||
build-std-features = ["compiler-builtins-mem"]
|
build-std-features = ["compiler-builtins-mem"]
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "log"]
|
||||||
|
path = kernel/libs/log
|
||||||
|
url = https://github.com/rust-lang/log.git
|
242
Cargo.lock
generated
242
Cargo.lock
generated
|
@ -2,6 +2,75 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "0.99.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"multiboot2",
|
||||||
|
"pc-keyboard",
|
||||||
|
"pic8259",
|
||||||
|
"spin 0.9.8",
|
||||||
|
"uart_16550",
|
||||||
|
"x86",
|
||||||
|
"x86_64",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
dependencies = [
|
||||||
|
"spin 0.5.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.21"
|
version = "0.4.21"
|
||||||
|
@ -9,8 +78,177 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "poppin-kernel"
|
name = "multiboot2"
|
||||||
version = "0.1.0"
|
version = "0.20.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad7ef048d4783355163fd0c874aac3db54b919dc6a86dc29bb13f67308b114b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"derive_more",
|
||||||
"log",
|
"log",
|
||||||
|
"ptr_meta",
|
||||||
|
"uefi-raw",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pc-keyboard"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed089a1fbffe3337a1a345501c981f1eb1e47e69de5a40e852433e12953c3174"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pic8259"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62d9a86c292b165f757e47e7fd66855def189b2564609bc4203727b27c33db22"
|
||||||
|
dependencies = [
|
||||||
|
"x86_64",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.85"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ptr_meta"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607"
|
||||||
|
dependencies = [
|
||||||
|
"ptr_meta_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ptr_meta_derive"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "raw-cpuid"
|
||||||
|
version = "10.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uart_16550"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dc00444796f6c71f47c85397a35e9c4dbf9901902ac02386940d178e2b78687"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"rustversion",
|
||||||
|
"x86",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uefi-raw"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efa8716f52e8cab8bcedfd5052388a0f263b69fe5cc2561548dc6a530678333c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"ptr_meta",
|
||||||
|
"uguid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uguid"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab14ea9660d240e7865ce9d54ecdbd1cd9fa5802ae6f4512f093c7907e921533"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "volatile"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x86"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"raw-cpuid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x86_64"
|
||||||
|
version = "0.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"rustversion",
|
||||||
|
"volatile",
|
||||||
]
|
]
|
||||||
|
|
|
@ -23,6 +23,9 @@ _start:
|
||||||
; load the 64-bit GDT
|
; load the 64-bit GDT
|
||||||
lgdt [gdt64.pointer]
|
lgdt [gdt64.pointer]
|
||||||
|
|
||||||
|
mov dword [0xb8000], 0x2f4b2f4f
|
||||||
|
|
||||||
|
|
||||||
jmp gdt64.code:long_mode_start
|
jmp gdt64.code:long_mode_start
|
||||||
|
|
||||||
; print `OK` to screen
|
; print `OK` to screen
|
||||||
|
|
7
build.sh
7
build.sh
|
@ -46,7 +46,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/libpoppin_kernel.a
|
${BUILD_DIR}/x86_64-unknown-none/release/libkernel.a
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_mb() {
|
function check_mb() {
|
||||||
|
@ -67,7 +67,10 @@ function make_iso() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_qemu() {
|
function run_qemu() {
|
||||||
qemu-system-x86_64 -cdrom $ISO
|
qemu-system-x86_64 \
|
||||||
|
-cdrom $ISO \
|
||||||
|
-serial stdio \
|
||||||
|
-device VGA
|
||||||
}
|
}
|
||||||
|
|
||||||
function print_help() {
|
function print_help() {
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
[package]
|
[package]
|
||||||
name = "poppin-kernel"
|
name = "kernel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
test=false
|
test=false
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name="poppin_kernel"
|
name="kernel"
|
||||||
test=false
|
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
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
|
multiboot2 = "0.20.2"
|
||||||
|
pc-keyboard = "0.7.0"
|
||||||
|
pic8259 = "0.11.0"
|
||||||
|
spin = "0.9.8"
|
||||||
|
uart_16550 = "0.3.0"
|
||||||
|
x86 = "0.52.0"
|
||||||
|
x86_64 = "0.15.1"
|
||||||
|
|
12
kernel/src/events/mod.rs
Normal file
12
kernel/src/events/mod.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub struct KernelEventHandler {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KernelEventHandler {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
50
kernel/src/gdt/mod.rs
Normal file
50
kernel/src/gdt/mod.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use core::ptr::addr_of;
|
||||||
|
|
||||||
|
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
use x86_64::structures::tss::TaskStateSegment;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
let stack_start = VirtAddr::from_ptr(unsafe { addr_of!(STACK) });
|
||||||
|
let stack_end = stack_start + STACK_SIZE as u64;
|
||||||
|
stack_end
|
||||||
|
};
|
||||||
|
tss
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
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 })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Selectors {
|
||||||
|
code_selector: SegmentSelector,
|
||||||
|
tss_selector: SegmentSelector,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
log::debug!("GDT init");
|
||||||
|
use x86_64::instructions::tables::load_tss;
|
||||||
|
use x86_64::instructions::segmentation::{CS, Segment};
|
||||||
|
|
||||||
|
GDT.0.load();
|
||||||
|
unsafe {
|
||||||
|
CS::set_reg(GDT.1.code_selector);
|
||||||
|
load_tss(GDT.1.tss_selector);
|
||||||
|
}
|
||||||
|
}
|
31
kernel/src/interrupts/handlers/mod.rs
Normal file
31
kernel/src/interrupts/handlers/mod.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode};
|
||||||
|
use crate::interrupts::InterruptIndex;
|
||||||
|
|
||||||
|
mod ps2_keyboard;
|
||||||
|
|
||||||
|
pub use ps2_keyboard::ps2_kb_int;
|
||||||
|
|
||||||
|
pub extern "x86-interrupt" fn breakpoint(sf: InterruptStackFrame){
|
||||||
|
log::error!("EXCEPT: BREAKPOINT\n{:#?}", sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "x86-interrupt" fn timer_interrupt(_: InterruptStackFrame){
|
||||||
|
//log::debug!("INT: TIMER\n{:#?}", sf);
|
||||||
|
// print!(".");
|
||||||
|
unsafe {
|
||||||
|
super::PICS.lock()
|
||||||
|
.notify_end_of_interrupt(InterruptIndex::Timer as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, _: u64) -> ! {
|
||||||
|
panic!("EXCEPT: DOUBLE FAULT \n{:#?}", stack_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "x86-interrupt" fn page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) {
|
||||||
|
use x86_64::registers::control::Cr2;
|
||||||
|
|
||||||
|
log::error!("EXCEPT: PAGE FAULT");
|
||||||
|
log::debug!("Addr: {:?}", Cr2::read());
|
||||||
|
log::debug!("ErrCo: {:?}\n{:#?}", error_code, stack_frame);
|
||||||
|
crate::utils::hcf();
|
||||||
|
}
|
35
kernel/src/interrupts/handlers/ps2_keyboard.rs
Normal file
35
kernel/src/interrupts/handlers/ps2_keyboard.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use x86_64::structures::idt::InterruptStackFrame;
|
||||||
|
|
||||||
|
use crate::interrupts::PICS;
|
||||||
|
|
||||||
|
pub extern "x86-interrupt" fn ps2_kb_int(_sf: InterruptStackFrame){
|
||||||
|
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||||
|
use spin::Mutex;
|
||||||
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||||
|
Mutex::new(Keyboard::new(ScancodeSet1::new(),
|
||||||
|
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) {
|
||||||
|
if false {
|
||||||
|
match key {
|
||||||
|
DecodedKey::Unicode(character) => print!("{}", character),
|
||||||
|
DecodedKey::RawKey(key) => print!("{:?}", key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
PICS.lock()
|
||||||
|
.notify_end_of_interrupt(super::InterruptIndex::Keyboard as u8);
|
||||||
|
}
|
||||||
|
}
|
48
kernel/src/interrupts/mod.rs
Normal file
48
kernel/src/interrupts/mod.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
use pic8259::ChainedPics;
|
||||||
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
|
mod handlers;
|
||||||
|
|
||||||
|
pub const PIC_1_OFFSET: u8 = 32;
|
||||||
|
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
||||||
|
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
|
|
||||||
|
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]
|
||||||
|
.set_handler_fn(handlers::ps2_kb_int);
|
||||||
|
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
idt.double_fault.set_handler_fn(handlers::double_fault)
|
||||||
|
.set_stack_index(crate::gdt::DOUBLE_FAULT_IST_INDEX);
|
||||||
|
}
|
||||||
|
idt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static PICS: spin::Mutex<ChainedPics> =
|
||||||
|
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum InterruptIndex {
|
||||||
|
Timer = PIC_1_OFFSET,
|
||||||
|
Keyboard, // PS/2
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_idt() {
|
||||||
|
log::debug!("IDT init");
|
||||||
|
IDT.load();
|
||||||
|
unsafe { PICS.lock().initialize() };
|
||||||
|
x86_64::instructions::interrupts::enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,50 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(abi_x86_interrupt)]
|
||||||
|
|
||||||
|
use multiboot2::BootInformationHeader;
|
||||||
|
use x86_64::registers::control::Cr3;
|
||||||
|
|
||||||
|
use crate::mem::FrameAllocator;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
mod logger;
|
mod logger;
|
||||||
|
mod interrupts;
|
||||||
|
mod gdt;
|
||||||
|
mod utils;
|
||||||
|
mod events;
|
||||||
|
mod mem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn kmain() -> ! {
|
extern "C" fn kmain(mb2_info_addr: usize) -> ! {
|
||||||
|
logger::init(log::LevelFilter::Trace).unwrap();
|
||||||
loop {
|
gdt::init();
|
||||||
|
interrupts::init_idt();
|
||||||
|
let mem_info = mem::MemInfo::load(mb2_info_addr);
|
||||||
|
let mut alloc = mem::area_frame_alloc::AreaFrameAllocator::new(mem_info);
|
||||||
|
|
||||||
|
for i in 0.. {
|
||||||
|
if let None = alloc.allocate_frame() {
|
||||||
|
println!("allocated {} frames", i);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let (level_4_page_table, _) = Cr3::read();
|
||||||
|
// println!("Level 4 page table at: {:?}", level_4_page_table.start_address());
|
||||||
|
|
||||||
|
|
||||||
|
utils::hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_pi: &core::panic::PanicInfo) -> ! {
|
fn panic(pi: &core::panic::PanicInfo) -> ! {
|
||||||
loop {}
|
log::error!("{pi}");
|
||||||
|
utils::hcf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
use log::{Record, Level, Metadata};
|
|
||||||
|
|
||||||
struct SimpleLogger {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl log::Log for SimpleLogger {
|
|
||||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
|
||||||
metadata.level() <= Level::Info
|
|
||||||
}
|
|
||||||
|
|
||||||
fn log(&self, record: &Record) {
|
|
||||||
if self.enabled(record.metadata()) {
|
|
||||||
println!("{} - {}", record.level(), record.args());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&self) {}
|
|
||||||
}
|
|
0
kernel/src/logger/macros.rs
Normal file
0
kernel/src/logger/macros.rs
Normal file
87
kernel/src/logger/mod.rs
Normal file
87
kernel/src/logger/mod.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
use log::{Level, LevelFilter, Metadata, Record, SetLoggerError};
|
||||||
|
|
||||||
|
use crate::logger::serial::{write_com, ANSI_COLORS, COM0};
|
||||||
|
|
||||||
|
use self::vga::{Color, ColorCode, WRITER};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod vga;
|
||||||
|
pub mod serial;
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
|
|
||||||
|
pub static LOGGER: KLogger = KLogger;
|
||||||
|
|
||||||
|
pub struct KLogger;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const C_TRACE: ColorCode = ColorCode::new(Color::Cyan, Color::Black);
|
||||||
|
const C_DEBUG: ColorCode = ColorCode::new(Color::Blue, Color::Black);
|
||||||
|
const C_INFO: ColorCode = ColorCode::new(Color::Green, Color::Black);
|
||||||
|
const C_WARN: ColorCode = ColorCode::new(Color::Yellow, Color::Black);
|
||||||
|
const C_ERROR: ColorCode = ColorCode::new(Color::Red, Color::Black);
|
||||||
|
const C_NORMAL: ColorCode = ColorCode::new(Color::White, Color::Black);
|
||||||
|
|
||||||
|
|
||||||
|
impl log::Log for KLogger {
|
||||||
|
fn enabled(&self, _: &Metadata) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &Record) {
|
||||||
|
if self.enabled(record.metadata()) {
|
||||||
|
{WRITER.lock().set_color(Color::Magenta, Color::Black); }
|
||||||
|
print!("[");
|
||||||
|
write_com(&COM0, format_args!("{}[", ANSI_COLORS::MAGENTA));
|
||||||
|
match record.level() {
|
||||||
|
Level::Trace => {
|
||||||
|
{WRITER.lock().set_color_code(C_TRACE); }
|
||||||
|
print!("TRACE");
|
||||||
|
write_com(&COM0, format_args!("{}TRACE", ANSI_COLORS::BLUE2));
|
||||||
|
}
|
||||||
|
Level::Debug => {
|
||||||
|
{WRITER.lock().set_color_code(C_DEBUG); }
|
||||||
|
print!("DEBUG");
|
||||||
|
write_com(&COM0, format_args!("{}DEBUG", ANSI_COLORS::BLUE));
|
||||||
|
}
|
||||||
|
Level::Info => {
|
||||||
|
{WRITER.lock().set_color_code(C_INFO); }
|
||||||
|
print!("INFO");
|
||||||
|
write_com(&COM0, format_args!("{}INFO", ANSI_COLORS::GREEN));
|
||||||
|
}
|
||||||
|
Level::Warn => {
|
||||||
|
{WRITER.lock().set_color_code(C_WARN); }
|
||||||
|
print!("WARN");
|
||||||
|
write_com(&COM0, format_args!("{}WARN", ANSI_COLORS::YELLOW));
|
||||||
|
}
|
||||||
|
Level::Error => {
|
||||||
|
{WRITER.lock().set_color_code(C_ERROR); }
|
||||||
|
print!("ERROR");
|
||||||
|
write_com(&COM0, format_args!("{}ERROR", ANSI_COLORS::RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{WRITER.lock().set_color(Color::Magenta, Color::Black); }
|
||||||
|
print!("]");
|
||||||
|
{WRITER.lock().set_color_code(C_NORMAL); }
|
||||||
|
|
||||||
|
write_com(&COM0, format_args!("{}]", ANSI_COLORS::MAGENTA));
|
||||||
|
|
||||||
|
println!(" {}: {}", record.module_path().unwrap_or(""), record.args());
|
||||||
|
|
||||||
|
write_com(&COM0, format_args!(" {}{}: {}\n", ANSI_COLORS::RESET, record.module_path().unwrap_or(""), record.args()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(lvl: LevelFilter) -> Result<(), SetLoggerError> {
|
||||||
|
log::set_logger(&LOGGER)?;
|
||||||
|
log::set_max_level(lvl);
|
||||||
|
log::info!("Logger init OK");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
64
kernel/src/logger/serial.rs
Normal file
64
kernel/src/logger/serial.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use spin::Mutex;
|
||||||
|
use uart_16550::SerialPort;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const COM_PORTS: [u16; 8] = [0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8];
|
||||||
|
|
||||||
|
|
||||||
|
fn init_com_port(port_no: u16) -> Mutex<SerialPort> {
|
||||||
|
let mut p = unsafe {SerialPort::new(port_no)};
|
||||||
|
p.init();
|
||||||
|
Mutex::new(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static!(
|
||||||
|
pub static ref COM0: Mutex<SerialPort> = init_com_port(COM_PORTS[0]);
|
||||||
|
pub static ref COM1: Mutex<SerialPort> = init_com_port(COM_PORTS[1]);
|
||||||
|
pub static ref COM2: Mutex<SerialPort> = init_com_port(COM_PORTS[2]);
|
||||||
|
);
|
||||||
|
|
||||||
|
pub fn write_com(cp: &'static Mutex<SerialPort>, args: core::fmt::Arguments) {
|
||||||
|
use x86_64::instructions::interrupts::without_interrupts;
|
||||||
|
without_interrupts(|| {
|
||||||
|
cp.lock().write_fmt(args).unwrap();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub mod ANSI_COLORS {
|
||||||
|
pub const RESET: &str = "\x1b[0m";
|
||||||
|
pub const BOLD: &str = "\x1b[1m";
|
||||||
|
pub const ITALIC: &str = "\x1b[3m";
|
||||||
|
pub const UNDERLINE: &str = "\x1b[4m";
|
||||||
|
pub const BLINK: &str = "\x1b[5m";
|
||||||
|
pub const BLINK2: &str = "\x1b[6m";
|
||||||
|
pub const SELECTED: &str = "\x1b[7m";
|
||||||
|
pub const BLACK: &str = "\x1b[30m";
|
||||||
|
pub const RED: &str = "\x1b[31m";
|
||||||
|
pub const GREEN: &str = "\x1b[32m";
|
||||||
|
pub const YELLOW: &str = "\x1b[33m";
|
||||||
|
pub const BLUE: &str = "\x1b[34m";
|
||||||
|
pub const MAGENTA: &str = "\x1b[35m";
|
||||||
|
pub const BEIGE: &str = "\x1b[36m";
|
||||||
|
pub const WHITE: &str = "\x1b[37m";
|
||||||
|
pub const BLACKBG: &str = "\x1b[40m";
|
||||||
|
pub const REDBG: &str = "\x1b[41m";
|
||||||
|
pub const GREENBG: &str = "\x1b[42m";
|
||||||
|
pub const YELLOWBG: &str = "\x1b[43m";
|
||||||
|
pub const BLUEBG: &str = "\x1b[44m";
|
||||||
|
pub const MAGENTABG: &str = "\x1b[45m";
|
||||||
|
pub const BEIGEBG: &str = "\x1b[46m";
|
||||||
|
pub const WHITEBG: &str = "\x1b[47m";
|
||||||
|
pub const GREY: &str = "\x1b[90m";
|
||||||
|
pub const RED2: &str = "\x1b[91m";
|
||||||
|
pub const GREEN2: &str = "\x1b[92m";
|
||||||
|
pub const YELLOW2: &str = "\x1b[93m";
|
||||||
|
pub const BLUE2: &str = "\x1b[94m";
|
||||||
|
pub const MAGENTA2: &str = "\x1b[95m";
|
||||||
|
pub const BEIGE2: &str = "\x1b[96m";
|
||||||
|
pub const WHITE2: &str = "\x1b[97m";
|
||||||
|
}
|
30
kernel/src/logger/vga/macros.rs
Normal file
30
kernel/src/logger/vga/macros.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use core::fmt;
|
||||||
|
use x86_64::instructions::interrupts;
|
||||||
|
|
||||||
|
use crate::logger::vga::Writer;
|
||||||
|
|
||||||
|
impl fmt::Write for Writer {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
self.write_string(s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ($crate::logger::vga::macros::_print(format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
() => ($crate::print!("\n"));
|
||||||
|
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn _print(args: fmt::Arguments) {
|
||||||
|
use core::fmt::Write;
|
||||||
|
interrupts::without_interrupts(|| {
|
||||||
|
crate::logger::vga::WRITER.lock().write_fmt(args).unwrap();
|
||||||
|
});
|
||||||
|
}
|
199
kernel/src/logger/vga/mod.rs
Normal file
199
kernel/src/logger/vga/mod.rs
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
use x86::io::{outb, inb};
|
||||||
|
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
|
|
||||||
|
lazy_static::lazy_static!{
|
||||||
|
pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
const BUFFER_HEIGHT: usize = 25;
|
||||||
|
const BUFFER_WIDTH: usize = 80;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum Color {
|
||||||
|
Black = 0,
|
||||||
|
Blue = 1,
|
||||||
|
Green = 2,
|
||||||
|
Cyan = 3,
|
||||||
|
Red = 4,
|
||||||
|
Magenta = 5,
|
||||||
|
Brown = 6,
|
||||||
|
LightGray = 7,
|
||||||
|
DarkGray = 8,
|
||||||
|
LightBlue = 9,
|
||||||
|
LightGreen = 10,
|
||||||
|
LightCyan = 11,
|
||||||
|
LightRed = 12,
|
||||||
|
Pink = 13,
|
||||||
|
Yellow = 14,
|
||||||
|
White = 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct ColorCode(u8);
|
||||||
|
|
||||||
|
impl ColorCode {
|
||||||
|
pub const fn new(foreground: Color, background: Color) -> ColorCode {
|
||||||
|
ColorCode((background as u8) << 4 | (foreground as u8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct VgaChar {
|
||||||
|
pub chr: u8,
|
||||||
|
pub color: ColorCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Buffer {
|
||||||
|
chars: [[VgaChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Writer {
|
||||||
|
col: usize,
|
||||||
|
line: usize,
|
||||||
|
buffer: &'static mut Buffer,
|
||||||
|
color: ColorCode
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Writer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut s = Self {
|
||||||
|
col: 0,
|
||||||
|
line: 0,
|
||||||
|
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
|
||||||
|
color: ColorCode::new(Color::White, Color::Black)
|
||||||
|
};
|
||||||
|
s.clear_screen();
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_byte(&mut self, chr: u8) {
|
||||||
|
match chr {
|
||||||
|
b'\n' => self.new_line(),
|
||||||
|
_ => {
|
||||||
|
if self.col >= BUFFER_WIDTH {
|
||||||
|
self.new_line();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buffer.chars[self.line][self.col] = VgaChar {
|
||||||
|
chr,
|
||||||
|
color: self.color,
|
||||||
|
};
|
||||||
|
self.col += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_string(&mut self, s: &str) {
|
||||||
|
for c in s.as_bytes() {
|
||||||
|
match c {
|
||||||
|
// printable ASCII byte or newline
|
||||||
|
0x20..=0x7e | b'\n' => self.write_byte(*c),
|
||||||
|
// not part of printable ASCII range
|
||||||
|
_ => self.write_byte(0xfe),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update_cursor(self.col as u16, self.line as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_color(&mut self, fg: Color, bg: Color) {
|
||||||
|
self.color = ColorCode::new(fg, bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_color_code(&mut self, c: ColorCode) {
|
||||||
|
self.color = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_screen(&mut self) {
|
||||||
|
let color = ColorCode::new(Color::White, Color::Black);
|
||||||
|
for line in 0..BUFFER_HEIGHT {
|
||||||
|
for col in 0..BUFFER_WIDTH {
|
||||||
|
self.buffer.chars[line][col] = VgaChar {
|
||||||
|
chr: 0,
|
||||||
|
color,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_line(&mut self, line: usize) {
|
||||||
|
let color = ColorCode::new(Color::White, Color::Black);
|
||||||
|
for col in 0..BUFFER_WIDTH {
|
||||||
|
self.buffer.chars[line][col] = VgaChar {
|
||||||
|
chr: 0,
|
||||||
|
color,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_line(&mut self) {
|
||||||
|
if self.line >= BUFFER_HEIGHT - 1{
|
||||||
|
for row in 1..BUFFER_HEIGHT {
|
||||||
|
for col in 0..BUFFER_WIDTH {
|
||||||
|
let chr = self.buffer.chars[row][col];
|
||||||
|
self.buffer.chars[row - 1][col] = chr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.clear_line(BUFFER_HEIGHT - 1);
|
||||||
|
} else {
|
||||||
|
self.line += 1;
|
||||||
|
}
|
||||||
|
self.col = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn enable_cursor(cur_start: u8, cur_end: u8) {
|
||||||
|
unsafe {
|
||||||
|
outb(0x3D4, 0x0A);
|
||||||
|
outb(0x3D5, (inb(0x3D5) & 0xC0) | cur_start);
|
||||||
|
|
||||||
|
outb(0x3D4, 0x0B);
|
||||||
|
outb(0x3D5, (inb(0x3D5) & 0xE0) | cur_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn disable_cursor() {
|
||||||
|
unsafe {
|
||||||
|
outb(0x3D4, 0x0A);
|
||||||
|
outb(0x3D5, 0x20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_cursor(x: u16, y: u16) {
|
||||||
|
unsafe {
|
||||||
|
|
||||||
|
let pos: u16 = y * ( BUFFER_WIDTH as u16) + x;
|
||||||
|
|
||||||
|
outb(0x3D4, 0x0F);
|
||||||
|
outb(0x3D5, (pos & 0xFF) as u8);
|
||||||
|
outb(0x3D4, 0x0E);
|
||||||
|
outb(0x3D5, ((pos >> 8 ) & 0xFF) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn get_cursor_position() -> (u16, u16) {
|
||||||
|
let mut pos: u16 = 0;
|
||||||
|
unsafe {
|
||||||
|
|
||||||
|
outb(0x3D4, 0x0F);
|
||||||
|
pos |= inb(0x3D5) as u16;
|
||||||
|
outb(0x3D4, 0x0E);
|
||||||
|
pos |= (inb(0x3D5) as u16) << 8;
|
||||||
|
}
|
||||||
|
(pos / (BUFFER_WIDTH as u16), pos % (BUFFER_WIDTH as u16))
|
||||||
|
}
|
86
kernel/src/mem/area_frame_alloc.rs
Normal file
86
kernel/src/mem/area_frame_alloc.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use core::slice::Iter;
|
||||||
|
|
||||||
|
use super::{Frame, FrameAllocator, MemInfo, MemoryAreaIter};
|
||||||
|
use multiboot2::MemoryArea;
|
||||||
|
|
||||||
|
pub struct AreaFrameAllocator<'a> {
|
||||||
|
next_free_frame: Frame,
|
||||||
|
current_area: Option<&'a MemoryArea>,
|
||||||
|
areas: MemoryAreaIter,
|
||||||
|
kernel_start: Frame,
|
||||||
|
kernel_end: Frame,
|
||||||
|
multiboot_start: Frame,
|
||||||
|
multiboot_end: Frame,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FrameAllocator for AreaFrameAllocator<'a> {
|
||||||
|
fn allocate_frame(&mut self) -> Option<Frame> {
|
||||||
|
if let Some(area) = self.current_area {
|
||||||
|
// "Clone" the frame to return it if it's free. Frame doesn't
|
||||||
|
// implement Clone, but we can construct an identical frame.
|
||||||
|
let frame = Frame{ number: self.next_free_frame.number };
|
||||||
|
|
||||||
|
// the last frame of the current area
|
||||||
|
let current_area_last_frame = {
|
||||||
|
let address = area.start_address() + area.size() - 1;
|
||||||
|
Frame::containing_address(address as usize)
|
||||||
|
};
|
||||||
|
|
||||||
|
if frame > current_area_last_frame {
|
||||||
|
// all frames of current area are used, switch to next area
|
||||||
|
self.choose_next_area();
|
||||||
|
} else if frame >= self.kernel_start && frame <= self.kernel_end {
|
||||||
|
// `frame` is used by the kernel
|
||||||
|
self.next_free_frame = Frame {
|
||||||
|
number: self.kernel_end.number + 1
|
||||||
|
};
|
||||||
|
} else if frame >= self.multiboot_start && frame <= self.multiboot_end {
|
||||||
|
// `frame` is used by the multiboot information structure
|
||||||
|
self.next_free_frame = Frame {
|
||||||
|
number: self.multiboot_end.number + 1
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// frame is unused, increment `next_free_frame` and return it
|
||||||
|
self.next_free_frame.number += 1;
|
||||||
|
return Some(frame);
|
||||||
|
}
|
||||||
|
// `frame` was not valid, try it again with the updated `next_free_frame`
|
||||||
|
self.allocate_frame()
|
||||||
|
} else {
|
||||||
|
None // no free frames left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deallocate_frame(&mut self, _: Frame) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AreaFrameAllocator<'a> {
|
||||||
|
fn choose_next_area(&mut self) {
|
||||||
|
self.current_area = self.areas.clone().filter(|area| {
|
||||||
|
let address = area.start_address() + area.size() - 1;
|
||||||
|
Frame::containing_address(address as usize) >= self.next_free_frame
|
||||||
|
}).min_by_key(|area| area.start_address());
|
||||||
|
|
||||||
|
if let Some(area) = self.current_area {
|
||||||
|
let start_frame = Frame::containing_address(area.start_address() as usize);
|
||||||
|
if self.next_free_frame < start_frame {
|
||||||
|
self.next_free_frame = start_frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new(mi: MemInfo) -> AreaFrameAllocator<'a> {
|
||||||
|
let mut allocator = AreaFrameAllocator {
|
||||||
|
next_free_frame: Frame::containing_address(0),
|
||||||
|
current_area: None,
|
||||||
|
areas: mi.mem_area_iter,
|
||||||
|
kernel_start: Frame::containing_address(mi.kernel_start),
|
||||||
|
kernel_end: Frame::containing_address(mi.kernel_end),
|
||||||
|
multiboot_start: Frame::containing_address(mi.mb_start),
|
||||||
|
multiboot_end: Frame::containing_address(mi.mb_end),
|
||||||
|
};
|
||||||
|
allocator.choose_next_area();
|
||||||
|
allocator
|
||||||
|
}
|
||||||
|
}
|
115
kernel/src/mem/mod.rs
Normal file
115
kernel/src/mem/mod.rs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
use core::{alloc::{GlobalAlloc, Layout}, ops::Deref};
|
||||||
|
|
||||||
|
use multiboot2::{BootInformation, BootInformationHeader, MemoryArea, MemoryAreaType, MemoryMapTag, TagTrait};
|
||||||
|
|
||||||
|
pub mod area_frame_alloc;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static GLOBAL_ALLOCATOR: DummyAlloc = DummyAlloc;
|
||||||
|
pub struct DummyAlloc;
|
||||||
|
unsafe impl GlobalAlloc for DummyAlloc {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 0 as *mut u8 }
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Frame {
|
||||||
|
number: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
fn containing_address(address: usize) -> Frame {
|
||||||
|
Frame{ number: address / PAGE_SIZE }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FrameAllocator {
|
||||||
|
fn allocate_frame(&mut self) -> Option<Frame>;
|
||||||
|
fn deallocate_frame(&mut self, frame: Frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MemoryAreaIter {
|
||||||
|
current_area: *const MemoryArea,
|
||||||
|
last_area: *const MemoryArea,
|
||||||
|
entry_size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for MemoryAreaIter {
|
||||||
|
type Item = &'static MemoryArea;
|
||||||
|
fn next(&mut self) -> Option<&'static MemoryArea> {
|
||||||
|
if self.current_area > self.last_area {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let area = unsafe{&*self.current_area};
|
||||||
|
self.current_area = ((self.current_area as u32) + self.entry_size)
|
||||||
|
as *const MemoryArea;
|
||||||
|
if area.typ() == MemoryAreaType::Available {
|
||||||
|
Some(area)
|
||||||
|
} else {self.next()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryAreaIter {
|
||||||
|
pub fn new(mmap_tag: &MemoryMapTag) -> Self {
|
||||||
|
let self_ptr = mmap_tag as *const MemoryMapTag;
|
||||||
|
let start_area = (mmap_tag.memory_areas().first().unwrap()) as *const MemoryArea;
|
||||||
|
MemoryAreaIter {
|
||||||
|
current_area: start_area,
|
||||||
|
last_area: ((self_ptr as *const () as usize) + mmap_tag.size() - mmap_tag.entry_size() as usize) as *const MemoryArea,
|
||||||
|
entry_size: mmap_tag.entry_size(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MemInfo{
|
||||||
|
mem_area_iter: MemoryAreaIter,
|
||||||
|
pub kernel_start: usize,
|
||||||
|
pub kernel_end: usize,
|
||||||
|
pub mb_start: usize,
|
||||||
|
pub mb_end: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemInfo {
|
||||||
|
pub fn load(mb_ptr: usize) -> Self {
|
||||||
|
let boot_info = unsafe {
|
||||||
|
multiboot2::BootInformation::load(mb_ptr as *const BootInformationHeader).unwrap()
|
||||||
|
};
|
||||||
|
let mmap_tag = boot_info.memory_map_tag().unwrap().clone();
|
||||||
|
|
||||||
|
// log::debug!("Memory areas:");
|
||||||
|
// for area in mmap_tag.memory_areas() {
|
||||||
|
// log::debug!(" start: 0x{:x}, sz: 0x{:x}", area.start_address(), area.size());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// log::debug!("kernel sections:");
|
||||||
|
// for section in boot_info.elf_sections().unwrap() {
|
||||||
|
// log::debug!("{}: start: 0x{:x}, sz: 0x{:x}, flags: 0b{:b}", section.name().unwrap_or("NONE"),
|
||||||
|
// section.start_address(), section.size(), section.flags());
|
||||||
|
// }
|
||||||
|
let kernel_start = boot_info.elf_sections().unwrap().clone().map(|s| s.start_address()).min().unwrap() as usize;
|
||||||
|
let kernel_end = boot_info.elf_sections().unwrap().clone().map(|s| s.end_address()).max().unwrap() as usize;
|
||||||
|
let mb_start = boot_info.start_address();
|
||||||
|
let mb_end = boot_info.end_address();
|
||||||
|
|
||||||
|
//log::debug!("Kernel: start: 0x{:x} sz: 0x{:x}", mi.kernel_start, mi.kernel_end - mi.kernel_start);
|
||||||
|
//log::debug!("Multiboot: start: 0x{:x} sz: 0x{:x}", mi.mb_start, mi.mb_end - mi.mb_start);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
mem_area_iter: MemoryAreaIter::new(mmap_tag),
|
||||||
|
kernel_start,
|
||||||
|
kernel_end,
|
||||||
|
mb_start,
|
||||||
|
mb_end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
kernel/src/utils.rs
Normal file
12
kernel/src/utils.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use x86_64::instructions;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn hcf() -> ! {
|
||||||
|
loop {
|
||||||
|
instructions::hlt();
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user