- added a new libary libm containing procedural macros for the kernel.

these should be used to include external files and resources in the kernel binary
  at compile time.
  - libm currently supports loading psf-1 formatted fonts
- added two fonts that are included in the binary at compile time
- refactored libk to make the crate structure more organised and maintainable in future.
  new structure:
    - drivers   (hardware interaction)
    - resources (consts and statics included either manually or via macros)
    - std       (standard functions for higher level interaction with the os, for example creating windows)
- added geometry.rs
  - provides the Vec2<T> struct for use with dimensions, coordinates etc.
- added window.rs
  - provides the Window struct for rendering the state of an application to the screen
- added application.rs
  - provides the Application trait for custom programs to implement in order to run
This commit is contained in:
2025-02-24 03:26:49 +00:00
parent 7ff33659fe
commit d9bbdff08c
36 changed files with 421 additions and 39 deletions
Generated
+99
View File
@@ -64,6 +64,47 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "darling"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "foundry_os" name = "foundry_os"
version = "0.1.0" version = "0.1.0"
@@ -101,12 +142,19 @@ dependencies = [
"pin-utils", "pin-utils",
] ]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "libk" name = "libk"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"crossbeam", "crossbeam",
"futures-util", "futures-util",
"libm",
"limine", "limine",
"linked_list_allocator", "linked_list_allocator",
"pc-keyboard", "pc-keyboard",
@@ -114,6 +162,16 @@ dependencies = [
"x86_64", "x86_64",
] ]
[[package]]
name = "libm"
version = "0.1.0"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "limine" name = "limine"
version = "0.3.1" version = "0.3.1"
@@ -169,6 +227,24 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.19" version = "1.0.19"
@@ -205,6 +281,29 @@ dependencies = [
"lock_api", "lock_api",
] ]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[package]] [[package]]
name = "volatile" name = "volatile"
version = "0.4.6" version = "0.4.6"
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["kernel", "libk"] members = ["kernel", "libk", "libm"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
+1 -1
View File
@@ -189,7 +189,7 @@
"command-palette:Open command palette": false "command-palette:Open command palette": false
} }
}, },
"active": "e1fb15cab546d0b6", "active": "add883d295e04659",
"lastOpenFiles": [ "lastOpenFiles": [
"Usage", "Usage",
"Welcome.md", "Welcome.md",
+1 -1
View File
@@ -96,7 +96,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
let mut port = Port::new(0x60); let mut port = Port::new(0x60);
let scancode: u8 = unsafe { port.read() }; let scancode: u8 = unsafe { port.read() };
libk::io::keyboard::add_scancode(scancode); libk::drivers::io::keyboard::add_scancode(scancode);
unsafe { unsafe {
PICS.lock() PICS.lock()
+2 -2
View File
@@ -6,7 +6,7 @@ extern crate alloc;
use core::arch::asm; use core::arch::asm;
use limine::BaseRevision; use limine::BaseRevision;
use libk::kalloc::init_heap; use libk::drivers::kalloc::allocator::init_heap;
use libk::prelude::*; use libk::prelude::*;
use x86_64::VirtAddr; use x86_64::VirtAddr;
@@ -51,7 +51,7 @@ pub fn boot() -> Result<(), &'static str> {
let memory_map = memmap::get_memory_map(); let memory_map = memmap::get_memory_map();
print_log!(" Initialising Serial... "); print_log!(" Initialising Serial... ");
libk::io::serial::init()?; libk::drivers::io::serial::init()?;
println_log!("[Success]"); println_log!("[Success]");
print_log!(" Setting Up Global Descriptor Table... "); print_log!(" Setting Up Global Descriptor Table... ");
+7 -6
View File
@@ -4,10 +4,13 @@
extern crate alloc; extern crate alloc;
use libk::{ use libk::{
io::{self, keyboard},
prelude::*,
scheduling::task::{Executor, Task},
// scheduling::task::{Executor, Task}, // scheduling::task::{Executor, Task},
drivers::{
io::{self, ascii::WRITER, keyboard},
scheduling::task::{Executor, Task},
},
prelude::*,
resources::font::FONT_SPLEEN_8X16,
}; };
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
@@ -20,7 +23,7 @@ extern "C" fn kmain() -> ! {
println_log!("[ Kernel Initialised Successfully ] "); println_log!("[ Kernel Initialised Successfully ] ");
let dimensions = io::ascii::screensize_chars(); let dimensions = io::ascii::screensize_chars();
let dimensions2 = io::ascii::screensize_px(); let dimensions2 = io::framebuffer::display::screensize_px();
println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1); println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1);
println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1); println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1);
@@ -49,6 +52,4 @@ extern "C" fn kmain() -> ! {
let mut executor = Executor::new(); let mut executor = Executor::new();
executor.spawn(Task::new(keyboard::print_keypresses())); executor.spawn(Task::new(keyboard::print_keypresses()));
executor.run(); executor.run();
loop {}
} }
+1
View File
@@ -19,3 +19,4 @@ futures-util = { version = "0.3.31", default-features = false, features = [
"alloc", "alloc",
] } ] }
linked_list_allocator = "0.10.5" linked_list_allocator = "0.10.5"
libm = { path = "../libm" }
Binary file not shown.
Binary file not shown.
@@ -2,11 +2,9 @@ use core::fmt;
use spin::{Lazy, Mutex}; use spin::{Lazy, Mutex};
use x86_64::instructions::interrupts; use x86_64::instructions::interrupts;
pub use super::framebuffer::screensize_px; use super::framebuffer::{colour::Colour, display::FRAMEBUFFER_WRITER};
use super::framebuffer::{Colour, FRAMEBUFFER_WRITER};
mod font; use crate::resources::font::{FONT_CP850_8X16, Font};
use font::FONT;
static FONT_WIDTH: u32 = 8; static FONT_WIDTH: u32 = 8;
static FONT_HEIGHT: u32 = 16; static FONT_HEIGHT: u32 = 16;
@@ -19,6 +17,7 @@ pub fn screensize_chars() -> (u32, u32) {
} }
pub struct Writer { pub struct Writer {
font: &'static Font,
/// Measured in chars not pixels. /// Measured in chars not pixels.
screen_width: u32, screen_width: u32,
/// Measured in chars not pixels. /// Measured in chars not pixels.
@@ -48,6 +47,7 @@ impl Writer {
panic!("Framebuffer writer not initialized."); panic!("Framebuffer writer not initialized.");
}, },
|writer| Self { |writer| Self {
font: &FONT_CP850_8X16,
screen_width: writer.width() / 8, screen_width: writer.width() / 8,
screen_height: writer.height() / 16, screen_height: writer.height() / 16,
text_line: 0, text_line: 0,
@@ -60,6 +60,10 @@ impl Writer {
) )
} }
pub fn set_font(&mut self, font: &'static Font) {
self.font = font;
}
pub fn write_glyph(&mut self, c: u16) { pub fn write_glyph(&mut self, c: u16) {
if c as u8 == b'\n' { if c as u8 == b'\n' {
self.newline(); self.newline();
@@ -67,7 +71,7 @@ impl Writer {
} }
// get the character data from the font array. -- each byte is a row of pixels // get the character data from the font array. -- each byte is a row of pixels
let data: &[u8] = &FONT[c as usize * 16..(c as usize + 1) * 16]; let data: &[u8] = &self.font.0[c as usize];
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
for (row, line) in data.iter().enumerate().take(16) { for (row, line) in data.iter().enumerate().take(16) {
@@ -190,7 +194,7 @@ macro_rules! println_log {
#[macro_export] #[macro_export]
macro_rules! print_log { macro_rules! print_log {
($($arg:tt)*) => ($crate::io::ascii::_print_log(format_args!($($arg)*))); ($($arg:tt)*) => ($crate::_print_log(format_args!($($arg)*)));
} }
#[macro_export] #[macro_export]
@@ -201,7 +205,7 @@ macro_rules! println {
#[macro_export] #[macro_export]
macro_rules! print { macro_rules! print {
($($arg:tt)*) => ($crate::io::ascii::_print(format_args!($($arg)*))); ($($arg:tt)*) => ($crate::_print(format_args!($($arg)*)));
} }
#[macro_export] #[macro_export]
@@ -4,9 +4,7 @@ use limine::request::FramebufferRequest;
#[unsafe(link_section = ".requests")] #[unsafe(link_section = ".requests")]
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
mod colour; use super::colour::Colour;
pub use colour::Colour;
use core::panic; use core::panic;
use limine::framebuffer::Framebuffer; use limine::framebuffer::Framebuffer;
+2
View File
@@ -0,0 +1,2 @@
pub mod colour;
pub mod display;
@@ -5,14 +5,14 @@ use core::{
use spin::{Lazy, Mutex}; use spin::{Lazy, Mutex};
#[macro_export] #[macro_export]
macro_rules! serial_println { macro_rules! serial_print {
() => ($crate::serial_print!("\n")); ($($arg:tt)*) => ($crate::_serial_write(format_args!($($arg)*)));
($($arg:tt)*) => ($crate::io::serial_print!("{}\n", format_args!($($arg)*)));
} }
#[macro_export] #[macro_export]
macro_rules! serial_print { macro_rules! serial_println {
($($arg:tt)*) => ($crate::io::serial::_serial_write(format_args!($($arg)*))); () => ($crate::serial_print!("\n"));
($($arg:tt)*) => (serial_print!("{}\n", format_args!($($arg)*)));
} }
use super::port::{inb, outb}; use super::port::{inb, outb};
+1
View File
@@ -0,0 +1 @@
pub mod allocator;
+3
View File
@@ -0,0 +1,3 @@
pub mod io;
pub mod kalloc;
pub mod scheduling;
@@ -1,10 +1,8 @@
use alloc::boxed::Box; use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake};
use alloc::collections::{BTreeMap, VecDeque};
use alloc::sync::Arc;
use alloc::task::Wake;
use core::sync::atomic::AtomicU64; use core::sync::atomic::AtomicU64;
use core::task::Waker;
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use core::task::{RawWaker, Waker};
use core::{future::Future, pin::Pin}; use core::{future::Future, pin::Pin};
use crossbeam::queue::ArrayQueue; use crossbeam::queue::ArrayQueue;
use x86_64::instructions::interrupts::{self, enable_and_hlt}; use x86_64::instructions::interrupts::{self, enable_and_hlt};
-3
View File
@@ -1,3 +0,0 @@
pub mod allocator;
pub use self::allocator::init_heap;
+16 -4
View File
@@ -1,4 +1,5 @@
#![no_std] #![no_std]
#![allow(async_fn_in_trait)]
#![warn(tail_expr_drop_order)] #![warn(tail_expr_drop_order)]
#![warn(clippy::correctness, clippy::perf, clippy::nursery)] #![warn(clippy::correctness, clippy::perf, clippy::nursery)]
// alloc // alloc
@@ -8,11 +9,22 @@
extern crate alloc; extern crate alloc;
pub mod io; pub mod drivers;
pub mod kalloc; pub mod resources;
pub mod scheduling; pub mod std;
/// Re-exports most of the IO macros. /// Re-exports most of the IO macros as well as standard allocation stuff
pub mod prelude { pub mod prelude {
pub use crate::drivers::io::ascii::{_print, _print_log};
pub use crate::{print, print_log, println, println_log, serial_print, serial_println}; pub use crate::{print, print_log, println, println_log, serial_print, serial_println};
pub use alloc::{
boxed::Box,
string::{String, ToString},
vec::Vec,
};
} }
pub use crate::drivers::io::{
ascii::{_print, _print_log},
serial::_serial_write,
};
+12
View File
@@ -0,0 +1,12 @@
use libm::include_font;
pub mod ibm_vga_8x16;
pub static FONT_SPLEEN_8X16: Font = Font(include_font!(
"/home/zxq5/Projects/OSDev/FoundryOS/libk/resources/font/spleen-8x16.psf"
));
pub static FONT_CP850_8X16: Font = Font(include_font!(
"/home/zxq5/Projects/OSDev/FoundryOS/libk/resources/font/cp850-8x16.psf"
));
pub struct Font(pub [[u8; 16]; 512]);
+1
View File
@@ -0,0 +1 @@
pub mod font;
+14
View File
@@ -0,0 +1,14 @@
use crate::prelude::*;
pub trait Application {
type Output;
async fn run(&mut self, args: Vec<String>) -> Result<Self::Output, Error>;
}
#[derive(Debug)]
pub enum Error {
UnknownCommand(String),
ApplicationFailed(String),
KernelError(String),
}
+2
View File
@@ -0,0 +1,2 @@
pub mod application;
pub mod window;
+74
View File
@@ -0,0 +1,74 @@
use crate::{prelude::*, std::maths::geometry::Vec2};
pub struct Window {
dimensions: Vec2<usize>,
position: Vec2<usize>,
bordered: bool,
opened: bool,
title: String,
}
impl Window {
pub const fn new() -> Window {
Window {
dimensions: Vec2::new(0, 0),
position: Vec2::new(0, 0),
bordered: true,
opened: false,
title: String::new(),
}
}
pub fn is_bordered(&self) -> bool {
self.bordered
}
pub fn is_open(&self) -> bool {
self.opened
}
pub fn open(&mut self) {
self.opened = true;
}
pub fn close(&mut self) {
self.opened = false;
}
// some basic getters and setters for utility.
pub fn title(&self) -> &str {
&self.title
}
pub fn dimensions(&self) -> Vec2<usize> {
self.dimensions
}
pub fn position(&self) -> Vec2<usize> {
self.position
}
pub fn set_title(&mut self, title: String) {
self.title = title;
}
pub fn move_window(&mut self, offset: Vec2<usize>) {
self.position += offset;
}
pub fn set_position(&mut self, position: Vec2<usize>) {
self.position = position;
}
pub fn set_dimensions(&mut self, dimensions: Vec2<usize>) {
self.dimensions = dimensions;
}
}
impl Drop for Window {
fn drop(&mut self) {
if self.opened {
self.close();
}
}
}
+73
View File
@@ -0,0 +1,73 @@
use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
pub trait Coordinate:
Copy + Clone + PartialEq + AddAssign + MulAssign + SubAssign + DivAssign
{
}
impl Coordinate for usize {}
impl Coordinate for isize {}
impl Coordinate for u8 {}
impl Coordinate for i8 {}
impl Coordinate for u16 {}
impl Coordinate for i16 {}
impl Coordinate for u32 {}
impl Coordinate for i32 {}
impl Coordinate for u64 {}
impl Coordinate for i64 {}
impl Coordinate for u128 {}
impl Coordinate for i128 {}
impl Coordinate for f32 {}
impl Coordinate for f64 {}
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
pub struct Vec2<T: Coordinate> {
x: T,
y: T,
}
impl<T: Coordinate> Vec2<T> {
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn into<S: Coordinate + From<T>>(&self) -> Vec2<S> {
Vec2::new(self.x.clone().into(), self.y.clone().into())
}
pub fn x(&self) -> T {
self.x
}
pub fn y(&self) -> T {
self.y
}
}
impl<T: Coordinate> AddAssign for Vec2<T> {
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl<T: Coordinate> SubAssign for Vec2<T> {
fn sub_assign(&mut self, rhs: Self) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl<T: Coordinate> MulAssign<T> for Vec2<T> {
fn mul_assign(&mut self, rhs: T) {
self.x *= rhs;
self.y *= rhs;
}
}
impl<T: Coordinate> DivAssign<T> for Vec2<T> {
fn div_assign(&mut self, rhs: T) {
self.x /= rhs;
self.y /= rhs;
}
}
+1
View File
@@ -0,0 +1 @@
pub mod geometry;
+2
View File
@@ -0,0 +1,2 @@
pub mod application;
pub mod maths;
+15
View File
@@ -0,0 +1,15 @@
[package]
name = "libm"
version.workspace = true
edition.workspace = true
authors.workspace = true
[dependencies]
darling = "0.20.10"
proc-macro2 = "1.0.93"
quote = "1.0.38"
syn = "2.0.98"
[lib]
proc-macro = true
+69
View File
@@ -0,0 +1,69 @@
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use proc_macro::TokenStream;
use quote::quote;
use syn::{LitStr, parse_macro_input};
extern crate proc_macro;
#[proc_macro]
pub fn include_font(item: TokenStream) -> TokenStream {
let filename = parse_macro_input!(item as LitStr);
let file_path = filename.value().to_string();
println!("Loading font: [{}]", file_path);
let font_data = match Font::new(load_file(file_path)) {
Ok(font) => font.0,
Err(e) => panic!("{}", e),
};
quote!(
[
#(
[#(#font_data),*]
),*
]
)
.into()
}
struct Font([[u8; 16]; 512]);
impl Font {
const MAGIC: u16 = 0x3604;
pub fn new(data: [u8; (32 + 2) * 512 + 4]) -> Result<Font, &'static str> {
let magic: u16 = (data[0] as u16) << 8 | data[1] as u16;
let mode = data[2];
let size = data[3];
if magic != Self::MAGIC {
return Err("Magic value is invalid!");
}
let has_512_glyphs = (mode & 0x01) != 0;
let mut glyphs = [[0; 16]; 512];
let glyph_count = if has_512_glyphs { 512 } else { 256 };
for i in 0..(glyph_count as usize) {
let mut buff: [u8; 16] = [0; 16];
for j in 0..(size as usize) {
buff[j] = data[4 + i * (size as usize) + j];
}
glyphs[i] = buff;
}
Ok(Font(glyphs))
}
}
fn load_file(filename: String) -> [u8; (32 + 2) * 512 + 4] {
let mut buf = [0; (32 + 2) * 512 + 4];
let mut f = File::open(filename).unwrap();
f.seek(SeekFrom::Start(0)).unwrap();
f.read(&mut buf).unwrap();
return buf;
}
+4 -1
View File
@@ -176,10 +176,13 @@ kvm_flag=""
trap 'check_test_res "tests completed"' ERR trap 'check_test_res "tests completed"' ERR
# $build_dir/image.iso
cd "$project_root" cd "$project_root"
qemu-system-x86_64 -M q35 \ qemu-system-x86_64 -M q35 \
${kvm_flag} \
-cdrom "$build_dir/image.iso" \ -cdrom "$build_dir/image.iso" \
${kvm_flag} \
-boot d \ -boot d \
-m 2G \ -m 2G \
${serial_flags} \ ${serial_flags} \