Compare commits

...

2 Commits

Author SHA1 Message Date
fekhesk 4574150d2b
memory 2022-10-26 01:50:22 -07:00
fekhesk 3222bcbfe2
refactor a ton of code to be multiboot compatible 2022-10-26 00:05:53 -07:00
25 changed files with 566 additions and 236 deletions

3
.gitignore vendored
View File

@ -34,3 +34,6 @@ Cargo.lock
#/target
#Cargo.lock
/boot.o
/build/
/OVMF-pure-efi.fd

View File

@ -1,5 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MakefileSettings">
<option name="linkedExternalProjectsSettings">
<MakefileProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="version" value="2" />
</MakefileProjectSettings>
</option>
</component>
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="SwUserDefinedSpecifications">
<option name="specTypeByUrl">
<map />

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/windows.iml" filepath="$PROJECT_DIR$/.idea/windows.iml" />
</modules>
</component>
</project>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/simple_boot/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/alloc/benches" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/alloc/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/alloc/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -3,9 +3,18 @@ name = "wukkOS"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"]
[dependencies]
spin = "0.9.1"
x86_64 = "0.14.10"
rlibc = "1.0"
multiboot2 = { version = "0.14.0", optional = true }
[dependencies.lazy_static]
version = "1.4.0"
features = ["spin_no_std"]
features = ["spin_no_std"]
[features]
default = ["f_multiboot2"]
f_multiboot2 = ["dep:multiboot2"]

51
Makefile Normal file
View File

