1
0
Fork 0
forked from koniifer/ableos

Removed unused code

This commit is contained in:
Erin 2022-12-23 23:11:57 +01:00 committed by ondra05
parent e33014d000
commit 8d640b6a9b
154 changed files with 0 additions and 16398 deletions

View file

@ -1,14 +0,0 @@
[build]
# target = "riscv64gc-unknown-none-elf"
target = "json_targets/x86_64-ableos.json"
[unstable]
build-std = ["core", "compiler_builtins", "alloc"]
build-std-features = ["compiler-builtins-mem"]
[target.'cfg(target_arch = "x86_64")']
rustflags = ["-C", "target-feature=+rdrand"]
[target.riscv64gc-unknown-none-elf]
rustflags = "-C link-arg=-Tableos/src/arch/riscv/virt.lds"
# ableos/src/arch/riscv/virt.lds

View file

@ -1,120 +0,0 @@
[package]
edition = "2021"
name = "ableos"
version = "0.1.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[profile.release]
panic = "abort"
[package.metadata.bootimage]
test-args = [
"-device",
"isa-debug-exit,iobase=0xf4,iosize=0x04",
"-serial",
"stdio",
]
[dependencies]
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
qrcode = { path = "../qrcode-rust" }
bitflags = "1.3"
lliw = "0.2.0"
spin = "0.9"
pretty-hex = "0.2.1"
unicode-width = "0.1.7"
picorand = "0.1.0"
watson = "0.4"
genfs = "0.1.0"
axel = { git = "https://git.ablecorp.us/able/aos_userland" }
versioning = { git = "https://git.ablecorp.us/able/aos_userland" }
# embedded-graphics = "*"
pc-keyboard = "0.5"
# mini-backtrace = "0.1"
clparse = { git = "https://git.ablecorp.us/able/core_utils", default-features = false }
seq-macro = "0.3"
[dependencies.linked_list_allocator]
version = "0.9.0"
features = ["use_spin_nightly"]
[dependencies.log]
version = "0.4.17"
default-features = false
[dependencies.logos]
version = "0.12"
default-features = false
features = ["export_derive"]
[dependencies.rdrand]
version = "0.8"
default-features = false
[dependencies.kernel]
path = "../kernel"
[dependencies.serde]
version = "1.0"
default-features = false
features = ["derive", "alloc"]
[dependencies.hashbrown]
version = "0.12"
default-features = false
features = ["inline-more"]
[dependencies.rkyv]
version = "0.7"
default-features = false
features = ["size_64", "alloc"]
# [dependencies.smoltcp]
# version = "0.8.0"
# default-features = false
# features = ["log", "proto-ipv4"]
[dependencies.y-compositor-protocol]
git = "https://git.ablecorp.us:443/able/y-compositor-protocol.git"
[dependencies.ext2]
path = "../ext2-rs"
[dependencies.toml]
git = "https://git.ablecorp.us:443/theoddgarlic/toml-rs"
# version = "0.5.8"
default-features = false
[dependencies.facepalm]
path = "../facepalm"
[dependencies.ab_glyph]
version = "*"
default-features = false
features = ["libm"]
[dependencies.wasmi]
default-features = false
features = ["core"]
version = "*"
[dependencies.libwasm]
git = "https://git.ablecorp.us:443/able/libwasm.git"
default-features = false
[dependencies.externc-libm]
git = "https://git.ablecorp.us:443/able/externc-libm.git"
[target.'cfg(target_arch = "riscv")'.dependencies]
riscv = "*"
[target.'cfg(target_arch = "x86_64")'.dependencies]
limine = "0.1"
cpuio = { git = "https://git.ablecorp.us/ondra05/cpuio.git" }
pic8259 = "0.10.1"
uart_16550 = "0.2.0"
volatile = "0.2.6"
x86_64 = "0.14.8"
pc-beeper = { git = "https://github.com/AbleOS/pc-beeper" }
acpi = "4.1.0"
vga = { git = "https://git.ablecorp.us:443/able/vga.git" }
# vga = { path = "../../vga" }

View file

