mirror of
https://github.com/realmicrosoft/windows.git
synced 2024-08-14 22:46:44 +00:00
refactor a ton of code to be multiboot compatible
This commit is contained in:
parent
f2ff9da1fb
commit
3222bcbfe2
20 changed files with 382 additions and 197 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -34,3 +34,6 @@ Cargo.lock
|
|||
|
||||
#/target
|
||||
#Cargo.lock
|
||||
/boot.o
|
||||
/build/
|
||||
/OVMF-pure-efi.fd
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -3,9 +3,13 @@ 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"
|
||||
[dependencies.lazy_static]
|
||||
version = "1.4.0"
|
||||
features = ["spin_no_std"]
|
51
Makefile
Normal file
51
Makefile
Normal 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
|
||||
|
||||
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
|
||||
|
||||
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 $@
|
||||
|
||||
quick_invalidate:
|
||||
@echo "quick invalidation"
|
||||
@rm -rf build/arch/$(arch)
|
||||
@rm -rf $(kernel)
|
160
arch/x86_64/boot.asm
Normal file
160
arch/x86_64/boot.asm
Normal file
|
@ -0,0 +1,160 @@
|
|||
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
|
||||
|
||||
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 64
|
||||
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
7
arch/x86_64/grub.cfg
Normal 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
16
arch/x86_64/linker.ld
Normal file
|
@ -0,0 +1,16 @@
|
|||
ENTRY(start)
|
||||
|
||||
SECTIONS {
|
||||
. = 1M;
|
||||
|
||||
.boot :
|
||||
{
|
||||
/* ensure that the multiboot header is at the beginning */
|
||||
KEEP(*(.multiboot_header))
|
||||
}
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
}
|
17
arch/x86_64/longmodestart.asm
Normal file
17
arch/x86_64/longmodestart.asm
Normal 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
|
16
arch/x86_64/multiboot_header.asm
Normal file
16
arch/x86_64/multiboot_header.asm
Normal 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:
|
|
@ -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:
|
3
build.rs
3
build.rs
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("cargo:rustc-link-arg=-Tlinker.ld");
|
||||
}
|
29
linker.ld
29
linker.ld
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
13
serial.log
Normal file
13
serial.log
Normal file
|
@ -0,0 +1,13 @@
|
|||
[2J[01;01H[=3h[2J[01;01H[2J[01;01H[=3h[2J[01;01H[2J[01;01H[=3h[2J[01;01H[2J[01;01H[=3h[2J[01;01HBdsDxe: 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)
|
||||
[0m[30m[47mWelcome to GRUB!
|
||||
|
||||
[0m[37m[40m[0m[30m[40m[2J[01;01H[0m[37m[40m 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
|
|
@ -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);
|
||||
*/
|
||||
}
|
|
@ -3,27 +3,28 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use alloc::format;
|
||||
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 crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
|
||||
use crate::serial::potential_serial_ports;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
|
||||
use crate::serial::{Port, potential_serial_ports, terminal_helpers, terminal::ST};
|
||||
|
||||
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();
|
||||
|
@ -39,12 +40,27 @@ const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, C
|
|||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! { loop {} }
|
||||
|
||||
fn KernelPanic(msg: KernelError, fb: &mut FrameBuffer) {
|
||||
// cover the screen in red
|
||||
#[no_mangle]
|
||||
pub extern fn kernel_main() -> ! {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn kernel_main() -> ! {
|
||||
if let Some(i) = console_port {
|
||||
let port = &serial_ports.ports[i];
|
||||
ST.init_from_port(*port);
|
||||
}
|
||||
|
||||
ST.logln("");
|
||||
ST.logln("");
|
||||
ST.logln("");
|
||||
ST.logln("welcome to wukkOS!");
|
||||
ST.logln("(c) 2022 Real Microsoft, LLC");
|
||||
|
||||
loop {}
|
||||
}
|
|
@ -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
37
src/serial/terminal.rs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
9
src/serial/terminal_helpers.rs
Normal file
9
src/serial/terminal_helpers.rs
Normal 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"
|
||||
}
|
Loading…
Reference in a new issue