mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
10 Commits
post-12-te
...
post-12-wi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d21a78dc0b | ||
|
|
0186f65ece | ||
|
|
2772abc8eb | ||
|
|
51f90236a5 | ||
|
|
90abd5c8c5 | ||
|
|
a6273614e4 | ||
|
|
3a2a468a0b | ||
|
|
05f6abd261 | ||
|
|
255982a8b7 | ||
|
|
f885f17b70 |
146
Cargo.lock
generated
146
Cargo.lock
generated
@@ -1,5 +1,11 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.9.0"
|
||||
@@ -17,6 +23,10 @@ name = "blog_os"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bootloader",
|
||||
"conquer-once",
|
||||
"cooked-waker",
|
||||
"crossbeam-queue",
|
||||
"futures-util",
|
||||
"lazy_static",
|
||||
"linked_list_allocator",
|
||||
"pc-keyboard",
|
||||
@@ -29,9 +39,51 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.8.8"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3ed4f735c4e455ba86a3d2939b1c0729414153642106c9d035693355630a42c"
|
||||
checksum = "152a28c753e229e037e910b4cd4cd16a90c53dd9a67fd751fa304b4b4a03970c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "conquer-once"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f7644600a548ecad74e4a918392af1798f7dd045be610be3203b9e129b4f98f"
|
||||
dependencies = [
|
||||
"conquer-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conquer-util"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "654fb2472cc369d311c547103a1fa81d467bef370ae7a0680f65939895b1182a"
|
||||
|
||||
[[package]]
|
||||
name = "cooked-waker"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0032e8be0680b63daf14b0fd7fd57f85fd6897951e110b041d32e839a831914"
|
||||
dependencies = [
|
||||
"cooked-waker-derive",
|
||||
"stowaway",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cooked-waker-derive"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74ded02b04a8ff53ea7328cd71297cde598bee70d165ad92512bdb7e20be9d74"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpuio"
|
||||
@@ -39,6 +91,49 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -81,6 +176,30 @@ dependencies = [
|
||||
"cpuio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
@@ -102,6 +221,23 @@ dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stowaway"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32b13d61e782863c0eaeeaf7e8e580dc956a625851fd2fb73e5e92db9601c891"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uart_16550"
|
||||
version = "0.2.4"
|
||||
@@ -112,6 +248,12 @@ dependencies = [
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.2.6"
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -13,7 +13,7 @@ name = "stack_overflow"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
bootloader = { version = "0.8.0", features = ["map_physical_memory"]}
|
||||
bootloader = { version = "0.8.8", features = ["map_physical_memory"]}
|
||||
volatile = "0.2.6"
|
||||
spin = "0.5.2"
|
||||
x86_64 = "0.9.6"
|
||||
@@ -21,11 +21,25 @@ uart_16550 = "0.2.0"
|
||||
pic8259_simple = "0.1.1"
|
||||
pc-keyboard = "0.5.0"
|
||||
linked_list_allocator = "0.8.0"
|
||||
cooked-waker = "1.0.2"
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1.0"
|
||||
features = ["spin_no_std"]
|
||||
|
||||
[dependencies.crossbeam-queue]
|
||||
version = "0.2.1"
|
||||
default-features = false
|
||||
features = ["alloc"]
|
||||
|
||||
[dependencies.conquer-once]
|
||||
version = "0.2.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.futures-util]
|
||||
version = "0.3.4"
|
||||
default-features = false
|
||||
features = ["alloc"]
|
||||
|
||||
[package.metadata.bootimage]
|
||||
test-args = [
|
||||
|
||||
@@ -80,28 +80,11 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut InterruptSt
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
|
||||
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
lazy_static! {
|
||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> = Mutex::new(
|
||||
Keyboard::new(layouts::Us104Key, ScancodeSet1, 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) {
|
||||
match key {
|
||||
DecodedKey::Unicode(character) => print!("{}", character),
|
||||
DecodedKey::RawKey(key) => print!("{:?}", key),
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::task::keyboard::add_scancode(scancode);
|
||||
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
|
||||
@@ -18,6 +18,7 @@ pub mod gdt;
|
||||
pub mod interrupts;
|
||||
pub mod memory;
|
||||
pub mod serial;
|
||||
pub mod task;
|
||||
pub mod vga_buffer;
|
||||
|
||||
pub fn init() {
|
||||
|
||||
38
src/main.rs
38
src/main.rs
@@ -6,7 +6,6 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{boxed::Box, rc::Rc, vec, vec::Vec};
|
||||
use blog_os::println;
|
||||
use bootloader::{entry_point, BootInfo};
|
||||
use core::panic::PanicInfo;
|
||||
@@ -16,6 +15,7 @@ entry_point!(kernel_main);
|
||||
fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||
use blog_os::allocator;
|
||||
use blog_os::memory::{self, BootInfoFrameAllocator};
|
||||
use blog_os::task::{keyboard, simple_executor::SimpleExecutor, Task};
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
println!("Hello World{}", "!");
|
||||
@@ -27,29 +27,10 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||
|
||||
allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
|
||||
|
||||
// allocate a number on the heap
|
||||
let heap_value = Box::new(41);
|
||||
println!("heap_value at {:p}", heap_value);
|
||||
|
||||
// create a dynamically sized vector
|
||||
let mut vec = Vec::new();
|
||||
for i in 0..500 {
|
||||
vec.push(i);
|
||||
}
|
||||
println!("vec at {:p}", vec.as_slice());
|
||||
|
||||
// create a reference counted vector -> will be freed when count reaches 0
|
||||
let reference_counted = Rc::new(vec![1, 2, 3]);
|
||||
let cloned_reference = reference_counted.clone();
|
||||
println!(
|
||||
"current reference count is {}",
|
||||
Rc::strong_count(&cloned_reference)
|
||||
);
|
||||
core::mem::drop(reference_counted);
|
||||
println!(
|
||||
"reference count is {} now",
|
||||
Rc::strong_count(&cloned_reference)
|
||||
);
|
||||
let mut executor = SimpleExecutor::new();
|
||||
executor.spawn(Task::new(example_task()));
|
||||
executor.spawn(Task::new(keyboard::print_keypresses()));
|
||||
executor.run();
|
||||
|
||||
#[cfg(test)]
|
||||
test_main();
|
||||
@@ -58,6 +39,15 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||
blog_os::hlt_loop();
|
||||
}
|
||||
|
||||
async fn async_number() -> u32 {
|
||||
42
|
||||
}
|
||||
|
||||
async fn example_task() {
|
||||
let number = async_number().await;
|
||||
println!("async number: {}", number);
|
||||
}
|
||||
|
||||
/// This function is called on panic.
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
|
||||
79
src/task/keyboard.rs
Normal file
79
src/task/keyboard.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use crate::print;
|
||||
use crate::println;
|
||||
use conquer_once::spin::OnceCell;
|
||||
use core::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use futures_util::stream::StreamExt;
|
||||
use futures_util::{stream::Stream, task::AtomicWaker};
|
||||
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||
|
||||
static SCANCODE_QUEUE: OnceCell<ArrayQueue<u8>> = OnceCell::uninit();
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
/// Called by the keyboard interrupt handler
|
||||
///
|
||||
/// Must not block or allocate.
|
||||
pub(crate) fn add_scancode(scancode: u8) {
|
||||
if let Ok(queue) = SCANCODE_QUEUE.try_get() {
|
||||
if let Err(_) = queue.push(scancode) {
|
||||
println!("WARNING: scancode queue full; dropping keyboard input");
|
||||
} else {
|
||||
WAKER.wake();
|
||||
}
|
||||
} else {
|
||||
println!("WARNING: scancode queue uninitialized");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ScancodeStream {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl ScancodeStream {
|
||||
pub fn new() -> Self {
|
||||
SCANCODE_QUEUE
|
||||
.try_init_once(|| ArrayQueue::new(100))
|
||||
.expect("ScancodeStream::new should only be called once");
|
||||
ScancodeStream { _private: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for ScancodeStream {
|
||||
type Item = u8;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<u8>> {
|
||||
let queue = SCANCODE_QUEUE
|
||||
.try_get()
|
||||
.expect("scancode queue not initialized");
|
||||
|
||||
// fast path
|
||||
if let Ok(scancode) = queue.pop() {
|
||||
return Poll::Ready(Some(scancode));
|
||||
}
|
||||
|
||||
WAKER.register(&cx.waker());
|
||||
match queue.pop() {
|
||||
Ok(scancode) => Poll::Ready(Some(scancode)),
|
||||
Err(crossbeam_queue::PopError) => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn print_keypresses() {
|
||||
let mut scancodes = ScancodeStream::new();
|
||||
let mut keyboard = Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore);
|
||||
|
||||
while let Some(scancode) = scancodes.next().await {
|
||||
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
|
||||
if let Some(key) = keyboard.process_keyevent(key_event) {
|
||||
match key {
|
||||
DecodedKey::Unicode(character) => print!("{}", character),
|
||||
DecodedKey::RawKey(key) => print!("{:?}", key),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/task/mod.rs
Normal file
26
src/task/mod.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use alloc::boxed::Box;
|
||||
use core::task::{Context, Poll};
|
||||
use core::{future::Future, pin::Pin};
|
||||
|
||||
pub mod keyboard;
|
||||
pub mod simple_executor;
|
||||
|
||||
pub struct Task {
|
||||
future: Pin<Box<dyn Future<Output = ()>>>,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub fn new(future: impl Future<Output = ()> + 'static) -> Task {
|
||||
Task {
|
||||
future: Box::pin(future),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&mut self, context: &mut Context) -> Poll<()> {
|
||||
self.future.as_mut().poll(context)
|
||||
}
|
||||
|
||||
fn id(&self) -> usize {
|
||||
&*self.future as *const _ as *const () as usize
|
||||
}
|
||||
}
|
||||
86
src/task/simple_executor.rs
Normal file
86
src/task/simple_executor.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use super::Task;
|
||||
use alloc::{
|
||||
collections::{BTreeMap, VecDeque},
|
||||
sync::Arc,
|
||||
};
|
||||
use cooked_waker::IntoWaker;
|
||||
use core::task::{Context, Poll};
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
|
||||
pub struct SimpleExecutor {
|
||||
task_queue: VecDeque<Task>,
|
||||
waiting_tasks: BTreeMap<usize, Task>,
|
||||
wake_queue: Arc<ArrayQueue<usize>>,
|
||||
}
|
||||
|
||||
impl SimpleExecutor {
|
||||
pub fn new() -> SimpleExecutor {
|
||||
SimpleExecutor {
|
||||
task_queue: VecDeque::new(),
|
||||
waiting_tasks: BTreeMap::new(),
|
||||
wake_queue: Arc::new(ArrayQueue::new(100)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn(&mut self, task: Task) {
|
||||
self.task_queue.push_back(task)
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
loop {
|
||||
self.handle_wakeups();
|
||||
self.run_ready_tasks();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_wakeups(&mut self) {
|
||||
while let Ok(task_id) = self.wake_queue.pop() {
|
||||
if let Some(task) = self.waiting_tasks.remove(&task_id) {
|
||||
self.task_queue.push_back(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_ready_tasks(&mut self) {
|
||||
while let Some(mut task) = self.task_queue.pop_front() {
|
||||
let waker = TaskWaker {
|
||||
task_id: task.id(),
|
||||
wake_queue: self.wake_queue.clone(),
|
||||
}
|
||||
.into_waker();
|
||||
let mut context = Context::from_waker(&waker);
|
||||
match task.poll(&mut context) {
|
||||
Poll::Ready(()) => {} // task done
|
||||
Poll::Pending => {
|
||||
if self.waiting_tasks.insert(task.id(), task).is_some() {
|
||||
panic!("Same task inserted into waiting_tasks twice");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, IntoWaker)]
|
||||
struct TaskWaker {
|
||||
task_id: usize,
|
||||
wake_queue: Arc<ArrayQueue<usize>>,
|
||||
}
|
||||
|
||||
impl TaskWaker {
|
||||
fn wake_task(&self) {
|
||||
self.wake_queue.push(self.task_id).expect("wake queue full");
|
||||
}
|
||||
}
|
||||
|
||||
impl cooked_waker::WakeRef for TaskWaker {
|
||||
fn wake_by_ref(&self) {
|
||||
self.wake_task();
|
||||
}
|
||||
}
|
||||
|
||||
impl cooked_waker::Wake for TaskWaker {
|
||||
fn wake(self) {
|
||||
self.wake_task();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user