@ -1,11 +0,0 @@
,-""""-. OS: \0BLUE\0 AbleOS \0RESET\0
,'\ _ _`. Host: ???
/ \)_)-)_)-\ Kernel: AKern-{}-v{}
: : Uptime: {}
\ / Packages: None
\ / Shell: BuiltinShell
`. ,' Resolution: 640x480
`. ,' Terminal: VGABuffer
`.,' CPU: {}
/\`. ,-._ GPU: VGA Compatible
`-' Memory: {}/{}

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,6 +0,0 @@
[logging]
enabled = true
level = "Trace"
log_to_serial = true
log_to_vterm = false
filter = ["ableos::ps2_mouse", "ableos::vterm", "ableos::devices::pci"]

View file

@ -1,17 +0,0 @@
pub struct KeyEvent{
lctrl 1
rctrl 2
lalt 3
ralt 4
lsup 5
rsup 6
lshift 7
rshift 8
caps 9
down 10
# Keycodes
key 11-32
}

View file

@ -1 +0,0 @@
{"rustc_fingerprint":3542195962280373086,"outputs":{"17598535894874457435":{"success":true,"status":"","code":0,"stdout":"rustc 1.58.0-nightly (efd048394 2021-10-20)\nbinary: rustc\ncommit-hash: efd0483949496b067cd5f7569d1b28cd3d5d3c72\ncommit-date: 2021-10-20\nhost: x86_64-unknown-linux-gnu\nrelease: 1.58.0-nightly\nLLVM version: 13.0.0\n","stderr":""},"2797684049618456168":{"success":false,"status":"exit status: 1","code":1,"stdout":"","stderr":"error: `-Csplit-debuginfo` is unstable on this platform\n\n"},"15537503139010883884":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n","stderr":""},"931469667778813386":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/elfein/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}

View file

@ -1,15 +0,0 @@
{
"llvm-target": "arm-none-eabihf",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "ableos",
"env": "eabi",
"vendor": "unknown",
"arch": "arm",
"linker-flavor": "gcc",
"linker": "arm-none-eabi-gcc",
"data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
"executables": true,
"relocation-model": "static"
}

View file

@ -1,24 +0,0 @@
{
"arch": "aarch64",
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
"disable-redzone": true,
"env": "",
"executables": true,
"features": "+strict-align,+neon,+fp-armv8",
"is-builtin": false,
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"linker-is-gnu": true,
"pre-link-args": {
"ld.lld": ["-Tsrc/arch/aarch64/aarch64-qemu.ld"]
},
"llvm-target": "aarch64-unknown-none",
"max-atomic-width": 128,
"os": "none",
"panic-strategy": "abort",
"relocation-model": "static",
"target-c-int-width": "32",
"target-endian": "little",
"target-pointer-width": "64",
"vendor": ""
}

View file

@ -1,15 +0,0 @@
{
"llvm-target": "arm-none-eabihf",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "ableos",
"env": "eabi",
"vendor": "unknown",
"arch": "arm",
"linker-flavor": "gcc",
"linker": "arm-none-eabi-gcc",
"data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
"executables": true,
"relocation-model": "static"
}

View file

@ -1,22 +0,0 @@
{
"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",
"code-model": "kernel",
"pre-link-args": {
"ld.lld": [
"--gc-sections",
"--script=kernel/lds/x86_64.ld"
]
}
}

View file

@ -1,256 +0,0 @@
0-
1-
2-
3-
4-
5-
6-
7-
8-
9-
10-
11-
12-
13-
14-
15-
16-
17-
18-
19-
20-
21-
22-
23-
24-
25-
26-
27-
28-
29-
30-
31-
32-
33-
34-
35-
36-
37-
38-
39-
40-
41-
42-
43-
44-
45-
46-
47-
48-
49-
50-
51-
52-
53-
54-
55-
56-
57-
58-
59-
60-
61-
62-
63-
64-
65-
66-
67-
68-
69-
70-
71-
72-
73-
74-
75-
76-
77-
78-
79-
80-
81-
82-
83-
84-
85-
86-
87-
88-
89-
90-
91-
92-
93-
94-
95-
96-
97-
98-
99-
100-
101-
102-
103-
104-
105-
106-
107-
108-
109-
110-
111-
112-
113-
114-
115-
116-
117-
118-
119-
120-
121-
122-
123-
124-
125-
126-
127-
128-
129-
130-
131-
132-
133-
134-
135-
136-
137-
138-
139-
140-
141-
142-
143-
144-
145-
146-
147-
148-
149-
150-
151-
152-
153-
154-
155-
156-
157-
158-
159-
160-
161-
162-
163-
164-
165-
166-
167-
168-
169-
170-
171-
172-
173-
174-
175-
176-
177-
178-
179-
180-
181-
182-
183-
184-
185-
186-
187-
188-
189-
190-
191-
192-
193-
194-
195-
196-
197-
198-
199-
200-
201-
202-
203-
204-
205-
206-
207-
208-
209-
210-
211-
212-
213-
214-
215-
216-
217-
218-
219-
220-
221-
222-
223-
224-
225-
226-
227-
228-
229-
230-
231-
232-
233-
234-
235-
236-
237-
238-
239-
240-
241-
242-
243-
244-
245-
246-
247-
248-
249-
250-
251-
252-
253-
254-
255-

View file

@ -1,252 +0,0 @@
# Able doesn't have a full keyboard
0-NONE
1-
2-
3-BACKSPACE
4-
5-
6-
7-
8-
9-TAB
10-
11-
12-
13-ENTER
14-
15-
16-SHIFT
17-CONTROL
18-ALT
19-PAUSE
20-CAPS_LOCK
21-
22-
23-
24-
25-
26-
27-
28-
29-
30-
31-
32-SPACE
33-PAGE_UP
34-PAGE_DOWN
35-END
36-HOME
37-ARROW_LEFT
38-ARROW_UP
39-ARROW_RIGHT
40-ARROW_DOWN
41-
42-
43-
44-
45-INSERT
46-DELETE
47-
48-0
49-1
50-2
51-3
52-4
53-5
54-6
55-7
56-8
57-9
58-
59-SEMICOLON
60-
61-EQUAL
62-
63-
64-
65-a
66-b
67-c
68-d
69-e
70-f
71-g
72-h
73-i
74-j
75-k
76-l
77-m
78-n
79-o
80-p
81-q
82-r
83-s
84-t
85-u
86-v
87-w
88-x
89-y
90-z
91-
92-
93-
94-
95-
96-
97-
98-
99-
100-
101-
102-
103-
106-
107-
108-
109-
110-
111-
112-FUNCTION_1
113-FUNCTION_2
114-FUNCTION_3
115-FUNCTION_4
116-FUNCTION_5
117-FUNCTION_6
118-FUNCTION_7
119-FUNCTION_8
120-FUNCTION_9
121-FUNCTION_10
122-FUNCTION_11
123-FUNCTION_12
124-
125-
126-
127-
128-
129-
130-
131-
132-
134-
135-
136-
137-
138-
139-
140-
141-
142-
143-
145-SCROLL_LOCK
146-
147-
148-
149-
150-
151-
152-
153-
154-
155-
156-
157-
158-
159-
160-
161-
162-
163-
164-
165-
166-
167-
168-
169-
170-
171-
172-
173-MINUS
174-
175-
176-
177-
178-
179-
180-
181-
182-
183-
184-
185-
186-
187-
188-COMMA
189-
190-PERIOD
191-FORWARD_SLASH
192-GRAVE
193-
194-
195-
196-
197-
198-
199-
200-
201-
202-
203-
204-
205-
206-
207-
208-
209-
210-
211-
212-
213-
214-
215-
216-
218-
219-BRACKET_LEFT
220-BACK_SLASH
221-BRACKET_RIGHT
222-QUOTE
223-
224-
225-
226-
227-
228-
229-
230-
231-
232-
233-
234-
235-
236-
237-
238-
239-
240-
241-
242-
243-
244-
245-
246-
247-
248-
249-
250-
251-
252-
253-
254-
255-

View file

@ -1,73 +0,0 @@
//! The allocator to be implemented by ableOS
//!
//! NOTE: All memory regions are taken from https://wiki.osdev.org/Memory_Map_(x86)
use alloc::alloc::{GlobalAlloc, Layout};
use core::{fmt::Display, ptr::null_mut};
const HEAP_START: usize = 600_000_000;
const BLOCK_SIZE: usize = 1024;
const BLOCK_COUNT: usize = 512;
#[derive(Debug, Clone, Copy)]
pub struct MemoryRegion {
_start: usize,
_end: usize,
}
#[derive(Debug, Clone, Copy)]
pub struct AAlloc {
current_region: usize,
memory_regions: [Option<MemoryRegion>; 512],
}
impl AAlloc {
pub fn add_region(&mut self, mem: MemoryRegion) {
self.memory_regions[self.current_region] = Some(mem);
self.current_region += 1;
}
pub fn intialize() {
info!("Heap Start: {}", HEAP_START);
info!("Heap Size: {}", BLOCK_SIZE * BLOCK_COUNT);
info!("Heap End: {}", HEAP_START + BLOCK_SIZE * BLOCK_COUNT);
let mut aalloc = AAlloc {
current_region: 0,
memory_regions: [None; 512],
};
aalloc.add_region(MemoryRegion {
_start: 0x00100000,
_end: 0x00EFFFFF,
});
debug!("{}", aalloc);
}
}
impl Display for AAlloc {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "AAlloc {{\n\tcurrent_region: {},\n", self.current_region)?;
for x in 0..self.current_region {
if let Some(region) = self.memory_regions[x] {
write!(f, "\tRegion {}: {:?}\n", x, region)?;
}
}
write!(f, "}}")?;
Ok(())
}
}
unsafe impl GlobalAlloc for AAlloc {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
println!("Allocating memory");
println!("{}", _layout.size());
println!("{}", _layout.align());
null_mut()
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
panic!("dealloc should be never called")
}
}

View file

@ -1,19 +0,0 @@
pub mod aalloc;
pub use aalloc::*;
pub const HEAP_START: usize = 0x_4444_4444_0000;
pub const HEAP_MULTIPLIER: usize = 100000;
pub const HEAP_BASE: usize = 100;
pub const HEAP_SIZE: usize = HEAP_BASE * HEAP_MULTIPLIER;
/*
#[global_allocator]
pub static ALLOCATOR: LockedHeap = LockedHeap::empty();
#[alloc_error_handler]
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
panic!("allocation error: {:?}", layout)
}
*/

View file

@ -1,14 +0,0 @@
ENTRY(_start)
SECTIONS
{
. = 0x40000000;
.text.boot : { *(.text.boot) }
.text : { *(.text) }
.data : { *(.data) }
.rodata : { *(.rodata) }
.bss : { *(.bss) }
. = ALIGN(8);
. = . + 0x4000;
LD_STACK_PTR = .;
}

View file

@ -1,15 +0,0 @@
.globl _start
.extern LD_STACK_PTR
.section ".text.boot"
_start:
ldr x30, =LD_STACK_PTR
mov sp, x30
bl not_main
.equ PSCI_SYSTEM_OFF, 0x84000008
.globl system_off
system_off:
ldr x0, =PSCI_SYSTEM_OFF
hvc #0

View file

@ -1,13 +0,0 @@
use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr::null_mut;
pub struct Dummy;
unsafe impl GlobalAlloc for Dummy {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
null_mut()
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
panic!("dealloc should be never called")
}
}

View file

@ -1,37 +0,0 @@
use crate::driver_traits::graphics::{Graphics, Point, Rgb};
pub struct GraphicsBuffer;
#[allow(unused)]
impl Graphics for GraphicsBuffer {
fn put_line(coords_start: Point, coords_end: Point, thickness: u32, color: Rgb) {
todo!()
}
fn put_rect(coords_start: Point, coords_end: Point, color: Rgb) {
todo!()
}
fn put_circle(coords: Point, radius: u32) {
todo!()
}
fn put_triangle(coords_1: Point, coords_2: Point, coords_3: Point, thickness: u32, color: Rgb) {
todo!();
}
fn put_pixel(coords: Point, color: Rgb) {
todo!()
}
fn paint_cursor(coords: Point) {
todo!()
}
fn hide_cursor() {}
fn show_cursor() {}
fn draw() {}
fn clear() {
todo!()
}
}

View file

@ -1,4 +0,0 @@
pub mod allocator;
pub mod graphics;
pub mod nrf52;
pub mod serial;

View file

@ -1,70 +0,0 @@
//! A not-very-useful abstraction of GPIOs in Rust
#![allow(dead_code)]
use core::sync::atomic::{AtomicBool, Ordering::SeqCst};
const REG_P0_PIN_CNF_BASE: *mut u32 = 0x5000_0700 as *mut u32;
const REG_P0_OUT_SET: *mut u32 = 0x5000_0508 as *mut u32;
const REG_P0_OUT_CLR: *mut u32 = 0x5000_050C as *mut u32;
const PIN_CNF_DIR_OUTPUT: u32 = 0x0000_0001;
const PIN_CNF_INPUT_CONNECT: u32 = 0x0000_0000;
const PIN_CNF_PULL_DISABLED: u32 = 0x0000_0000;
const PIN_CNF_DRIVE_S0S1: u32 = 0x0000_0000;
const PIN_CNF_SENSE_DISABLED: u32 = 0x0000_0000;
/// A struct that represents an nRF52 Pin
pub struct Pin(u8);
impl Pin {
/// Set a pin to be a push pull output
pub fn set_push_pull_output(&mut self, level: Level) {
// set level
match level {
Level::High => self.set_high(),
Level::Low => self.set_low(),
}
let set_val = PIN_CNF_DIR_OUTPUT
| PIN_CNF_INPUT_CONNECT
| PIN_CNF_PULL_DISABLED
| PIN_CNF_DRIVE_S0S1
| PIN_CNF_SENSE_DISABLED;
unsafe {
core::ptr::write_volatile(REG_P0_PIN_CNF_BASE.offset(self.0 as isize), set_val);
}
}
/// Set a pin to output level low
pub fn set_low(&mut self) {
unsafe { core::ptr::write_volatile(REG_P0_OUT_SET, 1 << (self.0 as u32)) }
}
/// Set a pin to output level high
pub fn set_high(&mut self) {
unsafe { core::ptr::write_volatile(REG_P0_OUT_CLR, 1 << (self.0 as u32)) }
}
}
/// The level of a GPIO
#[derive(Copy, Clone)]
pub enum Level {
Low,
High,
}
/// A struct that represents P0 of the nRF52
pub struct Pins {
pub p0_31: Pin,
}
impl Pins {
/// A function to obtain a Port 0 singleton structure
pub fn take() -> Self {
static TAKEN: AtomicBool = AtomicBool::new(false);
// Enforce this as a singleton
assert!(!TAKEN.swap(true, SeqCst));
Self { p0_31: Pin(31) }
}
}

View file

@ -1,13 +0,0 @@
/// Prints to the host through the serial interface.
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {};
}
/// Prints to the host through the serial interface, appending a newline.
#[macro_export]
macro_rules! serial_println {
() => {};
($fmt:expr) => {};
($fmt:expr, $($arg:tt)*) => {};
}

View file

@ -1 +0,0 @@
pub fn init() {}

View file

@ -1,66 +0,0 @@
pub mod drivers;
pub mod init;
use crate::arch::drivers::nrf52::{Level, Pins};
use core::ptr;
use core::ptr::write_volatile;
global_asm!(include_str!("boot.s"));
fn delay(ticks: usize) {
static mut DUMMY: usize = 0;
// Reduce the number of iterations when in debug mode
#[cfg(debug_assertions)]
let ticks = ticks / 128;
for t in 0..ticks {
// Prevent the optimizer from removing this loop
unsafe {
write_volatile(&mut DUMMY, t);
}
}
}
use crate::print;
#[no_mangle]
pub extern "C" fn not_main() {
const UART0: *mut u8 = 0x0900_0000 as *mut u8;
for byte in b"ableOS Arm 64" {
unsafe {
ptr::write_volatile(UART0, *byte);
}
}
// let gpios = Pins::take();
// let mut led = gpios.p0_31;
//
// loop {
// led.set_high();
// delay(2_000_000);
//
// led.set_low();
// delay(6_000_000);
// }
//
// led.set_push_pull_output(Level::Low);
crate::kmain::kernel_main();
sloop();
}
pub fn sloop() -> ! {
loop {}
}
pub fn print() {
for byte in b"ableOS Arm 64" {
const UART0: *mut u8 = 0x0900_0000 as *mut u8;
unsafe {
ptr::write_volatile(UART0, *byte);
}
}
}
pub fn shutdown() {}

View file

@ -1,4 +0,0 @@
cargo build --target=json_targets/aarch64-ableos.json --release &&\
qemu-system-aarch64 -machine virt -m 1024M -cpu cortex-a53 \
-kernel target/aarch64-ableos/release/ableos -serial stdio \
-device virtio-keyboard

View file

@ -1,13 +0,0 @@
use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr::null_mut;
pub struct Dummy;
unsafe impl GlobalAlloc for Dummy {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
null_mut()
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
panic!("dealloc should be never called")
}
}

View file

@ -1,37 +0,0 @@
use crate::driver_traits::graphics::{Graphics, Point, Rgb};
pub struct GraphicsBuffer;
#[allow(unused)]
impl Graphics for GraphicsBuffer {
fn put_line(coords_start: Point, coords_end: Point, thickness: u32, color: Rgb) {
todo!()
}
fn put_rect(coords_start: Point, coords_end: Point, color: Rgb) {
todo!()
}
fn put_circle(coords: Point, radius: u32) {
todo!()
}
fn put_triangle(coords_1: Point, coords_2: Point, coords_3: Point, thickness: u32, color: Rgb) {
todo!();
}
fn put_pixel(coords: Point, color: Rgb) {
todo!()
}
fn paint_cursor(coords: Point) {
todo!()
}
fn hide_cursor() {}
fn show_cursor() {}
fn draw() {}
fn clear() {
todo!()
}
}

View file

@ -1,35 +0,0 @@
/// # Safety
///
/// We label the mmio function unsafe since
/// we will be working with raw memory. Rust cannot
/// make any guarantees when we do this.
#[inline(always)]
fn mmio_write(address: usize, offset: usize, value: u8) {
// Set the pointer based off of the address
let reg = address as *mut u8;
// write_volatile is a member of the *mut raw
// and we can use the .add() to give us another pointer
// at an offset based on the original pointer's memory
// address. NOTE: The add uses pointer arithmetic so it is
// new_pointer = old_pointer + sizeof(pointer_type) * offset
unsafe {
reg.add(offset).write_volatile(value);
}
}
/// # Safety
///
/// We label the mmio function unsafe since
/// we will be working with raw memory. Rust cannot
/// make any guarantees when we do this.
fn mmio_read(address: usize, offset: usize, value: u8) -> u8 {
// Set the pointer based off of the address
let reg = address as *mut u8;
// read_volatile() is much like write_volatile() except it
// will grab 8-bits from the pointer and give that value to us.
// We don't add a semi-colon at the end here so that the value
// is "returned".
unsafe { reg.add(offset).read_volatile() }
}

View file

@ -1,5 +0,0 @@
pub mod allocator;
pub mod graphics;
pub mod mmio;
pub mod sysinfo;
pub mod uart;

View file

@ -1,23 +0,0 @@
pub fn sysinfo() {}
pub fn master() -> Option<Master> {
Some(Master {
brand_string: Some("riscv".to_string()),
})
}
pub struct Master {
// TODO: Rename struct
// version_information: Option<VersionInformation>,
// thermal_power_management_information: Option<ThermalPowerManagementInformation>,
// structured_extended_information: Option<StructuredExtendedInformation>,
// extended_processor_signature: Option<ExtendedProcessorSignature>,
pub brand_string: Option<String>,
// cache_line: Option<CacheLine>,
// time_stamp_counter: Option<TimeStampCounter>,
// physical_address_size: Option<PhysicalAddressSize>,
}
impl Master {
pub fn brand_string(&self) -> Option<&str> {
self.brand_string.as_deref()
}
}

View file

@ -1,129 +0,0 @@
use core::fmt::{Error, Write};
/// Initialize the UART driver by setting
/// the word length, FIFOs, and interrupts
pub fn uart_init(base_addr: usize) {
let ptr = base_addr as *mut u8;
unsafe {
// First, set the word length, which
// are bits 0, and 1 of the line control register (LCR)
// which is at base_address + 3
// We can easily write the value 3 here or 0b11, but I'm
// extending it so that it is clear we're setting two individual
// fields
// Word 0 Word 1
// ~~~~~~ ~~~~~~
let lcr = (1 << 0) | (1 << 1);
ptr.add(3).write_volatile(lcr);
// Now, enable the FIFO, which is bit index 0 of the FIFO
// control register (FCR at offset 2).
// Again, we can just write 1 here, but when we use left shift,
// it's easier to see that we're trying to write bit index #0.
ptr.add(2).write_volatile(1 << 0);
// Enable receiver buffer interrupts, which is at bit index
// 0 of the interrupt enable register (IER at offset 1).
ptr.add(1).write_volatile(1 << 0);
// If we cared about the divisor, the code below would set the divisor
// from a global clock rate of 22.729 MHz (22,729,000 cycles per second)
// to a signaling rate of 2400 (BAUD). We usually have much faster signalling
// rates nowadays, but this demonstrates what the divisor actually does.
// The formula given in the NS16500A specification for calculating the divisor
// is:
// divisor = ceil( (clock_hz) / (baud_sps x 16) )
// So, we substitute our values and get:
// divisor = ceil( 22_729_000 / (2400 x 16) )
// divisor = ceil( 22_729_000 / 38_400 )
// divisor = ceil( 591.901 ) = 592
// The divisor register is two bytes (16 bits), so we need to split the value
// 592 into two bytes. Typically, we would calculate this based on measuring
// the clock rate, but again, for our purposes [qemu], this doesn't really do
// anything.
let divisor: u16 = 592;
let divisor_least: u8 = (divisor & 0xff).try_into().unwrap();
let divisor_most: u8 = (divisor >> 8).try_into().unwrap();
// Notice that the divisor register DLL (divisor latch least) and DLM (divisor
// latch most) have the same base address as the receiver/transmitter and the
// interrupt enable register. To change what the base address points to, we
// open the "divisor latch" by writing 1 into the Divisor Latch Access Bit
// (DLAB), which is bit index 7 of the Line Control Register (LCR) which
// is at base_address + 3.
ptr.add(3).write_volatile(lcr | 1 << 7);
// Now, base addresses 0 and 1 point to DLL and DLM, respectively.
// Put the lower 8 bits of the divisor into DLL
ptr.add(0).write_volatile(divisor_least);
ptr.add(1).write_volatile(divisor_most);
// Now that we've written the divisor, we never have to touch this again. In
// hardware, this will divide the global clock (22.729 MHz) into one suitable
// for 2,400 signals per second. So, to once again get access to the
// RBR/THR/IER registers, we need to close the DLAB bit by clearing it to 0.
ptr.add(3).write_volatile(lcr);
}
}
fn uart_get(base_addr: usize) -> Option<u8> {
let ptr = base_addr as *mut u8;
unsafe {
// Bit index #5 is the Line Control Register.
if ptr.add(5).read_volatile() & 1 == 0 {
// The DR bit is 0, meaning no data
None
} else {
// The DR bit is 1, meaning data!
Some(ptr.add(0).read_volatile())
}
}
}
fn uart_put(base_addr: usize, c: u8) {
let ptr = base_addr as *mut u8;
unsafe {
// If we get here, the transmitter is empty, so transmit
// our stuff!
ptr.add(0).write_volatile(c);
}
}
pub struct Uart {
base_address: usize,
}
impl Uart {
pub fn new(base_address: usize) -> Self {
Uart { base_address }
}
pub fn get(&self) -> Option<u8> {
uart_get(self.base_address)
}
pub fn put(&self, c: u8) {
uart_put(self.base_address, c);
}
pub fn init(&self) {
uart_init(self.base_address);
}
}
// This is a slightly different syntax. Write is this "trait", meaning it is much like
// an interface where we're just guaranteeing a certain function signature. In the Write
// trait, one is absolutely required to be implemented, which is write_str. There are other
// functions, but they all rely on write_str(), so their default implementation is OK for now.
impl Write for Uart {
// The trait Write expects us to write the function write_str
// which looks like:
fn write_str(&mut self, s: &str) -> Result<(), Error> {
for c in s.bytes() {
self.put(c);
}
// Return that we succeeded.
Ok(())
}
}

View file

@ -1 +0,0 @@
pub fn init() {}

View file

@ -1,99 +0,0 @@
pub mod drivers;
pub mod init;
use crate::print;
use crate::println;
use core::arch::asm;
#[naked]
#[no_mangle]
unsafe extern "C" fn _boot() -> ! {
#[rustfmt::skip]
asm!("
csrw sie, zero
csrci sstatus, 2
.option push
.option norelax
lla gp, __global_pointer$
.option pop
lla sp, __tmp_stack_top
lla t0, __bss_start
lla t1, __bss_end
1:
beq t0, t1, 2f
sd zero, (t0)
addi t0, t0, 8
j 1b
2:
j {}
",
sym _start, options(noreturn));
}
extern "C" fn _start() -> ! {
use crate::serial_println;
let uart = crate::arch::drivers::uart::Uart::new(0x1000_0000);
uart.init();
log!("Hello, world!\r");
loop {
if let Some(c) = uart.get() {
match c {
66 => break,
10 | 13 => {
uart.put('\n' as u8);
uart.put('\r' as u8);
}
/*
91 => {
if let Some(ch) = uart.get() {
match ch as char {
'A' => {
serial_println!("That's the up arrow!");
}
'B' => {
serial_println!("That's the down arrow!");
}
'C' => {
serial_println!("That's the right arrow!");
}
'D' => {
serial_println!("That's the left arrow!");
}
_ => {
serial_println!("That's something else!");
}
}
}
}
*/
_ => {
uart.put(c);
}
}
}
}
serial_println!("Serial connection closed.\r");
sloop()
}
pub fn sloop() -> ! {
loop {
unsafe {
asm!("wfi");
};
}
}
pub fn shutdown() {}
pub fn generate_process_pass() -> u128 {
123
}

View file

@ -1,64 +0,0 @@
OUTPUT_ARCH(riscv64gc)
ENTRY(_boot);
SECTIONS {
. = 0x80200000;
.text : {
PROVIDE(__text_start = .);
PROVIDE(KERNEL_START = .);
*(.init.boot)
*(.init.rust)
*(.text .text.*)
. = ALIGN(4K);
PROVIDE(__text_end = .);
}
.data : {
PROVIDE(__data_start = .);
*(.data .data.* .rodata .rodata.*)
. = ALIGN(8);
PROVIDE(__tmp_stack_bottom = .);
. += 1024 * 1024 * 4;
PROVIDE(__tmp_stack_top = .);
. += 4096;
PROVIDE(__scratch_stack = .);
. = ALIGN(8);
}
. = ALIGN(8);
.sdata : {
PROVIDE(__global_pointer$ = .);
*(.sdata .sdata.*)
. = ALIGN(4K);
PROVIDE(__data_end = .);
}
PROVIDE(__bss_start = .);
.sbss : {
*(.sbss .sbss.*);
}
.bss : {
*(.bss .bss.*)
}
. = ALIGN(4K);
PROVIDE(__bss_end = .);
.tdata : {
. = ALIGN(4K);
PROVIDE(__tdata_start = .);
*(.tdata .tdata.*)
. = ALIGN(4K);
PROVIDE(__tdata_end = .);
}
. = ALIGN(2M);
PROVIDE(KERNEL_END = .);
/DISCARD/ : { *(.eh_frame_hdr .eh_frame) }
}

View file

@ -1,48 +0,0 @@
use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr::null_mut;
use kernel::allocator::{HEAP_SIZE, HEAP_START};
use x86_64::{
structures::paging::{
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
},
VirtAddr,
};
pub struct Dummy;
unsafe impl GlobalAlloc for Dummy {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
null_mut()
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
panic!("dealloc should be never called")
}
}
pub fn init_heap(
mapper: &mut impl Mapper<Size4KiB>,
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
) -> Result<(), MapToError<Size4KiB>> {
let page_range = {
let heap_start = VirtAddr::new(HEAP_START as u64);
let heap_end = heap_start + HEAP_SIZE - 1u64;
let heap_start_page = Page::containing_address(heap_start);
let heap_end_page = Page::containing_address(heap_end);
Page::range_inclusive(heap_start_page, heap_end_page)
};
for page in page_range {
let frame = frame_allocator
.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
}
unsafe {
kernel::allocator::ALLOCATOR
.lock()
.init(HEAP_START, HEAP_SIZE);
}
Ok(())
}

View file

@ -1,42 +0,0 @@
use crate::driver_traits::graphics::{Graphics, Point, Rgb};
use cpuio::outw;
pub struct GraphicsBuffer;
#[allow(unused)]
impl Graphics for GraphicsBuffer {
fn put_line(coords_start: Point, coords_end: Point, thickness: u32, color: Rgb) {
todo!()
}
fn put_rect(coords_start: Point, coords_end: Point, color: Rgb) {}
fn put_circle(coords: Point, radius: u32) {
todo!()
}
fn put_triangle(coords_1: Point, coords_2: Point, coords_3: Point, thickness: u32, color: Rgb) {
todo!();
}
fn put_pixel(coords: Point, color: Rgb) {
todo!()
}
fn paint_cursor(coords: Point) {
todo!()
}
fn hide_cursor() {
unsafe {
outw(0x0A, 0x3D4);
outw(0x20, 0x3D5);
}
}
fn show_cursor() {}
fn draw() {}
fn clear() {
todo!()
}
}

View file

@ -1,8 +0,0 @@
pub mod allocator;
// pub mod graphics;
pub mod serial;
pub mod sysinfo;
pub mod timer;
#[deprecated(note = "The use of hardware specific drivers for VGA is discouraged")]
pub mod vga;

View file

@ -1,36 +0,0 @@
use spin::{Lazy, Mutex};
use uart_16550::SerialPort;
pub static SERIAL1: Lazy<Mutex<SerialPort>> = Lazy::new(|| {
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Mutex::new(serial_port)
});
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;
// /*
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
// */
}
/// Prints to the host through the serial interface.
#[macro_export]
macro_rules! sprint {
($($arg:tt)*) => {
$crate::arch::drivers::serial::_print(format_args!($($arg)*));
};
}
/// Prints to the host through the serial interface, appending a newline.
#[macro_export]
macro_rules! sprintln {
() => ($crate::sprint!("\n"));
($fmt:expr) => ($crate::sprint!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => ($crate::sprint!(
concat!($fmt, "\n"), $($arg)*));
}

View file

@ -1,954 +0,0 @@
//! ```
//! extern crate cupid;
//!
//! fn main() {
//! let information = cupid::master();
//! println!("{:#?}", information);
//! if let Some(information) = information {
//! if information.sse4_2() {
//! println!("SSE 4.2 Available");
//! }
//! }
//! }
//! ```
#![cfg_attr(
not(any(target_arch = "x86_64", target_arch = "x86")),
allow(dead_code)
)]
use core::arch::asm;
use core::ops::Deref;
use core::{fmt, slice, str};
// 3 calls of 4 registers of 4 bytes
const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;
macro_rules! bit {
($reg:ident, {$($idx:expr => $name:ident),+ $(,)?}) => {
$(pub fn $name(self) -> bool {
((self.$reg >> $idx) & 1) != 0
})+
}
}
macro_rules! dump {
($me:expr, $f: expr, $sname:expr, {$($name:ident),+ $(,)?}) => {
$f.debug_struct($sname)
$(.field(stringify!($name), &$me.$name()))+
.finish()
}
}
macro_rules! delegate_flag {
($item:ident, {$($name:ident),+ $(,)?}) => {
$(pub fn $name(&self) -> bool {
self.$item.map(|i| i.$name()).unwrap_or(false)
})+
}
}
macro_rules! master_attr_reader {
($name:ident, $kind:ty) => {
pub fn $name(&self) -> Option<&$kind> {
self.$name.as_ref()
}
};
}
#[repr(u32)]
pub enum RequestType {
BasicInformation = 0x00000000,
VersionInformation = 0x00000001,
ThermalPowerManagementInformation = 0x00000006,
StructuredExtendedInformation = 0x00000007,
ExtendedFunctionInformation = 0x80000000,
ExtendedProcessorSignature = 0x80000001,
BrandString1 = 0x80000002,
BrandString2 = 0x80000003,
BrandString3 = 0x80000004,
// reserved = 0x80000005,
CacheLine = 0x80000006,
TimeStampCounter = 0x80000007,
PhysicalAddressSize = 0x80000008,
}
#[derive(Copy, Clone)]
pub struct VersionInformation {
eax: u32,
ebx: u32,
ecx: u32,
edx: u32,
}
impl VersionInformation {
pub fn new() -> VersionInformation {
let (a, b, c, d) = cpuid(RequestType::VersionInformation);
VersionInformation {
eax: a,
ebx: b,
ecx: c,
edx: d,
}
}
pub fn family_id(self) -> u32 {
let family_id = bits_of(self.eax, 8, 11);
let extended_family_id = bits_of(self.eax, 20, 27);
if family_id != 0x0F {
family_id
} else {
extended_family_id + family_id
}
}
pub fn model_id(self) -> u32 {
let family_id = self.family_id();
let model_id = bits_of(self.eax, 4, 7);
let extended_model_id = bits_of(self.eax, 16, 19);
if family_id == 0x06 || family_id == 0x0F {
(extended_model_id << 4) + model_id
} else {
model_id
}
}
pub fn stepping(self) -> u32 {
bits_of(self.eax, 0, 3)
}
fn processor_signature(self) -> u32 {
self.eax
}
pub fn brand_string(self) -> Option<&'static str> {
let brand_index = bits_of(self.ebx, 0, 7);
let processor_signature = self.processor_signature();
match brand_index {
0x00 => None,
0x01 => Some("Intel(R) Celeron(R)"),
0x02 => Some("Intel(R) Pentium(R) III"),
0x03 => {
if processor_signature == 0x06B1 {
Some("Intel(R) Celeron(R)")
} else {
Some("Intel(R) Pentium(R) III Xeon(R)")
}
}
0x04 => Some("Intel(R) Pentium(R) III"),
0x06 => Some("Mobile Intel(R) Pentium(R) III-M"),
0x07 => Some("Mobile Intel(R) Celeron(R)"),
0x08 => Some("Intel(R) Pentium(R) 4"),
0x09 => Some("Intel(R) Pentium(R) 4"),
0x0A => Some("Intel(R) Celeron(R)"),
0x0B => {
if processor_signature == 0x0F13 {
Some("Intel(R) Xeon(R) MP")
} else {
Some("Intel(R) Xeon(R)")
}
}
0x0C => Some("Intel(R) Xeon(R) MP"),
0x0E => {
if processor_signature == 0x0F13 {
Some("Intel(R) Xeon(R)")
} else {
Some("Mobile Intel(R) Pentium(R) 4-M")
}
}
0x0F => Some("Mobile Intel(R) Celeron(R)"),
0x11 => Some("Mobile Genuine Intel(R)"),
0x12 => Some("Intel(R) Celeron(R) M"),
0x13 => Some("Mobile Intel(R) Celeron(R)"),
0x14 => Some("Intel(R) Celeron(R)"),
0x15 => Some("Mobile Genuine Intel(R)"),
0x16 => Some("Intel(R) Pentium(R) M"),
0x17 => Some("Mobile Intel(R) Celeron(R)"),
_ => None,
}
}
bit!(ecx, {
0 => sse3,
1 => pclmulqdq,
2 => dtes64,
3 => monitor,
4 => ds_cpl,
5 => vmx,
6 => smx,
7 => eist,
8 => tm2,
9 => ssse3,
10 => cnxt_id,
11 => sdbg,
12 => fma,
13 => cmpxchg16b,
14 => xtpr_update_control,
15 => pdcm,
// 16 - reserved
17 => pcid,
18 => dca,
19 => sse4_1,
20 => sse4_2,
21 => x2apic,
22 => movbe,
23 => popcnt,
24 => tsc_deadline,
25 => aesni,
26 => xsave,
27 => osxsave,
28 => avx,
29 => f16c,
30 => rdrand,
// 31 - unused,
});
bit!(edx, {
0 => fpu,
1 => vme,
2 => de,
3 => pse,
4 => tsc,
5 => msr,
6 => pae,
7 => mce,
8 => cx8,
9 => apic,
// 10 - reserved
11 => sep,
12 => mtrr,
13 => pge,
14 => mca,
15 => cmov,
16 => pat,
17 => pse_36,
18 => psn,
19 => clfsh,
// 20 - reserved
21 => ds,
22 => acpi,
23 => mmx,
24 => fxsr,
25 => sse,
26 => sse2,
27 => ss,
28 => htt,
29 => tm,
// 30 -reserved
31 => pbe,
});
}
impl Default for VersionInformation {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for VersionInformation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "VersionInformation", {
family_id,
model_id,
stepping,
brand_string,
sse3,
pclmulqdq,
dtes64,
monitor,
ds_cpl,
vmx,
smx,
eist,
tm2,
ssse3,
cnxt_id,
sdbg,
fma,
cmpxchg16b,
xtpr_update_control,
pdcm,
pcid,
dca,
sse4_1,
sse4_2,
x2apic,
movbe,
popcnt,
tsc_deadline,
aesni,
xsave,
osxsave,
avx,
f16c,
rdrand,
fpu,
vme,
de,
pse,
tsc,
msr,
pae,
mce,
cx8,
apic,
sep,
mtrr,
pge,
mca,
cmov,
pat,
pse_36,
psn,
clfsh,
ds,
acpi,
mmx,
fxsr,
sse,
sse2,
ss,
htt,
tm,
pbe,
})
}
}
#[derive(Copy, Clone)]
pub struct ExtendedProcessorSignature {
ecx: u32,
edx: u32,
}
impl ExtendedProcessorSignature {
fn new() -> ExtendedProcessorSignature {
let (_, _, c, d) = cpuid(RequestType::ExtendedProcessorSignature);
ExtendedProcessorSignature { ecx: c, edx: d }
}
bit!(ecx, {
0 => lahf_sahf_in_64_bit,
// 1-4 reserved
5 => lzcnt,
// 6-7 reserved
8 => prefetchw,
// 9-31 reserved
});
bit!(edx, {
// 0-10 reserved
11 => syscall_sysret_in_64_bit,
// 12-19 reserved
20 => execute_disable,
// 21-25 reserved
26 => gigabyte_pages,
27 => rdtscp_and_ia32_tsc_aux,
// 28 reserved
29 => intel_64_bit_architecture,
// 30-31 reserved
});
}
impl fmt::Debug for ExtendedProcessorSignature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "ThermalPowerManagementInformation", {
lahf_sahf_in_64_bit,
lzcnt,
prefetchw,
syscall_sysret_in_64_bit,
execute_disable,
gigabyte_pages,
rdtscp_and_ia32_tsc_aux,
intel_64_bit_architecture,
})
}
}
pub struct BrandString {
bytes: [u8; BRAND_STRING_LENGTH],
}
impl BrandString {
fn new() -> BrandString {
fn append_bytes(a: RequestType, bytes: &mut [u8]) {
let (a, b, c, d) = cpuid(a);
let result_bytes = as_bytes(&a)
.iter()
.chain(as_bytes(&b).iter())
.chain(as_bytes(&c).iter())
.chain(as_bytes(&d).iter());
for (output, input) in bytes.iter_mut().zip(result_bytes) {
*output = *input
}
}
let mut brand_string = BrandString {
bytes: [0; BRAND_STRING_LENGTH],
};
append_bytes(RequestType::BrandString1, &mut brand_string.bytes[0..]);
append_bytes(RequestType::BrandString2, &mut brand_string.bytes[16..]);
append_bytes(RequestType::BrandString3, &mut brand_string.bytes[32..]);
brand_string
}
}
impl Clone for BrandString {
fn clone(&self) -> Self {
let mut bytes = [0; BRAND_STRING_LENGTH];
for (d, s) in bytes.iter_mut().zip(self.bytes.iter()) {
*d = *s;
}
BrandString { bytes }
}
}
impl Deref for BrandString {
type Target = str;
fn deref(&self) -> &str {
let nul_terminator = self.bytes.iter().position(|&b| b == 0).unwrap_or(0);
let usable_bytes = &self.bytes[..nul_terminator];
unsafe { str::from_utf8_unchecked(usable_bytes) }.trim()
}
}
impl fmt::Display for BrandString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &str).fmt(f)
}
}
impl fmt::Debug for BrandString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &str).fmt(f)
}
}
#[derive(Copy, Clone)]
pub struct ThermalPowerManagementInformation {
eax: u32,
ebx: u32,
ecx: u32,
}
impl ThermalPowerManagementInformation {
fn new() -> ThermalPowerManagementInformation {
let (a, b, c, _) = cpuid(RequestType::ThermalPowerManagementInformation);
ThermalPowerManagementInformation {
eax: a,
ebx: b,
ecx: c,
}
}
bit!(eax, {
0 => digital_temperature_sensor,
1 => intel_turbo_boost,
2 => arat,
// 3 - reserved
4 => pln,
5 => ecmd,
6 => ptm,
7 => hwp,
8 => hwp_notification,
9 => hwp_activity_window,
10 => hwp_energy_performance_preference,
// 12 - reserved
13 => hdc,
});
pub fn number_of_interrupt_thresholds(self) -> u32 {
bits_of(self.ebx, 0, 3)
}
bit!(ecx, {
0 => hardware_coordination_feedback,
// 1-2 - reserved
3 => performance_energy_bias
});
}
impl fmt::Debug for ThermalPowerManagementInformation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "ThermalPowerManagementInformation", {
digital_temperature_sensor,
intel_turbo_boost,
arat,
pln,
ecmd,
ptm,
hwp,
hwp_notification,
hwp_activity_window,
hwp_energy_performance_preference,
hdc,
number_of_interrupt_thresholds,
hardware_coordination_feedback,
performance_energy_bias
})
}
}
#[derive(Copy, Clone)]
pub struct StructuredExtendedInformation {
ebx: u32,
ecx: u32,
}
impl StructuredExtendedInformation {
fn new() -> StructuredExtendedInformation {
let (_, b, c, _) = cpuid(RequestType::StructuredExtendedInformation);
StructuredExtendedInformation { ebx: b, ecx: c }
}
bit!(ebx, {
0 => fsgsbase,
1 => ia32_tsc_adjust_msr,
// 2 - reserved
3 => bmi1,
4 => hle,
5 => avx2,
// 6 - reserved
7 => smep,
8 => bmi2,
9 => enhanced_rep_movsb_stosb,
10 => invpcid,
11 => rtm,
12 => pqm,
13 => deprecates_fpu_cs_ds,
// 14 - reserved
15 => pqe,
// 16-17 - reserved
18 => rdseed,
19 => adx,
20 => smap,
// 21-24 - reserved
25 => intel_processor_trace,
// 26-31 - reserved
});
bit!(ecx, {
0 => prefetchwt1
});
}
impl fmt::Debug for StructuredExtendedInformation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "StructuredExtendedInformation", {
fsgsbase,
ia32_tsc_adjust_msr,
bmi1,
hle,
avx2,
smep,
bmi2,
enhanced_rep_movsb_stosb,
invpcid,
rtm,
pqm,
deprecates_fpu_cs_ds,
pqe,
rdseed,
adx,
smap,
intel_processor_trace,
prefetchwt1,
})
}
}
#[derive(Debug, Copy, Clone)]
pub enum CacheLineAssociativity {
Disabled,
DirectMapped,
TwoWay,
FourWay,
EightWay,
SixteenWay,
Full,
}
#[derive(Copy, Clone)]
pub struct CacheLine(u32);
impl CacheLine {
fn new() -> CacheLine {
let (_, _, c, _) = cpuid(RequestType::CacheLine);
CacheLine(c)
}
pub fn cache_line_size(self) -> u32 {
bits_of(self.0, 0, 7)
}
pub fn l2_associativity(self) -> Option<CacheLineAssociativity> {
match bits_of(self.0, 12, 15) {
0x00 => Some(CacheLineAssociativity::Disabled),
0x01 => Some(CacheLineAssociativity::DirectMapped),
0x02 => Some(CacheLineAssociativity::TwoWay),
0x04 => Some(CacheLineAssociativity::FourWay),
0x06 => Some(CacheLineAssociativity::EightWay),
0x08 => Some(CacheLineAssociativity::SixteenWay),
0x0F => Some(CacheLineAssociativity::Full),
_ => None,
}
}
pub fn cache_size(self) -> u32 {
bits_of(self.0, 16, 31)
}
}
impl fmt::Debug for CacheLine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "CacheLine", {
cache_line_size,
l2_associativity,
cache_size
})
}
}
#[derive(Copy, Clone)]
pub struct TimeStampCounter {
edx: u32,
}
impl TimeStampCounter {
fn new() -> TimeStampCounter {
let (_, _, _, d) = cpuid(RequestType::TimeStampCounter);
TimeStampCounter { edx: d }
}
bit!(edx, {
// 0-7 - reserved
8 => invariant_tsc
// 9-31 - reserved
});
}
impl fmt::Debug for TimeStampCounter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "TimeStampCounter", { invariant_tsc })
}
}
#[derive(Copy, Clone)]
pub struct PhysicalAddressSize(u32);
impl PhysicalAddressSize {
fn new() -> PhysicalAddressSize {
let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
PhysicalAddressSize(a)
}
pub fn physical_address_bits(self) -> u32 {
bits_of(self.0, 0, 7)
}
pub fn linear_address_bits(self) -> u32 {
bits_of(self.0, 8, 15)
}
}
impl fmt::Debug for PhysicalAddressSize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "PhysicalAddressSize", {
physical_address_bits,
linear_address_bits
})
}
}
/// Information about the currently running processor
///
/// Feature flags match the feature mnemonic listed in the Intel
/// Instruction Set Reference. This struct provides a facade for flags
/// so the consumer doesn't need to worry about which particular CPUID
/// leaf provides the information.
///
/// For data beyond simple feature flags, you will need to retrieve
/// the nested struct and call the appropriate methods on it.
#[derive(Debug, Clone)]
pub struct Master {
// TODO: Rename struct
version_information: Option<VersionInformation>,
thermal_power_management_information: Option<ThermalPowerManagementInformation>,
structured_extended_information: Option<StructuredExtendedInformation>,
extended_processor_signature: Option<ExtendedProcessorSignature>,
brand_string: Option<BrandString>,
cache_line: Option<CacheLine>,
time_stamp_counter: Option<TimeStampCounter>,
physical_address_size: Option<PhysicalAddressSize>,
}
impl Master {
pub fn new() -> Master {
fn when_supported<F, T>(max: u32, kind: RequestType, then: F) -> Option<T>
where
F: FnOnce() -> T,
{
if max >= kind as u32 {
Some(then())
} else {
None
}
}
let (max_value, _, _, _) = cpuid(RequestType::BasicInformation);
let vi = when_supported(max_value, RequestType::VersionInformation, || {
VersionInformation::new()
});
let tpm = when_supported(
max_value,
RequestType::ThermalPowerManagementInformation,
ThermalPowerManagementInformation::new,
);
let sei = when_supported(
max_value,
RequestType::StructuredExtendedInformation,
StructuredExtendedInformation::new,
);
// Extended information
let (max_value, _, _, _) = cpuid(RequestType::ExtendedFunctionInformation);
let eps = when_supported(max_value, RequestType::ExtendedProcessorSignature, || {
ExtendedProcessorSignature::new()
});
let brand_string = when_supported(max_value, RequestType::BrandString3, BrandString::new);
let cache_line = when_supported(max_value, RequestType::CacheLine, CacheLine::new);
let tsc = when_supported(max_value, RequestType::TimeStampCounter, || {
TimeStampCounter::new()
});
let pas = when_supported(max_value, RequestType::PhysicalAddressSize, || {
PhysicalAddressSize::new()
});
Master {
version_information: vi,
thermal_power_management_information: tpm,
structured_extended_information: sei,
extended_processor_signature: eps,
brand_string,
cache_line,
time_stamp_counter: tsc,
physical_address_size: pas,
}
}
master_attr_reader!(version_information, VersionInformation);
master_attr_reader!(
thermal_power_management_information,
ThermalPowerManagementInformation
);
master_attr_reader!(
structured_extended_information,
StructuredExtendedInformation
);
master_attr_reader!(extended_processor_signature, ExtendedProcessorSignature);
master_attr_reader!(cache_line, CacheLine);
master_attr_reader!(time_stamp_counter, TimeStampCounter);
master_attr_reader!(physical_address_size, PhysicalAddressSize);
pub fn brand_string(&self) -> Option<&str> {
self.brand_string
.as_ref()
.map(|bs| bs as &str)
.or_else(|| self.version_information.and_then(|vi| vi.brand_string()))
}
delegate_flag!(version_information, {
sse3,
pclmulqdq,
dtes64,
monitor,
ds_cpl,
vmx,
smx,
eist,
tm2,
ssse3,
cnxt_id,
sdbg,
fma,
cmpxchg16b,
xtpr_update_control,
pdcm,
pcid,
dca,
sse4_1,
sse4_2,
x2apic,
movbe,
popcnt,
tsc_deadline,
aesni,
xsave,
osxsave,
avx,
f16c,
rdrand,
fpu,
vme,
de,
pse,
tsc,
msr,
pae,
mce,
cx8,
apic,
sep,
mtrr,
pge,
mca,
cmov,
pat,
pse_36,
psn,
clfsh,
ds,
acpi,
mmx,
fxsr,
sse,
sse2,
ss,
htt,
tm,
pbe,
});
delegate_flag!(thermal_power_management_information, {
digital_temperature_sensor,
intel_turbo_boost,
arat,
pln,
ecmd,
ptm,
hwp,
hwp_notification,
hwp_activity_window,
hwp_energy_performance_preference,
hdc,
hardware_coordination_feedback,
performance_energy_bias,
});
delegate_flag!(structured_extended_information, {
fsgsbase,
ia32_tsc_adjust_msr,
bmi1,
hle,
avx2,
smep,
bmi2,
enhanced_rep_movsb_stosb,
invpcid,
rtm,
pqm,
deprecates_fpu_cs_ds,
pqe,
rdseed,
adx,
smap,
intel_processor_trace,
prefetchwt1
});
delegate_flag!(extended_processor_signature, {
lahf_sahf_in_64_bit,
lzcnt,
prefetchw,
syscall_sysret_in_64_bit,
execute_disable,
gigabyte_pages,
rdtscp_and_ia32_tsc_aux,
intel_64_bit_architecture,
});
delegate_flag!(time_stamp_counter, { invariant_tsc });
}
impl Default for Master {
fn default() -> Self {
Self::new()
}
}
/// The main entrypoint to the CPU information
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
pub fn master() -> Option<Master> {
Some(Master::new())
}
pub fn sysinfo() {}
pub fn as_bytes(v: &u32) -> &[u8] {
let start = v as *const u32 as *const u8;
// TODO: use u32::BYTES
unsafe { slice::from_raw_parts(start, 4) }
}
pub fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
let eax;
let ebx;
let ecx;
let edx;
unsafe {
asm!(
"movq %rbx, {0:r}",
"cpuid",
"xchgq %rbx, {0:r}",
lateout(reg) ebx,
inlateout("eax") code as u32 => eax,
inlateout("ecx") 0 => ecx,
lateout("edx") edx,
options(nostack, preserves_flags, att_syntax),
);
}
(eax, ebx, ecx, edx)
}
// This matches the Intel Architecture guide, with bits 31 -> 0.
// The bit positions are inclusive.
fn bits_of(val: u32, start_bit: u8, end_bit: u8) -> u32 {
let mut silly = 0;
for _ in start_bit..end_bit + 1 {
silly <<= 1;
silly |= 1;
}
(val >> start_bit) & silly
}
/*
cfg_if! {
if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
#[test]
fn basic_genuine_intel() {
let (_, b, c, d) = cpuid(RequestType::BasicInformation);
assert_eq!(b"Genu", as_bytes(&b));
assert_eq!(b"ntel", as_bytes(&c));
assert_eq!(b"ineI", as_bytes(&d));
}
#[test]
fn brand_string_contains_intel() {
assert!(master().unwrap().brand_string().unwrap().contains("Intel(R)"))
}
} else {}
}
*/

View file

@ -1,2 +0,0 @@
/// This magic value is the herts of the timer interupts normalized
pub const TIMER_INTERRUPT_HERTZ: f64 = 1193182.0;

View file

@ -1 +0,0 @@

View file

@ -1,48 +0,0 @@
use spin::Lazy;
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
use x86_64::structures::tss::TaskStateSegment;
use x86_64::VirtAddr;
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
struct Selectors {
code_selector: SegmentSelector,
tss_selector: SegmentSelector,
}
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
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 { &STACK });
stack_start + STACK_SIZE
};
tss
});
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
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,
},
)
});
pub fn init() {
use x86_64::instructions::segmentation::{Segment, CS};
use x86_64::instructions::tables::load_tss;
log::debug!("Initialising GDT");
GDT.0.load();
unsafe {
CS::set_reg(GDT.1.code_selector);
load_tss(GDT.1.tss_selector);
}
}

View file

@ -1,38 +0,0 @@
// #![allow(clippy::print_literal)]
use super::{gdt, interrupts};
// use crate::{logger, serial_println, TERM};
use crate::{logger, serial_println};
/// x86_64 initialization
pub fn init() {
// use crate::{network::socket::SimpleSock, relib::network::socket::Socket};
// let mut log_socket_id = SimpleSock::new();
// log_socket_id.register_protocol("Logger".to_string());
let result = logger::init();
match result {
Ok(_) => {
info!("Logger initialized");
}
Err(err) => serial_println!("{}", err),
}
trace!("gdt");
gdt::init();
trace!("idt");
interrupts::init_idt();
unsafe { interrupts::PICS.lock().initialize() };
// trace!("term");
// let term = &*TERM;
// trace!("term.lock()");
// let mut term = term.lock();
// term.initialize();
// term.set_dirty(true);
// term.draw_term();
// drop(term);
x86_64::instructions::interrupts::enable();
}

View file

@ -1,285 +0,0 @@
/*
* Copyright (c) 2022, able <abl3theabove@gmail.com>
*
* SPDX-License-Identifier: MPL-2.0
*/
use core::panic::PanicInfo;
use crate::{arch::gdt, println, rhai_shell::KEYBUFF};
use cpuio::outb;
use pic8259::ChainedPics;
use qrcode::QrCode;
use seq_macro::seq;
use spin::Lazy;
use x86_64::{
registers::control::Cr2,
structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
};
use super::sloop;
pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
pub static PICS: spin::Mutex<ChainedPics> =
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
/// Interrupt offsets.
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum InterruptIndex {
Timer = PIC_1_OFFSET,
Keyboard,
/// Mouse offset
Mouse = 44,
/// Disk offset
Disk = 46,
// SecondInterrupt = PIC_2_OFFSET,
Cmos = 0x70,
}
impl InterruptIndex {
fn as_u8(self) -> u8 {
self as u8
}
fn as_usize(self) -> usize {
usize::from(self.as_u8())
}
}
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
reset_pit_for_cpu();
let mut idt = InterruptDescriptorTable::new();
seq!(N in 32..=255 {
idt[N].set_handler_fn(undefined_handler_~N);
});
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.page_fault.set_handler_fn(page_fault_handler);
unsafe {
idt.double_fault
.set_handler_fn(double_fault_handler)
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
}
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
idt[InterruptIndex::Mouse.as_usize()].set_handler_fn(crate::hardware::mouse_interrupt_handler);
// run `a + b + l + e + o + s print;` in ablescript and its 54 thats why this seemingly arbitrary number was chosen
idt[54].set_handler_fn(software_int_handler);
idt
});
seq!(N in 32..=255 {
extern "x86-interrupt" fn undefined_handler_~N(stack_frame: InterruptStackFrame) {
error!("INT {}: {:?}", N, stack_frame);
unsafe {
PICS.lock()
.notify_end_of_interrupt(N);
}
}
});
extern "x86-interrupt" fn software_int_handler(stack_frame: InterruptStackFrame) {
trace!("EXCEPTION: SOFTWARE INT\n{:#?}", stack_frame);
unsafe {
PICS.lock().notify_end_of_interrupt(54);
}
}
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
trace!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}
extern "x86-interrupt" fn page_fault_handler(
stack_frame: InterruptStackFrame,
error_code: PageFaultErrorCode,
) {
error!("EXCEPTION: PAGE FAULT {error_code:?}\n{:#?}", stack_frame);
trace!("CR2: {:x}", Cr2::read_raw());
trace!("SCREE");
loop {}
}
extern "x86-interrupt" fn double_fault_handler(
stack_frame: InterruptStackFrame,
// NOTE(able): ignore this always is 0
_error_code: u64,
) -> ! {
// bsod(BSODSource::DoubleFault(&stack_frame));
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
}
/* SAFETY
* DO NOT TOUCH
* The `#[naked]` macro removes various error/bounds checks that
* the Rust compiler would normally add.
* *Early return* and *enabling interrupts* in this function are
* undefined behavior.
* As long as nothing in this function does something that would
* normally trigger an error, this function is relatively safe.
*/
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
crate::kmain::tick();
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
}
}
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
use pc_keyboard::{
layouts::Us104Key, DecodedKey, HandleControl, KeyCode, Keyboard, ScancodeSet1,
};
use spin::Mutex;
use x86_64::instructions::port::Port;
static KEYBOARD: Lazy<Mutex<Keyboard<Us104Key, ScancodeSet1>>> =
Lazy::new(|| Mutex::new(Keyboard::new(Us104Key, ScancodeSet1, HandleControl::Ignore)));
let mut keyboard = KEYBOARD.lock();
if let Ok(Some(key)) = keyboard
.add_byte(unsafe { Port::new(0x60).read() })
.map(|x| x.and_then(|ev| keyboard.process_keyevent(ev)))
{
// trace!("{key:?}");
match key {
DecodedKey::Unicode(chr) => match chr {
'\n' => {
KEYBUFF.lock().push('\n');
}
// Backspace
'\u{8}' => {
// TODO: Fix this and apply to new term
KEYBUFF.lock().push(8.into());
// trace!("8");
// print!("\u{8}");
}
// '^' => KERNEL_STATE.lock().shutdown(),
chr => {
KEYBUFF.lock().push(chr);
// trace!("{chr}");
// print!("{chr}");
}
},
DecodedKey::RawKey(key) => {
use KeyCode::*;
match KeyCode::from(key) {
AltLeft | AltRight => (),
ArrowDown | ArrowRight | ArrowLeft | ArrowUp => {
// warn!("ArrowKeys are unsupported currently");
}
_kc => {
// trace!("Unprintable key: {kc:?}"),
}
};
}
}
}
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
}
}
pub fn init_idt() {
IDT.load();
}
/// https://wiki.osdev.org/Pit
///
const PIT_MAX_FREQ: u32 = 1193182;
pub fn set_pit_frequency(pit: u16, freq: u32) {
// Dividing the maximum frequency by the desired frequency
// gives roughly what the maximum value for the timer
// counter should be to run at the desired frequency.
let ret = (PIT_MAX_FREQ / freq).try_into();
// Type-bounded counter maximum.
let divisor: u16 = match ret {
Ok(div) => div,
Err(err) => {
error!("{}", err);
warn!("Defaulting to 1000 on PIT{}", pit);
1000
}
};
unsafe {
outb(0x36, 0x43);
outb((divisor & 0xFF) as u8, 0x39 + pit);
outb((divisor >> 8) as u8, 0x40 + pit);
}
}
pub fn set_pit_1(freq: u32) {
set_pit_frequency(1, freq);
}
pub fn set_pit_2(freq: u32) {
set_pit_frequency(2, freq);
}
pub fn set_pit_3(freq: u32) {
set_pit_frequency(3, freq);
}
pub fn reset_pit_for_cpu() {
set_pit_1(1000);
set_pit_2(1000);
set_pit_3(1000);
}
pub fn bsod(src: BSODSource) -> ! {
let src1 = match src {
BSODSource::DoubleFault(_) => "DoubleFault".to_string(),
BSODSource::Panic(panic_info) => {
let strr = format!("PANIC: {}", panic_info);
strr
}
};
let st = format!(
"We fucked up ඞ : \n{}\nThe following qr code will link you to the wiki which hopefully solves your problems",
src1
);
println!("\n{}", st);
// let sf = format!("https://git.ablecorp.us/able/ableos/wiki/Double-Faults");
let sd = match src {
BSODSource::DoubleFault(_) => "https://git.ablecorp.us/able/ableos/wiki/Double-Faults",
BSODSource::Panic(_) => {
trace!("panic");
"https://git.ablecorp.us/able/ableos/wiki/Panic"
}
};
let code = QrCode::new(sd).unwrap();
let image = code
.render::<char>()
.quiet_zone(false)
.module_dimensions(2, 1)
.build();
println!("{}", image);
sloop();
}
#[derive(Debug)]
pub enum BSODSource<'a> {
DoubleFault(&'a InterruptStackFrame),
Panic(&'a PanicInfo<'a>),
}

View file

@ -1,62 +0,0 @@
use limine::{LimineMemmapResponse, LimineMemoryMapEntryType};
use x86_64::{
structures::paging::{
FrameAllocator, FrameDeallocator, OffsetPageTable, PageTable, PhysFrame,
Size4KiB,
},
PhysAddr, VirtAddr,
};
pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
let level_4_table = active_level_4_table(physical_memory_offset);
OffsetPageTable::new(level_4_table, physical_memory_offset)
}
unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
use x86_64::registers::control::Cr3;
let (level_4_table_frame, _) = Cr3::read();
let phys = level_4_table_frame.start_address();
let virt = physical_memory_offset + phys.as_u64();
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
// THIS IS UNSAFE
&mut *page_table_ptr
}
pub struct BootInfoFrameAllocator {
memory_map: &'static LimineMemmapResponse,
next: usize,
}
impl BootInfoFrameAllocator {
pub unsafe fn init(memory_map: &'static LimineMemmapResponse) -> Self {
Self {
memory_map,
next: 0,
}
}
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
self.memory_map.mmap().unwrap().iter()
.filter(|r| r.typ == LimineMemoryMapEntryType::Usable)
.map(|r| r.base..r.base + r.len)
.flat_map(|r| r.step_by(4096))
.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)))
}
}
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
let frame = self.usable_frames().nth(self.next);
self.next += 1;
frame
}
}
impl FrameDeallocator<Size4KiB> for BootInfoFrameAllocator {
unsafe fn deallocate_frame(&mut self, _frame: PhysFrame<Size4KiB>) {
// TODO
}
}

View file

@ -1,60 +0,0 @@
/*
* Copyright (c) 2022, able <abl3theabove@gmail.com>
*
* SPDX-License-Identifier: MPL-2.0
*/
pub mod drivers;
pub mod gdt;
pub mod init;
pub mod interrupts;
pub mod memory;
use limine::*;
use x86_64::{instructions::hlt, VirtAddr};
use crate::serial_println;
use self::drivers::allocator;
static HHDM: LimineHhdmRequest = LimineHhdmRequest::new(0);
static MMAP: LimineMmapRequest = LimineMmapRequest::new(0);
#[no_mangle]
pub fn x86_64_start() -> ! {
let hhdm = HHDM.get_response().get().unwrap();
let mmap = MMAP.get_response().get().unwrap();
let phys_mem_offset = VirtAddr::new(hhdm.offset);
let mut mapper = unsafe { memory::init(phys_mem_offset) };
let mut frame_allocator = unsafe { memory::BootInfoFrameAllocator::init(mmap) };
allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
crate::kmain::kernel_main(mapper, frame_allocator);
}
#[allow(unused)]
pub fn shutdown() -> ! {
info!("Shutting down");
unsafe {
cpuio::outw(0x2000, 0x604);
}
sloop();
}
pub fn sloop() -> ! {
loop {
hlt();
}
}
// TODO: Split up into the randomness and the password generation
pub fn generate_process_pass() -> u128 {
// TODO: Move this into entropy_pool module
use rdrand::RdRand;
let gen = RdRand::new().unwrap();
(gen.try_next_u64().unwrap() as u128) << 64 | (gen.try_next_u64().unwrap() as u128)
}

View file

@ -1,72 +0,0 @@
use log::LevelFilter;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Debug, Deserialize)]
pub enum LogLevel {
/// A level lower than all log levels.
Off,
/// Corresponds to the `Error` log level.
Error,
/// Corresponds to the `Warn` log level.
Warn,
/// Corresponds to the `Info` log level.
Info,
/// Corresponds to the `Debug` log level.
Debug,
/// Corresponds to the `Trace` log level.
Trace,
}
#[derive(Serialize, Debug, Deserialize)]
pub struct KernelConfig {
pub logging: LoggingConfig,
}
impl KernelConfig {
pub fn new() -> Self {
KernelConfig::default()
}
pub fn load_from_string(toml_string: &str) -> Self {
match toml::from_str(toml_string) {
Ok(kernel_conf) => kernel_conf,
Err(err) => {
error!("Error {}", err);
KernelConfig::new()
}
}
}
pub fn log_level(&self) -> LevelFilter {
use LevelFilter::*;
match self.logging.level {
LogLevel::Off => Off,
LogLevel::Error => Error,
LogLevel::Warn => Warn,
LogLevel::Info => Info,
LogLevel::Debug => Debug,
LogLevel::Trace => Trace,
}
}
}
impl Default for KernelConfig {
fn default() -> Self {
Self {
logging: LoggingConfig {
enabled: true,
log_to_serial: true,
log_to_vterm: false,
level: LogLevel::Trace,
filter: Vec::new(),
},
}
}
}
#[derive(Serialize, Debug, Deserialize)]
pub struct LoggingConfig {
pub enabled: bool,
pub log_to_serial: bool,
pub log_to_vterm: bool,
pub level: LogLevel,
pub filter: Vec<String>,
}

View file

@ -1,6 +0,0 @@
//! Block device interface
/// Block device interface
pub trait BlockDevice {
// TODO
}

View file

@ -1,22 +0,0 @@
//!
/// Character device interface.
pub trait CharacterDevice {
/// Returns true if the device can be read from.
fn can_read(&self) -> bool;
/// Returns true if the device can be written to
fn can_write(&self) -> bool;
/// Reads a single character from the device
fn read_char(&mut self) -> Option<char>;
/// Writes a single character to the device and returns true if the write was successful
fn write_char(&mut self, c: char) -> bool;
/// Reset the device to its initial state
fn reset(&mut self);
/// initializes the device, returns true if successful
fn initialize(&mut self) -> bool;
}

View file

@ -1,7 +0,0 @@
//! Platform Agnostic Device
mod block;
mod character;
pub use block::BlockDevice;
pub use character::CharacterDevice;

View file

@ -1,29 +0,0 @@
use crate::device_interface::CharacterDevice;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DevNull;
impl CharacterDevice for DevNull {
fn can_read(&self) -> bool {
true
}
fn can_write(&self) -> bool {
true
}
fn read_char(&mut self) -> Option<char> {
Some(0x00 as char)
}
fn write_char(&mut self, _: char) -> bool {
true
}
fn reset(&mut self) {
todo!()
}
fn initialize(&mut self) -> bool {
todo!()
}
}

View file

@ -1,49 +0,0 @@
use crate::device_interface::CharacterDevice;
#[derive(Debug)]
pub struct DevUnicode {
pub next_write_char: char,
pub next_read_char: char,
}
impl CharacterDevice for DevUnicode {
fn can_read(&self) -> bool {
true
}
fn can_write(&self) -> bool {
true
}
fn read_char(&mut self) -> Option<char> {
let c = self.next_read_char;
self.next_read_char = add1_char(c);
Some(c)
}
fn write_char(&mut self, c: char) -> bool {
if self.next_write_char != c {
return false;
}
true
}
fn reset(&mut self) {
self.next_write_char = 0x00 as char;
self.next_read_char = 0x00 as char;
}
fn initialize(&mut self) -> bool {
true
}
}
fn add1_char(c: char) -> char {
if c == char::MAX {
return 0x00 as char;
}
char::from_u32(c as u32 + 1).unwrap()
}

View file

@ -1,27 +0,0 @@
use crate::device_interface::CharacterDevice;
#[derive(Debug)]
pub struct DevZero;
impl CharacterDevice for DevZero {
fn can_read(&self) -> bool {
true
}
fn can_write(&self) -> bool {
true
}
fn read_char(&mut self) -> Option<char> {
Some(0 as char)
}
fn write_char(&mut self, _: char) -> bool {
true
}
fn reset(&mut self) {}
fn initialize(&mut self) -> bool {
true
}
}

View file

@ -1,5 +0,0 @@
pub mod dev_null;
pub mod dev_unicode;
pub mod dev_zero;
pub use crate::device_interface::CharacterDevice;

View file

@ -1,265 +0,0 @@
// ! A virtual terminal device.
use crate::device_interface::CharacterDevice;
use core::ops::Not;
use core::sync::atomic::AtomicU32;
use core::sync::atomic::Ordering;
use crate::pixel_format::Rgba64;
pub const VTERM_HEIGHT: u32 = 40;
pub const VTERM_WIDTH: u32 = 100;
pub static VIRTUAL_TERMINAL_COUNT: AtomicU32 = AtomicU32::new(0);
/// Fg and bg colors for vterm
pub type ColorCharacter = (Rgba64, Rgba64);
/// A vterm representation of a character
#[derive(Debug, Clone, Copy)]
pub struct VtermCharacter {
pub character: char,
//
pub style: Style,
//
pub char_color: ColorCharacter,
}
#[derive(Default, Debug, Clone, Copy)]
pub struct Style(pub u8);
impl Style {
pub fn bold(&self) -> bool {
(self.0 & 0x01) > 0
}
pub fn underlined(&self) -> bool {
(self.0 & 0x02) > 0
}
pub fn italic(&self) -> bool {
(self.0 & 0x04) > 0
}
pub fn blinking(&self) -> bool {
(self.0 & 0x08) > 0
}
pub fn reversed(&self) -> bool {
(self.0 & 0x10) > 0
}
pub fn struck(&self) -> bool {
(self.0 & 0x20) > 0
}
#[must_use]
pub fn set_bold(mut self, v: bool) -> Self {
if v {
self.0 |= 0x01;
} else {
self.0 &= 0x01u8.not();
}
self
}
#[must_use]
pub fn set_underlined(mut self, v: bool) -> Self {
if v {
self.0 |= 0x02;
} else {
self.0 &= 0x02u8.not();
}
self
}
#[must_use]
pub fn set_italic(mut self, v: bool) -> Self {
if v {
self.0 |= 0x04;
} else {
self.0 &= 0x04u8.not();
}
self
}
#[must_use]
pub fn set_blinking(mut self, v: bool) -> Self {
if v {
self.0 |= 0x08;
} else {
self.0 &= 0x08u8.not();
}
self
}
#[must_use]
pub fn set_reversed(mut self, v: bool) -> Self {
if v {
self.0 |= 0x10;
} else {
self.0 &= 0x10u8.not();
}
self
}
#[must_use]
pub fn set_struck(mut self, v: bool) -> Self {
if v {
self.0 |= 0x20;
} else {
self.0 &= 0x20u8.not();
}
self
}
}
#[derive(Debug)]
pub struct VTerm {
pub characters: [[VtermCharacter; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize],
pub cursor_visible: bool,
/// Internal ID of the vterm
iid: u32,
/// The internal representation of the vterm
style: Style,
/// The cursor position in layout x,y
cursor_position: (u32, u32),
key_buff: Vec<char>,
}
impl Default for VTerm {
fn default() -> Self {
VTerm {
iid: 0,
characters: [[VtermCharacter {
character: 0x00 as char,
char_color: (0xff_ff_ff_ff, 0x00_00_00_00),
style: Style::default(),
}; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize],
cursor_position: (0, 0),
cursor_visible: true,
style: Style::default(),
key_buff: vec![],
}
}
}
/// The primitive interface for a vterm
impl VTerm {
pub fn new() -> Self {
let mut vterm = VTerm::default();
let mut vtc = VIRTUAL_TERMINAL_COUNT.load(Ordering::Relaxed);
vterm.iid = vtc;
vtc += 1;
VIRTUAL_TERMINAL_COUNT.store(vtc, Ordering::Relaxed);
vterm
}
/// Set the vterm cursor to the given position
pub fn set_cursor_position(&mut self, x: u32, y: u32) {
if x > VTERM_WIDTH {
self.cursor_position.0 = VTERM_WIDTH;
error!("Cursor x position out of bounds");
} else {
self.cursor_position.0 = x;
}
if y > VTERM_HEIGHT {
error!("Cursor y position out of bounds");
self.cursor_position.1 = VTERM_HEIGHT;
} else {
self.cursor_position.1 = y;
}
}
/// Set the vterm style
pub fn set_vterm_style(&mut self, style: Style) {
self.style = style;
}
}
impl CharacterDevice for VTerm {
fn can_read(&self) -> bool {
true
}
fn can_write(&self) -> bool {
true
}
fn read_char(&mut self) -> Option<char> {
if let Some(c) = self.key_buff.pop() {
return Some(c);
}
None
}
fn write_char(&mut self, c: char) -> bool {
match c {
'\n' => {
self.cursor_position.1 += 1;
self.cursor_position.0 = 0;
true
}
'\r' => {
self.cursor_position.0 = 0;
true
}
'\t' => {
self.cursor_position.0 += 4;
true
}
'\x08' => {
self.cursor_position.0 -= 1;
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
.character = ' ';
true
}
// This is a form feed, which is used to clear the screen
'\x0c' => {
self.characters = [[VtermCharacter {
character: ' ',
char_color: (0xff_ff_ff_ff, 0x00_00_00_00),
style: Style::default(),
}; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize];
true
}
_ => {
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
.character = c;
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
.char_color = (0xff_ff_ff_ff, 0x00_00_00_00);
self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize]
.style = self.style;
if self.cursor_position.0 < VTERM_WIDTH {
self.cursor_position.0 += 1;
true
} else {
self.cursor_position.0 = 0;
self.cursor_position.1 += 1;
true
}
}
}
}
fn reset(&mut self) {
self.characters = [[VtermCharacter {
character: ' ',
char_color: (0xff_ff_ff_ff, 0x00_00_00_00),
style: Style::default(),
}; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize];
self.cursor_position = (0, 0);
self.cursor_visible = true;
self.style = Style::default();
}
fn initialize(&mut self) -> bool {
true
}
}

View file

@ -1,14 +0,0 @@
#[derive(Debug)]
pub enum Vendor {
Unknown = 0,
Ati = 1002,
}
pub fn match_vendor(id: u16) -> Vendor {
use Vendor::*;
match id {
1002 => Ati,
_ => Unknown,
}
}

View file

@ -1,59 +0,0 @@
pub mod character_devs;
mod dev_vterm;
pub mod id;
pub mod pci;
pub use self::Device::*;
use crate::device_interface::{BlockDevice, CharacterDevice};
use crate::devices::dev_vterm::VTerm;
use character_devs::{dev_null::DevNull, dev_unicode::DevUnicode, dev_zero::DevZero};
use hashbrown::HashMap;
use spin::Lazy;
pub static DEVICE_TABLE: Lazy<spin::Mutex<DeviceTable>> =
Lazy::new(|| spin::Mutex::new(DeviceTable::new()));
// FIXME: This is a hack to hold a device.
// #[derive(Debug)]
pub enum Device {
Block(Box<dyn BlockDevice>),
Character(Box<dyn CharacterDevice>),
Vterm(Box<VTerm>),
}
unsafe impl Sync for Device {}
unsafe impl Send for Device {}
pub struct DeviceTable {
pub devices: HashMap<String, Device>,
}
impl DeviceTable {
pub fn new() -> Self {
DeviceTable {
devices: [
("null", Character(Box::new(DevNull))),
("zero", Character(Box::new(DevZero))),
(
"unicode",
Character(Box::new(DevUnicode {
next_write_char: 0x00 as char,
next_read_char: 0x00 as char,
})),
),
("kvterm", Vterm(Box::new(VTerm::new()))),
]
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect(),
}
}
}
impl Default for DeviceTable {
fn default() -> Self {
Self::new()
}
}

View file

@ -1,240 +0,0 @@
/*
* Copyright (c) 2022, able <abl3theabove@gmail.com>
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
use core::fmt::Display;
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
/// Class specification for a PCI device
pub enum PciClass {
Unclassified = 0x00,
MassStorage = 0x01,
Network = 0x02,
Display = 0x03,
Multimedia = 0x04,
Memory = 0x05,
Bridge = 0x06,
Unknown = 0xFF,
}
impl From<u8> for PciClass {
/// Convert a u8 into the corresponding PciClass
fn from(n: u8) -> Self {
use PciClass::*;
match n {
0x00 => Unclassified,
0x01 => MassStorage,
0x02 => Network,
0x03 => Display,
0x04 => Multimedia,
0x05 => Memory,
0x06 => Bridge,
_ => Unknown,
}
}
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
/// Full class specification (type and subtype) for a PCI device.
///
/// Uses non-camel-case types for readability.
pub enum PciFullClass {
Unclassified_NonVgaCompatible = 0x0000,
Unclassified_VgaCompatible = 0x0001,
MassStorage_ScsiBus = 0x0100,
MassStorage_IDE = 0x0101,
MassStorage_Floppy = 0x0102,
MassStorage_IpiBus = 0x0103,
MassStorage_RAID = 0x0104,
MassStorage_ATA = 0x0105,
MassStorage_SATA = 0x0106,
MassStorage_SerialSCSI = 0x0107,
MassStorage_NVM = 0x0108,
MassStorage_Other = 0x0180,
Network_Ethernet = 0x0200,
Network_TokenRing = 0x0201,
Network_FDDI = 0x0202,
Network_ATM = 0x0203,
Network_ISDN = 0x0204,
Network_WorldFlip = 0x0205,
Network_PICMG = 0x0206,
Network_Infiniband = 0x0207,
Network_Fabric = 0x0208,
Network_Other = 0x0280,
Display_VGA = 0x0300,
Display_XGA = 0x0301,
Display_3D = 0x0302,
Display_Other = 0x0380,
Multimedia_Video = 0x0400,
Multimedia_AudioController = 0x0401,
Multimedia_Telephony = 0x0402,
Multimedia_AudioDevice = 0x0403,
Multimedia_Other = 0x0480,
Memory_RAM = 0x0500,
Memory_Flash = 0x0501,
Memory_Other = 0x0580,
Bridge_Host = 0x0600,
Bridge_ISA = 0x0601,
Bridge_EISA = 0x0602,
Bridge_MCA = 0x0603,
Bridge_PciToPci = 0x0604,
Bridge_PCMCIA = 0x0605,
Bridge_NuBus = 0x0606,
Bridge_CardBus = 0x0607,
Bridge_RACEway = 0x0608,
Bridge_PciToPciSemiTransparent = 0x0609,
Bridge_InfinibandToPci = 0x060A,
Bridge_Other = 0x0680,
Unknown = 0xFFFF,
}
impl PciFullClass {
// listen, i know this sucks, but i didn't want to include
// `num`, `num-traits` and `num-derive` as dependencies for
// this crate just for a convenience function
/// Convert a u16 into the corresponding PciFullClass
pub fn from_u16(n: u16) -> PciFullClass {
match n {
0x0000 => PciFullClass::Unclassified_NonVgaCompatible,
0x0001 => PciFullClass::Unclassified_VgaCompatible,
0x0100 => PciFullClass::MassStorage_ScsiBus,
0x0101 => PciFullClass::MassStorage_IDE,
0x0102 => PciFullClass::MassStorage_Floppy,
0x0103 => PciFullClass::MassStorage_IpiBus,
0x0104 => PciFullClass::MassStorage_RAID,
0x0105 => PciFullClass::MassStorage_ATA,
0x0106 => PciFullClass::MassStorage_SATA,
0x0107 => PciFullClass::MassStorage_SerialSCSI,
0x0108 => PciFullClass::MassStorage_NVM,
0x0180 => PciFullClass::MassStorage_Other,
0x0200 => PciFullClass::Network_Ethernet,
0x0201 => PciFullClass::Network_TokenRing,
0x0202 => PciFullClass::Network_FDDI,
0x0203 => PciFullClass::Network_ATM,
0x0204 => PciFullClass::Network_ISDN,
0x0205 => PciFullClass::Network_WorldFlip,
0x0206 => PciFullClass::Network_PICMG,
0x0207 => PciFullClass::Network_Infiniband,
0x0208 => PciFullClass::Network_Fabric,
0x0280 => PciFullClass::Network_Other,
0x0300 => PciFullClass::Display_VGA,
0x0301 => PciFullClass::Display_XGA,
0x0302 => PciFullClass::Display_3D,
0x0380 => PciFullClass::Display_Other,
0x0400 => PciFullClass::Multimedia_Video,
0x0401 => PciFullClass::Multimedia_AudioController,
0x0402 => PciFullClass::Multimedia_Telephony,
0x0403 => PciFullClass::Multimedia_AudioDevice,
0x0480 => PciFullClass::Multimedia_Other,
0x0500 => PciFullClass::Memory_RAM,
0x0501 => PciFullClass::Memory_Flash,
0x0580 => PciFullClass::Memory_Other,
0x0600 => PciFullClass::Bridge_Host,
0x0601 => PciFullClass::Bridge_ISA,
0x0602 => PciFullClass::Bridge_EISA,
0x0603 => PciFullClass::Bridge_MCA,
0x0604 => PciFullClass::Bridge_PciToPci,
0x0605 => PciFullClass::Bridge_PCMCIA,
0x0606 => PciFullClass::Bridge_NuBus,
0x0607 => PciFullClass::Bridge_CardBus,
0x0608 => PciFullClass::Bridge_RACEway,
0x0609 => PciFullClass::Bridge_PciToPciSemiTransparent,
0x060A => PciFullClass::Bridge_InfinibandToPci,
0x0680 => PciFullClass::Bridge_Other,
_ => PciFullClass::Unknown,
}
}
/// Convert a PciFullClass to its u16 representation
pub fn as_u16(&self) -> u16 {
*self as u16
}
}
impl From<u16> for PciFullClass {
/// Convert a u16 into the corresponding PciFullClass
fn from(n: u16) -> Self {
Self::from_u16(n)
}
}
impl Display for PciFullClass {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, " Class: ")?;
match self {
PciFullClass::Unclassified_NonVgaCompatible => write!(f, "\0LIGHTBLUE\0")?,
PciFullClass::Unclassified_VgaCompatible => write!(f, "\0LIGHTBLUE\0")?,
PciFullClass::MassStorage_ScsiBus => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_IDE => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_Floppy => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_IpiBus => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_RAID => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_ATA => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_SATA => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_SerialSCSI => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_NVM => write!(f, "\0CYAN\0")?,
PciFullClass::MassStorage_Other => write!(f, "\0CYAN\0")?,
PciFullClass::Network_Ethernet => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_TokenRing => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_FDDI => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_ATM => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_ISDN => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_WorldFlip => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_PICMG => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_Infiniband => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_Fabric => write!(f, "\0MAGENTA\0")?,
PciFullClass::Network_Other => write!(f, "\0MAGENTA\0")?,
PciFullClass::Display_VGA => write!(f, "\0YELLOW\0")?,
PciFullClass::Display_XGA => write!(f, "\0YELLOW\0")?,
PciFullClass::Display_3D => write!(f, "\0YELLOW\0")?,
PciFullClass::Display_Other => write!(f, "\0YELLOW\0")?,
PciFullClass::Multimedia_Video => write!(f, "\0LIGHTBLUE\0")?,
PciFullClass::Multimedia_AudioController => write!(f, "\0LIGHTBLUE\0")?,
PciFullClass::Multimedia_Telephony => write!(f, "\0LIGHTBLUE\0")?,
PciFullClass::Multimedia_AudioDevice => write!(f, "\0LIGHTBLUE\0")?,
PciFullClass::Multimedia_Other => write!(f, "\0LIGHTBLUE\0")?,
PciFullClass::Memory_RAM => write!(f, "\0BLUE\0")?,
PciFullClass::Memory_Flash => write!(f, "\0WHITE\0")?,
PciFullClass::Memory_Other => write!(f, "\0LIGHTGREY\0")?,
PciFullClass::Bridge_Host => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_ISA => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_EISA => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_MCA => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_PciToPci => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_PCMCIA => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_NuBus => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_CardBus => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_RACEway => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_PciToPciSemiTransparent => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_InfinibandToPci => write!(f, "\0GREEN\0")?,
PciFullClass::Bridge_Other => write!(f, "\0GREEN\0")?,
PciFullClass::Unknown => write!(f, "\0RED\0")?,
}
write!(f, "{:?} ({:#06X})\0RESET\0", self, self.as_u16())?;
Ok(())
}
}

View file

@ -1,194 +0,0 @@
/*
* Copyright (c) 2022, able <abl3theabove@gmail.com>
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
use core::fmt;
use x86_64::instructions::port::Port;
use super::{
vendors::Vendor::{self, *},
PciClass, PciFullClass,
};
// FIXME: Unknown class
pub const S3_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900);
// MassStorage_IDE (0x0101)
pub const INTEL_PIIX3_IDE: DeviceID = DeviceID::new(IntelCorp, 0x7010);
pub const INTEL_PIIX4_IDE: DeviceID = DeviceID::new(IntelCorp, 0x7111);
// Display_VGA (0x0300)
pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMWareInc, 0x0405);
#[derive(Copy, Clone, Debug)]
/// A struct containing info about a PCI device.
pub struct PciDeviceInfo {
pub header_type: u8,
pub device: u8,
pub bus: u8,
pub device_id: DeviceID,
pub full_class: PciFullClass,
pub rev_id: u8,
}
impl PciDeviceInfo {
/// Get the class of the PCI device as a PciClass
pub fn class(&self) -> PciClass {
(((self.full_class.as_u16() >> 8) & 0xFF) as u8).into()
}
/// Get the bar, 0-indexed
pub fn bar(&self, bar: u8) -> u32 {
assert!(bar < 6);
unsafe { self.read(0, 0x10 + bar * 4) }
}
/// Get the interrupt pin
pub fn interrupt_pin(&self) -> u8 {
let last_row = unsafe { self.read(0, 0x3C) };
((last_row >> 8) & 0xFF) as u8
}
/// Enable bus mastering. This allows the PCI device to do DMA
pub fn enable_bus_mastering(&self) {
let command = unsafe { self.read(0, 4) } | 1 << 2;
unsafe { self.write(0, 4, command) }
}
/// Read from configuration space
pub unsafe fn read(&self, func: u8, offset: u8) -> u32 {
pci_config_read(self.bus, self.device, func, offset)
}
/// Write to IO space
pub unsafe fn write(&self, func: u8, offset: u8, value: u32) {
pci_config_write(self.bus, self.device, func, offset, value)
}
}
impl fmt::Display for PciDeviceInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let vendor_name = &self.device_id.vendor;
let device_id = &self.device_id.id;
writeln!(
f,
"Device: {} | Bus: 0x{:X} | Vendor: {} | Device ID: 0x{:X}",
self.device, self.bus, vendor_name, device_id,
)?;
writeln!(f, "{}", self.full_class)?;
writeln!(f, " Header type: 0x{:X}", self.header_type)?;
writeln!(f, " Revision ID: {}", self.rev_id)?;
// write!(f, " Supported functions: 0")?;
// for (i, b) in self.supported_fns.iter().enumerate().skip(1) {
// if *b {
// write!(f, ", {}", i)?;
// }
// }
// writeln!(f)?;
// write!(f, " BARs: [ ")?;
// for i in self.bars.iter() {
// if *i == 0 {
// write!(f, "0x0 ")?;
// } else {
// write!(f, "{:#010X} ", i)?;
// }
// }
// writeln!(f, "]")?;
// writeln!(
// f,
// " Interrupt line / pin: {} / {}",
// self.interrupt_line, self.interrupt_pin
// )?;
Ok(())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DeviceID {
pub vendor: Vendor,
pub id: u16,
}
impl DeviceID {
pub const fn new(vendor: Vendor, id: u16) -> Self {
Self { vendor, id }
}
}
pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
assert!(device < 32);
let (device_id, vendor_id) = get_ids(bus, device, 0);
if vendor_id == 0xFFFF {
// Device doesn't exist
return None;
}
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
let class = ((reg2 >> 16) & 0x0000FFFF) as u16;
let pci_class = PciFullClass::from_u16(class);
let header_type = get_header_type(bus, device, 0);
Some(PciDeviceInfo {
header_type,
device,
bus,
device_id: DeviceID {
vendor: vendor_id.into(),
id: device_id,
},
full_class: pci_class,
rev_id: (reg2 & 0x000000FF) as u8,
})
}
unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
let bus = bus as u32;
let device = device as u32;
let func = func as u32;
let offset = offset as u32;
// construct address param
let address =
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32;
// write address
Port::new(0xCF8).write(address);
// read data
Port::new(0xCFC).read()
}
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
let bus = bus as u32;
let device = device as u32;
let func = func as u32;
let offset = offset as u32;
// construct address param
let address =
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32;
// write address
Port::new(0xCF8).write(address);
// write data
Port::new(0xCFC).write(value);
}
fn get_header_type(bus: u8, device: u8, function: u8) -> u8 {
assert!(device < 32);
assert!(function < 8);
let res = unsafe { pci_config_read(bus, device, function, 0x0C) };
((res >> 16) & 0xFF) as u8
}
fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) {
assert!(device < 32);
assert!(function < 8);
let res = unsafe { pci_config_read(bus, device, function, 0) };
let dev_id = ((res >> 16) & 0xFFFF) as u16;
let vnd_id = (res & 0xFFFF) as u16;
(dev_id, vnd_id)
}

View file

@ -1,674 +0,0 @@
/*
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
use core::num::TryFromIntError;
// FIXME: platform agnostic-ify these
use x86_64::instructions::{interrupts, port::Port};
use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB};
use x86_64::structures::paging::{FrameAllocator, FrameDeallocator};
use x86_64::VirtAddr;
use crate::arch::memory::BootInfoFrameAllocator;
use crate::devices::pci::check_device;
use super::PciDeviceInfo;
// FIXME: un-hardcode these
const PRDT_START: u64 = 0xffff_ffff_0000_0000;
const BUFFER_START: u64 = 0xffff_ffff_0000_1000;
/// ATA logical sector size, in bytes
const SECTOR_SIZE: u16 = 512;
/// Bus Master IDE Command
const BMIC_OFFSET: u16 = 0;
/// Bus Master IDE Status
const BMIS_OFFSET: u16 = 2;
/// Bus Master IDE Descriptor Table Pointer
const BMIDTP_OFFSET: u16 = 4;
/// Bus Master IDE Secondary Offset
const BMI_SECONDARY: u16 = 8;
/// Primary command block offset
const PRIMARY_COMMAND: u16 = 0x01F0;
/// Secondary command block offset
const SECONDARY_COMMAND: u16 = 0x0170;
/// Data register offset
const DATA_OFFSET: u16 = 0;
/// Sector count register offset
const SECCOUNT_OFFSET: u16 = 2;
/// LBA0 register offset
const LBA0_OFFSET: u16 = 3;
/// LBA1 register offset
const LBA1_OFFSET: u16 = 4;
/// LBA2 register offset
const LBA2_OFFSET: u16 = 5;
/// Drive/Head register offset
const DRIVE_HEAD_OFFSET: u16 = 6;
/// Command/status register offset
const COMMAND_STATUS_OFFSET: u16 = 7;
/// Secondary control block offset
const SECONDARY_CONTROL: u16 = 0x0374;
/// Primary control block offset
const PRIMARY_CONTROL: u16 = 0x03F4;
/// Alternative status offset
const ALT_STATUS_OFFSET: u16 = 2;
/// ATA identification command
const CMD_IDENTIFY: u8 = 0xEC;
/// ATA read using LBA28 DMA command
const CMD_READ_DMA: u8 = 0xC8;
/// ATA write using LBA28 DMA command
const CMD_WRITE_DMA: u8 = 0xCA;
/// ATA read using LBA48 DMA command
const CMD_READ_DMA_EXT: u8 = 0x25;
/// ATA write using LBA48 DMA command
const CMD_WRITE_DMA_EXT: u8 = 0x35;
pub struct PciIde {
device_info: PciDeviceInfo,
ide_devices: Vec<IdeDevice>,
prdt_frame: Option<PhysFrame>,
buffer_frames: Option<Vec<PhysFrame>>,
bmiba: u16,
}
impl PciIde {
// FIXME: make this return a Result
pub fn new(bus: u8, device: u8) -> Option<Self> {
let device_info = check_device(bus, device)?;
device_info.enable_bus_mastering();
let idetim = unsafe { device_info.read(0, 0x40) };
trace!("idetim: {idetim:b}");
// FIXME: enable the right bits in idetim (and sidetim) to use fast timings
let mut ide_devices = Vec::with_capacity(4);
for ch in 0..2 {
let channel = if ch == 0 {
Channel::Primary
} else {
Channel::Secondary
};
'drive: for dr in 0..2 {
let drive = if dr == 0 { Drive::Master } else { Drive::Slave };
unsafe {
select_drive(drive, channel);
// FIXME: clear sector count and lba0, lba1, lba2 registers
let status = ata_send_command(CMD_IDENTIFY, channel);
if status == 0 {
continue; // If status = 0, no device
}
loop {
let status = {
let addr = if channel.secondary() {
SECONDARY_COMMAND
} else {
PRIMARY_COMMAND
} + COMMAND_STATUS_OFFSET;
Port::<u8>::new(addr).read()
};
if status & 1 == 1 {
// if error (bit 0), device is not ATA
// FIXME: ATAPI devices
continue 'drive;
}
if !((status >> 7) & 1 == 1) && (status >> 3) & 1 == 1 {
// BSY cleared, DRQ set, everything is right
break;
}
}
// Read identification space of device
let addr = if channel.secondary() {
SECONDARY_COMMAND
} else {
PRIMARY_COMMAND
} + DATA_OFFSET;
let mut buffer = [0_u8; 512];
read_dword_buffer(addr, buffer.as_mut_ptr() as *mut _, 128);
// for (i, byte) in buffer.iter().enumerate() {
// if byte.is_ascii() {
// trace!("byte {i}: {byte:b}, ascii: {}", *byte as char);
// } else {
// trace!("byte {i}: {byte:b}");
// }
// }
if buffer[99] & 1 != 1 {
// FIXME: PIO mode support
error!("IDE drive {channel:?}/{drive:?} does not support DMA");
continue;
}
// FIXME: CHS support
let lba48 = (buffer[167] >> 2) & 1 == 1;
let size = buffer[200] as u64
| (buffer[201] as u64) << 8
| (buffer[202] as u64) << 16
| (buffer[203] as u64) << 24
| (buffer[204] as u64) << 32
| (buffer[205] as u64) << 40
| (buffer[206] as u64) << 48
| (buffer[207] as u64) << 54;
trace!("IDE drive {channel:?}/{drive:?} has {size} sectors");
ide_devices.push(IdeDevice {
channel,
drive,
size,
lba48_support: lba48,
});
}
}
}
let bmiba = device_info.bar(4) & 0xFFFFFFFC;
Some(Self {
device_info,
ide_devices,
prdt_frame: None,
buffer_frames: None,
bmiba: bmiba.try_into().ok()?,
})
}
pub fn allocate_dma_frame(
&mut self,
mapper: &mut impl Mapper<Size4KiB>,
frame_allocator: &mut BootInfoFrameAllocator,
) -> Result<(), MapToError<Size4KiB>> {
use x86_64::structures::paging::PageTableFlags as Flags;
let prdt_frame = frame_allocator
.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
let buffer_frames = {
let mut frame = frame_allocator
.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
while !frame.start_address().is_aligned(0x10000u64) {
unsafe {
frame_allocator.deallocate_frame(frame);
}
frame = frame_allocator
.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
}
let mut frames = Vec::with_capacity(16);
frames.push(frame);
for _ in 0..15 {
let frame = frame_allocator
.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
frames.push(frame);
}
frames
};
let flags = Flags::NO_CACHE | Flags::PRESENT | Flags::WRITABLE;
unsafe {
mapper
.map_to(
Page::containing_address(VirtAddr::new(PRDT_START)),
prdt_frame,
flags,
frame_allocator,
)?
.flush();
for (i, frame) in buffer_frames.iter().enumerate() {
mapper
.map_to(
Page::containing_address(VirtAddr::new(BUFFER_START + i as u64 * 0x1000)),
*frame,
flags,
frame_allocator,
)?
.flush()
}
}
self.prdt_frame = Some(prdt_frame);
self.buffer_frames = Some(buffer_frames);
Ok(())
}
pub fn read(
&mut self,
channel: Channel,
drive: Drive,
lba: u64,
sector_count: u16,
buffer: &mut Vec<u8>,
) -> Result<(), TryFromIntError> {
let lba48_support = self
.ide_devices
.iter()
.find(|d| d.channel == channel && d.drive == drive)
.map(|d| d.lba48_support)
.unwrap(); // FIXME: make this an error
let lba48 = lba > 0xFFFFFFF && lba48_support;
// FIXME: make this an error
assert!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF));
let byte_count = sector_count * SECTOR_SIZE;
// prepare PRD table
let prd = PRDT_START as *mut PhysRegionDescriptor;
unsafe {
(*prd).data_buffer = self.buffer_frames.as_ref().unwrap()[0]
.start_address()
.as_u64()
.try_into()?;
(*prd).byte_count = byte_count;
// this is the end of table
(*prd).eot = 1 << 7;
// this byte is reserved, we should probably set it to 0
(*prd)._0 = 0;
}
unsafe {
self.load_prdt(channel);
self.stop(channel);
self.set_read(channel);
self.clear_bmi_status(channel);
select_drive(drive, channel);
set_lba(channel, lba, sector_count, lba48);
if lba48 {
ata_send_command(CMD_READ_DMA_EXT, channel);
} else {
ata_send_command(CMD_READ_DMA, channel);
}
self.start(channel);
}
loop {
let status = unsafe { self.bmi_status(channel) };
// FIXME: error handling
// Bit 2 (INT) set?
if (status >> 2) & 1 == 1 {
break;
}
}
unsafe {
// Stop DMA
self.stop(channel);
// Clear the interrupt bit
self.clear_bmi_status(channel);
}
for i in 0..byte_count as u64 {
let addr = (BUFFER_START + i) as *mut u8;
buffer.push(unsafe { *addr });
}
Ok(())
}
pub fn write(
&mut self,
channel: Channel,
drive: Drive,
lba: u64,
data: &[u8],
) -> Result<(), TryFromIntError> {
// FIXME: make this an error
assert!(data.len() % SECTOR_SIZE as usize == 0);
let lba48_support = self
.ide_devices
.iter()
.find(|d| d.channel == channel && d.drive == drive)
.map(|d| d.lba48_support)
.unwrap(); // FIXME: make this an error
let lba48 = lba > 0xFFFFFFF && lba48_support;
// FIXME: make this an error
assert!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF));
let byte_count = data.len() as u16;
let sector_count = byte_count / SECTOR_SIZE;
// prepare PRD table
let prd = PRDT_START as *mut PhysRegionDescriptor;
unsafe {
(*prd).data_buffer = self.buffer_frames.as_ref().unwrap()[0]
.start_address()
.as_u64()
.try_into()?;
(*prd).byte_count = byte_count;
// this is the end of table
(*prd).eot = 1 << 7;
// this byte is reserved, we should probably set it to 0
(*prd)._0 = 0;
}
// copy the data over to the DMA buffer
for i in 0..byte_count {
let addr = (BUFFER_START + i as u64) as *mut u8;
unsafe {
*addr = *data.get(i as usize).unwrap_or(&0);
}
}
unsafe {
self.load_prdt(channel);
self.stop(channel);
self.set_write(channel);
self.clear_bmi_status(channel);
select_drive(drive, channel);
set_lba(channel, lba, sector_count, lba48);
if lba48 {
ata_send_command(CMD_WRITE_DMA_EXT, channel);
} else {
ata_send_command(CMD_WRITE_DMA, channel);
}
self.start(channel);
}
loop {
let status = unsafe { self.bmi_status(channel) };
// FIXME: error handling
// Bit 2 (INT) set?
if (status >> 2) & 1 == 1 {
break;
}
}
unsafe {
// Stop DMA
self.stop(channel);
// Clear the interrupt bit
self.clear_bmi_status(channel);
}
Ok(())
}
pub fn device_info(&self) -> PciDeviceInfo {
self.device_info
}
unsafe fn load_prdt(&self, channel: Channel) {
let addr = if channel.secondary() {
BMI_SECONDARY
} else {
0
} + self.bmiba
+ BMIDTP_OFFSET;
Port::<u32>::new(addr).write(
self.prdt_frame
.unwrap()
.start_address()
.as_u64()
.try_into()
.unwrap(),
);
}
unsafe fn start(&self, channel: Channel) {
let addr = if channel.secondary() {
BMI_SECONDARY
} else {
0
} + self.bmiba
+ BMIC_OFFSET;
let mut port: Port<u8> = Port::new(addr);
let mut bmic = port.read();
// start transfer
bmic |= 1;
// write the new bmic
port.write(bmic);
}
unsafe fn stop(&self, channel: Channel) {
let addr = if channel.secondary() {
BMI_SECONDARY
} else {
0
} + self.bmiba
+ BMIC_OFFSET;
let mut port: Port<u8> = Port::new(addr);
let mut bmic = port.read();
// stop ongoing transfer
bmic &= !1;
// write the new bmic
port.write(bmic);
}
unsafe fn set_read(&self, channel: Channel) {
let addr = if channel.secondary() {
BMI_SECONDARY
} else {
0
} + self.bmiba
+ BMIC_OFFSET;
let mut port: Port<u8> = Port::new(addr);
let mut bmic = port.read();
// mark bit 3 as 0 (read)
bmic &= !(1 << 3);
// write the new bmic
port.write(bmic);
}
unsafe fn set_write(&self, channel: Channel) {
let addr = if channel.secondary() {
BMI_SECONDARY
} else {
0
} + self.bmiba
+ BMIC_OFFSET;
let mut port: Port<u8> = Port::new(addr);
let mut bmic = port.read();
// mark bit 3 as 1 (write)
bmic |= 1 << 3;
// write the new bmic
port.write(bmic);
}
unsafe fn bmi_status(&self, channel: Channel) -> u8 {
let addr = if channel.secondary() {
BMI_SECONDARY
} else {
0
} + self.bmiba
+ BMIS_OFFSET;
let mut port = Port::new(addr);
port.read()
}
unsafe fn clear_bmi_status(&self, channel: Channel) {
let addr = if channel.secondary() {
BMI_SECONDARY
} else {
0
} + self.bmiba
+ BMIS_OFFSET;
let mut port: Port<u8> = Port::new(addr);
let mut bmis = port.read();
// write 1 to bits 1 (DMA error) and 2 (int status) which clears them
bmis |= 1 << 1 | 1 << 2;
// write the new bmis
port.write(bmis);
}
}
unsafe fn select_drive(drive: Drive, channel: Channel) {
let addr = if channel.secondary() {
SECONDARY_COMMAND
} else {
PRIMARY_COMMAND
} + DRIVE_HEAD_OFFSET;
let mut port: Port<u8> = Port::new(addr);
// FIXME: CHS support
let drive_command = if drive.slave() {
// slave & LBA
0b11110000
} else {
// master & LBA
0b11100000
};
// write the new drive/head register
port.write(drive_command);
ata_delay(channel);
}
/// Send ATA command and read status afterwards
unsafe fn ata_send_command(command: u8, channel: Channel) -> u8 {
let addr = if channel.secondary() {
SECONDARY_COMMAND
} else {
PRIMARY_COMMAND
} + COMMAND_STATUS_OFFSET;
let mut port = Port::new(addr);
port.write(command);
ata_delay(channel);
port.read()
}
/// Read the alternate status register 14 times to create a ~420ns delay
unsafe fn ata_delay(channel: Channel) {
let addr = if channel.secondary() {
SECONDARY_CONTROL
} else {
PRIMARY_CONTROL
} + ALT_STATUS_OFFSET;
let mut port: Port<u8> = Port::new(addr);
for _ in 0..14 {
port.read();
}
}
/// Set LBA and sector count registers. sector_count of 0 means 65536 sectors
unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16, lba48: bool) {
let command_block = if channel.secondary() {
SECONDARY_COMMAND
} else {
PRIMARY_COMMAND
};
let mut seccount = Port::new(command_block + SECCOUNT_OFFSET);
let mut lba0 = Port::new(command_block + LBA0_OFFSET);
let mut lba1 = Port::new(command_block + LBA1_OFFSET);
let mut lba2 = Port::new(command_block + LBA2_OFFSET);
let mut head = Port::new(command_block + DRIVE_HEAD_OFFSET);
let head_value: u8 = head.read();
let lba_bytes = lba.to_le_bytes();
let sector_count_bytes = sector_count.to_le_bytes();
// write the new LBA & sector count registers
// FIXME: CHS support
if lba48 {
seccount.write(sector_count_bytes[1]);
lba0.write(lba_bytes[3]);
lba1.write(lba_bytes[4]);
lba2.write(lba_bytes[5]);
} else {
head.write(head_value | (lba_bytes[3] & 0x0F));
}
seccount.write(sector_count_bytes[0]);
lba0.write(lba_bytes[0]);
lba1.write(lba_bytes[1]);
lba2.write(lba_bytes[2]);
}
unsafe fn read_dword_buffer(port: u16, buffer: *mut u32, mut count: u32) {
// FIXME: this assumes x86-64
interrupts::without_interrupts(|| {
asm!("
cld
repne
insd",
in("di") buffer,
in("dx") port,
inout("cx") count,
)
});
}
struct IdeDevice {
pub channel: Channel,
pub drive: Drive,
pub size: u64, // in sectors
pub lba48_support: bool,
// FIXME: model
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Channel {
Primary,
Secondary,
}
impl Channel {
fn secondary(&self) -> bool {
matches!(self, Self::Secondary)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Drive {
Master,
Slave,
}
impl Drive {
fn slave(&self) -> bool {
matches!(self, Self::Slave)
}
}
#[repr(C, packed)]
struct PhysRegionDescriptor {
/// Pointer to the data buffer
pub data_buffer: u32,
/// Byte count, 64K maximum per PRD transfer. 0 means 64K
pub byte_count: u16,
/// Reserved byte
pub _0: u8,
/// MSB marks end of transfer
pub eot: u8,
}

View file

@ -1,71 +0,0 @@
/*
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
pub mod class;
pub mod device;
pub mod vendors;
// MassStorage_IDE (0x0101)
pub mod ide;
use alloc::sync::Arc;
pub use class::*;
pub use device::*;
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::structures::paging::{Mapper, Size4KiB};
use crate::arch::memory::BootInfoFrameAllocator;
// MassStorage_IDE (0x0101)
use self::ide::PciIde;
lazy_static! {
pub static ref PCI_DEVICES: Mutex<Vec<Arc<Mutex<PciDevice>>>> = Default::default();
}
#[non_exhaustive]
pub enum PciDevice {
Ide(PciIde),
// Variant so that we aren't about irrefutable if-let patterns
// FIXME: remove as soon as we have other variants
_0,
}
/// Enumerate PCI devices and run initialisation routines on ones we support
pub fn init(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut BootInfoFrameAllocator) {
for bus in 0..=255 {
for device in 0..32 {
if let Some(device_info) = device::check_device(bus, device) {
trace!("{device_info}");
match device_info.device_id {
// FIXME: Unknown class
S3_TRIO64V2 => {}
// MassStorage_IDE (0x0101)
ide_controller if device_info.full_class == PciFullClass::MassStorage_IDE => {
if !matches!(ide_controller, INTEL_PIIX3_IDE | INTEL_PIIX4_IDE) {
// not one of our tested IDE controllers, but
// we shouldn't have any problems
warn!("Unsupported PCI IDE controller device {device} on bus {bus}")
}
let mut ide = PciIde::new(bus, device).unwrap();
ide.allocate_dma_frame(mapper, frame_allocator).unwrap();
let mut devices = PCI_DEVICES.lock();
devices.push(Arc::new(Mutex::new(PciDevice::Ide(ide))));
}
// Display_VGA (0x0300)
VMWARE_SVGA2 => {}
_ => {
trace!("Unknown PCI device {device} on bus {bus}")
}
}
}
}
}
}

View file

@ -1,180 +0,0 @@
/*
* Copyright (c) 2022, able <abl3theabove@gmail.com>
*
* SPDX-License-Identifier: MPL-2.0
*/
use core::fmt::Display;
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
#[repr(u16)]
pub enum Vendor {
ThreeDfxInteractiveInc = 0x121a,
ThreeDLabs = 0x3d3d,
AllianceSemiconductorCorp = 0x1142,
ARKLogicInc = 0xedd8,
ATITechnologiesInc = 0x1002,
AvanceLogicIncALI = 0x1005,
ChipsandTechnologies = 0x102c,
CirrusLogic = 0x1013,
Compaq = 0x0e11,
CyrixCorp = 0x1078,
DiamondMultimediaSystems = 0x1092,
DigitalEquipmentCorp = 0x1011,
Iit = 0x1061,
IntegratedMicroSolutionsInc = 0x10e0,
IntelCorp = 0x8086,
IntergraphicsSystems = 0x10ea,
MacronixInc = 0x10d9,
MatroxGraphicsInc = 0x102b,
MiroComputersProductsAG = 0x1031,
NationalSemiconductorCorp = 0x100b,
NeoMagicCorp = 0x10c8,
Number9ComputerCompany = 0x105d,
NVidiaCorporation = 0x10de,
NVidiaSgsthomson = 0x12d2,
OakTechnologyInc = 0x104e,
Qemu = 0x1234,
QuantumDesignsHKLtd = 0x1098,
Real3D = 0x003d,
Rendition = 0x1163,
S3Inc = 0x5333,
SierraSemiconductor = 0x10a8,
SiliconIntegratedSystemsSiS = 0x1039,
SiliconMotionInc = 0x126f,
STBSystemsInc = 0x10b4,
TexasInstruments = 0x104c,
ToshibaAmericaInfoSystems = 0x1179,
TridentMicrosystems = 0x1023,
TsengLabsInc = 0x100c,
TundraSemiconductorCorp = 0x10e3,
VIATechnologiesInc = 0x1106,
VirtIO = 0x1AF4,
VMWareInc = 0x15ad,
Weitek = 0x100e,
Unknown(u16),
}
impl From<u16> for Vendor {
fn from(vendor_id: u16) -> Self {
use Vendor::*;
match vendor_id {
0x121a => ThreeDfxInteractiveInc,
0x3d3d => ThreeDLabs,
0x1142 => AllianceSemiconductorCorp,
0xedd8 => ARKLogicInc,
0x1002 => ATITechnologiesInc,
0x1005 => AvanceLogicIncALI,
0x102c => ChipsandTechnologies,
0x1013 => CirrusLogic,
0x0e11 => Compaq,
0x1078 => CyrixCorp,
0x1092 => DiamondMultimediaSystems,
0x1011 => DigitalEquipmentCorp,
0x1061 => Iit,
0x10e0 => IntegratedMicroSolutionsInc,
0x8086 => IntelCorp,
0x10ea => IntergraphicsSystems,
0x10d9 => MacronixInc,
0x102b => MatroxGraphicsInc,
0x1031 => MiroComputersProductsAG,
0x100b => NationalSemiconductorCorp,
0x10c8 => NeoMagicCorp,
0x105d => Number9ComputerCompany,
0x10de => NVidiaCorporation,
0x12d2 => NVidiaSgsthomson,
0x104e => OakTechnologyInc,
0x1234 => Qemu,
0x1098 => QuantumDesignsHKLtd,
0x003d => Real3D,
0x1163 => Rendition,
0x5333 => S3Inc,
0x10a8 => SierraSemiconductor,
0x1039 => SiliconIntegratedSystemsSiS,
0x126f => SiliconMotionInc,
0x10b4 => STBSystemsInc,
0x104c => TexasInstruments,
0x1179 => ToshibaAmericaInfoSystems,
0x1023 => TridentMicrosystems,
0x100c => TsengLabsInc,
0x10e3 => TundraSemiconductorCorp,
0x1106 => VIATechnologiesInc,
0x1AF4 => VirtIO,
0x15ad => VMWareInc,
0x100e => Weitek,
id => Unknown(id),
}
}
}
impl Into<u16> for Vendor {
fn into(self) -> u16 {
use Vendor::*;
match self {
ThreeDfxInteractiveInc => 0x121a,
ThreeDLabs => 0x3d3d,
AllianceSemiconductorCorp => 0x1142,
ARKLogicInc => 0xedd8,
ATITechnologiesInc => 0x1002,
AvanceLogicIncALI => 0x1005,
ChipsandTechnologies => 0x102c,
CirrusLogic => 0x1013,
Compaq => 0x0e11,
CyrixCorp => 0x1078,
DiamondMultimediaSystems => 0x1092,
DigitalEquipmentCorp => 0x1011,
Iit => 0x1061,
IntegratedMicroSolutionsInc => 0x10e0,
IntelCorp => 0x8086,
IntergraphicsSystems => 0x10ea,
MacronixInc => 0x10d9,
MatroxGraphicsInc => 0x102b,
MiroComputersProductsAG => 0x1031,
NationalSemiconductorCorp => 0x100b,
NeoMagicCorp => 0x10c8,
Number9ComputerCompany => 0x105d,
NVidiaCorporation => 0x10de,
NVidiaSgsthomson => 0x12d2,
OakTechnologyInc => 0x104e,
Qemu => 0x1234,
QuantumDesignsHKLtd => 0x1098,
Real3D => 0x003d,
Rendition => 0x1163,
S3Inc => 0x5333,
SierraSemiconductor => 0x10a8,
SiliconIntegratedSystemsSiS => 0x1039,
SiliconMotionInc => 0x126f,
STBSystemsInc => 0x10b4,
TexasInstruments => 0x104c,
ToshibaAmericaInfoSystems => 0x1179,
TridentMicrosystems => 0x1023,
TsengLabsInc => 0x100c,
TundraSemiconductorCorp => 0x10e3,
VIATechnologiesInc => 0x1106,
VirtIO => 0x1AF4,
VMWareInc => 0x15ad,
Weitek => 0x100e,
Unknown(id) => id,
}
}
}
impl Display for Vendor {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use Vendor::*;
match self {
Qemu => write!(f, "{}", "\0PINK\0QEMU (0x1234)"),
VirtIO => write!(f, "{}", "\0PINK\0VirtIO (0x1AF4)"),
VMWareInc => write!(f, "{}", "\0PINK\0VMWARE (0x15AD)"),
S3Inc => write!(f, "{}", "\0YELLOW\0S3 Incorporated (0x5333)"),
IntelCorp => write!(f, "{}", "\0BLUE\0Intel Corp. (0x8086)"),
ATITechnologiesInc => write!(f, "{}", "\0RED\0ATI (0x1002)"),
Unknown(id) => write!(f, "\0RED\0Unknown ({:#6})", id),
other => write!(f, "{other:?}"),
}?;
write!(f, "\0RESET\0")?;
Ok(())
}
}

View file

@ -1,44 +0,0 @@
#![allow(unused)]
pub const REFRESH_RATE: u8 = 60;
pub type RefreshRate = u8;
pub type Resolution = (usize, usize);
pub type Point = (GCoord, GCoord);
pub type GCoord = usize;
pub enum GModes {
Vga800x600,
Custom(u16, u16),
}
// TODO remap to a bitmasked u32
// REASON: More effecient memory wise so less overhead on the wasm memory
// Current: u32+u32+u32
// Proposed: u32 with bitmaps
pub struct Rgb {
pub r: u32,
pub g: u32,
pub b: u32,
}
impl Rgb {
fn to_vga_color() {
todo!();
}
}
pub struct FrameBuffer;
pub trait Graphics {
fn put_line(coords_start: Point, coords_end: Point, thickness: u32, color: Rgb);
fn put_rect(coords_start: Point, coords_end: Point, color: Rgb);
fn put_circle(coords: Point, radius: u32);
fn put_pixel(coords: Point, color: Rgb);
fn put_triangle(coords_1: Point, coords_2: Point, coords_3: Point, thickness: u32, color: Rgb);
fn paint_cursor(coords: Point);
fn hide_cursor();
fn show_cursor();
/// Actually move the double buffer to the single buffer and "update" the screen
fn draw();
fn clear();
}

View file

@ -1,2 +0,0 @@
pub mod graphics;
pub mod serial;

View file

@ -1,16 +0,0 @@
// TODO: Bitmasking
pub enum Mouse {
Button1,
Button2,
Button3,
Button4,
Button5,
X(i8),
Y(i8),
Wheel(i8),
}
pub trait PS2Mouse {
fn movement();
fn button();
}

View file

@ -1,37 +0,0 @@
use crate::device_interface::CharacterDevice;
pub struct Serial {
pub base: usize,
}
impl CharacterDevice for Serial {
fn can_read(&self) -> bool {
true
}
fn can_write(&self) -> bool {
true
}
fn read_char(&mut self) -> Option<char> {
todo!()
}
fn write_char(&mut self, _c: char) -> bool {
todo!()
}
fn reset(&mut self) {
todo!()
}
fn initialize(&mut self) -> bool {
false
}
}
pub fn new_serial_test() {
let mut serial = Serial { base: 0x3F8 };
serial.initialize();
serial.write_char('a');
}

View file

@ -1 +0,0 @@
Anything in experiments is heavily unstable and likely to change

View file

@ -1,107 +0,0 @@
use logos::{Lexer, Logos};
// TODO improve tokenizer/parser
pub fn colorify(eval: &str) {
let y = eval.split('$');
for z in y {
match z {
"BLACK" => {
// set_vga_color(Color::Black, Color::Black);
}
"RED" => {
// set_vga_color(Color::Red, Color::Black);
}
"GREEN" => {
// set_vga_color(Color::Green, Color::Black);
}
"BLUE" => {
// set_vga_color(Color::Blue, Color::Black);
}
"CYAN" => {
// set_vga_color(Color::Cyan, Color::Black);
}
"MAGENTA" => {
// set_vga_color(Color::Magenta, Color::Black);
}
"BROWN" => {
// set_vga_color(Color::Brown, Color::Black);
}
"LIGHTGRAY" => {
// set_vga_color(Color::LightGray, Color::Black);
}
"DARKGRAY" => {
// set_vga_color(Color::DarkGray, Color::Black);
}
"LIGHTBLUE" => {
// set_vga_color(Color::LightBlue, Color::Black);
}
"LIGHTGREEN" => {
// set_vga_color(Color::LightGreen, Color::Black);
}
"LIGHTCYAN" => {
// set_vga_color(Color::LightCyan, Color::Black);
}
"LIGHTRED" => {
// set_vga_color(Color::LightRed, Color::Black);
}
"PINK" => {
// set_vga_color(Color::Pink, Color::Black);
}
"YELLOW" => {
// set_vga_color(Color::Yellow, Color::Black);
}
"WHITE" => {
// set_vga_color(Color::White, Color::Black);
}
"RESET" => {
// set_vga_color(Color::White, Color::Black);
}
_elk => {
// kprint!("{}", elk);
}
}
}
}
#[derive(Logos, Debug, PartialEq)]
pub enum Token {
// Hex(u32),
#[regex(r"\$RED\$")]
Red,
#[regex(r"\$RESET\$")]
Reset,
#[regex("[a-zA-Z!@#$%^&*\">()\n ]+", parse_text, priority = 2)]
Text(String),
#[error]
#[regex(r"[ \t\n\f]+", logos::skip)]
Error,
}
pub fn colorify_2(eval: &str) {
let lexer = Token::lexer(eval);
for token in lexer {
use Token::*;
match token {
Red => {
// set_vga_color(Color::Red, Color::Black);
}
Reset => {
// set_vga_color(Color::White, Color::Black);
}
Text(_text) => {
// kprint!("{}", text);
}
err => {
error!("Error parsing {:?}", err);
}
}
}
}
fn parse_text(lex: &mut Lexer<Token>) -> Option<String> {
let slice = lex.slice();
Some(String::from(slice))
}

View file

@ -1,7 +0,0 @@
##### #####
## ##### # ###### ## ## # #
# # # # # # # # #
# # ##### # ##### # # #####
###### # # # # # # #
# # # # # # ## ## # #
# # ##### ###### ###### ##### #####

View file

@ -1,53 +0,0 @@
use alloc::{string::String, vec, vec::Vec};
pub static CLIPBOARD: spin::Mutex<Clipboard> = spin::Mutex::new(Clipboard::new());
#[derive(Debug)]
pub enum Mime {
None,
Text(String),
}
// ctrl+v paste but not pop and pastes
// ctrl+shift+v pops from the stack and pastes
// ctrl+c pushes to the stack
// ctrl+shift+< move stack pointer left
// ctrl+shift+> move stack pointer right
pub struct Clipboard {
pub index: usize,
pub pages: Vec<Mime>,
}
impl Clipboard {
pub const fn new() -> Clipboard {
Clipboard {
index: 0,
pages: vec![],
}
}
pub fn clear(&mut self) {
self.pages = vec![];
}
pub fn set_index(&mut self, index_new: usize) {
self.index = index_new;
}
pub fn clip_end(&mut self) {
self.index = 0;
}
pub fn clip_home(&mut self) {
self.index = self.pages.len();
}
pub fn copy(&mut self, copy_mime: Mime) {
self.pages.push(copy_mime);
}
pub fn paste(&mut self) -> &Mime {
&self.pages[self.index] as _
}
}

View file

@ -1,22 +0,0 @@
struct Permissions {
write_files: bool,
read_files: bool,
execute_files: bool,
// Every other user is part of global
global_write_files: bool,
global_read_files: bool,
global_execute_files: bool,
}
pub struct File {
owner: u8,
permissions: Permissions,
data: Vec<u8>,
}
pub struct Folder {
owner: u8,
permissions: Permissions,
folders: Vec<Folder>,
files: Vec<File>,
}

View file

@ -1,15 +0,0 @@
<user>/home/app1
<user>/conf/app1
<user>/apps/app1
file:app1
conf:app1
apps:app1
// Discouraged
raw:
/<user>/<protocol>/app1
protocol.toml
hi = ""

View file

@ -1,57 +0,0 @@
use core::time::Duration;
pub struct AtomicU32(u32);
impl AtomicU32 {
//if v != current value
pub fn wait(&self, _v: u32) {
todo!();
}
pub fn wait_timeout(&self, _v: u32, _timeout: Duration) -> bool {
todo!();
}
pub fn wake_single(&self) {
todo!();
}
pub fn wake_all(&self) {
todo!();
}
}
/*
// SUPER HANDWAVEY
// YOU WILL NEED LOCKING THAT I DIDNT WRITE OUT (you == zuurr#9735)
// all the red is by design
pub fn futex_wait(atom: &AtomicU32, value: usize, current_thread: ThreadID) {
let address = atomic as *const _ as usize;
let waiters = waiters_for(address); // Hold lock
waiters.add(current_thread);
if self.load() == value {
current_thread.sleep();
} else {
waiters.remove(current_thread);
}
}
pub fn futex_wake(atom: &AtomicU32, threads_to_wake: usize) {
let address = atomic as *const _ as usize;
let waiters = waiters_for(address);
for waiting_thread in waiters.into_iter().take(threads_to_wake) {
waiting_thread.wake()
}
}
*/
struct FutexWaitlist {
address: u8,
// data: Vec<ThreadID>,
}
impl FutexWaitlist {
pub fn remove(&mut self) {
todo!();
}
pub fn add(&mut self) {
todo!();
}
}

View file

@ -1,75 +0,0 @@
use super::systeminfo::SystemMemory;
use crate::arch::drivers::sysinfo::master;
use core::fmt::Display;
use kernel::allocator::ALLOCATOR;
use versioning::Version;
use x86_64::instructions::interrupts::{disable, enable};
pub enum CpuType {
RiscV(String),
X86_64(String),
}
impl Display for CpuType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{}",
match self {
CpuType::RiscV(s) => s,
CpuType::X86_64(s) => s,
}
)
}
}
/// simple info you would want to know in a neofetch like program
pub struct KernelInfo {
// os: String,
// host: String,
pub kernel_version: Version,
pub cpu: CpuType,
// gpu: String,
pub memory: SystemMemory,
}
impl KernelInfo {
pub fn get() -> KernelInfo {
disable();
let allocator = ALLOCATOR.lock();
let total = allocator.size();
let used = allocator.used();
enable();
let cpu = CpuType::X86_64(master().unwrap().brand_string().unwrap().to_string());
KernelInfo {
kernel_version: Version {
major: 0,
minor: 0,
patch: 0,
},
cpu,
memory: SystemMemory { total, used },
}
}
}
impl Display for KernelInfo {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"
OS: AbleOS
Host: {{}}
Kernel: {}.{}.{}
CPU: {}
Memory: {}/{}
",
self.kernel_version.major,
self.kernel_version.minor,
self.kernel_version.patch,
self.cpu,
self.memory.used,
self.memory.total
)
}
}

View file

@ -1,113 +0,0 @@
#![allow(dead_code)]
// TODO: Evaluate variable sized mailboxes
pub struct MailBoxes {
flags: u8,
mailboxes: [u64; 4],
}
impl MailBoxes {
pub fn new() -> Self {
Self {
flags: 0b0000_0000,
mailboxes: [0; 4],
}
}
pub fn reset(&mut self) {
self.flags = 0b0000_0000;
self.mailboxes = [0; 4];
}
pub fn set_mailbox(&mut self, mailbox_num: u8, mailbox_data: u64) {
if let 0..=3 = mailbox_num {
self.mailboxes[mailbox_num as usize] = mailbox_data
}
}
pub fn set_flag(&mut self, flag_num: u8) {
match flag_num {
0 => {
self.flags |= 0b0000_0001;
}
1 => {
self.flags |= 0b0000_0010;
}
2 => {
self.flags |= 0b0000_0100;
}
3 => {
self.flags |= 0b0000_1000;
}
4 => {
self.flags |= 0b0001_0000;
}
5 => {
self.flags |= 0b0010_0000;
}
6 => {
self.flags |= 0b0100_0000;
}
7 => {
self.flags |= 0b1000_0000;
}
_ => {}
}
}
pub fn dump_flags(&self) {
trace!(
"Flag 0: {:08b} | {}",
self.flags & 0b0000_0001,
self.flags & 0b0000_0001
);
trace!(
"Flag 1: {:08b} | {}",
self.flags & 0b0000_0010,
self.flags >> 1 & 0b0000_0001
);
trace!(
"Flag 2: {:08b} | {}",
self.flags & 0b0000_0100,
self.flags >> 2 & 0b0000_0001
);
trace!(
"Flag 3: {:08b} | {}",
self.flags & 0b0000_1000,
self.flags >> 3 & 0b0000_0001
);
trace!(
"Flag 4: {:08b} | {}",
self.flags & 0b0001_0000,
self.flags >> 4 & 0b0000_0001
);
trace!(
"Flag 5: {:08b} | {}",
self.flags & 0b0010_0000,
self.flags >> 5 & 0b0000_0001
);
trace!(
"Flag 6: {:08b} | {}",
self.flags & 0b0100_0000,
self.flags >> 6 & 0b0000_0001
);
trace!(
"Flag 7: {:08b} | {}",
self.flags & 0b1000_0000,
self.flags >> 7 & 0b0000_0001
);
}
}
impl Default for MailBoxes {
fn default() -> Self {
Self::new()
}
}

View file

@ -1,13 +0,0 @@
#![allow(dead_code)]
pub mod absi;
pub mod clip;
pub mod futex;
pub mod kinfo;
pub mod mail;
pub mod server;
pub mod systeminfo;
pub mod virtual_memory;
pub mod y_compositor;
pub const BANNER: &str = include_str!("banner.txt");

View file

@ -1,7 +0,0 @@
pub type thumbnail = u8;
pub struct Notification {
thumbnail: thumbnail,
text_body: String,
time: u64,
}

View file

@ -1,45 +0,0 @@
use crate::experiments::kinfo::SemanticVersion;
// Scuffed
pub type Hash = u8;
pub type PackageName = String;
pub struct MetaPackage {
pub name: u8,
pub version: SemanticVersion,
pub authors: [u8; 8],
pub support_email: u8,
pub hash: Hash,
}
impl MetaPackage {
pub fn new() -> Self {
Self {
name: 0,
version: SemanticVersion {
major: 0,
minor: 0,
patch: 0,
},
authors: [0; 8],
support_email: 8,
hash: 0,
}
}
fn validate_hash(&self) {}
}
impl core::fmt::Display {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"Packname: {}
Version: {}
Authors: {:?}
Support Email: {}
Hash: {}",
self.name, self.version, self.authors, self.support_email, self.hash
)
}
}

View file

@ -1,13 +0,0 @@
pub trait Server {
/// Initialize the server and return a number
fn initialize() -> u32;
/// kill the server
fn kill() -> bool;
// put data in the servers outbox
fn send();
// put data in the servers inbox and notify it
fn recieve();
}

View file

@ -1,39 +0,0 @@
| low \\ high | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
| ----------- | ------------------- | ------------------------ | ------------------------------------------------------------------------------------------ | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
| 0 | **kill** | <sub>reserved</sub> | **sleep** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 1 | **stdout_reset** | <sub>reserved</sub> | **sleep_until** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 2 | **stdin** | <sub>reserved</sub> | [**nanosleep**](https://www.reddit.com/r/anime/comments/e7sg7g/nichijou_trouble_sleeping/) | **aes_encrypt** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 3 | **stdout** | <sub>reserved</sub> | **nanosleep_until** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 4 | **stdin_get_title** | <sub>reserved</sub> | **get_time** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 5 | **stdin_set_title** | <sub>reserved</sub> | **set_time** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 6 | **get_pid** | **make_directory** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 7 | **pinfo** | **delete_directory** | **socket_bind** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 8 | <sub>reserved</sub> | **rename_directory** | **socket_connect** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 9 | <sub>reserved</sub> | **set_directory_access** | **socket_disconnect** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| A | **set_priority** | **make_file** | **socket_send** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| B | **get_priority** | **delete_file** | **socket_receive** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| C | **get_hostname** | **rename_file** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| D | **set_hostname** | **set_file_access** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| E | <sub>reserved</sub> | **file_read** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| F | <sub>reserved</sub> | **file_write** | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| low \\ high | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 1A | 1B | 1C | 1D | 1E | 1F |
| ----------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
| 0 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 1 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 2 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 3 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 4 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 5 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 6 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 7 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 8 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| 9 | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| A | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| B | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| C | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| D | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| E | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |
| F | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> | <sub>reserved</sub> |

View file

@ -1,21 +0,0 @@
// Can be standardized
// NOTE: move the file to the src/ dir
pub const KERNEL_VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(debug_assertions)]
/// A constant to check if the kernel is in debug mode
pub const RELEASE_TYPE: &str = "debug";
#[cfg(not(debug_assertions))]
/// A constant to check if the kernel is in release mode
pub const RELEASE_TYPE: &str = "release";
pub struct SystemMemory {
pub used: usize,
pub total: usize,
}
impl core::fmt::Display for SystemMemory {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{} Bytes / {} Bytes", self.used, self.total)
}
}

View file

@ -1,4 +0,0 @@
pub struct User {
id: u8,
clipboard: Clipboard,
}

View file

@ -1,7 +0,0 @@
#![allow(dead_code)]
pub struct Scheduler {
executables: usize,
}
pub struct RunQueue;

View file

@ -1,12 +0,0 @@
pub struct Compositor;
impl Compositor {
pub fn new() -> Self {
Self
}
}
impl Default for Compositor {
fn default() -> Self {
Self::new()
}
}

View file

@ -1,3 +0,0 @@
//!
pub mod compositor;
pub mod window;

View file

@ -1,37 +0,0 @@
// use crate::driver_traits::graphics::Point;
pub type MenuBar = Vec<MenuOption>;
pub struct MenuOption {
symbol: char,
}
pub struct Window {
title: String,
// position: Point,
fullscreen: bool,
}
// all of these should return a result
impl Window {
pub fn new(title: String, /*position: Point,*/ fullscreen: bool) -> Self {
Self {
title,
// position,
fullscreen,
}
}
pub fn fullscreen(&mut self) {
self.fullscreen = true;
}
pub fn revert_fullscreen(&mut self) {
self.fullscreen = false;
}
pub fn set_title(&mut self) {
todo!();
}
pub fn set_position(&mut self /*pos: Point*/) {
// self.position = pos;
}
}

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
#[derive(Copy, Clone, Debug)]
pub enum FsError {
EndOfFile,
InodeNotFound,
InvalidDevice,
InvalidPath,
IsDirectory,
NotAbsolute,
NotADirectory,
NotFound,
Recursion,
UnsupportedOperation,
}
impl Into<FsError> for ext2::error::Error {
fn into(self) -> FsError {
match self {
ext2::error::Error::Other(_) => todo!(),
ext2::error::Error::BadMagic { magic: _ } => todo!(),
ext2::error::Error::OutOfBounds { index: _ } => todo!(),
ext2::error::Error::AddressOutOfBounds {
sector: _,
offset: _,
size: _,
} => todo!(),
ext2::error::Error::BadBlockGroupCount {
by_blocks: _,
by_inodes: _,
} => todo!(),
ext2::error::Error::InodeNotFound { inode: _ } => FsError::InodeNotFound,
ext2::error::Error::NotADirectory { inode: _, name: _ } => FsError::NotADirectory,
ext2::error::Error::NotAbsolute { name: _ } => todo!(),
ext2::error::Error::NotFound { name: _ } => FsError::NotFound,
}
}
}

View file

@ -1,177 +0,0 @@
/*
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
use alloc::sync::{Arc, Weak};
use ext2::fs::{sync::Synced, Ext2};
use ext2::sector::SectorSize;
use ext2::sys::inode::TypePerm;
use ext2::volume::Volume;
use crate::handle::{Handle, HandleResource};
use super::errors::FsError;
use super::vfs::{DirectoryEntry, FsFlags, VirtualFileSystem, VFS};
use super::{FsNode, FsResult as Result, StorageDevice};
pub struct Ext2StorageDevice<S, V>
where
S: SectorSize,
V: Volume<u8, S>,
{
fs: Synced<Ext2<S, V>>,
device_handle: Handle,
root_handle: Handle,
}
impl<S, V> Ext2StorageDevice<S, V>
where
S: SectorSize,
V: Volume<u8, S>,
{
pub fn new(volume: V) -> Result<Self> {
let fs = Synced::new(volume).map_err(|e| e.into())?;
let root_inode = fs.root_inode();
let device_handle = Handle::new(HandleResource::StorageDevice);
let root = Arc::new(FsNode::new(
FsFlags::DIRECTORY,
root_inode.size(),
2,
device_handle,
Weak::new(),
));
let mut vfs = VFS.lock();
let root_handle = vfs.add_fs_node(root.clone());
Ok(Self {
fs,
device_handle,
root_handle,
})
}
}
impl<S, V> StorageDevice for Ext2StorageDevice<S, V>
where
S: SectorSize + Send,
V: Volume<u8, S> + Send,
{
fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<()> {
let inode = self
.fs
.inode_nth(node.inode() as usize)
.ok_or_else(|| FsError::InodeNotFound)?;
// FIXME: I don't really know how Ext2 works, so for now we don't
// support non-zero offsets and buffer sizes that don't match
// the file length. We always read the whole file.
if offset > 0 || size != inode.size() {
Err(FsError::UnsupportedOperation)?;
}
inode.read_to_end(buffer).map_err(|e| e.into())?;
Ok(())
}
fn write(&self, _node: &FsNode, _offset: usize, _buffer: &[u8]) -> Result<()> {
todo!()
}
fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry> {
let inode = self
.fs
.inode_nth(node.inode() as usize)
.ok_or_else(|| FsError::InodeNotFound)?;
let mut dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?;
let entry = dir
.nth(index)
.ok_or_else(|| FsError::InodeNotFound)?
.map_err(|e| e.into())?;
let entry_inode = self
.fs
.inode_nth(entry.inode)
.ok_or_else(|| FsError::InodeNotFound)?;
let mut vfs = VFS.lock();
let entry_node_handle = vfs
.find_fs_node(entry.inode, self.device_handle)
.unwrap_or_else(|| {
vfs.add_fs_node(Arc::new(FsNode::new(
ext2_type_to_fs_flags(entry_inode.type_perm()),
entry_inode.size(),
entry.inode,
self.device_handle,
Weak::new(),
)))
});
Ok(DirectoryEntry::new(
entry.file_name_string(),
entry_node_handle,
))
}
fn find_dir(&self, vfs: &mut VirtualFileSystem, node: &FsNode, name: &str) -> Result<Handle> {
let inode = self
.fs
.inode_nth(node.inode() as usize)
.ok_or_else(|| FsError::InodeNotFound)?;
let dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?;
let mut found_node = Err(FsError::NotFound);
for entry in dir {
if entry.is_err() {
continue;
}
let entry = entry.unwrap();
let entry_inode = self
.fs
.inode_nth(entry.inode as usize)
.ok_or_else(|| FsError::InodeNotFound)?;
if entry.file_name_string() == name {
found_node = Ok(vfs
.find_fs_node(entry.inode, self.device_handle)
.unwrap_or_else(|| {
vfs.add_fs_node(Arc::new(FsNode::new(
ext2_type_to_fs_flags(entry_inode.type_perm()),
entry_inode.size(),
entry.inode,
self.device_handle,
Weak::new(),
)))
}));
break;
}
}
found_node
}
fn root(&self) -> Handle {
self.root_handle
}
fn device_handle(&self) -> Handle {
self.device_handle
}
}
fn ext2_type_to_fs_flags(type_perm: TypePerm) -> FsFlags {
trace!("{type_perm:?}");
let is_directory = type_perm & TypePerm::DIRECTORY == TypePerm::DIRECTORY;
let is_symlink = type_perm & TypePerm::SYMLINK == TypePerm::SYMLINK;
let t = if is_directory {
FsFlags::DIRECTORY
} else {
FsFlags::FILE
};
let s = if is_symlink {
FsFlags::SYMBOLIC_LINK
} else {
FsFlags::empty()
};
t | s
}

View file

@ -1,90 +0,0 @@
/*
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
pub mod errors;
pub mod ext2;
pub mod vfs;
use ::ext2::sector::Size1024;
use alloc::sync::Arc;
use crate::{filesystem::vfs::VFS, handle::Handle, KERNEL_STATE};
use self::{
errors::FsError,
ext2::Ext2StorageDevice,
vfs::{DirectoryEntry, FsNode, VirtualFileSystem},
};
use FsResult as Result;
pub type FsResult<T> = core::result::Result<T, FsError>;
/// The methods on this trait are to be used internally.
pub trait StorageDevice
where
Self: Send,
{
fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<()>;
fn write(&self, node: &FsNode, offset: usize, buffer: &[u8]) -> Result<()>;
fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry>;
fn find_dir(&self, vfs: &mut VirtualFileSystem, node: &FsNode, name: &str) -> Result<Handle>;
// TODO: flush to disk
fn root(&self) -> Handle;
fn device_handle(&self) -> Handle;
}
pub fn init() -> Result<()> {
let mut state = KERNEL_STATE.lock();
let fs = load_fs()?;
let mut vfs = VFS.lock();
vfs.set_root(fs.root())?;
state.add_storage_device(fs);
Ok(())
}
fn load_fs() -> Result<Ext2StorageDevice<Size1024, Vec<u8>>> {
let mut volume = Vec::new();
volume.extend_from_slice(include_bytes!("../../../userland/root_fs/ext2.img"));
Ext2StorageDevice::new(volume)
}
pub fn tree(path: &str) -> Result<()> {
let dir = {
let mut vfs = VFS.lock();
let handle = vfs.resolve(path)?;
vfs.fs_node(handle).ok_or_else(|| FsError::NotFound)?
};
tree_inner(
dir,
if path.starts_with('/') {
&path[1..]
} else {
path
},
);
Ok(())
}
fn tree_inner<S: Into<String>>(dir: Arc<FsNode>, path: S) {
let path = path.into();
if let Some(dir) = dir.directory() {
for entry in dir {
let fs_node = {
let vfs = VFS.lock();
vfs.fs_node(entry.node()).unwrap()
};
println!("{}/{} => {}", path, entry.name(), fs_node.inode());
trace!("{entry:#?}");
if entry.name() != "." && entry.name() != ".." {
tree_inner(fs_node, format!("{}/{}", path, entry.name()));
}
}
}
}

View file

@ -1,305 +0,0 @@
/*
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
use core::cmp;
use alloc::sync::{Arc, Weak};
use hashbrown::HashMap;
use lazy_static::lazy_static;
use spin::Mutex;
use super::{errors::FsError, FsResult as Result};
use crate::{
handle::{Handle, HandleResource},
KERNEL_STATE,
};
/// The limit for symlink recursion. In POSIX, this is at least 8. In Linux, this is 40.
const SYMLINK_RECURSION_LIMIT: u8 = 8;
lazy_static! {
pub static ref VFS: Mutex<VirtualFileSystem> = Default::default();
}
pub struct VirtualFileSystem {
fs_nodes: HashMap<Handle, Arc<FsNode>>,
root_node: Weak<FsNode>,
root_handle: Option<Handle>,
}
impl VirtualFileSystem {
/// Sets the VFS root to the given VFS node handle.
pub fn set_root(&mut self, handle: Handle) -> Result<()> {
let root_node = self.fs_node(handle).ok_or_else(|| FsError::NotFound)?;
self.root_node = Arc::downgrade(&root_node);
self.root_handle = Some(handle);
Ok(())
}
/// Resolves the path to a handle. If the resulting node is a symlink,
/// the symlink itself is returned. All symlinks but the resulting node
/// are traversed.
///
/// Requires a mutable reference because internally it might open new VFS
/// nodes while resolving the path.
pub fn resolve<S: AsRef<str>>(&mut self, path: S) -> Result<Handle> {
// TODO: caching
let path = path.as_ref();
if !path.starts_with('/') {
// FIXME: use current process working directory for relative paths?
Err(FsError::NotAbsolute)?;
}
let mut components = path.split_terminator('/');
components.next(); // throw the empty string caused by the root /
// will be initialised beforehand so okay to unwrap
let mut resolved_node = self.root_handle.unwrap();
// let mut symlink_recursion_level = 0;
for component in components {
// if symlink_recursion_level >= SYMLINK_RECURSION_LIMIT {
// Err(FsError::Recursion)?;
// }
if component == "" {
Err(FsError::InvalidPath)?;
}
// checked by previous iteration so okay to unwrap
let parent = self.fs_node(resolved_node).unwrap();
// TODO: permission checks
// FIXME: find_dir checks that this is a directory already but
// that's just more boilerplate in StorageDevice impls
// we should probably check that here instead to reduce
// required boilerplate
// if !parent.is_dir() {
// Err(FsError::NotADirectory)?;
// }
// FIXME: handle mount points
// FIXME: handle symlinks
resolved_node = parent.find_dir(self, component)?;
}
Ok(resolved_node)
}
pub fn add_fs_node(&mut self, fs_node: Arc<FsNode>) -> Handle {
let handle = Handle::new(HandleResource::FsNode);
self.fs_nodes.insert(handle, fs_node);
handle
}
pub fn find_fs_node(&mut self, inode: usize, device_handle: Handle) -> Option<Handle> {
self.fs_nodes.iter().find_map(|(handle, fs_node)| {
if fs_node.inode == inode && fs_node.device_handle == device_handle {
Some(*handle)
} else {
None
}
})
}
pub fn fs_node(&self, handle: Handle) -> Option<Arc<FsNode>> {
self.fs_nodes.get(&handle).cloned()
}
pub fn root_node(&self) -> Arc<FsNode> {
// okay to unwrap since this should never be called before init
self.root_node.upgrade().unwrap()
}
}
impl Default for VirtualFileSystem {
fn default() -> Self {
Self {
fs_nodes: HashMap::new(),
root_node: Weak::new(),
root_handle: None,
}
}
}
/// A VFS node, that can either be a file or a directory.
///
/// VFS nodes are created whenever a file that doesn't have an open VFS node is
/// opened. When there are no open file descriptors to a file, the associated
/// VFS node is dropped.
#[derive(Debug)]
pub struct FsNode {
flags: FsFlags,
size: usize, // in bytes
inode: usize, // implementation specific identifier for the node
device_handle: Handle, // uniquely assigned device handle
ptr: Weak<FsNode>, // used by mountpoints and symlinks
// TODO: permissions mask
// TODO: owning user/group
}
impl FsNode {
pub fn new(
flags: FsFlags,
size: usize,
inode: usize,
device_handle: Handle,
ptr: Weak<FsNode>,
) -> Self {
Self {
flags,
size,
inode,
device_handle,
ptr,
}
}
/// This method opens a new file descriptor for this VFS node.
// TODO: make this take flags
pub fn open(self: Arc<Self>) -> Result<Handle> {
let mut state = KERNEL_STATE.lock();
let handle = state.open_file_descriptor(self);
Ok(handle)
}
/// This method reads from the VFS node without opening a new file
/// descriptor. This is intended to be used internally, if you're trying to
/// read a file then you probably want to read from a file descriptor.
pub fn read(&self, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<usize> {
let state = KERNEL_STATE.lock();
let device = state
.storage_device(self.device_handle)
.ok_or_else(|| FsError::InvalidDevice)?;
if self.is_dir() {
Err(FsError::IsDirectory)?;
}
if offset > self.size {
Err(FsError::EndOfFile)?;
}
let readable_size = cmp::min(size, self.size - offset);
device.read(self, offset, readable_size, buffer)?;
Ok(readable_size)
}
/// This method writes to the VFS node without opening a new file
/// descriptor. This is intended to be used internally, if you're trying to
/// write to a file then you probably want to write to a file descriptor.
pub fn write(&self, offset: usize, buffer: &[u8]) -> Result<()> {
let state = KERNEL_STATE.lock();
let device = state
.storage_device(self.device_handle)
.ok_or_else(|| FsError::InvalidDevice)?;
device.write(self, offset, buffer)
}
pub fn read_dir(&self, index: usize) -> Result<DirectoryEntry> {
let state = KERNEL_STATE.lock();
let device = state
.storage_device(self.device_handle)
.ok_or_else(|| FsError::InvalidDevice)?;
device.read_dir(self, index)
}
pub fn find_dir(&self, vfs: &mut VirtualFileSystem, name: &str) -> Result<Handle> {
let state = KERNEL_STATE.lock();
let device = state
.storage_device(self.device_handle)
.ok_or_else(|| FsError::InvalidDevice)?;
device.find_dir(vfs, self, name)
}
pub fn directory(self: Arc<Self>) -> Option<Directory> {
if self.is_dir() {
Some(Directory::new(self))
} else {
None
}
}
pub fn is_dir(&self) -> bool {
(self.flags & FsFlags::DIRECTORY) == FsFlags::DIRECTORY
}
pub fn inode(&self) -> usize {
self.inode
}
pub fn size(&self) -> usize {
self.size
}
}
impl Drop for FsNode {
fn drop(&mut self) {
trace!("dropping VFS node: {self:#?}");
// TODO: flush to disk here
}
}
bitflags! {
/// Flags associated with VFS nodes and file descriptors
///
/// 0x00000MST \
/// T is set to 0 for files, 1 for directories \
/// S is set when the file is a symbolic link \
/// M is set if the file is an active mount point
pub struct FsFlags: u8 {
const FILE = 0b00000000;
const DIRECTORY = 0b00000001;
const SYMBOLIC_LINK = 0b00000010;
const MOUNT_POINT = 0b00000100;
}
}
pub struct Directory {
node: Arc<FsNode>,
index: usize,
}
impl Directory {
fn new(node: Arc<FsNode>) -> Self {
Self { node, index: 0 }
}
}
impl Iterator for Directory {
type Item = DirectoryEntry;
fn next(&mut self) -> Option<Self::Item> {
let value = self.node.read_dir(self.index).ok();
self.index += 1;
value
}
}
#[derive(Clone, Debug)]
pub struct DirectoryEntry {
name: String,
node: Handle,
}
impl DirectoryEntry {
pub(super) fn new(name: String, node: Handle) -> Self {
Self { name, node }
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn node(&self) -> Handle {
self.node
}
}

View file

@ -1,342 +0,0 @@
pub mod pixel_format;
use spin::Lazy;
use vga::{colors::Color16, writers::GraphicsWriter};
use crate::vga_e::VGAE;
use pixel_format::*;
pub static SCREEN_BUFFER: Lazy<spin::Mutex<ScreenBuffer>> =
Lazy::new(|| spin::Mutex::new(ScreenBuffer::new(640, 480)));
const FONT_SCALE: f32 = 1.6;
const GLYPH_HEIGHT: f32 = 18.0;
const GLYPH_WIDTH: f32 = 10.0;
#[derive(Debug)]
pub struct ScreenSize {
pub x: usize,
pub y: usize,
}
impl ScreenSize {
pub fn new(x: usize, y: usize) -> Self {
Self { x, y }
}
}
pub enum GraphicsReturn {
Ok,
ImproperScreenSize,
}
pub struct ScreenBuffer {
pub size: ScreenSize,
pub clear_color: Rgba64,
pub buff: Box<[Rgba64]>,
}
impl ScreenBuffer {
// Add optional size later
pub fn new(x: usize, y: usize) -> Self {
Self {
size: ScreenSize::new(x, y),
clear_color: 0,
buff: vec![0u64; x * y].into_boxed_slice(),
}
}
pub fn draw_filled_circle(&mut self, cx: i32, cy: i32, radius: usize, color: Rgba64) {
let r = radius as i32 * 2;
for y in 0..640 {
for x in 0..480 {
let dx = cx - x as i32 * 2 - 1;
let dy = cy - y as i32 * 2 - 1;
if dx * dx + dy * dy <= r * r {
self.set_pixel(x, y, color);
};
}
}
}
#[inline]
pub fn set_pixel(&mut self, x: usize, y: usize, color: Rgba64) {
self.buff[y * self.size.x + x] = color;
}
pub fn clear(&mut self) {
self.buff = vec![0u64; self.buff.len()].into_boxed_slice();
}
pub fn blit(&mut self, _width: usize, _height: usize) {}
pub fn draw_filled_rect(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, color: Rgba64) {
for y in y1..y2 {
for x in x1..x2 {
self.set_pixel(x, y, color);
}
}
}
pub fn draw_unfilled_rect(
&mut self,
x1: usize,
y1: usize,
x2: usize,
y2: usize,
color: Rgba64,
) {
// x1 y1 => x2 y1 => x2 y2 => x1 y2 => x1 y1
self.draw_line(x1, y1, x2, y1, color);
self.draw_line(x2, y1, x2, y2, color);
self.draw_line(x2, y2, x1, y2, color);
self.draw_line(x1, y2, x1, y1, color);
}
#[inline]
pub fn draw_line(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, color: Rgba64) {
let x = crate::graphics::get_coordinates(
x1.try_into().unwrap(),
y1.try_into().unwrap(),
x2.try_into().unwrap(),
y2.try_into().unwrap(),
);
for coord in x {
self.set_pixel(coord.0, coord.1, color);
}
}
// pub fn shade(&mut self) {
// for y in 0..100 {
// for x in 0..100 {
// let rgba_ret = evaluate_shader(x, y, self.buff[y * self.size.x + x]);
// match rgba_ret {
// Ok(pixel) => {
// // info!("{:?}", pixel);
// self.set_pixel(x, y, pixel);
// }
// Err(err) => error!("{}", err),
// }
// }
// }
// info!("Shaders done");
// }
// TODO force clear
pub fn force_redraw(&mut self) {
let vga = VGAE.lock();
vga.set_mode();
vga.clear_screen(vga::colors::Color16::Black);
}
}
pub fn get_coordinates(x1: i32, y1: i32, x2: i32, y2: i32) -> Vec<(usize, usize)> {
let mut coordinates: Vec<(usize, usize)> = vec![];
let dx: i32 = i32::abs(x2 - x1);
let dy: i32 = i32::abs(y2 - y1);
let sx: i32 = {
if x1 < x2 {
1
} else {
-1
}
};
let sy: i32 = {
if y1 < y2 {
1
} else {
-1
}
};
let mut error: i32 = (if dx > dy { dx } else { -dy }) / 2;
let mut current_x: i32 = x1;
let mut current_y: i32 = y1;
loop {
coordinates.push((current_x as usize, current_y as usize));
// info!("0 {:?}", (current_x, current_y));
if current_x == x2 && current_y == y2 {
break;
}
let error2: i32 = error;
if error2 > -dx {
error -= dy;
current_x += sx;
}
if error2 < dy {
error += dx;
current_y += sy;
}
}
coordinates
}
pub trait VgaBuffer {
fn copy_to_buffer(&self) -> GraphicsReturn;
}
impl VgaBuffer for ScreenBuffer {
fn copy_to_buffer(&self) -> GraphicsReturn {
let mode = VGAE.lock();
for y in 0..self.size.y {
for x in 0..self.size.x {
let vga_color = into_vga_16(self.buff[y * self.size.x + x]);
if into_vga_16(self.clear_color) != vga_color {
mode.set_pixel(x, y, vga_color);
}
}
}
GraphicsReturn::Ok
}
}
pub fn into_vga_16(rgba_64: Rgba64) -> Color16 {
use pixel_format::ChannelValue::*;
use vga::colors::Color16::*;
match (
get_r(rgba_64).into(),
get_g(rgba_64).into(),
get_b(rgba_64).into(),
) {
(Dark, Dark, Dark) => Black,
(Dark, Dark, Low) => Black,
(Dark, Dark, Mid) => Blue,
(Dark, Dark, High) => Blue,
(Dark, Low, Dark) => Black,
(Dark, Low, Low) => Black,
(Dark, Low, Mid) => Blue,
(Dark, Low, High) => Blue,
(Dark, Mid, Dark) => Green,
(Dark, Mid, Low) => Green,
(Dark, Mid, Mid) => Cyan,
(Dark, Mid, High) => Cyan,
(Dark, High, Dark) => Green,
(Dark, High, Low) => Green,
(Dark, High, Mid) => Green,
(Dark, High, High) => Cyan,
(Low, Dark, Dark) => Black,
(Low, Dark, Low) => Black,
(Low, Dark, Mid) => Blue,
(Low, Dark, High) => Blue,
(Low, Low, Dark) => Black,
(Low, Low, Low) => DarkGrey,
(Low, Low, Mid) => LightGrey,
(Low, Low, High) => Blue,
(Low, Mid, Dark) => DarkGrey,
(Low, Mid, Low) => LightGrey,
(Low, Mid, Mid) => Cyan,
(Low, Mid, High) => Cyan,
(Low, High, Dark) => Green,
(Low, High, Low) => Green,
(Low, High, Mid) => Cyan,
(Low, High, High) => Cyan,
(Mid, Dark, Dark) => Red,
(Mid, Dark, Low) => Red,
(Mid, Dark, Mid) => Magenta,
(Mid, Dark, High) => Magenta,
(Mid, Low, Dark) => Brown,
(Mid, Low, Low) => Red,
(Mid, Low, Mid) => DarkGrey,
(Mid, Low, High) => LightBlue,
(Mid, Mid, Dark) => Brown,
(Mid, Mid, Low) => Brown,
(Mid, Mid, Mid) => LightGrey,
(Mid, Mid, High) => LightBlue,
(Mid, High, Dark) => Green,
(Mid, High, Low) => Green,
(Mid, High, Mid) => LightGreen,
(Mid, High, High) => LightCyan,
(High, Dark, Dark) => Red,
(High, Dark, _) => Magenta,
(High, Low, Dark) => Red,
(High, Low, Low) => LightRed,
(High, Low, Mid) => Pink,
(High, Low, High) => Magenta,
(High, Mid, Dark) => Yellow,
(High, Mid, Low) => Yellow,
(High, Mid, Mid) => LightRed,
(High, Mid, High) => Pink,
(High, High, Dark) => Yellow,
(High, High, Low) => White,
(High, High, Mid) => White,
(High, High, High) => White,
}
}
// TODO: Incorporate this into the ableos vga crate
// /// Draw a glyph on the screen at the given position
// ///
// /// # Arguments
// /// * `x` - the x position of the glyph
// /// * `y` - the y position of the glyph
// /// * `glyph` - the glyph to draw
// /// * `color` - the color of the glyph
// pub fn draw_char(&mut self, mut x: u32, mut y: u32, character: char, color: Rgba64) {
// // trace!["Judy Hopps is thicc af"];
// // let mode = *VGAE.lock();
// // trace!["She got them bouncy bunny buns"];
// let basic_multingual_plane = FontRef::try_from_slice(include_bytes!(
// "../../../ableos/assets/fonts/unifont-14.0.01.ttf"
// ))
// .unwrap();
// let supplementary_multilingual_plane = FontRef::try_from_slice(include_bytes!(
// "../../../ableos/assets/fonts/unifont_upper-14.0.01.ttf"
// ))
// .unwrap();
// // let mut has_char = false;
// // for x in font.codepoint_ids() {
// // if x.1 == character {
// // has_char = true;
// // break;
// // }
// // }
// let in_supp_plane = character as u32 > 0xffff;
// let plane = match in_supp_plane {
// false => basic_multingual_plane,
// true => supplementary_multilingual_plane,
// };
// match character {
// '\n' => {
// // x = 0;
// // y += (GLYPH_HEIGHT * FONT_SCALE) as u32;
// }
// _ => {
// let q_glyph: Glyph = plane.glyph_id(character).with_scale_and_position(
// 20.0 * FONT_SCALE,
// ab_glyph::point(GLYPH_WIDTH * FONT_SCALE, GLYPH_HEIGHT * FONT_SCALE),
// );
// // elf: I don't know if GLYPH_HEIGHT is in the right units here. I'm just guessing.
// if x as usize > self.size.x {
// x = 0;
// y += (GLYPH_HEIGHT * FONT_SCALE) as u32;
// }
// if let Some(q) = plane.outline_glyph(q_glyph) {
// q.draw(|gx, gy, c| {
// if c > 0.0015 {
// let corner = q.px_bounds().min;
// self.set_pixel(
// gx as usize + corner.x as usize + x as usize,
// gy as usize + corner.y as usize + y as usize,
// color,
// );
// }
// });
// }
// }
// }
// }

View file

@ -1,55 +0,0 @@
use core::ops::{BitAnd, BitOr, Shr};
pub type Rgba64 = u64;
pub enum ChannelValue {
Dark,
Low,
Mid,
High,
}
impl From<u8> for ChannelValue {
fn from(b: u8) -> Self {
use ChannelValue::*;
match b {
0x00..=0x3f => Dark,
0x40..=0x7f => Low,
0x80..=0xbf => Mid,
0xc0..=0xff => High,
}
}
}
pub fn get_r(rgba: Rgba64) -> u8 {
rgba.bitand(0xff_00_00_00).shr(0o30) as u8
}
pub fn get_g(rgba: Rgba64) -> u8 {
rgba.bitand(0xff_00_00).shr(0o20) as u8
}
pub fn get_b(rgba: Rgba64) -> u8 {
rgba.bitand(0xff_00).shr(0o10) as u8
}
pub fn get_a(rgba: Rgba64) -> u8 {
(rgba & 0xff) as u8
}
pub fn set_r(rgba: Rgba64, r: u8) -> Rgba64 {
rgba.bitand(0xffffffff_00_ff_ff_ff)
.bitor((r as Rgba64).shr(0o30))
}
pub fn set_g(rgba: Rgba64, g: u8) -> Rgba64 {
rgba.bitand(0xffffffff_ff_00_ff_ff)
.bitor((g as Rgba64).shr(0o20))
}
pub fn set_b(rgba: Rgba64, b: u8) -> Rgba64 {
rgba.bitand(0xffffffff_ff_ff_00_ff)
.bitor((b as Rgba64).shr(0o10))
}
pub fn set_a(rgba: Rgba64, a: u8) -> Rgba64 {
rgba.bitand(0xffffffff_ff_ff_ff_00).bitor(a as Rgba64)
}
pub fn rgba_div(a: Rgba64, b: Rgba64) -> Rgba64 {
set_r(0, get_r(a) / get_r(b))
| set_g(0, get_g(a) / get_g(b))
| set_g(0, get_b(a) / get_b(b))
| set_g(0, get_a(a) / get_a(b))
}
pub fn new_rgba64(r: u8, g: u8, b: u8, a: u8) -> Rgba64 {
set_r(0, r) | set_g(0, g) | set_b(0, b) | set_a(0, a)
}

View file

@ -1,24 +0,0 @@
// TODO: Reorganize and make part of this into a limine agnostic API for general purpose graphics
use crate::kmain::FRAMEBUFFER;
pub fn clear_screen() {
{
// TODO: setup a proper framebuffer handler
let fb_response = FRAMEBUFFER.get_response().get().unwrap();
for fb in fb_response.framebuffers().unwrap() {
trace!("Framebuffer {}x{}", fb.width, fb.height);
trace!("{}", fb.memory_model);
trace!("{}", fb.bpp);
let mut count = 0;
let total = fb.width * fb.height * 3;
while count != total {
unsafe {
let fb_ptr = fb.address.as_mut_ptr().unwrap();
*fb_ptr.offset((count).try_into().unwrap()) = 0x00;
*fb_ptr.offset((count + 1).try_into().unwrap()) = 0x00;
*fb_ptr.offset((count + 2).try_into().unwrap()) = 0x00;
}
count += 3;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more