@ -0,0 +1,51 @@
arch ?= x86_64
kernel := target/$(arch)-custom/debug/libwukkOS.a
iso := build/arch/$(arch)/wukkOS.iso
target ?= $(arch)-custom
final := build/arch/$(arch)/wukkOS.bin
efi_bios := build/arch/$(arch)/OVMF-pure-efi.fd
linker_script := arch/$(arch)/linker.ld
grub_cfg := arch/$(arch)/grub.cfg
assembly_source_files := $(wildcard arch/$(arch)/*.asm)
assembly_object_files := $(patsubst arch/$(arch)/%.asm, \
build/arch/$(arch)/%.o, $(assembly_source_files))
.PHONY: all clean run iso quick_invalidate
all: $(final) $(iso)
clean:
@xargo clean
@rm -rf build
run: $(final) $(iso)
@qemu-system-$(arch) -bios $(efi_bios) -cdrom $(iso) \
-chardev stdio,id=char0,mux=on,logfile=serial.log,signal=off \
-serial chardev:char0 -mon chardev=char0
quick_invalidate:
@echo "quick invalidation"
@rm -rf build/arch/$(arch)
@rm -rf $(kernel)
iso: $(iso)
$(iso): $(final) $(grub_cfg)
@cp OVMF-pure-efi.fd build/arch/$(arch)/OVMF-pure-efi.fd # TODO! remove this, it's only for testing and i don't think we can distribute it
@mkdir -p isodir/boot/grub
@cp $(final) isodir/boot/wukkOS.bin
@cp $(grub_cfg) isodir/boot/grub/grub.cfg
@grub-mkrescue -o $(iso) isodir
@rm -rf isodir
$(final): $(kernel) $(linker_script) $(assembly_object_files)
@ld -n -T $(linker_script) -o $(final) $(assembly_object_files) $(kernel) \
--gc-sections
$(kernel):
@RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc
build/arch/$(arch)/%.o: arch/$(arch)/%.asm
@mkdir -p $(shell dirname $@)
@nasm -felf64 $< -o $@

161
arch/x86_64/boot.asm Normal file
View File

@ -0,0 +1,161 @@
global start
extern long_mode_start
section .text
bits 32
;; basic boilerplate stuff from blog_os, expect to be changed
start:
mov esp, stack_top
mov edi, ebx
call check_multiboot
call check_cpuid
call check_long_mode
call setup_page_tables
call enable_paging
lgdt [gdt64.pointer]
jmp gdt64.code:long_mode_start
hlt
check_multiboot:
cmp eax, 0x36d76289
jne .no_multiboot
ret
.no_multiboot:
mov al, "0"
jmp error
check_cpuid:
; Check if CPUID is supported by attempting to flip the ID bit (bit 21)
; in the FLAGS register. If we can flip it, CPUID is available.
; Copy FLAGS in to EAX via stack
pushfd
pop eax
; Copy to ECX as well for comparing later on
mov ecx, eax
; Flip the ID bit
xor eax, 1 << 21
; Copy EAX to FLAGS via the stack
push eax
popfd
; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
pushfd
pop eax
; Restore FLAGS from the old version stored in ECX (i.e. flipping the
; ID bit back if it was ever flipped).
push ecx
popfd
; Compare EAX and ECX. If they are equal then that means the bit
; wasn't flipped, and CPUID isn't supported.
cmp eax, ecx
je .no_cpuid
ret
.no_cpuid:
mov al, "1"
jmp error
check_long_mode:
; test if extended processor info in available
mov eax, 0x80000000 ; implicit argument for cpuid
cpuid ; get highest supported argument
cmp eax, 0x80000001 ; it needs to be at least 0x80000001
jb .no_long_mode ; if it's less, the CPU is too old for long mode
; use extended info to test if long mode is available
mov eax, 0x80000001 ; argument for extended processor info
cpuid ; returns various feature bits in ecx and edx
test edx, 1 << 29 ; test if the LM-bit is set in the D-register
jz .no_long_mode ; If it's not set, there is no long mode
ret
.no_long_mode:
mov al, "2"
jmp error
setup_page_tables:
; map first P4 entry to P3 table
mov eax, p3_table
or eax, 0b11 ; present + writable
mov [p4_table], eax
; map first P3 entry to P2 table
mov eax, p2_table
or eax, 0b11 ; present + writable
mov [p3_table], eax
; map each P2 entry to a huge 2MiB page
mov ecx, 0 ; counter variable
.map_p2_table:
; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
mov eax, 0x200000 ; 2MiB
mul ecx ; start address of ecx-th page
or eax, 0b10000011 ; present + writable + huge
mov [p2_table + ecx * 8], eax ; map ecx-th entry
inc ecx ; increase counter
cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped
jne .map_p2_table ; else map the next entry
ret
enable_paging:
; load P4 to cr3 register (cpu uses this to access the P4 table)
mov eax, p4_table
mov cr3, eax
; enable PAE-flag in cr4 (Physical Address Extension)
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; set the long mode bit in the EFER MSR (model specific register)
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
; enable paging in the cr0 register
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
ret
; Prints `ERR: ` and the given error code to screen and hangs.
; parameter: error code (in ascii) in al
error:
mov dword [0xb8000], 0x4f524f45
mov dword [0xb8004], 0x4f3a4f52
mov dword [0xb8008], 0x4f204f20
mov byte [0xb800a], al
hlt
section .bss
align 4096
p4_table:
resb 4096
p3_table:
resb 4096
p2_table:
resb 4096
stack_bottom:
resb 4096 * 4 ;; 16 KiB
stack_top:
section .rodata
gdt64:
dq 0 ; zero entry
.code: equ $ - gdt64 ; new
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
.pointer:
dw $ - gdt64 - 1
dq gdt64

7
arch/x86_64/grub.cfg Normal file
View File

@ -0,0 +1,7 @@
set timeout=0
set default=0
menuentry "wukkOS basic kernel" {
multiboot2 /boot/wukkOS.bin
boot
}

16
arch/x86_64/linker.ld Normal file
View File

@ -0,0 +1,16 @@
ENTRY(start)
SECTIONS {
. = 1M;
.boot :
{
/* ensure that the multiboot header is at the beginning */
KEEP(*(.multiboot_header))
}
.text :
{
*(.text)
}
}

View File

@ -0,0 +1,17 @@
global long_mode_start
extern kernel_main
section .text
bits 64
long_mode_start:
mov ax, 0x00
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
extern kernel_main
call kernel_main
hlt

View File

@ -0,0 +1,16 @@
section .multiboot_header
header_start:
align 4
; multiboot 2 magic
dd 0xe85250d6
dd 0x00000000
dd header_end - header_start
; checksum
dd 0x100000000 - (0xe85250d6 + 0x00000000 + (header_end - header_start))
; required end tag
dw 0 ; type
dw 0 ; flags
dd 8 ; size
header_end:

View File

@ -1,31 +0,0 @@
;; bootstrap code from osdev.org
MBALIGN equ 1 << 0
MEMINFO equ 1 << 1
FLAGS equ MBALIGN | MEMINFO
MAGIC equ 0x1BADB002
CHECKSUM equ -(MAGIC + FLAGS)
section .multiboot
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
section .bss
align 16
stack_bottom:
resb 16384 ; 16 KiB stack
stack_top:
section .text
global _start:function (_start.end - _start)
_start:
mov esp, stack_top
extern kernel_main
call kernel_main
cli
.hang: hlt
jmp .hang
.end:

