can someone help me fix my code pls
This commit is contained in:
parent
9e136b0c02
commit
c68fdd7dd2
9
.cargo/config.toml
Normal file
9
.cargo/config.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[build]
|
||||||
|
target = "/Users/missing/Projects/os/target.json"
|
||||||
|
|
||||||
|
[unstable]
|
||||||
|
build-std-features = ["compiler-builtins-mem"]
|
||||||
|
build-std = ["core", "compiler_builtins", "alloc"]
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "none")']
|
||||||
|
runner = "bootimage runner"
|
108
Cargo.lock
generated
Normal file
108
Cargo.lock
generated
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bootloader"
|
||||||
|
version = "0.9.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de78decc37247c7cfac5dbf3495c7298c6ac97cb355161caa7e15969c6648e6c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked_list_allocator"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a"
|
||||||
|
dependencies = [
|
||||||
|
"spinning_top",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"bootloader",
|
||||||
|
"linked_list_allocator",
|
||||||
|
"pc-keyboard",
|
||||||
|
"pic8259",
|
||||||
|
"spin",
|
||||||
|
"x86_64",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pc-keyboard"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c6f2d937e3b8d63449b01401e2bae4041bc9dd1129c2e3e0d239407cf6635ac"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pic8259"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24ec21f514e2e16e94649f1d041ca4a7069b512c037ac156360652a775e6229d"
|
||||||
|
dependencies = [
|
||||||
|
"x86_64",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spinning_top"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "volatile"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4c2dbd44eb8b53973357e6e207e370f0c1059990df850aca1eca8947cf464f0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x86_64"
|
||||||
|
version = "0.14.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "958ab3202b01bc43ba2eb832102c4a487ed93151667a2289062e5f2b00058be2"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"bitflags",
|
||||||
|
"volatile",
|
||||||
|
]
|
27
Cargo.toml
Normal file
27
Cargo.toml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[package]
|
||||||
|
name = "os"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "os"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "os"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags = "1.3.2"
|
||||||
|
bootloader = { version = "0.9.8", features = ["map_physical_memory"] }
|
||||||
|
linked_list_allocator = "0.9.1"
|
||||||
|
pc-keyboard = "0.5.1"
|
||||||
|
pic8259 = "0.10.2"
|
||||||
|
spin = "0.9.2"
|
||||||
|
# x = { path = "../x" }
|
||||||
|
x86_64 = "0.14.8"
|
||||||
|
|
||||||
|
[package.metadata.bootimage]
|
||||||
|
# run-args = ["-s", "-S"]
|
1
rust-toolchain
Normal file
1
rust-toolchain
Normal file
|
@ -0,0 +1 @@
|
||||||
|
nightly
|
58
src/gdt.rs
Normal file
58
src/gdt.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use crate::lazy_static;
|
||||||
|
use x86_64::{
|
||||||
|
instructions::tables::load_tss,
|
||||||
|
registers::segmentation::{Segment, SegmentSelector, CS},
|
||||||
|
structures::{
|
||||||
|
gdt::{Descriptor, GlobalDescriptorTable},
|
||||||
|
tss::TaskStateSegment,
|
||||||
|
},
|
||||||
|
VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref TSS: TaskStateSegment = {
|
||||||
|
let mut tss = TaskStateSegment::new();
|
||||||
|
tss.interrupt_stack_table[crate::interrupts::DOUBLE_FAULT_STACK_IDX as usize] = {
|
||||||
|
const STACK_SIZE: usize = 4096 * 5;
|
||||||
|
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||||
|
|
||||||
|
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
|
||||||
|
let stack_end = stack_start + STACK_SIZE;
|
||||||
|
stack_end
|
||||||
|
};
|
||||||
|
tss.interrupt_stack_table[crate::interrupts::TIMER_STACK_IDX as usize] = {
|
||||||
|
const STACK_SIZE: usize = 4096 * 5;
|
||||||
|
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||||
|
|
||||||
|
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
|
||||||
|
let stack_end = stack_start + STACK_SIZE;
|
||||||
|
stack_end
|
||||||
|
};
|
||||||
|
tss
|
||||||
|
};
|
||||||
|
static ref GDT: (GlobalDescriptorTable, Selectors) = {
|
||||||
|
let mut gdt = GlobalDescriptorTable::new();
|
||||||
|
let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
|
||||||
|
let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
|
||||||
|
(
|
||||||
|
gdt,
|
||||||
|
Selectors {
|
||||||
|
code_selector,
|
||||||
|
tss_selector,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Selectors {
|
||||||
|
code_selector: SegmentSelector,
|
||||||
|
tss_selector: SegmentSelector,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_gdt() {
|
||||||
|
GDT.0.load();
|
||||||
|
unsafe {
|
||||||
|
CS::set_reg(GDT.1.code_selector);
|
||||||
|
load_tss(GDT.1.tss_selector);
|
||||||
|
}
|
||||||
|
}
|
39
src/heap.rs
Normal file
39
src/heap.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use core::alloc::Layout;
|
||||||
|
|
||||||
|
use linked_list_allocator::LockedHeap;
|
||||||
|
use x86_64::{
|
||||||
|
structures::paging::{Page, PageTableFlags},
|
||||||
|
VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{mem::map_next, assert_canonical};
|
||||||
|
|
||||||
|
// address range is 0x4ea900000000 to 0x4ea9000fffff
|
||||||
|
static HEAP_START: u64 = 0x_4ea9_0000_0000; // '4ea9' is supposed to be 'heap', so its easy to spot
|
||||||
|
static HEAP_SIZE: u64 = 1024 * 1024; // 1 MebiByte or 0xfffff
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOC: LockedHeap = LockedHeap::empty();
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn alloc_error_handler(layout: Layout) -> ! {
|
||||||
|
panic!("Alloc error: {:#?}", layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
assert_canonical(HEAP_START);
|
||||||
|
|
||||||
|
let page_start = Page::containing_address(VirtAddr::new(HEAP_START));
|
||||||
|
let page_end = Page::containing_address(VirtAddr::new(HEAP_START + HEAP_SIZE - 1));
|
||||||
|
let page_range = Page::range_inclusive(page_start, page_end);
|
||||||
|
|
||||||
|
for page in page_range {
|
||||||
|
map_next(page, PageTableFlags::PRESENT | PageTableFlags::WRITABLE)
|
||||||
|
.unwrap()
|
||||||
|
.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ALLOC.lock().init(HEAP_START as usize, HEAP_SIZE as usize);
|
||||||
|
}
|
||||||
|
}
|
182
src/interrupts.rs
Normal file
182
src/interrupts.rs
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
use core::{intrinsics::transmute, arch::asm};
|
||||||
|
|
||||||
|
use crate::{lazy_static, print, println, proc::{self, Registers}};
|
||||||
|
use pc_keyboard::{layouts, DecodedKey, Keyboard, ScancodeSet1};
|
||||||
|
use pic8259::ChainedPics;
|
||||||
|
use spin::Mutex;
|
||||||
|
use x86_64::{
|
||||||
|
instructions::{interrupts, port::Port},
|
||||||
|
structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DOUBLE_FAULT_STACK_IDX: u16 = 0;
|
||||||
|
pub const TIMER_STACK_IDX: u16 = 1;
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Interrupt {
|
||||||
|
Timer = PIC_1_OFFSET,
|
||||||
|
Keyboard,
|
||||||
|
Syscall = 0x80
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
idt.double_fault
|
||||||
|
.set_handler_fn(double_fault)
|
||||||
|
.set_stack_index(DOUBLE_FAULT_STACK_IDX)
|
||||||
|
};
|
||||||
|
|
||||||
|
idt.breakpoint.set_handler_fn(breakpoint);
|
||||||
|
idt.page_fault.set_handler_fn(page_fault);
|
||||||
|
idt.invalid_opcode.set_handler_fn(invalid_opcode);
|
||||||
|
idt.segment_not_present.set_handler_fn(segment_not_present);
|
||||||
|
idt.stack_segment_fault.set_handler_fn(stack_segment_fault);
|
||||||
|
idt.general_protection_fault.set_handler_fn(general_protection_fault);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
idt[Interrupt::Timer as usize]
|
||||||
|
.set_handler_fn(transmute(timer_naked as *const ()))
|
||||||
|
.set_stack_index(TIMER_STACK_IDX)
|
||||||
|
.disable_interrupts(true) // this is the default but i want to make EXTRA SURE there will be no stupid edge case
|
||||||
|
};
|
||||||
|
idt[Interrupt::Keyboard as usize].set_handler_fn(keyboard);
|
||||||
|
idt[Interrupt::Syscall as usize].set_handler_fn(syscall);
|
||||||
|
|
||||||
|
idt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn breakpoint(stack: InterruptStackFrame) {
|
||||||
|
println!("breakpoint: {:#?}", stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn page_fault(stack: InterruptStackFrame, error: PageFaultErrorCode) {
|
||||||
|
panic!("page fault: {:?}\n{:#?}", error, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn invalid_opcode(stack: InterruptStackFrame) {
|
||||||
|
panic!("invalid opcode: {:#?}", stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn segment_not_present(stack: InterruptStackFrame, error: u64) {
|
||||||
|
panic!("segment not present: {} {:#?}", error, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn stack_segment_fault(stack: InterruptStackFrame, error: u64) {
|
||||||
|
panic!("stack segment fault: {} {:#?}", error, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn general_protection_fault(stack: InterruptStackFrame, error: u64) {
|
||||||
|
panic!("general protection fault: {} {:#?}", error, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn double_fault(stack: InterruptStackFrame, error: u64) -> ! {
|
||||||
|
panic!("aaaaaaaaaaaaa (error code: {}) {:#?}", error, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn syscall(_: InterruptStackFrame) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dont even breathe on this code
|
||||||
|
#[naked]
|
||||||
|
unsafe extern "x86-interrupt" fn timer_naked() {
|
||||||
|
asm! {
|
||||||
|
// push the `Registers` struct
|
||||||
|
"push r15",
|
||||||
|
"push r14",
|
||||||
|
"push r13",
|
||||||
|
"push r12",
|
||||||
|
"push r11",
|
||||||
|
"push r10",
|
||||||
|
"push r9",
|
||||||
|
"push r8",
|
||||||
|
"push rbp",
|
||||||
|
"push rdi",
|
||||||
|
"push rsi",
|
||||||
|
"push rdx",
|
||||||
|
"push rcx",
|
||||||
|
"push rbx",
|
||||||
|
"push rax",
|
||||||
|
// call the `extern "C"` version
|
||||||
|
"call {}",
|
||||||
|
// pop the `Registers` struct off the stack and back into the registers
|
||||||
|
"pop rax",
|
||||||
|
"pop rbx",
|
||||||
|
"pop rcx",
|
||||||
|
"pop rdx",
|
||||||
|
"pop rsi",
|
||||||
|
"pop rdi",
|
||||||
|
"pop rbp",
|
||||||
|
"pop r8",
|
||||||
|
"pop r9",
|
||||||
|
"pop r10",
|
||||||
|
"pop r11",
|
||||||
|
"pop r12",
|
||||||
|
"pop r13",
|
||||||
|
"pop r14",
|
||||||
|
"pop r15",
|
||||||
|
"iretq",
|
||||||
|
sym timer_c,
|
||||||
|
options(noreturn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FREQUENCY_DIVIDER: u8 = 15;
|
||||||
|
|
||||||
|
static mut TIMER_COUNT: u8 = 0;
|
||||||
|
|
||||||
|
extern "C" fn timer_c(mut registers: Registers, mut stack: InterruptStackFrame) {
|
||||||
|
unsafe {
|
||||||
|
TIMER_COUNT = (TIMER_COUNT + 1) % FREQUENCY_DIVIDER;
|
||||||
|
if TIMER_COUNT == 0 {
|
||||||
|
proc::timer(stack.as_mut().extract_inner(), &mut registers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
PICS.lock().notify_end_of_interrupt(Interrupt::Timer as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn keyboard(_: InterruptStackFrame) {
|
||||||
|
lazy_static! {
|
||||||
|
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> = {
|
||||||
|
Mutex::new(Keyboard::new(
|
||||||
|
layouts::Us104Key,
|
||||||
|
ScancodeSet1,
|
||||||
|
pc_keyboard::HandleControl::Ignore,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut port = Port::new(0x60);
|
||||||
|
let scancode: u8 = unsafe { port.read() };
|
||||||
|
let mut keyboard = KEYBOARD.lock();
|
||||||
|
if let Ok(Some(event)) = keyboard.add_byte(scancode) {
|
||||||
|
if let Some(key) = keyboard.process_keyevent(event) {
|
||||||
|
match key {
|
||||||
|
DecodedKey::RawKey(key_code) => print!("{:?}", key_code),
|
||||||
|
DecodedKey::Unicode(char) => print!("{}", char),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
PICS.lock().notify_end_of_interrupt(Interrupt::Keyboard as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_interrupts() {
|
||||||
|
IDT.load();
|
||||||
|
unsafe { PICS.lock().initialize() }
|
||||||
|
interrupts::enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const PIC_1_OFFSET: u8 = 32;
|
||||||
|
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
||||||
|
|
||||||
|
pub static PICS: Mutex<ChainedPics> = Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
|
297
src/keyboard.rs
Normal file
297
src/keyboard.rs
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
// #[derive(Debug)]
|
||||||
|
// pub struct KeyPress {
|
||||||
|
// released: bool,
|
||||||
|
// key: Key
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[derive(Debug)]
|
||||||
|
// pub enum Key {
|
||||||
|
// Char(char),
|
||||||
|
// Control(ControlKey),
|
||||||
|
// Escape,
|
||||||
|
// Unknown(u8)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[derive(Debug)]
|
||||||
|
// pub enum ControlKey {
|
||||||
|
// Escape,
|
||||||
|
// Backspace,
|
||||||
|
// Tab,
|
||||||
|
// Enter,
|
||||||
|
// LControl,
|
||||||
|
// LShift,
|
||||||
|
// RShift,
|
||||||
|
// LAlt,
|
||||||
|
// CapsLock,
|
||||||
|
// F(u8),
|
||||||
|
// NumberLock,
|
||||||
|
// ScrollLock,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn get_key_from_scancode(scancode: u8) -> KeyPress {
|
||||||
|
// if scancode == 0xe0 {
|
||||||
|
// return KeyPress {
|
||||||
|
// released: false,
|
||||||
|
// key: Key::Escape
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let released = (scancode >> 7) == 1;
|
||||||
|
// let scancode = scancode & 0b01111111;
|
||||||
|
|
||||||
|
// let key = match scancode {
|
||||||
|
// 0x01 => Key::Control(ControlKey::Escape),
|
||||||
|
// 0x02 => Key::Char('1'),
|
||||||
|
// 0x03 => Key::Char('2'),
|
||||||
|
// 0x04 => Key::Char('3'),
|
||||||
|
// 0x05 => Key::Char('4'),
|
||||||
|
// 0x06 => Key::Char('5'),
|
||||||
|
// 0x07 => Key::Char('6'),
|
||||||
|
// 0x08 => Key::Char('7'),
|
||||||
|
// 0x09 => Key::Char('8'),
|
||||||
|
// 0x0A => Key::Char('9'),
|
||||||
|
// 0x0B => Key::Char('0'),
|
||||||
|
// 0x0C => Key::Char('-'),
|
||||||
|
// 0x0D => Key::Char('='),
|
||||||
|
// 0x0E => Key::Control(ControlKey::Backspace),
|
||||||
|
// 0x0F => Key::Control(ControlKey::Tab),
|
||||||
|
// 0x10 => Key::Char('Q'),
|
||||||
|
// 0x11 => Key::Char('W'),
|
||||||
|
// 0x12 => Key::Char('E'),
|
||||||
|
// 0x13 => Key::Char('R'),
|
||||||
|
// 0x14 => Key::Char('T'),
|
||||||
|
// 0x15 => Key::Char('Y'),
|
||||||
|
// 0x16 => Key::Char('U'),
|
||||||
|
// 0x17 => Key::Char('I'),
|
||||||
|
// 0x18 => Key::Char('O'),
|
||||||
|
// 0x19 => Key::Char('P'),
|
||||||
|
// 0x1A => Key::Char('['),
|
||||||
|
// 0x1B => Key::Char(']'),
|
||||||
|
// 0x1C => Key::Control(ControlKey::Enter),
|
||||||
|
// 0x1D => Key::Control(ControlKey::LControl),
|
||||||
|
// 0x1E => Key::Char('A'),
|
||||||
|
// 0x1F => Key::Char('S'),
|
||||||
|
// 0x20 => Key::Char('D'),
|
||||||
|
// 0x21 => Key::Char('F'),
|
||||||
|
// 0x22 => Key::Char('G'),
|
||||||
|
// 0x23 => Key::Char('H'),
|
||||||
|
// 0x24 => Key::Char('J'),
|
||||||
|
// 0x25 => Key::Char('K'),
|
||||||
|
// 0x26 => Key::Char('L'),
|
||||||
|
// 0x27 => Key::Char(';'),
|
||||||
|
// 0x28 => Key::Char('\''),
|
||||||
|
// 0x29 => Key::Char('`'),
|
||||||
|
// 0x2A => Key::Control(ControlKey::LShift),
|
||||||
|
// 0x2B => Key::Char('\\'),
|
||||||
|
// 0x2C => Key::Char('Z'),
|
||||||
|
// 0x2D => Key::Char('X'),
|
||||||
|
// 0x2E => Key::Char('C'),
|
||||||
|
// 0x2F => Key::Char('V'),
|
||||||
|
// 0x30 => Key::Char('B'),
|
||||||
|
// 0x31 => Key::Char('N'),
|
||||||
|
// 0x32 => Key::Char('M'),
|
||||||
|
// 0x33 => Key::Char(','),
|
||||||
|
// 0x34 => Key::Char('.'),
|
||||||
|
// 0x35 => Key::Char('/'),
|
||||||
|
// 0x36 => Key::Control(ControlKey::RShift),
|
||||||
|
// 0x37 => Key::Char('*'),
|
||||||
|
// 0x38 => Key::Control(ControlKey::LAlt),
|
||||||
|
// 0x39 => Key::Char(' '),
|
||||||
|
// 0x3A => Key::Control(ControlKey::CapsLock),
|
||||||
|
// 0x3B => Key::Control(ControlKey::F(1)),
|
||||||
|
// 0x3C => Key::Control(ControlKey::F(2)),
|
||||||
|
// 0x3D => Key::Control(ControlKey::F(3)),
|
||||||
|
// 0x3E => Key::Control(ControlKey::F(4)),
|
||||||
|
// 0x3F => Key::Control(ControlKey::F(5)),
|
||||||
|
// 0x40 => Key::Control(ControlKey::F(6)),
|
||||||
|
// 0x41 => Key::Control(ControlKey::F(7)),
|
||||||
|
// 0x42 => Key::Control(ControlKey::F(8)),
|
||||||
|
// 0x43 => Key::Control(ControlKey::F(9)),
|
||||||
|
// 0x44 => Key::Control(ControlKey::F(10 )),
|
||||||
|
// 0x45 => Key::Control(ControlKey::NumberLock),
|
||||||
|
// 0x46 => Key::Control(ControlKey::ScrollLock),
|
||||||
|
// 0x47 => Key::Char('7'), // keypad
|
||||||
|
// 0x48 => Key::Char('8'), // keypad
|
||||||
|
// 0x49 => Key::Char('9'), // keypad
|
||||||
|
// 0x4A => Key::Char('-'), // keypad
|
||||||
|
// 0x4B => Key::Char('4'), // keypad
|
||||||
|
// 0x4C => Key::Char('5'), // keypad
|
||||||
|
// 0x4D => Key::Char('6'), // keypad
|
||||||
|
// 0x4E => Key::Char('+'), // keypad
|
||||||
|
// 0x4F => Key::Char('1'), // keypad
|
||||||
|
// 0x50 => Key::Char('2'), // keypad
|
||||||
|
// 0x51 => Key::Char('3'), // keypad
|
||||||
|
// 0x52 => Key::Char('0'), // keypad
|
||||||
|
// 0x53 => Key::Char('.'), // keypad
|
||||||
|
// // 3 missing here?
|
||||||
|
// 0x57 => Key::Control(ControlKey::F(11)),
|
||||||
|
// 0x58 => Key::Control(ControlKey::F(12)),
|
||||||
|
// _ => Key::Unknown(scancode)
|
||||||
|
// };
|
||||||
|
|
||||||
|
// KeyPress {
|
||||||
|
// released,
|
||||||
|
// key
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /*
|
||||||
|
// 0xE0, 0x10
|
||||||
|
// (multimedia) previous track pressed
|
||||||
|
// 0xE0, 0x19
|
||||||
|
// (multimedia) next track pressed
|
||||||
|
// 0xE0, 0x1C
|
||||||
|
// (keypad) enter pressed
|
||||||
|
// 0xE0, 0x1D
|
||||||
|
// right control pressed
|
||||||
|
// 0xE0, 0x20
|
||||||
|
// (multimedia) mute pressed
|
||||||
|
// 0xE0, 0x21
|
||||||
|
// (multimedia) calculator pressed
|
||||||
|
// 0xE0, 0x22
|
||||||
|
// (multimedia) play pressed
|
||||||
|
// 0xE0, 0x24
|
||||||
|
// (multimedia) stop pressed
|
||||||
|
// 0xE0, 0x2E
|
||||||
|
// (multimedia) volume down pressed
|
||||||
|
// 0xE0, 0x30
|
||||||
|
// (multimedia) volume up pressed
|
||||||
|
// 0xE0, 0x32
|
||||||
|
// (multimedia) WWW home pressed
|
||||||
|
// 0xE0, 0x35
|
||||||
|
// (keypad) / pressed
|
||||||
|
// 0xE0, 0x38
|
||||||
|
// right alt (or altGr) pressed
|
||||||
|
// 0xE0, 0x47
|
||||||
|
// home pressed
|
||||||
|
// 0xE0, 0x48
|
||||||
|
// cursor up pressed
|
||||||
|
// 0xE0, 0x49
|
||||||
|
// page up pressed
|
||||||
|
// 0xE0, 0x4B
|
||||||
|
// cursor left pressed
|
||||||
|
// 0xE0, 0x4D
|
||||||
|
// cursor right pressed
|
||||||
|
// 0xE0, 0x4F
|
||||||
|
// end pressed
|
||||||
|
// 0xE0, 0x50
|
||||||
|
// cursor down pressed
|
||||||
|
// 0xE0, 0x51
|
||||||
|
// page down pressed
|
||||||
|
// 0xE0, 0x52
|
||||||
|
// insert pressed
|
||||||
|
// 0xE0, 0x53
|
||||||
|
// delete pressed
|
||||||
|
// 0xE0, 0x5B
|
||||||
|
// left GUI pressed
|
||||||
|
// 0xE0, 0x5C
|
||||||
|
// right GUI pressed
|
||||||
|
// 0xE0, 0x5D
|
||||||
|
// "apps" pressed
|
||||||
|
// 0xE0, 0x5E
|
||||||
|
// (ACPI) power pressed
|
||||||
|
// 0xE0, 0x5F
|
||||||
|
// (ACPI) sleep pressed
|
||||||
|
// 0xE0, 0x63
|
||||||
|
// (ACPI) wake pressed
|
||||||
|
// 0xE0, 0x65
|
||||||
|
// (multimedia) WWW search pressed
|
||||||
|
// 0xE0, 0x66
|
||||||
|
// (multimedia) WWW favorites pressed
|
||||||
|
// 0xE0, 0x67
|
||||||
|
// (multimedia) WWW refresh pressed
|
||||||
|
// 0xE0, 0x68
|
||||||
|
// (multimedia) WWW stop pressed
|
||||||
|
// 0xE0, 0x69
|
||||||
|
// (multimedia) WWW forward pressed
|
||||||
|
// 0xE0, 0x6A
|
||||||
|
// (multimedia) WWW back pressed
|
||||||
|
// 0xE0, 0x6B
|
||||||
|
// (multimedia) my computer pressed
|
||||||
|
// 0xE0, 0x6C
|
||||||
|
// (multimedia) email pressed
|
||||||
|
// 0xE0, 0x6D
|
||||||
|
// (multimedia) media select pressed
|
||||||
|
// 0xE0, 0x90
|
||||||
|
// (multimedia) previous track released
|
||||||
|
// 0xE0, 0x99
|
||||||
|
// (multimedia) next track released
|
||||||
|
// 0xE0, 0x9C
|
||||||
|
// (keypad) enter released
|
||||||
|
// 0xE0, 0x9D
|
||||||
|
// right control released
|
||||||
|
// 0xE0, 0xA0
|
||||||
|
// (multimedia) mute released
|
||||||
|
// 0xE0, 0xA1
|
||||||
|
// (multimedia) calculator released
|
||||||
|
// 0xE0, 0xA2
|
||||||
|
// (multimedia) play released
|
||||||
|
// 0xE0, 0xA4
|
||||||
|
// (multimedia) stop released
|
||||||
|
// 0xE0, 0xAE
|
||||||
|
// (multimedia) volume down released
|
||||||
|
// 0xE0, 0xB0
|
||||||
|
// (multimedia) volume up released
|
||||||
|
// 0xE0, 0xB2
|
||||||
|
// (multimedia) WWW home released
|
||||||
|
// 0xE0, 0xB5
|
||||||
|
// (keypad) / released
|
||||||
|
// 0xE0, 0xB8
|
||||||
|
// right alt (or altGr) released
|
||||||
|
// 0xE0, 0xC7
|
||||||
|
// home released
|
||||||
|
// 0xE0, 0xC8
|
||||||
|
// cursor up released
|
||||||
|
// 0xE0, 0xC9
|
||||||
|
// page up released
|
||||||
|
// 0xE0, 0xCB
|
||||||
|
// cursor left released
|
||||||
|
// 0xE0, 0xCD
|
||||||
|
// cursor right released
|
||||||
|
// 0xE0, 0xCF
|
||||||
|
// end released
|
||||||
|
// 0xE0, 0xD0
|
||||||
|
// cursor down released
|
||||||
|
// 0xE0, 0xD1
|
||||||
|
// page down released
|
||||||
|
// 0xE0, 0xD2
|
||||||
|
// insert released
|
||||||
|
// 0xE0, 0xD3
|
||||||
|
// delete released
|
||||||
|
// 0xE0, 0xDB
|
||||||
|
// left GUI released
|
||||||
|
// 0xE0, 0xDC
|
||||||
|
// right GUI released
|
||||||
|
// 0xE0, 0xDD
|
||||||
|
// "apps" released
|
||||||
|
// 0xE0, 0xDE
|
||||||
|
// (ACPI) power released
|
||||||
|
// 0xE0, 0xDF
|
||||||
|
// (ACPI) sleep released
|
||||||
|
// 0xE0, 0xE3
|
||||||
|
// (ACPI) wake released
|
||||||
|
// 0xE0, 0xE5
|
||||||
|
// (multimedia) WWW search released
|
||||||
|
// 0xE0, 0xE6
|
||||||
|
// (multimedia) WWW favorites released
|
||||||
|
// 0xE0, 0xE7
|
||||||
|
// (multimedia) WWW refresh released
|
||||||
|
// 0xE0, 0xE8
|
||||||
|
// (multimedia) WWW stop released
|
||||||
|
// 0xE0, 0xE9
|
||||||
|
// (multimedia) WWW forward released
|
||||||
|
// 0xE0, 0xEA
|
||||||
|
// (multimedia) WWW back released
|
||||||
|
// 0xE0, 0xEB
|
||||||
|
// (multimedia) my computer released
|
||||||
|
// 0xE0, 0xEC
|
||||||
|
// (multimedia) email released
|
||||||
|
// 0xE0, 0xED
|
||||||
|
// (multimedia) media select released
|
||||||
|
// 0xE0, 0x2A, 0xE0, 0x37
|
||||||
|
// print screen pressed
|
||||||
|
// 0xE0, 0xB7, 0xE0, 0xAA
|
||||||
|
// print screen released
|
||||||
|
// 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5
|
||||||
|
// pause pressed
|
||||||
|
// */
|
||||||
|
// }
|
37
src/lib.rs
Normal file
37
src/lib.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(abi_x86_interrupt)] // for `mod interrupts`
|
||||||
|
#![feature(const_fn_trait_bound)] // for `mod sync`
|
||||||
|
#![feature(alloc_error_handler)] // for `mod heap`
|
||||||
|
#![feature(naked_functions)] // for `mod proc`
|
||||||
|
#![feature(asm_sym)] // for `mod interrupts`
|
||||||
|
#![feature(bench_black_box)] // for `mod proc`
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use bootloader::BootInfo;
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
|
||||||
|
mod gdt;
|
||||||
|
mod heap;
|
||||||
|
mod interrupts;
|
||||||
|
mod keyboard;
|
||||||
|
pub mod mem;
|
||||||
|
pub mod sync;
|
||||||
|
pub mod vga_text;
|
||||||
|
pub mod proc;
|
||||||
|
// pub use x;
|
||||||
|
|
||||||
|
pub fn init(info: &'static BootInfo) {
|
||||||
|
gdt::init_gdt();
|
||||||
|
interrupts::init_interrupts();
|
||||||
|
mem::init(info.physical_memory_offset, &info.memory_map);
|
||||||
|
heap::init();
|
||||||
|
proc::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_canonical(addr: u64) {
|
||||||
|
if VirtAddr::new_truncate(addr).as_u64() != addr {
|
||||||
|
panic!("Address 0x{:x} was not canonical!", addr);
|
||||||
|
}
|
||||||
|
}
|
94
src/main.rs
Normal file
94
src/main.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(bench_black_box)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use bootloader::{entry_point, BootInfo};
|
||||||
|
use core::{panic::PanicInfo, arch::asm, hint::black_box};
|
||||||
|
use os::{println, proc::{PROCESSES, ProcessControlBlock, Registers}};
|
||||||
|
use x86_64::{instructions::{hlt, interrupts::{without_interrupts, self}}, structures::idt::InterruptStackFrameValue, registers::{segmentation::{CS, Segment, SS}, self}, VirtAddr};
|
||||||
|
|
||||||
|
entry_point!(main);
|
||||||
|
fn main(bootinfo: &'static BootInfo) -> ! {
|
||||||
|
without_interrupts(|| os::init(bootinfo));
|
||||||
|
|
||||||
|
println!("creating procs...");
|
||||||
|
|
||||||
|
// or else interrupts are disabled in the new processes
|
||||||
|
let rflags = registers::rflags::read_raw();
|
||||||
|
|
||||||
|
// without_interrupts for the PROCESSES lock
|
||||||
|
without_interrupts(|| {
|
||||||
|
let mut procs = PROCESSES.lock();
|
||||||
|
|
||||||
|
static mut PROC_1_STACK: [u8; 1024] = [0; 1024];
|
||||||
|
|
||||||
|
let stack_frame = InterruptStackFrameValue {
|
||||||
|
instruction_pointer: VirtAddr::new(proc1 as u64),
|
||||||
|
code_segment: CS::get_reg().0 as u64,
|
||||||
|
cpu_flags: rflags,
|
||||||
|
stack_pointer: VirtAddr::new(unsafe { &PROC_1_STACK } as *const _ as u64) + 1024usize,
|
||||||
|
stack_segment: SS::get_reg().0 as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
let registers = Registers::default();
|
||||||
|
|
||||||
|
procs[1].write(ProcessControlBlock { stack_frame, registers });
|
||||||
|
|
||||||
|
static mut PROC_2_STACK: [u8; 1024] = [0; 1024];
|
||||||
|
|
||||||
|
let stack_frame = InterruptStackFrameValue {
|
||||||
|
instruction_pointer: VirtAddr::new(proc2 as u64),
|
||||||
|
code_segment: CS::get_reg().0 as u64,
|
||||||
|
cpu_flags: rflags,
|
||||||
|
stack_pointer: VirtAddr::new(unsafe { &PROC_2_STACK } as *const _ as u64) + 1024usize,
|
||||||
|
stack_segment: SS::get_reg().0 as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
let registers = Registers::default();
|
||||||
|
|
||||||
|
procs[2].write(ProcessControlBlock { stack_frame, registers });
|
||||||
|
|
||||||
|
procs[0].next = 1;
|
||||||
|
procs[0].prev = 2;
|
||||||
|
|
||||||
|
procs[1].next = 2;
|
||||||
|
procs[1].prev = 2;
|
||||||
|
|
||||||
|
procs[2].next = 1;
|
||||||
|
procs[2].prev = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
println!("Hi from main proc!");
|
||||||
|
for i in 0..500000 { black_box(i); }
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
hlt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(named_asm_labels)]
|
||||||
|
extern "C" fn proc1() -> ! {
|
||||||
|
loop {
|
||||||
|
println!("Hi from proc 1!");
|
||||||
|
for i in 0..500000 { black_box(i); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn proc2() -> ! {
|
||||||
|
loop {
|
||||||
|
println!("Hi from proc 2, foo bar baz!");
|
||||||
|
for i in 0..500000 { black_box(i); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
println!("{}", info);
|
||||||
|
loop {
|
||||||
|
hlt();
|
||||||
|
}
|
||||||
|
}
|
85
src/mem.rs
Normal file
85
src/mem.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
|
||||||
|
use spin::Mutex;
|
||||||
|
use x86_64::{
|
||||||
|
registers::control::Cr3,
|
||||||
|
structures::paging::{
|
||||||
|
mapper::{MapToError, MapperFlush},
|
||||||
|
*,
|
||||||
|
},
|
||||||
|
PhysAddr, VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
static MAPPER: Mutex<Option<OffsetPageTable>> = Mutex::new(None);
|
||||||
|
static ALLOCATOR: Mutex<Option<Allocator>> = Mutex::new(None);
|
||||||
|
|
||||||
|
pub(crate) fn init(phys_offset: u64, memory_map: &'static MemoryMap) {
|
||||||
|
let table4 = unsafe { &mut *(Cr3::read().0.start_address().as_u64() as *mut PageTable) };
|
||||||
|
MAPPER
|
||||||
|
.lock()
|
||||||
|
.replace(unsafe { OffsetPageTable::new(table4, VirtAddr::new(phys_offset)) });
|
||||||
|
ALLOCATOR
|
||||||
|
.lock()
|
||||||
|
.replace(unsafe { Allocator::new(memory_map) });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate_addr(addr: VirtAddr) -> Option<PhysAddr> {
|
||||||
|
MAPPER.lock().as_ref().unwrap().translate_addr(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(
|
||||||
|
page: Page,
|
||||||
|
frame: PhysFrame,
|
||||||
|
flags: PageTableFlags,
|
||||||
|
) -> Result<MapperFlush<Size4KiB>, MapToError<Size4KiB>> {
|
||||||
|
unsafe {
|
||||||
|
MAPPER.lock().as_mut().unwrap().map_to(
|
||||||
|
page,
|
||||||
|
frame,
|
||||||
|
flags,
|
||||||
|
ALLOCATOR.lock().as_mut().unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_next(
|
||||||
|
page: Page,
|
||||||
|
flags: PageTableFlags,
|
||||||
|
) -> Result<MapperFlush<Size4KiB>, MapToError<Size4KiB>> {
|
||||||
|
let next_page = ALLOCATOR
|
||||||
|
.lock()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.allocate_frame()
|
||||||
|
.ok_or(MapToError::FrameAllocationFailed)?;
|
||||||
|
map(page, next_page, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Allocator {
|
||||||
|
memory_map: &'static MemoryMap,
|
||||||
|
next: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Allocator {
|
||||||
|
unsafe fn new(memory_map: &'static MemoryMap) -> Self {
|
||||||
|
Self {
|
||||||
|
memory_map,
|
||||||
|
next: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl FrameAllocator<Size4KiB> for Allocator {
|
||||||
|
fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
|
||||||
|
let next = self
|
||||||
|
.memory_map
|
||||||
|
.iter()
|
||||||
|
.filter(|v| v.region_type == MemoryRegionType::Usable)
|
||||||
|
.map(|v| v.range.start_addr()..v.range.end_addr())
|
||||||
|
.flat_map(|v| v.step_by(4096))
|
||||||
|
.nth(self.next);
|
||||||
|
|
||||||
|
self.next += 1;
|
||||||
|
|
||||||
|
Some(PhysFrame::from_start_address(PhysAddr::new(next?)).unwrap())
|
||||||
|
}
|
||||||
|
}
|
164
src/proc.rs
Normal file
164
src/proc.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
use core::{fmt::Debug, mem, hint::black_box};
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use spin::Mutex;
|
||||||
|
use x86_64::{VirtAddr, structures::{paging::{Page, PageTableFlags}, idt::InterruptStackFrameValue}};
|
||||||
|
|
||||||
|
use crate::{sync::SyncLazy, mem::map_next, lazy_static, assert_canonical, println};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct ProcessControlBlock {
|
||||||
|
pub stack_frame: InterruptStackFrameValue,
|
||||||
|
pub registers: Registers
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Registers {
|
||||||
|
pub rax: usize,
|
||||||
|
pub rbx: usize,
|
||||||
|
pub rcx: usize,
|
||||||
|
pub rdx: usize,
|
||||||
|
pub rsi: usize,
|
||||||
|
pub rdi: usize,
|
||||||
|
pub rbp: usize,
|
||||||
|
pub r8: usize,
|
||||||
|
pub r9: usize,
|
||||||
|
pub r10: usize,
|
||||||
|
pub r11: usize,
|
||||||
|
pub r12: usize,
|
||||||
|
pub r13: usize,
|
||||||
|
pub r14: usize,
|
||||||
|
pub r15: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Registers {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("Registers")
|
||||||
|
.field("rax", &format_args!("{:#018x}", self.rax))
|
||||||
|
.field("rbx", &format_args!("{:#018x}", self.rbx))
|
||||||
|
.field("rcx", &format_args!("{:#018x}", self.rcx))
|
||||||
|
.field("rdx", &format_args!("{:#018x}", self.rdx))
|
||||||
|
.field("rsi", &format_args!("{:#018x}", self.rsi))
|
||||||
|
.field("rdi", &format_args!("{:#018x}", self.rdi))
|
||||||
|
.field("rbp", &format_args!("{:#018x}", self.rbp))
|
||||||
|
.field("r8", &format_args!("{:#018x}", self.r8))
|
||||||
|
.field("r9", &format_args!("{:#018x}", self.r9))
|
||||||
|
.field("r10", &format_args!("{:#018x}", self.r10))
|
||||||
|
.field("r11", &format_args!("{:#018x}", self.r11))
|
||||||
|
.field("r12", &format_args!("{:#018x}", self.r12))
|
||||||
|
.field("r13", &format_args!("{:#018x}", self.r13))
|
||||||
|
.field("r14", &format_args!("{:#018x}", self.r14))
|
||||||
|
.field("r15", &format_args!("{:#018x}", self.r15))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_PROCESSES: usize = 0x7fff;
|
||||||
|
const PROCESS_LIST_ADDR: usize = 0x7fff_0000_0000;
|
||||||
|
|
||||||
|
pub struct ProcListElement {
|
||||||
|
pub pcb: Option<&'static mut ProcessControlBlock>, // npo for the win!
|
||||||
|
pub prev: u16, // only needed to patch an element out of the list
|
||||||
|
pub next: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcListElement {
|
||||||
|
pub fn write(&mut self, pcb: ProcessControlBlock) {
|
||||||
|
println!("write");
|
||||||
|
match self.pcb.as_deref_mut() {
|
||||||
|
None => {
|
||||||
|
let addr = Box::leak(Box::new(pcb));
|
||||||
|
// with this println, it tries to execute 0x0. without it, it (sometimes) tries to execute PROCESS_LIST_ADDR.
|
||||||
|
// whatever the case, it happens after 1 println in `fn timer`, before this code is even hit.
|
||||||
|
// if the line up above ^^^ is inlined, it faults after 2 printlns instead. what in the actual fuck
|
||||||
|
// println!("addr: {:x}", addr as *mut _ as usize);
|
||||||
|
self.pcb.replace(addr);
|
||||||
|
}
|
||||||
|
Some(v) => { *v = pcb; }
|
||||||
|
}
|
||||||
|
// println!("end write");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref PROCESSES: Mutex<&'static mut [ProcListElement; MAX_PROCESSES]> = {
|
||||||
|
let ptr = PROCESS_LIST_ADDR as *mut [_; MAX_PROCESSES];
|
||||||
|
// const gaming
|
||||||
|
const DEFAULT: ProcListElement = ProcListElement { pcb: None, next: 0, prev: 0 };
|
||||||
|
unsafe { ptr.write([DEFAULT; MAX_PROCESSES]) }
|
||||||
|
Mutex::new(unsafe { &mut *ptr })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURRENT_PROCESS: Mutex<u64> = Mutex::new(0);
|
||||||
|
|
||||||
|
// here i make the assumption that the privilege level is *somewhere* in `InterruptStackFrame`
|
||||||
|
pub fn timer(stack_frame: &mut InterruptStackFrameValue, registers: &mut Registers) {
|
||||||
|
println!("Hello there from timer interrupt");
|
||||||
|
|
||||||
|
let mut curr_pid = CURRENT_PROCESS.lock();
|
||||||
|
let mut procs = PROCESSES.lock();
|
||||||
|
|
||||||
|
println!("Hello there from timer interrupt 2");
|
||||||
|
|
||||||
|
// first, save the stack and registers values in the pcb for this pid
|
||||||
|
procs[*curr_pid as usize].write(ProcessControlBlock {
|
||||||
|
stack_frame: *stack_frame,
|
||||||
|
registers: *registers,
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("Hello there from timer interrupt 3");
|
||||||
|
|
||||||
|
// then, choose the next pid
|
||||||
|
let next_pid = procs[*curr_pid as usize].next as u64;
|
||||||
|
*curr_pid = next_pid;
|
||||||
|
let next = procs[next_pid as usize].pcb.as_deref().unwrap();
|
||||||
|
|
||||||
|
println!("Hello there from timer interrupt 4");
|
||||||
|
|
||||||
|
// last, load the stack and registers values from the new pid
|
||||||
|
*stack_frame = next.stack_frame;
|
||||||
|
*registers = next.registers;
|
||||||
|
|
||||||
|
// println!("Next pid: {}", *curr_pid);
|
||||||
|
// println!("Next stack_frame: {:?}", stack_frame);
|
||||||
|
// println!("Next registers: {:?}", registers);
|
||||||
|
|
||||||
|
for i in 0..5000000 { black_box(i); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
assert_canonical(PROCESS_LIST_ADDR as u64);
|
||||||
|
|
||||||
|
let page_start = Page::containing_address(VirtAddr::new(PROCESS_LIST_ADDR as u64));
|
||||||
|
let page_end = Page::containing_address(VirtAddr::new((PROCESS_LIST_ADDR + MAX_PROCESSES * mem::size_of::<ProcListElement>()) as u64 - 1));
|
||||||
|
let page_range = Page::range_inclusive(page_start, page_end);
|
||||||
|
|
||||||
|
for page in page_range {
|
||||||
|
map_next(page, PageTableFlags::PRESENT | PageTableFlags::WRITABLE)
|
||||||
|
.unwrap()
|
||||||
|
.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = SyncLazy::get(&PROCESSES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// macro_rules! new_stack_frame {
|
||||||
|
// () => {unsafe {
|
||||||
|
// let ip: usize;
|
||||||
|
// let cs: usize;
|
||||||
|
// let flags: usize;
|
||||||
|
// let sp: usize;
|
||||||
|
// let ss: usize;
|
||||||
|
// ::core::arch::asm! {
|
||||||
|
// "mov rax, rip",
|
||||||
|
// out("rax") ip
|
||||||
|
// }
|
||||||
|
// }};
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn foo() {
|
||||||
|
// new_stack_frame!()
|
||||||
|
// }
|
101
src/sync.rs
Normal file
101
src/sync.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
use core::{
|
||||||
|
cell::UnsafeCell,
|
||||||
|
ops::Deref,
|
||||||
|
sync::atomic::{AtomicBool, Ordering}, mem::MaybeUninit,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A wrapper around a type that is safe to read but unsafe to write.
|
||||||
|
///
|
||||||
|
/// Always implements [`Send`] and [`Sync`], because data races cannot happen without writes.
|
||||||
|
///
|
||||||
|
/// This type [`Deref`]s to its contents, so you write using [`UnsafeWriteCell::write()`] instead of `cell.write()`.
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct UnsafeWriteCell<T> {
|
||||||
|
val: UnsafeCell<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UnsafeWriteCell<T> {
|
||||||
|
/// Creates a new `UnsafeWrite` containing the passed value.
|
||||||
|
pub const fn new(val: T) -> Self {
|
||||||
|
Self {
|
||||||
|
val: UnsafeCell::new(val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overwrites the value in the `UnsafeWrite` with the provided value.
|
||||||
|
///
|
||||||
|
/// Takes an `&Self` so that one can write to statics.
|
||||||
|
pub unsafe fn write(this: &Self, val: T) {
|
||||||
|
*this.val.get() = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for UnsafeWriteCell<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { &*self.val.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// safe because data races cannot happen without a write
|
||||||
|
unsafe impl<T> Send for UnsafeWriteCell<T> {}
|
||||||
|
unsafe impl<T> Sync for UnsafeWriteCell<T> {}
|
||||||
|
|
||||||
|
/// A struct which is only initialized once and can be shared between threads.
|
||||||
|
pub struct SyncLazy<T, F: Fn() -> T = fn() -> T> {
|
||||||
|
val: UnsafeCell<MaybeUninit<T>>,
|
||||||
|
used: AtomicBool,
|
||||||
|
closure: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: Fn() -> T> SyncLazy<T, F> {
|
||||||
|
/// Creates a new `SyncLazy` containing the specified value.
|
||||||
|
pub const fn new(closure: F) -> Self {
|
||||||
|
Self {
|
||||||
|
val: UnsafeCell::new(MaybeUninit::uninit()),
|
||||||
|
used: AtomicBool::new(false),
|
||||||
|
closure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a reference to the value in the `SyncLazy`.
|
||||||
|
///
|
||||||
|
/// Cannot be called as `lazy.get()` to prevent interference with a method on `T` through [`Deref`].
|
||||||
|
pub fn get(this: &Self) -> &T {
|
||||||
|
let val = unsafe { &mut *this.val.get() };
|
||||||
|
|
||||||
|
if this
|
||||||
|
.used
|
||||||
|
.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
val.write((this.closure)());
|
||||||
|
// i think this is the right way to ensure that the write above never causes a data race?
|
||||||
|
this.used.store(true, Ordering::Release);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { val.assume_init_ref() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: Fn() -> T> Deref for SyncLazy<T, F> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
Self::get(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// safe cause we use AtomicBool to make sure that we only write once
|
||||||
|
unsafe impl<T: Send, F: Send + Fn() -> T> Send for SyncLazy<T, F> {}
|
||||||
|
unsafe impl<T: Sync, F: Sync + Fn() -> T> Sync for SyncLazy<T, F> {}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! lazy_static {
|
||||||
|
($($vis:vis static ref $ident:ident : $ty:ty = $expr:expr;)+) => {
|
||||||
|
$(
|
||||||
|
$vis static $ident: $crate::sync::SyncLazy<$ty> = $crate::sync::SyncLazy::new(|| $expr);
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
97
src/vga_text.rs
Normal file
97
src/vga_text.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use crate::lazy_static;
|
||||||
|
use core::fmt::{Arguments, Write};
|
||||||
|
use spin::Mutex;
|
||||||
|
use x86_64::instructions::interrupts::without_interrupts;
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum Color {
|
||||||
|
Black = 0x0,
|
||||||
|
Blue = 0x1,
|
||||||
|
Green = 0x2,
|
||||||
|
Cyan = 0x3,
|
||||||
|
Red = 0x4,
|
||||||
|
Magenta = 0x5,
|
||||||
|
Brown = 0x6,
|
||||||
|
Gray = 0x7,
|
||||||
|
}
|
||||||
|
|
||||||
|
const VGA_COLUMNS: usize = 80;
|
||||||
|
const VGA_ROWS: usize = 25;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct Buffer([[(u8, u8); VGA_COLUMNS]; VGA_ROWS]);
|
||||||
|
|
||||||
|
pub struct VgaWriter {
|
||||||
|
buf: &'static mut Buffer,
|
||||||
|
row: usize,
|
||||||
|
col: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VgaWriter {
|
||||||
|
fn write_byte(&mut self, c: u8) {
|
||||||
|
self.buf.0[self.row][self.col] = (c, 0xb);
|
||||||
|
self.col += 1;
|
||||||
|
if self.col == VGA_COLUMNS {
|
||||||
|
self.new_line()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_line(&mut self) {
|
||||||
|
if self.row == VGA_ROWS - 1 {
|
||||||
|
for i in 0..(VGA_ROWS - 1) {
|
||||||
|
self.buf.0[i] = self.buf.0[i + 1];
|
||||||
|
}
|
||||||
|
self.buf.0[VGA_ROWS - 1] = [(0, 0); VGA_COLUMNS];
|
||||||
|
} else {
|
||||||
|
self.row += 1;
|
||||||
|
}
|
||||||
|
self.col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for VgaWriter {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
for byte in s.bytes() {
|
||||||
|
if byte == b'\n' {
|
||||||
|
self.new_line();
|
||||||
|
} else {
|
||||||
|
self.write_byte(byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref VGA_TEXT: Mutex<VgaWriter> = {
|
||||||
|
Mutex::new(VgaWriter {
|
||||||
|
buf: unsafe { &mut *(0xb8000 as *mut Buffer) },
|
||||||
|
row: 0,
|
||||||
|
col: 0,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _print(args: Arguments) {
|
||||||
|
without_interrupts(|| {
|
||||||
|
write!(VGA_TEXT.lock(), "{}", args).unwrap();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($t:tt)+) => {
|
||||||
|
$crate::vga_text::_print(::core::format_args!($($t)+))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
() => {
|
||||||
|
$crate::print!("\n")
|
||||||
|
};
|
||||||
|
($($t:tt)+) => {
|
||||||
|
$crate::print!("{}\n", ::core::format_args!($($t)+))
|
||||||
|
};
|
||||||
|
}
|
15
target.json
Normal file
15
target.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"llvm-target": "x86_64-unknown-none",
|
||||||
|
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||||
|
"arch": "x86_64",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"target-c-int-width": "32",
|
||||||
|
"os": "none",
|
||||||
|
"executables": true,
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"disable-redzone": true,
|
||||||
|
"features": "-mmx,-sse,+soft-float"
|
||||||
|
}
|
Loading…
Reference in a new issue