ok
ok
This commit is contained in:
@@ -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;
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
})
|
||||
}
|
||||
*/
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)*
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fn init() -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
pub use crate::kernel::tasks::{Task, executor::Executor};
|
||||
|
||||
pub fn stop() -> ! {
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user