Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

303 changed files with 25577 additions and 7639 deletions

4
.gdbinit Normal file
View File

@ -0,0 +1,4 @@
set history save on
file target/x86_64-ableos/debug/ableos
target remote localhost:9000
tui enable

22
.github/workflows/rust.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Build
on:
- push
- pull_request
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
components: rust-src
- uses: actions-rs/cargo@v1
with:
command: repbuild
args: run

7
.gitignore vendored
View File

@ -1 +1,8 @@
userland/root_fs/mnt/
target/
limine/
.disk.img
.gdb_history
!*/.gitkeep
__pycache__/
debug.log

5
.gitmodules vendored
View File

@ -1,5 +0,0 @@
[submodule "limine"]
path = limine
url = https://github.com/limine-bootloader/limine.git
branch = v4.x-branch-binary
shallow = true

View File

@ -1,5 +1,6 @@
{
"files.associations": {
"stddef.h": "c"
},
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.showUnlinkedFileNotification": false,
"C_Cpp.errorSquiggles": "disabled"
}

1708
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,9 @@
[workspace]
resolver = "2"
members = ["kernel", "repbuild"]
members = [
"ableos",
"asl",
"ext2-rs",
"kernel",
"facepalm",
"repbuild"
]

View File

@ -1,18 +1,26 @@
# AbleOS
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
# ableOS
![Discord](https://img.shields.io/discord/831368967385120810) ![Code Size](https://img.shields.io/github/languages/code-size/abletheabove/ableos)
## Set up
Install [Qemu](https://www.qemu.org/)
# Community
[Discord](https://discord.gg/JrKVukDtgs)
> On Windows be sure to add `C:\Program Files\qemu` to your `PATH` variable
Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or on [Patreon](https://www.patreon.com/ablecorp)
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
`rustup component add rust-src`
# Compiling
AbleOS should be able to be built on any platform which is supported by
[Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools).
`rustup component add llvm-tools-preview`
For running AbleOS, `repbuild` uses QEMU.
`cargo install bootimage`
## Steps
1. `git submodule update --init`
2. `cargo repbuild`
## Running
repbuild can be used to run and build docs for able os
`cargo repbuild doc`
`cargo repbuild run`
## Testing on real hardware
I recommend using an old x86_64 computer
* `cargo run --release` to generate a binary image that is bootable
* flash it to a USB device via `dd` or balenaEtcher
* Remove said USB device and plug into test machine
* assure test machine boots from USB devices

46
TODO.md Normal file
View File

@ -0,0 +1,46 @@
# AbleOS
## General
- [ ] Improve EXT2
- [ ] Remove x86 specific code and refine the boot process
## Capabilities
A new process should not have any capabilities at all until it is given them or requests them and is approved.
- [ ] Filesystem cap
- [ ] Create a new filesystem
- [ ] Unmount/Mount a filesystem
- [ ] read a file
- [ ] write a file
- [ ] delete a file
- [ ] Network cap
- [ ] open/close socket
- [ ] bind/unbind socket
- [ ] Manage Process cap
- [ ] spawn Process cap
- [ ] kill Process cap
## Riscv
## ARM
- [ ] Get arm-version booting on real hardware
## Drivers
- [ ] Slim down driver specific program code
- [ ] Remove entry/exit functions for drivers
## Filesystem
- [ ] Create a vfs that ties into the capability system
- [ ] Remote home directory
- [ ] local file caching
- [ ] remote file changes
- [ ] Update file if the remote file changes
# Tooling
## Repbuild
- [ ] make generation of the ext2 image possible

15
ableos/.cargo/config.toml Normal file
View File

@ -0,0 +1,15 @@
[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"]
runner = "bootimage runner"
[target.riscv64gc-unknown-none-elf]
rustflags = "-C link-arg=-Tableos/src/arch/riscv/virt.lds"
# ableos/src/arch/riscv/virt.lds

159
ableos/Cargo.toml Normal file
View File

@ -0,0 +1,159 @@
[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]
run-command = [
"qemu-system-x86_64",
"-device",
"piix4-ide,id=ide",
"-drive",
"file={},format=raw,if=none,id=disk",
"-device",
"ide-hd,drive=disk,bus=ide.0"
]
run-args = [
# "--nodefaults",
"-cpu", "Broadwell-v3",
"-m", "4G",
"-serial", "stdio",
"-smp", "cores=2",
"-audiodev", "id=pa,driver=pa",
"-machine", "pcspk-audiodev=pa",
# "-device",
# "VGA",
# "-device",
# "virtio-gpu-pci",
"-device", "vmware-svga",
"-device", "sb16",
# "-machine", "pcspk-audiodev=0",
# "-qmp",
# "unix:../qmp-sock,server,nowait",
]
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]
bootloader = { version = "0.9.8", features = ["map_physical_memory"] }
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" }

11
ableos/assets/balloon.txt Normal file
View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

17
ableos/assets/kernel.toml Normal file
View File

@ -0,0 +1,17 @@
[boot]
system_processes = []
user_processes = ["shell"]
[logging]
enabled = true
level = "Trace"
log_to_serial = true
log_to_vterm = false
filter = ["ableos::ps2_mouse", "ableos::vterm", "ableos::filesystem::vfs"]
# Exact paths required
[tests]
run_tests = false
run_demos = false
run_shader_tests = false

View File

@ -0,0 +1,17 @@
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

@ -0,0 +1 @@
{"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

@ -0,0 +1,15 @@
{
"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

@ -0,0 +1,24 @@
{
"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

@ -0,0 +1,15 @@
{
"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

@ -11,12 +11,5 @@
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "",
"code-model": "kernel",
"pre-link-args": {
"ld.lld": [
"--gc-sections",
"--script=kernel/lds/x86_64.ld"
]
}
"features": "-mmx,-sse,+soft-float"
}

256
ableos/keymaps/empty.keymap Normal file
View File

@ -0,0 +1,256 @@
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

@ -0,0 +1,252 @@
# 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-

1
ableos/rust-toolchain Normal file
View File

@ -0,0 +1 @@
nightly

View File

@ -0,0 +1,73 @@
//! 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

@ -0,0 +1,19 @@
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

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

View File

@ -0,0 +1,15 @@
.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

@ -0,0 +1,13 @@
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

@ -0,0 +1,37 @@
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

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

View File

@ -0,0 +1,70 @@
//! 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

@ -0,0 +1,13 @@
/// 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

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

View File

@ -0,0 +1,66 @@
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

@ -0,0 +1,4 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,37 @@
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

@ -0,0 +1,35 @@
/// # 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

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

View File

@ -0,0 +1,23 @@
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

@ -0,0 +1,129 @@
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

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

View File

@ -0,0 +1,99 @@
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

@ -0,0 +1,64 @@
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

@ -0,0 +1,48 @@
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

@ -0,0 +1,42 @@
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

@ -0,0 +1,8 @@
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

@ -0,0 +1,36 @@
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,75 +1,31 @@
use crate::cpu_features;
//! ```
//! 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");
//! }
//! }
//! }
//! ```
use {
alloc::vec::Vec,
core::{arch::asm, fmt, ops::Deref, slice, str},
};
#[repr(u32)]
pub enum RequestType {
BasicInformation = 0x0000_0000,
VersionInformation = 0x0000_0001,
ThermalPowerManagementInformation = 0x0000_0006,
StructuredExtendedInformation = 0x0000_0007,
ExtendedFunctionInformation = 0x8000_0000,
ExtendedProcessorSignature = 0x8000_0001,
BrandString1 = 0x8000_0002,
BrandString2 = 0x8000_0003,
BrandString3 = 0x8000_0004,
// reserved = 0x80000005,
CacheLine = 0x8000_0006,
TimeStampCounter = 0x8000_0007,
PhysicalAddressSize = 0x8000_0008,
}
#[allow(clippy::similar_names)]
pub fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
let eax;
let ebx;
let ecx;
let edx;
#![cfg_attr(
not(any(target_arch = "x86_64", target_arch = "x86")),
allow(dead_code)
)]
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),
);
}
use core::arch::asm;
use core::ops::Deref;
use core::{fmt, slice, str};
(eax, ebx, ecx, edx)
}
/// The main entrypoint to the CPU information
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
pub fn master() -> Option<Master> {
Some(Master::new())
}
// 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
}
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) }
}
// 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),+}) => {
($reg:ident, {$($idx:expr => $name:ident),+ $(,)?}) => {
$(pub fn $name(self) -> bool {
((self.$reg >> $idx) & 1) != 0
})+
@ -77,7 +33,7 @@ macro_rules! bit {
}
macro_rules! dump {
($me:expr, $f: expr, $sname:expr, {$($name:ident),+}) => {
($me:expr, $f: expr, $sname:expr, {$($name:ident),+ $(,)?}) => {
$f.debug_struct($sname)
$(.field(stringify!($name), &$me.$name()))+
.finish()
@ -85,7 +41,7 @@ macro_rules! dump {
}
macro_rules! delegate_flag {
($item:ident, {$($name:ident),+}) => {
($item:ident, {$($name:ident),+ $(,)?}) => {
$(pub fn $name(&self) -> bool {
self.$item.map(|i| i.$name()).unwrap_or(false)
})+
@ -100,6 +56,23 @@ macro_rules! master_attr_reader {
};
}
#[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,
@ -149,7 +122,7 @@ impl VersionInformation {
fn processor_signature(self) -> u32 {
self.eax
}
// TODO: Change return type and move this to a file that has the list
pub fn brand_string(self) -> Option<&'static str> {
let brand_index = bits_of(self.ebx, 0, 7);
let processor_signature = self.processor_signature();
@ -229,8 +202,8 @@ impl VersionInformation {
27 => osxsave,
28 => avx,
29 => f16c,
30 => rdrand
// 31 - unused
30 => rdrand,
// 31 - unused,
});
bit!(edx, {
@ -265,10 +238,16 @@ impl VersionInformation {
28 => htt,
29 => tm,
// 30 -reserved
31 => pbe
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", {
@ -334,7 +313,7 @@ impl fmt::Debug for VersionInformation {
ss,
htt,
tm,
pbe
pbe,
})
}
}
@ -356,7 +335,7 @@ impl ExtendedProcessorSignature {
// 1-4 reserved
5 => lzcnt,
// 6-7 reserved
8 => prefetchw
8 => prefetchw,
// 9-31 reserved
});
@ -369,7 +348,7 @@ impl ExtendedProcessorSignature {
26 => gigabyte_pages,
27 => rdtscp_and_ia32_tsc_aux,
// 28 reserved
29 => intel_64_bit_architecture
29 => intel_64_bit_architecture,
// 30-31 reserved
});
}
@ -384,14 +363,11 @@ impl fmt::Debug for ExtendedProcessorSignature {
execute_disable,
gigabyte_pages,
rdtscp_and_ia32_tsc_aux,
intel_64_bit_architecture
intel_64_bit_architecture,
})
}
}
// 3 calls of 4 registers of 4 bytes
const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;
pub struct BrandString {
bytes: [u8; BRAND_STRING_LENGTH],
}
@ -484,7 +460,7 @@ impl ThermalPowerManagementInformation {
9 => hwp_activity_window,
10 => hwp_energy_performance_preference,
// 12 - reserved
13 => hdc
13 => hdc,
});
pub fn number_of_interrupt_thresholds(self) -> u32 {
@ -512,9 +488,7 @@ impl fmt::Debug for ThermalPowerManagementInformation {
hwp_activity_window,
hwp_energy_performance_preference,
hdc,
number_of_interrupt_thresholds,
hardware_coordination_feedback,
performance_energy_bias
})
@ -555,7 +529,7 @@ impl StructuredExtendedInformation {
19 => adx,
20 => smap,
// 21-24 - reserved
25 => intel_processor_trace
25 => intel_processor_trace,
// 26-31 - reserved
});
@ -584,7 +558,7 @@ impl fmt::Debug for StructuredExtendedInformation {
adx,
smap,
intel_processor_trace,
prefetchwt1
prefetchwt1,
})
}
}
@ -602,7 +576,6 @@ pub enum CacheLineAssociativity {
#[derive(Copy, Clone)]
pub struct CacheLine(u32);
impl CacheLine {
fn new() -> CacheLine {
let (_, _, c, _) = cpuid(RequestType::CacheLine);
@ -667,7 +640,6 @@ impl fmt::Debug for TimeStampCounter {
#[derive(Copy, Clone)]
pub struct PhysicalAddressSize(u32);
impl PhysicalAddressSize {
fn new() -> PhysicalAddressSize {
let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
@ -735,12 +707,12 @@ impl Master {
let tpm = when_supported(
max_value,
RequestType::ThermalPowerManagementInformation,
|| ThermalPowerManagementInformation::new(),
ThermalPowerManagementInformation::new,
);
let sei = when_supported(
max_value,
RequestType::StructuredExtendedInformation,
|| StructuredExtendedInformation::new(),
StructuredExtendedInformation::new,
);
// Extended information
@ -750,9 +722,8 @@ impl Master {
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 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()
});
@ -771,12 +742,6 @@ impl Master {
physical_address_size: pas,
}
}
// TODO: Macroify this and also include all of the cpu features from self
pub fn features(&self) -> Vec<(&str, bool)> {
let mut fv = Vec::new();
cpu_features!(self, fv);
return fv;
}
master_attr_reader!(version_information, VersionInformation);
master_attr_reader!(
@ -796,7 +761,7 @@ impl Master {
self.brand_string
.as_ref()
.map(|bs| bs as &str)
.or(self.version_information.and_then(|vi| vi.brand_string()))
.or_else(|| self.version_information.and_then(|vi| vi.brand_string()))
}
delegate_flag!(version_information, {
@ -858,7 +823,7 @@ impl Master {
ss,
htt,
tm,
pbe
pbe,
});
delegate_flag!(thermal_power_management_information, {
@ -874,7 +839,7 @@ impl Master {
hwp_energy_performance_preference,
hdc,
hardware_coordination_feedback,
performance_energy_bias
performance_energy_bias,
});
delegate_flag!(structured_extended_information, {
@ -906,11 +871,66 @@ impl Master {
execute_disable,
gigabyte_pages,
rdtscp_and_ia32_tsc_aux,
intel_64_bit_architecture
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"))] {

View File

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

View File

@ -0,0 +1,47 @@
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;
GDT.0.load();
unsafe {
CS::set_reg(GDT.1.code_selector);
load_tss(GDT.1.tss_selector);
}
}

View File

@ -0,0 +1,31 @@
// #![allow(clippy::print_literal)]
use super::{gdt, interrupts};
use crate::{logger, serial_println, TERM};
/// 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),
}
let mut term = TERM.lock();
// term.initialize();
term.set_dirty(true);
term.draw_term();
drop(term);
gdt::init();
interrupts::init_idt();
unsafe { interrupts::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();
}

View File

@ -0,0 +1,271 @@
/*
* 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::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
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);
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 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(1, 1)
.build();
println!("{}", image);
sloop();
}
#[derive(Debug)]
pub enum BSODSource<'a> {
DoubleFault(&'a InterruptStackFrame),
Panic(&'a PanicInfo<'a>),
}

View File

@ -0,0 +1,118 @@
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
use x86_64::{
structures::paging::{
FrameAllocator, FrameDeallocator, Mapper, OffsetPageTable, Page, 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
}
fn translate_addr_inner(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option<PhysAddr> {
use x86_64::registers::control::Cr3;
use x86_64::structures::paging::page_table::FrameError;
let (level_4_table_frame, _) = Cr3::read();
let table_indexes = [
addr.p4_index(),
addr.p3_index(),
addr.p2_index(),
addr.p1_index(),
];
let mut frame = level_4_table_frame;
for &index in &table_indexes {
// convert the frame into a page table reference
let virt = physical_memory_offset + frame.start_address().as_u64();
let table_ptr: *const PageTable = virt.as_ptr();
let table = unsafe { &*table_ptr };
let entry = &table[index];
frame = match entry.frame() {
Ok(frame) => frame,
Err(FrameError::FrameNotPresent) => return None,
Err(FrameError::HugeFrame) => panic!["huge pages not supported"],
};
}
Some(frame.start_address() + u64::from(addr.page_offset()))
}
pub unsafe fn translate_addr(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option<PhysAddr> {
translate_addr_inner(addr, physical_memory_offset)
}
pub fn create_example_mapping(
page: Page,
mapper: &mut OffsetPageTable,
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
) {
use x86_64::structures::paging::PageTableFlags as Flags;
let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000));
let flags = Flags::PRESENT | Flags::WRITABLE;
let map_to_result = unsafe { mapper.map_to(page, frame, flags, frame_allocator) };
map_to_result.expect("map_to failed").flush();
}
pub struct EmptyFrameAllocator;
unsafe impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
None
}
}
pub struct BootInfoFrameAllocator {
memory_map: &'static MemoryMap,
next: usize,
}
impl BootInfoFrameAllocator {
pub unsafe fn init(memory_map: &'static MemoryMap) -> Self {
Self {
memory_map,
next: 0,
}
}
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
let regions = self.memory_map.iter();
let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable);
let addr_range = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr());
let frame_address = addr_range.flat_map(|r| r.step_by(4096));
frame_address.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

@ -0,0 +1,63 @@
/*
* 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 crate::arch::drivers::allocator;
use bootloader::{entry_point, BootInfo};
use x86_64::{instructions::hlt, VirtAddr};
#[cfg(not(test))]
entry_point![start];
#[cfg(not(test))]
#[no_mangle]
pub fn start(boot_info: &'static BootInfo) -> ! {
let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset);
let mut mapper = unsafe { memory::init(phys_mem_offset) };
let mut frame_allocator =
unsafe { memory::BootInfoFrameAllocator::init(&boot_info.memory_map) };
// let page = Page::containing_address(VirtAddr::new(0xdeadbeaf000));
// memory::create_example_mapping(page, &mut mapper, &mut frame_allocator);
//
// let page_ptr: *mut u64 = page.start_address().as_mut_ptr();
// unsafe { page_ptr.offset(400).write_volatile(0xf021_f077_f065_804e) };
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)
}

70
ableos/src/boot_conf.rs Normal file
View File

@ -0,0 +1,70 @@
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 boot: BootConfig,
pub logging: LoggingConfig,
pub tests: TestsConfig,
}
impl KernelConfig {
pub fn new() -> Self {
toml::from_str(include_str!("../assets/kernel.toml")).unwrap()
}
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::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>,
}
#[derive(Serialize, Debug, Deserialize)]
pub struct TestsConfig {
pub run_tests: bool,
pub run_demos: bool,
pub run_shader_tests: bool,
}
#[derive(Serialize, Debug, Deserialize)]
pub struct BootConfig {
pub system_processes: Vec<String>,
pub user_processes: Vec<String>,
}

View File

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

View File

@ -0,0 +1,22 @@
//!
/// 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

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

View File

@ -0,0 +1,29 @@
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

@ -0,0 +1,49 @@
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

@ -0,0 +1,27 @@
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

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

View File

@ -0,0 +1,265 @@
// ! 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
}
}

14
ableos/src/devices/id.rs Normal file
View File

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

59
ableos/src/devices/mod.rs Normal file
View File

@ -0,0 +1,59 @@
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

@ -0,0 +1,245 @@
/*
* 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, "\u{001A}LIGHTBLUE\u{001A}")?,
PciFullClass::Unclassified_VgaCompatible => write!(f, "\u{001A}LIGHTBLUE\u{001A}")?,
PciFullClass::MassStorage_ScsiBus => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_IDE => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_Floppy => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_IpiBus => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_RAID => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_ATA => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_SATA => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_SerialSCSI => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_NVM => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::MassStorage_Other => write!(f, "\u{001A}CYAN\u{001A}")?,
PciFullClass::Network_Ethernet => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_TokenRing => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_FDDI => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_ATM => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_ISDN => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_WorldFlip => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_PICMG => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_Infiniband => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_Fabric => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Network_Other => write!(f, "\u{001A}MAGENTA\u{001A}")?,
PciFullClass::Display_VGA => write!(f, "\u{001A}YELLOW\u{001A}")?,
PciFullClass::Display_XGA => write!(f, "\u{001A}YELLOW\u{001A}")?,
PciFullClass::Display_3D => write!(f, "\u{001A}YELLOW\u{001A}")?,
PciFullClass::Display_Other => write!(f, "\u{001A}YELLOW\u{001A}")?,
PciFullClass::Multimedia_Video => write!(f, "\u{001A}LIGHTBLUE\u{001A}")?,
PciFullClass::Multimedia_AudioController => write!(f, "\u{001A}LIGHTBLUE\u{001A}")?,
PciFullClass::Multimedia_Telephony => write!(f, "\u{001A}LIGHTBLUE\u{001A}")?,
PciFullClass::Multimedia_AudioDevice => write!(f, "\u{001A}LIGHTBLUE\u{001A}")?,
PciFullClass::Multimedia_Other => write!(f, "\u{001A}LIGHTBLUE\u{001A}")?,
PciFullClass::Memory_RAM => write!(f, "\u{001A}BLUE\u{001A}")?,
PciFullClass::Memory_Flash => write!(f, "\u{001A}WHITE\u{001A}")?,
PciFullClass::Memory_Other => write!(f, "\u{001A}LIGHTGREY\u{001A}")?,
PciFullClass::Bridge_Host => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_ISA => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_EISA => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_MCA => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_PciToPci => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_PCMCIA => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_NuBus => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_CardBus => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_RACEway => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_PciToPciSemiTransparent => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_InfinibandToPci => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Bridge_Other => write!(f, "\u{001A}GREEN\u{001A}")?,
PciFullClass::Unknown => write!(f, "\u{001A}RED\u{001A}")?,
}
write!(
f,
"{:?} ({:#06X})\u{001A}RESET\u{001A}",
self,
self.as_u16()
)?;
Ok(())
}
}

View File

@ -0,0 +1,194 @@
/*
* 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

@ -0,0 +1,675 @@
/*
* 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;
#[derive(Debug)]
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,
)
});
}
#[derive(Debug)]
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

@ -0,0 +1,73 @@
/*
* 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]
#[derive(Debug)]
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}");
println!("{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

@ -0,0 +1,180 @@
/*
* 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, "{}", "\u{001A}PINK\u{001A}QEMU (0x1234)"),
VirtIO => write!(f, "{}", "\u{001A}PINK\u{001A}VirtIO (0x1AF4)"),
VMWareInc => write!(f, "{}", "\u{001A}PINK\u{001A}VMWARE (0x15AD)"),
S3Inc => write!(f, "{}", "\u{001A}YELLOW\u{001A}S3 Incorporated (0x5333)"),
IntelCorp => write!(f, "{}", "\u{001A}BLUE\u{001A}Intel Corp. (0x8086)"),
ATITechnologiesInc => write!(f, "{}", "\u{001A}RED\u{001A}ATI (0x1002)"),
Unknown(id) => write!(f, "\u{001A}RED\u{001A}Unknown ({:#6})", id),
other => write!(f, "{other:?}"),
}?;
write!(f, "\u{001A}RESET\u{001A}")?;
Ok(())
}
}

View File

@ -0,0 +1,44 @@
#![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

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

View File

@ -0,0 +1,16 @@
// 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

@ -0,0 +1,37 @@
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

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

View File

@ -0,0 +1,107 @@
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

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

View File

@ -0,0 +1,53 @@
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

@ -0,0 +1,22 @@
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

@ -0,0 +1,15 @@
<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

@ -0,0 +1,57 @@
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

@ -0,0 +1,75 @@
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

@ -0,0 +1,113 @@
#![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

@ -0,0 +1,13 @@
#![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

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

View File

@ -0,0 +1,45 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,39 @@
| 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

@ -0,0 +1,21 @@
// 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

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

View File

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

View File

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

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