View File

@ -1,3 +0,0 @@
fn main() {
println!("cargo:rustc-link-arg=-Tlinker.ld");
}

View File

@ -1,29 +0,0 @@
ENTRY(_start)
SECTIONS
{
. = 1M;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}

21
serial.log Normal file
View File

@ -0,0 +1,21 @@
[=3h[=3h[=3h[=3hBdsDxe: loading Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0)
BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0)
Welcome to GRUB!
 Booting `wukkOS basic kernel'
WARNING: no console will be available to OS
error: no suitable video mode found.
welcome to wukkOS!
(c) 2022 Real Microsoft, LLC
initialising memory maps...[OK]
memory map:
0 - a0000 : Available
100000 - 800000 : Available
808000 - 80b000 : Available
80c000 - 810000 : Available
900000 - 78ef000 : Available
7bff000 - 7f58000 : Available

27
src/boot/mod.rs Normal file
View File

@ -0,0 +1,27 @@
use alloc::vec::Vec;
use crate::KernelArgs;
#[cfg(feature = "f_multiboot2")]
pub mod multiboot2;
pub enum MemoryType {
Available,
Reserved,
AcpiReclaimable,
Nvs,
BadMemory,
Kernel,
Bootloader,
Unknown(u32)
}
pub struct MemoryArea {
pub start: usize,
pub end: usize,
pub area_type: MemoryType,
}
pub trait KernelInfo {
fn init_from_kernel_args(&mut self, args: KernelArgs);
fn get_memory_areas(&self) -> Vec<MemoryArea>;
}

View File

@ -0,0 +1,41 @@
extern crate multiboot2;
use alloc::vec;
use alloc::vec::Vec;
use multiboot2::{BootInformation, load, MemoryAreaType};
use crate::boot::{KernelInfo, MemoryArea, MemoryType};
use crate::KernelArgs;
#[derive(Default)]
pub struct Multiboot2Bootloader {
pub boot_info: Option<BootInformation>,
}
impl KernelInfo for Multiboot2Bootloader {
fn init_from_kernel_args(&mut self, args: KernelArgs) {
let boot_info = unsafe {
load(args.multiboot_information_address)
}.expect("invalid kernel args!");
self.boot_info = Some(boot_info);
}
fn get_memory_areas(&self) -> Vec<MemoryArea> {
let mut memory_areas = vec![];
let boot_info = self.boot_info.as_ref().unwrap();
let memory_map_tag = boot_info.memory_map_tag().expect("memory map tag required but not found!");
for area in memory_map_tag.memory_areas() {
memory_areas.push(MemoryArea {
start: area.start_address() as usize,
end: area.end_address() as usize,
area_type: match area.typ() {
MemoryAreaType::Available => MemoryType::Available,
MemoryAreaType::Reserved => MemoryType::Reserved,
MemoryAreaType::AcpiAvailable => MemoryType::AcpiReclaimable,
MemoryAreaType::ReservedHibernate => MemoryType::Reserved,
MemoryAreaType::Defective => MemoryType::BadMemory,
}
})
}
memory_areas
}
}

View File

@ -2,108 +2,11 @@
use core::borrow::{BorrowMut};
use crate::{InterruptStackFrame, font, FACEBOOK};
use crate::{InterruptStackFrame, font};
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::{COMMUNIST_RED, CUM_WHITE, Colour};
fn draw_box(x: usize, y: usize, width: usize, height: usize, color: Colour, mut fb: &mut [u8]) {
let pixelwidth = FACEBOOK.fb_pixelwidth.lock();
let pitch = FACEBOOK.fb_pitch.lock();
let colourtype = FACEBOOK.fb_colourtype.lock();
for i in 0..width {
for j in 0..height {
let pixel = (y * &*pitch) + (x * &*pixelwidth) + (i * &*pixelwidth) + (j * &*pitch);
if *colourtype == 0 { //BGR
unsafe {
fb[pixel + 0] = color.b;
fb[pixel + 1] = color.g;
fb[pixel + 2] = color.r;
}
} else if *colourtype == 1 { //RGB
unsafe {
fb[pixel + 0] = color.r;
fb[pixel + 1] = color.g;
fb[pixel + 2] = color.b;
}
} else {
// average values
let avg = (color.r as u16 + color.g as u16 + color.b as u16) / 3;
unsafe {fb[pixel + 0] = avg as u8;}
}
}
}
drop(pixelwidth);
drop(pitch);
drop(colourtype);
}
fn put_pixel(x: usize, y: usize, color: Colour, mut fb: &mut [u8]) {
let pixelwidth = FACEBOOK.fb_pixelwidth.lock();
let pitch = FACEBOOK.fb_pitch.lock();
let colourtype = FACEBOOK.fb_colourtype.lock();
let pixel = (y * &*pitch) + (x * &*pixelwidth);
if *colourtype == 0 { //BGR
unsafe {
fb[pixel + 0] = color.b;
fb[pixel + 1] = color.g;
fb[pixel + 2] = color.r;
}
} else if *colourtype == 1 { //RGB
unsafe {
fb[pixel + 0] = color.r;
fb[pixel + 1] = color.g;
fb[pixel + 2] = color.b;
}
} else {
// average values
let avg = (color.r as u16 + color.g as u16 + color.b as u16) / 3;
unsafe {fb[pixel + 0] = avg as u8;}
}
drop(pixelwidth);
drop(pitch);
drop(colourtype);
}
fn draw_char(x: usize, y: usize, c: char, color: Colour, mut fb: &mut [u8]) {
let font = font::BASIC_LEGACY;
// font is 8x8, stored in a 2d array of bytes
let char_width = 8;
let char_height = 8;
let char_index = c as usize;
let char_data = font[char_index];
for row in 0..char_height {
for col in 0..char_width {
let bit = (char_data[row] >> col) & 1;
if bit >= 1 {
put_pixel(x + col, y + row, color, fb);
}
}
}
}
fn draw_horizcentre_string(width: usize, y: usize, s: &str, color: Colour, fb: &mut [u8]) {
let mut x_tmp = (width - s.len() * 8) / 2;
let mut y_tmp = y;
for c in s.chars() {
if c == '\n' {
x_tmp = (width - s.len() * 8) / 2;
y_tmp += 8;
} else {
draw_char(x_tmp, y_tmp, c, color, fb.borrow_mut());
x_tmp += 8;
}
}
}
pub extern "x86-interrupt" fn breakpoint_exception(stack_frame: InterruptStackFrame) {
/*
// cover the screen in a nice communist red (:
let mut fb = FACEBOOK.fb_mutex.lock();
let fb_width = FACEBOOK.fb_width.lock();
@ -118,4 +21,5 @@ pub extern "x86-interrupt" fn breakpoint_exception(stack_frame: InterruptStackFr
drop(fb_width);
drop(fb_height);
drop(fb);
*/
}

120
src/lib.rs Normal file
View File

@ -0,0 +1,120 @@
#![feature(abi_x86_interrupt)]
#![feature(default_alloc_error_handler)]
#![feature(panic_info_message)]
#![no_std]
#![no_main]
use alloc::boxed::Box;
use alloc::format;
use alloc::string::ToString;
use alloc::sync::Arc;
use allocator::*;
extern crate alloc;
extern crate rlibc;
use alloc::vec::Vec;
use spin::Mutex;
use core::arch::asm;
use core::ops::Deref;
use lazy_static::lazy_static;
use core::panic::PanicInfo;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
use crate::boot::KernelInfo;
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
use crate::serial::{Port, potential_serial_ports, terminal_helpers, terminal::ST};
mod font;
mod serial;
mod internals;
mod allocator;
mod security;
mod boot;
lazy_static! {
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception);
idt
};
}
const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}];
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
ST.logln("---KERNEL FUCKY WUKKY UWU (panic)---");
ST.logln(if let Some(s) = info.payload().downcast_ref::<&str>() {
format!("panic payload: {s:?}")
} else {
format!("no panic payload")
}.as_str());
ST.logln(if let Some(msg) = info.message() {
format!("panic msg: {}", msg.as_str().unwrap_or("no message"))
} else {
"no message".to_string()
}.as_str());
ST.logln(if let Some(location) = info.location() {
format!("location: file {} line {}", location.file(), location.line())
} else {
"no location".to_string()
}.as_str());
loop {}
}
pub struct KernelArgs {
#[cfg(feature = "f_multiboot2")]
multiboot_information_address: usize
}
#[no_mangle]
pub extern fn kernel_main(args: KernelArgs) -> ! {
// initialise serial
let mut serial_ports = serial::init_serial();
let mut console_port = None;
for (i, enabled) in serial_ports.ports_enabled.iter().enumerate() {
if *enabled {
console_port = Some(i);
}
}
if let Some(i) = console_port {
let port = &serial_ports.ports[i];
ST.init_from_port(*port);
}
let kern_info: Box<dyn boot::KernelInfo> = {
#[cfg(feature = "f_multiboot2")]
{
let mut kern_info = boot::multiboot2::Multiboot2Bootloader::default();
kern_info.init_from_kernel_args(args);
Box::new(kern_info)
}
};
ST.logln("");
ST.logln("");
ST.logln("");
ST.logln("welcome to wukkOS!");
ST.logln("(c) 2022 Real Microsoft, LLC");
ST.log("initialising memory maps...");
let mem_areas = kern_info.get_memory_areas();
ST.logln("[OK]");
ST.logln("memory map:");
for area in mem_areas {
ST.logln(format!("{:x} - {:x} : {}", area.start, area.end, match area.area_type {
boot::MemoryType::Available => "Available",
boot::MemoryType::Reserved => "Reserved",
boot::MemoryType::AcpiReclaimable => "ACPI Reclaimable",
boot::MemoryType::Nvs => "NVS",
boot::MemoryType::BadMemory => "Bad Memory",
boot::MemoryType::Kernel => "Kernel",
boot::MemoryType::Bootloader => "Bootloader",
boot::MemoryType::Unknown(_) => "Unknown"
}).as_str());
}
loop {}
}

View File

@ -1,50 +0,0 @@
#![feature(abi_x86_interrupt)]
#![feature(default_alloc_error_handler)]
#![no_std]
#![no_main]
use allocator::*;
extern crate alloc;
use alloc::vec::Vec;
use spin::Mutex;
use core::arch::asm;
use lazy_static::lazy_static;
use core::panic::PanicInfo;
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
use crate::serial::potential_serial_ports;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
mod font;
mod serial;
mod internals;
mod allocator;
// THIS IS THE ONLY GLOBAL VARIABLE WE WILL EVER HAVE, MARK THIS ON MY FUCKING GRAVE
//pub static mut FRAMEBUFFER: Option<FBInfo> = None;
lazy_static! {
static ref IDT : InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception);
idt
};
}
const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}];
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! { loop {} }
fn KernelPanic(msg: KernelError, fb: &mut FrameBuffer) {
// cover the screen in red
}
#[no_mangle]
fn kernel_main() -> ! {
loop{}
}

1
src/security/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod stack_smashing_protection;

View File

@ -0,0 +1,8 @@
pub const STACK_CHK_GUARD: usize = usize::MAX;
pub const STACK_CHK_PTR: *const usize = &STACK_CHK_GUARD;
pub extern "C" fn __stack_chk_fail() -> ! {
panic!("stack fucking or uh smashing detected!");
loop {}
}

View File

@ -5,6 +5,8 @@ use core::borrow::{Borrow, BorrowMut};
use core::ops::Deref;
pub mod ps2;
pub mod terminal_helpers;
pub mod terminal;
#[derive(Clone, Copy, PartialEq)]
pub enum potential_serial_ports {
@ -84,6 +86,12 @@ impl Port {
command(self.base as u16 + serial_offsets::DATA as u16, data);
}
pub fn transmit_string(&self, data: &str) {
for c in data.chars() {
self.transmit(c as u8);
}
}
fn is_recv_full(&self) -> bool {
let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);
status & 0x01 == 0x01

37
src/serial/terminal.rs Normal file
View File

@ -0,0 +1,37 @@
use alloc::sync::Arc;
use core::ops::Deref;
use lazy_static::lazy_static;
use spin::Mutex;
use crate::serial::Port;
pub struct SerialTerminal {
pub port: Arc<Mutex<Option<Port>>>,
}
lazy_static! {
pub static ref ST: SerialTerminal = {
let mut serial_terminal = SerialTerminal {
port: Arc::new(Mutex::new(None)),
};
serial_terminal
};
}
impl SerialTerminal {
pub fn init_from_port(&self, port: Port) {
self.port.lock().replace(port);
}
pub fn log(&self, message: &str) {
if let Some(port) = self.port.lock().deref() {
port.transmit_string(message);
}
}
pub fn logln(&self, message: &str) {
if let Some(port) = self.port.lock().deref() {
port.transmit_string(message);
port.transmit_string("\r\n");
}
}
}

View File

@ -0,0 +1,9 @@
pub fn clear_screen() -> &'static str {
//"\033[2J"
"\x1B[2J"
}
pub fn init_cursor() -> &'static str {
//"\033[?25l"
"\x1B[H"
}