ok
This commit is contained in:
FantasyPvP
2023-03-10 00:25:08 +00:00
commit e491435dea
60 changed files with 4542 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr::null_mut;
use linked_list_allocator::LockedHeap;
use x86_64::{
structures::paging::{
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
},
VirtAddr,
};
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 { ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE); }
}
Ok(())
}
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!("this method should not be used")
}
}
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
pub const HEAP_START: usize = 0x_4444_4444_0000;
pub const HEAP_SIZE: usize = 100 * 1024;
+160
View File
@@ -0,0 +1,160 @@
use lazy_static::lazy_static;
use async_trait::async_trait;
use spin::Mutex;
use alloc::{vec::Vec, string::String, boxed::Box};
use crate::std::{self, application::{Error, Application}};
lazy_static! {
pub static ref FILESYSTEM: Mutex<Box<File>> = Mutex::new(Box::new(File::new(
String::from(""), // root
FileType::Dir(Directory::new()),
)));
}
pub type Directory = Vec<Box<File>>;
#[derive(Debug)]
pub struct File {
pub name: String,
pub data: FileType,
}
impl File {
pub fn new(name: String, data: FileType) -> Self {
Self { name, data }
}
}
#[derive(Debug)]
pub enum FileType {
Dir(Directory),
Txt(String),
Exe(Apppp),
}
pub fn mkfs() {
let mut fs = FILESYSTEM.lock();
match fs.data {
FileType::Dir(ref mut dir) => {
dir.push(Box::new(
File::new(
String::from("hello there"),
FileType::Txt(String::from("this is a basic text file")),
)
));
dir.push(Box::new(
File::new(
String::from("function that prints out an integer"),
FileType::Exe(Apppp::new()),
)
));
}
_ => {
()
}
}
}
#[derive(Debug)]
pub struct Apppp {}
#[async_trait]
impl std::application::Application for Apppp {
fn new() -> Self {
Self {}
}
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
Ok(())
}
}
/*
lazy_static! {
pub static ref FILESYSTEM: Mutex<Filesystem> = Mutex::new(Filesystem::new());
}
enum FsError {
FileNotFound,
AlreadyExists,
InvalidPath,
}
pub type Path = String;
impl Path {
pub fn new(path: &str) -> Result<Path, FsError> {
if path.is_empty() {
return Err(FsError::FileNotFound);
}
Ok(path.to_string())
}
pub fn dirs(&self) -> Vec<String> {
self.split('/').map(|s| s.to_string()).collect()
}
}
pub struct Filesystem {
pub root: Vec<File>
}
pub type Directory = Vec<File>;
impl Directory {
pub fn new(name: String, files: Vec<File>) -> Self {
Self { name, files }
}
pub fn size(&self) -> usize {
self.files.len()
}
pub fn mkdir(&mut self, name: &str, location: Path) -> Result<(), FsError> {
if self.exists(location.as_str()) {
return Err(FsError::AlreadyExists);
}
self.files.push(File::new(name, FileType::Directory(Box::new(Directory::new()))))
}
}
pub enum FileType {
Directory(Box<Directory>),
TextFile(Box<TextFile>),
BinaryFile(Box<BinaryFile>),
Executable(fn()),
}
pub struct File {
pub name: String,
pub file_type: FileType,
}
impl File {
pub fn new(name: String, file_type: FileType) -> Self {
Self { name, file_type }
}
}
pub struct TextFile {
pub name: String,
pub data: String,
}
impl TextFile {
pub fn new(name: String, data: String) -> Self {
Self { name, data }
}
pub fn size(&self) -> usize {
self.data.len()
}
}
*/
+50
View File
@@ -0,0 +1,50 @@
use x86_64::VirtAddr;
use x86_64::structures::tss::TaskStateSegment;
use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor, SegmentSelector};
use lazy_static::lazy_static;
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
lazy_static! {
static ref TSS: TaskStateSegment = {
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 });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss
};
}
lazy_static! {
static ref GDT: (GlobalDescriptorTable, Selectors) = {
let mut gdt = GlobalDescriptorTable::new();
let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
(gdt, Selectors { code_selector, tss_selector })
};
}
pub fn init() {
use x86_64::instructions::tables::load_tss;
use x86_64::instructions::segmentation::{CS, Segment};
GDT.0.load();
unsafe {
CS::set_reg(GDT.1.code_selector);
load_tss(GDT.1.tss_selector);
}
}
struct Selectors {
code_selector: SegmentSelector,
tss_selector: SegmentSelector,
}
+110
View File
@@ -0,0 +1,110 @@
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
use crate::{print, println};
use crate::kernel::gdt;
use lazy_static::lazy_static;
use spin;
use pic8259::ChainedPics;
pub fn init_idt() {
IDT.load();
}
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
println!("EXCEPTION: breakpoint\n{:#?}", stack_frame);
}
extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame, _error_code: u64) -> ! {
panic!("EXCEPTION: double fault\n{:#?}", stack_frame)
}
extern "x86-interrupt" fn timer_interrupt_handler(stack_frame: InterruptStackFrame) {
unsafe {
GLOBALTIMER.lock().inc();
PICS.lock().notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
}
}
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
use spin::Mutex;
use x86_64::instructions::port::Port;
lazy_static! {
static ref KEYBOARD: Mutex<Keyboard<layouts::Uk105Key, ScancodeSet1>> = {
Mutex::new(Keyboard::new(layouts::Uk105Key, ScancodeSet1, HandleControl::Ignore))
};
}
let mut keyboard = KEYBOARD.lock();
let mut port = Port::new(0x60);
let scancode: u8 = unsafe { port.read() };
crate::kernel::tasks::keyboard::add_scancode(scancode);
unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
}
}
lazy_static! {
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
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
};
}
lazy_static! {
pub static ref GLOBALTIMER: spin::Mutex<Timer> = spin::Mutex::new(Timer::new());
}
pub struct Timer {
pub val: i64
}
impl Timer {
pub fn new() -> Self {
Self { val: 0 }
}
pub fn inc(&mut self) {
self.val += 1
}
pub fn clear(&mut self) {
self.val = 0
}
}
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)
});
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum InterruptIndex {
Timer = PIC_1_OFFSET,
Keyboard,
}
impl InterruptIndex {
fn as_u8(self) -> u8 {
self as u8
}
fn as_usize(self) -> usize {
usize::from(self.as_u8())
}
}
+140
View File
@@ -0,0 +1,140 @@
use x86_64::{
structures::paging::{Page, PhysFrame, Mapper, Size4KiB, FrameAllocator, PageTable},
VirtAddr,
PhysAddr
};
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
use x86_64::structures::paging::OffsetPageTable;
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();
&mut *page_table_ptr
}
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)
}
pub struct BootInfoFrameAllocator {
memory_map: &'static MemoryMap,
next: usize,
}
impl BootInfoFrameAllocator {
pub unsafe fn init(memory_map: &'static MemoryMap) -> Self {
BootInfoFrameAllocator {
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 address_ranges = usable_regions.map(|r|
r.range.start_addr()..r.range.end_addr()
);
let frame_addresses = address_ranges.flat_map(|r| r.step_by(4096));
frame_addresses.map(|a| PhysFrame::containing_address(PhysAddr::new(a)))
}
}
pub struct EmptyFrameAllocator;
unsafe impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> {
None
}
}
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> {
let frame = self.usable_frames().nth(self.next);
self.next += 1;
frame
}
}
/*
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StackBounds {
start: VirtAddr,
end: VirtAddr,
}
impl StackBounds {
pub fn start(&self) -> VirtAddr {
self.start
}
pub fn end(&self) -> VirtAddr {
self.end
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ThreadId(u64);
impl ThreadId {
pub fn as_u64(&self) -> u64 {
self.0
}
fn new() -> Self {
use core::sync::atomic::{AtomicU64, Ordering};
static NEXT_THREAD_ID: AtomicU64 = AtomicU64::new(1);
ThreadId(NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed))
}
}
fn reserve_stack_memory(size_in_pages: u64) -> Page {
use core::sync::atomic::{AtomicU64, Ordering};
static STACK_ALLOC_NEXT: AtomicU64 = AtomicU64::new(0x_5555_5555_0000);
let start_addr = VirtAddr::new(STACK_ALLOC_NEXT.fetch_add(
size_in_pages * Page::<Size4KiB>::SIZE,
Ordering::Relaxed,
));
Page::from_start_address(start_addr).expect("STACK_ALLOC_NEXT: not page aligned")
}
pub fn alloc_stack(
size_in_pages: u64, mapper: &mut impl Mapper<Size4KiB>,
frame_allocator: &mut impl FrameAllocator<Size4KiB>
) -> Result<StackBounds, mapper::MapToError> {
use x86_64::structures::paging::PageTableFlags as Flags;
let guard_page = reserve_stack_memory(size_in_pages + 1);
let stack_start = guard_page + 1;
let stack_end = stack_start + size_in_pages;
for page in Page::range(stack_start, stack_end) {
let frame = frame_allocator.allocate_frame().ok_or(mapper.MapToError::FrameAllocatorFailed)?;
let flags = Flags::PRESENT | Flags::WRITABLE;
mapper.map_to(page, frame, flags, frame_allocator)?.flush();
}
Ok(StackBounds {
start: stack_start.start_address(),
end: stack_end.start_address(),
})
}
*/
+8
View File
@@ -0,0 +1,8 @@
pub mod allocator;
pub mod fs;
pub mod gdt;
pub mod interrupts;
pub mod memory;
pub mod render;
pub mod serial;
pub mod tasks;
+16
View File
@@ -0,0 +1,16 @@
use lazy_static::lazy_static;
use spin::Mutex;
use alloc::{string::String};
lazy_static! {
pub static ref OS: Mutex<SysInfo> = Mutex::new(SysInfo {
os: String::from("CrystalOS Alpha"),
version: String::from("0.2.1"),
});
}
pub struct SysInfo {
pub os: String,
pub version: String,
}
+286
View File
@@ -0,0 +1,286 @@
use volatile::Volatile;
use lazy_static::lazy_static;
use core::fmt;
use spin::Mutex;
use alloc::vec::Vec;
use alloc::vec;
use alloc::borrow::ToOwned;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
Pink = 13,
Yellow = 14,
White = 15,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct ColorCode(u8);
impl ColorCode {
pub fn new(foreground: Color, background: Color) -> ColorCode {
ColorCode((background as u8) << 5 | (foreground as u8))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
character: u8,
colour: ColorCode,
}
pub const BUFFER_HEIGHT: usize = 25;
pub const BUFFER_WIDTH: usize = 80;
#[repr(transparent)]
struct Buffer {
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
struct BufferSwap {
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
struct CharGrid {
chars: Vec<[ScreenChar; BUFFER_WIDTH]>
}
pub struct Renderer {
col_pos: usize,
pub col_code: ColorCode,
buffer: &'static mut Buffer,
userspace: BufferSwap,
upwards: CharGrid,
downwards: CharGrid,
pub sandbox: bool,
}
lazy_static! {
pub static ref RENDERER: Mutex<Renderer> = Mutex::new(Renderer {
col_pos: 0,
col_code: ColorCode::new(Color::White, Color::Black),
buffer: unsafe {
&mut *(0xb8000 as *mut Buffer)
},
userspace: BufferSwap {
chars: [[ScreenChar {
character: 179u8,
colour: ColorCode::new(Color::White, Color::Black),
}; BUFFER_WIDTH]; BUFFER_HEIGHT]
},
upwards: CharGrid {
chars: vec![
[ScreenChar {
character: 32u8,
colour: ColorCode::new(Color::White, Color::Black),
}; 80]
]
},
downwards: CharGrid {
chars: vec![
[ScreenChar {
character: 32u8,
colour: ColorCode::new(Color::White, Color::Black),
}; 80]
]
},
sandbox: false,
});
}
impl Renderer {
pub fn text_mode(&mut self) -> Result<(), ()> {
if !self.sandbox { return Err(()) };
self.buffer_swap().unwrap();
self.sandbox = false;
Ok(())
}
pub fn sandbox_mode(&mut self) -> Result<(), ()> {
if self.sandbox { return Err(()) };
self.buffer_swap().unwrap();
self.sandbox = true;
Ok(())
}
fn buffer_swap(&mut self) -> Result<(), ()> {
for (i, _) in self.userspace.chars.clone().iter().enumerate() {
let tmp = self.buffer.chars[i].clone();
for (j, col) in self.userspace.chars[i].clone().iter().enumerate() {
self.buffer.chars[i][j].write(col.to_owned())
}
for (j, _) in tmp.iter().enumerate() {
self.userspace.chars[i][j] = tmp[j].read().to_owned()
}
}
Ok(())
}
pub fn render_frame(&mut self, frame: [ [ char; BUFFER_WIDTH ]; BUFFER_HEIGHT]) {
for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
if let Some(c) = self.fancy_char(*col) {
self.buffer.chars[i][j].write(ScreenChar { character: c, colour: self.col_code});
} else {
self.buffer.chars[i][j].write(ScreenChar { character: *col as u8, colour: self.col_code});
}
}
}
}
pub fn write_string(&mut self, string: &str) {
for ch in string.chars() {
if let Some(x) = self.fancy_char(ch) {
self.write_byte(x)
} else {
match ch as u8 {
0x20..=0xff | b'\n' => self.write_byte(ch as u8),
_ => self.write_byte(0xfe),
}
}
}
}
fn fancy_char(&self, ch: char) -> Option<u8> {
let res: u8 = match ch {
'│' => 179,
'─' => 196,
'┴' => 193,
'┤' => 180,
'═' => 205,
'║' => 186,
'╗' => 187,
'╝' => 188,
'╚' => 200,
'╔' => 201,
'»' => 175,
'┐' => 191,
'└' => 192,
'┘' => 217,
'┌' => 218,
_ => { return None; }
};
Some(res)
}
pub fn backspace(&mut self) -> Result<(), ()> {
if self.col_pos == 0 {
self.undonewline();
}
self.col_pos -= 1;
let row = BUFFER_HEIGHT -1;
let col = self.col_pos;
let blank = ScreenChar {
character: b' ',
colour: self.col_code,
};
self.buffer.chars[row][col].write(blank);
Ok(())
}
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'\n' => {
self.newline()
},
byte => {
if self.col_pos >= BUFFER_WIDTH {
self.newline();
}
let row = BUFFER_HEIGHT -1;
let col = self.col_pos;
let col_code = self.col_code;
self.buffer.chars[row][col].write(ScreenChar {
character: byte,
colour: col_code,
});
self.col_pos += 1
}
}
}
fn newline(&mut self) {
for row in 1..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
let character = self.buffer.chars[row][col].read();
self.buffer.chars[row - 1][col].write(character);
}
}
self.clear_row(BUFFER_HEIGHT -1);
self.col_pos = 0;
}
pub fn undonewline(&mut self) {
for row in (0..BUFFER_HEIGHT-1).rev() {
for col in 0..BUFFER_WIDTH {
let character = self.buffer.chars[row][col].read();
self.buffer.chars[row + 1][col].write(character);
}
}
self.clear_row(0);
self.col_pos = BUFFER_WIDTH;
}
pub fn clear(&mut self) {
for row in (0..BUFFER_HEIGHT-1).rev() {
self.clear_row(row);
}
}
fn clear_row(&mut self, row: usize) {
let blank = ScreenChar {
character: b' ',
colour: self.col_code,
};
for col in 0..BUFFER_WIDTH {
self.buffer.chars[row][col].write(blank);
}
}
}
impl fmt::Write for Renderer {
fn write_str(&mut self, string:&str) -> fmt::Result {
self.write_string(string);
Ok(())
}
}
pub fn write(args: fmt::Arguments, cols: (Color, Color)) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(cols.0, cols.1);
writer.write_fmt(args).unwrap()
})
}
+46
View File
@@ -0,0 +1,46 @@
use uart_16550::SerialPort;
use spin::Mutex;
use lazy_static::lazy_static;
lazy_static! {
pub static ref SERIAL1: Mutex<SerialPort> = {
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;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
SERIAL1.lock().write_fmt(args).expect("unable to print to serial!")
})
}
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {
$crate::kernel::serial::_print(format_args!($($arg)*));
};
}
#[macro_export]
macro_rules! serial_println {
() => (serial_print!("\n"));
($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (
$crate::serial_print!(
concat!($fmt, "\n"), $($arg)*
)
);
}
+3
View File
@@ -0,0 +1,3 @@
fn init() -> Result<(), ()> {
Ok(())
}
+106
View File
@@ -0,0 +1,106 @@
use super::{Task, TaskId};
use alloc::{collections::BTreeMap, sync::Arc, task::Wake};
use core::task::{Waker, Context, Poll};
use crossbeam_queue::ArrayQueue;
pub struct Executor {
tasks: BTreeMap<TaskId, Task>,
task_queue: Arc<ArrayQueue<TaskId>>,
waker_cache: BTreeMap<TaskId, Waker>,
}
impl Executor {
pub fn new() -> Self {
Executor {
tasks: BTreeMap::new(),
task_queue: Arc::new(ArrayQueue::new(100)),
waker_cache: BTreeMap::new(),
}
}
pub fn spawn(&mut self, task: Task) {
let task_id = task.id;
if self.tasks.insert(task.id, task).is_some() {
panic!("a task with this id has already been allocated");
}
self.task_queue.push(task_id).expect("task queue is full");
}
fn run_ready_tasks(&mut self) {
let Self {
tasks, task_queue, waker_cache
} = self;
while let Ok(task_id) = task_queue.pop() {
let task = match tasks.get_mut(&task_id) {
Some(task) => task,
None => continue,
};
let waker = waker_cache.entry(task_id)
.or_insert_with(|| TaskWaker::new(task_id, task_queue.clone()));
let mut context = Context::from_waker(waker);
match task.poll(&mut context) {
Poll::Ready(()) => {
tasks.remove(&task_id);
waker_cache.remove(&task_id);
}
Poll::Pending => {}
}
}
}
pub fn run(&mut self) -> ! {
loop {
self.run_ready_tasks();
self.sleep_if_idle();
}
}
fn sleep_if_idle(&self) {
use x86_64::instructions::interrupts::{self, enable_and_hlt};
interrupts::disable();
if self.task_queue.is_empty() {
enable_and_hlt();
} else {
interrupts::enable();
}
}
}
struct TaskWaker {
task_id: TaskId,
task_queue: Arc<ArrayQueue<TaskId>>,
}
impl TaskWaker {
fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>) -> Waker {
Waker::from(Arc::new(TaskWaker {
task_id,
task_queue,
}))
}
fn wake_task(&self) {
self.task_queue.push(self.task_id).expect("task queue is full")
}
}
impl Wake for TaskWaker {
fn wake(self: Arc<Self>) {
self.wake_task();
}
fn wake_by_ref(self: &Arc<Self>) {
self.wake_task();
}
}
+161
View File
@@ -0,0 +1,161 @@
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::instructions::interrupts;
use conquer_once::spin::OnceCell;
use crossbeam_queue::ArrayQueue;
use crate::println;
use core::{pin::Pin, task::{Poll, Context}};
use futures_util::stream::Stream;
use futures_util::task::AtomicWaker;
use futures_util::stream::StreamExt;
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
use crate::print;
use crate::kernel::render::RENDERER;
use alloc::{string::String};
static WAKER: AtomicWaker = AtomicWaker::new();
static SCANCODE_QUEUE: OnceCell<ArrayQueue<u8>> = OnceCell::uninit();
/*
pub async fn print_keypresses() {
let mut scancodes = ScanCodeStream::new();
let mut keyboard = Keyboard::new(layouts::Uk105Key, ScancodeSet1, HandleControl::Ignore);
while let Some(scancode) = scancodes.next().await {
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
if let Some(key) = keyboard.process_keyevent(key_event) {
match key {
DecodedKey::Unicode(character) => {
let mut cmd = CMD.lock();
cmd.input(character).await;
}
DecodedKey::RawKey(key) => print!("{:?}", key),
}
}
}
}
}
*/
lazy_static! {
pub static ref KEYBOARD: Mutex<KeyboardHandler> = Mutex::new(KeyboardHandler::new());
}
pub struct KeyboardHandler {
scancodes: ScanCodeStream,
keyboard: Keyboard<layouts::Uk105Key, ScancodeSet1>,
}
impl KeyboardHandler {
pub fn new() -> KeyboardHandler {
KeyboardHandler {
scancodes: ScanCodeStream::new(),
keyboard: Keyboard::new(layouts::Uk105Key, ScancodeSet1, HandleControl::Ignore),
}
}
pub async fn get_keystroke_inner(&mut self) -> Option<char> {
loop {
if let Some(scancode) = self.scancodes.next().await {
if let Ok(Some(key_event)) = self.keyboard.add_byte(scancode) {
if let Some(key) = self.keyboard.process_keyevent(key_event) {
match key {
DecodedKey::Unicode(character) => {
if character == b'\x08' as char { // checks if the character is a backspace
interrupts::without_interrupts(|| {
RENDERER.lock().backspace(); // runs the backspace function of the vga buffer to remove the last character
});
return None;
} else {
return Some(character);
}
},
DecodedKey::RawKey(key) => { print!("{:?}", key) },
}
}
}
}
}
}
pub async fn get_keystroke(&mut self) -> char {
loop {
match self.get_keystroke_inner().await {
Some(c) => return c,
None => ()
}
}
}
pub async fn get_string(&mut self) -> String {
let mut val = String::new();
loop {
let character = match self.get_keystroke_inner().await {
Some(c) => { c },
None => { val.pop(); continue; },
};
print!("{}", character);
let (character, execute): (char, bool) = match character {
'\n' => (character, true),
_ => (character, false),
};
val.push(character);
if execute {
return val;
}
}
}
}
pub(crate) fn add_scancode(scancode: u8) {
if let Ok(queue) = SCANCODE_QUEUE.try_get() {
if let Err(_) = queue.push(scancode) {
println!("WARNING: queue is full - ignoring input");
} else {
WAKER.wake();
}
} else {
println!("WARNING: scancode queue has not been initialised");
}
}
pub struct ScanCodeStream {
_private: (),
}
impl ScanCodeStream {
pub fn new() -> Self {
SCANCODE_QUEUE.try_init_once(|| ArrayQueue::new(100))
.expect("ScanCodeStream::new has already been called once");
ScanCodeStream { _private: () }
}
}
impl Stream for ScanCodeStream {
type Item = u8;
fn poll_next(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<u8>> {
let queue = SCANCODE_QUEUE.try_get().expect("not initialised");
if let Ok(scancode) = queue.pop() {
return Poll::Ready(Some(scancode));
}
WAKER.register(&ctx.waker());
match queue.pop() {
Ok(scancode) => {
WAKER.take();
Poll::Ready(Some(scancode))
},
Err(crossbeam_queue::PopError) => Poll::Pending,
}
}
}
+36
View File
@@ -0,0 +1,36 @@
use core::{future::Future, pin::Pin};
use alloc::boxed::Box;
use core::task::{Context, Poll};
pub mod executor;
pub mod keyboard;
use core::sync::atomic::{AtomicU64, Ordering};
pub struct Task {
id: TaskId,
future: Pin<Box<dyn Future<Output = ()>>>,
}
impl Task {
pub fn new(future: impl Future<Output = ()> + 'static) -> Self {
Self {
id: TaskId::new(),
future: Box::pin(future),
}
}
fn poll(&mut self, context: &mut Context) -> Poll<()> {
self.future.as_mut().poll(context)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(u64);
impl TaskId {
fn new() -> Self {
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
TaskId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
}
}
+15
View File
@@ -0,0 +1,15 @@
/*
pub mod thread_switch;
use x86_64::VirtAddr;
use crate::memory::{ThreadId, StackBounds};
#[derive(Debug)]
pub struct Thread {
id: ThreadId,
stack_pointer: Option<VirtAddr>,
stack_bounds: Option<StackBounds>,
}
*/
@@ -0,0 +1,3 @@
use core::arch::global_asm;
global_asm!(include_str!("thread_switch.s"));
@@ -0,0 +1,13 @@
asm_thread_switch:
pushfq
mov rax, rsp
mov rsp, rdi
mov rdi, rax
call add_paused_thread
popfq
ret
+9
View File
@@ -0,0 +1,9 @@
pub mod std;
pub mod kernel;
pub fn init() {
kernel::gdt::init();
kernel::interrupts::init_idt();
unsafe { kernel::interrupts::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();
}
+19
View File
@@ -0,0 +1,19 @@
use async_trait::async_trait;
use alloc::{string::String, vec::Vec, boxed::Box};
#[async_trait]
pub trait Application {
fn new() -> Self;
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
Ok(())
}
}
#[derive(Debug)]
pub enum Error {
UnknownCommand(String),
CommandFailed(String),
EmptyCommand,
}
+210
View File
@@ -0,0 +1,210 @@
use crate::{
kernel::render::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode},
kernel::tasks::keyboard::KEYBOARD,
};
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec};
pub use crate::{print, println, serial_print, serial_println};
use lazy_static::lazy_static;
use spin::Mutex;
pub async fn stdin() -> String {
let string = KEYBOARD.lock().get_string().await;
string
}
pub async fn stdchar() -> char {
let chr = KEYBOARD.lock().get_keystroke().await;
chr
}
pub fn text_mode() {
RENDERER.lock().text_mode().unwrap();
}
pub fn sandbox_mode() {
RENDERER.lock().sandbox_mode().unwrap();
}
pub fn switch_mode() {
if RENDERER.lock().sandbox == true {
RENDERER.lock().text_mode().unwrap();
} else {
RENDERER.lock().sandbox_mode().unwrap();
}
}
pub fn clear() {
RENDERER.lock().clear();
}
pub type Frame = [ [ char; BUFFER_WIDTH ]; BUFFER_HEIGHT];
#[derive(Clone)]
pub struct Element {
frame: Vec<Vec<char>>,
dimensions: (u8, u8)
}
/// elements can be created using their from_str() method
/// you can then render the element to the current frame using the render() method
/// the position of the element by passing a tuple (x,y) to render()
///
/// nothing will appear on the screen until the frame is actually
impl Element {
pub fn from_str(elemstr: String) -> Self {
let mut element = Element { frame: Vec::<Vec<char>>::new(), dimensions: (0, 0) };
for line in elemstr.split("\n") {
let mut ln = Vec::<char>::new();
for col in line.chars() {
ln.push(col)
};
element.frame.push(ln);
}
for row in element.clone().frame {
let n = row.len();
if n > element.dimensions.0 as usize {
element.dimensions.0 = n as u8;
}
}
element
}
pub fn render(&mut self, pos: (u8, u8)) { // x,y
for (i, row) in self.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
println!("{} {} {}", i, j, col);
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = *col;
};
}
}
}
lazy_static! {
pub static ref FRAMEGEN: Mutex<FrameGen> = Mutex::new(FrameGen::new() );
}
#[derive(Clone, Copy)]
pub struct FrameGen {
frame: Frame,
}
impl FrameGen {
pub fn render_frame(&self) {
RENDERER.lock().render_frame(self.frame)
}
fn new() -> Self {
let mut frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[' '; BUFFER_WIDTH]; BUFFER_HEIGHT];
for i in 0..BUFFER_WIDTH {
frame[0][i] = "┌──────────────────────────────────────────────────────────────────────────────┐".chars().collect::<Vec<char>>()[i];
frame[BUFFER_HEIGHT -1][i] = "└──────────────────────────────────────────────────────────────────────────────┘".chars().collect::<Vec<char>>()[i];
}
for j in 1..BUFFER_HEIGHT -1 {
for i in 0..BUFFER_WIDTH {
frame[j][i] = "│ │".chars().collect::<Vec<char>>()[i];
}
}
Self { frame: Frame::from(frame) }
}
pub fn get_frame(&self) -> &[ [ char; BUFFER_WIDTH ]; BUFFER_HEIGHT] {
&self.frame
}
}
impl core::fmt::Display for FrameGen {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
println!(" ");
for row in &self.frame {
println!("{}", row.iter().collect::<String>());
};
Ok(())
}
}
#[macro_export]
macro_rules! println_log {
() => ($crate::print_log!("/n"));
($($arg:tt)*) => ($crate::print_log!("{}\n", format_args!($($arg)*)));
}
#[macro_export]
macro_rules! print_log {
($($arg:tt)*) => ($crate::std::io::_log(format_args!($($arg)*)));
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("/n"));
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ($crate::std::io::_print(format_args!($($arg)*)));
}
pub use crate::kernel::render::Color;
#[doc(hidden)]
pub fn _print(args: core::fmt::Arguments) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(Color::White, Color::Black);
writer.write_fmt(args).unwrap();
//WRITER.lock().write_fmt(args).unwrap();
});
}
#[doc(hidden)]
pub fn _log(args: core::fmt::Arguments) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(Color::Yellow, Color::Black);
writer.write_fmt(args).unwrap();
//WRITER.lock().write_fmt(args).unwrap();
});
}
pub fn write(args: core::fmt::Arguments, cols: (Color, Color)) {
crate::kernel::render::write(args, cols);
}
pub fn mkfs() {
use crate::kernel::fs;
fs::mkfs();
println!("{:?}", *(fs::FILESYSTEM.lock()));
}
+13
View File
@@ -0,0 +1,13 @@
pub mod io;
pub mod random;
pub mod application;
pub mod tasks;
pub mod os;
// this is where the standard library for the operating system will be defined
// my aim is to completely separate this from the shell.
// these functions should all be asynchronous.
+16
View File
@@ -0,0 +1,16 @@
use lazy_static::lazy_static;
use spin::Mutex;
use alloc::{string::String};
lazy_static! {
pub static ref OS: Mutex<SysInfo> = Mutex::new(SysInfo {
os: String::from("CrystalOS Alpha"),
version: String::from("0.2.1"),
});
}
pub struct SysInfo {
pub os: String,
pub version: String,
}
+35
View File
@@ -0,0 +1,35 @@
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec};
use rand::{Rng, SeedableRng, rngs::SmallRng, RngCore};
use spin::Mutex;
use lazy_static::lazy_static;
lazy_static! {
pub static ref RANDOM: Mutex<SmallRng> = Mutex::new(SmallRng::seed_from_u64(1));
}
pub struct Random;
impl Random {
pub fn int(lower: usize, upper: usize) -> usize {
loop {
let integer: u64 = RANDOM.lock().next_u64();
let mut integer: String = integer.to_string();
integer = "0".repeat(20 - integer.len()) + &integer;
let integer: usize = integer[1..upper.to_string().len() + 1].parse().unwrap();
if integer <= upper && integer >= lower {
return integer;
} else {
continue;
}
}
}
pub fn selection<T: Clone>(ls: Vec<T>) -> T {
let range = Random::int(0, ls.len() - 1);
ls[range as usize].clone()
}
}
+7
View File
@@ -0,0 +1,7 @@
pub use crate::kernel::tasks::{Task, executor::Executor};
pub fn stop() -> ! {
loop {
x86_64::instructions::hlt();
}
}