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
|
#/target
|
||||||
#Cargo.lock
|
#Cargo.lock
|
||||||
|
/boot.o
|
||||||
|
/build/
|
||||||
|
/OVMF-pure-efi.fd
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<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">
|
<component name="SwUserDefinedSpecifications">
|
||||||
<option name="specTypeByUrl">
|
<option name="specTypeByUrl">
|
||||||
<map />
|
<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"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
spin = "0.9.1"
|
spin = "0.9.1"
|
||||||
x86_64 = "0.14.10"
|
x86_64 = "0.14.10"
|
||||||
|
rlibc = "1.0"
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
features = ["spin_no_std"]
|
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 core::borrow::{BorrowMut};
|
||||||
|
|
||||||
|
|
||||||
use crate::{InterruptStackFrame, font, FACEBOOK};
|
use crate::{InterruptStackFrame, font};
|
||||||
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::{COMMUNIST_RED, CUM_WHITE, Colour};
|
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) {
|
pub extern "x86-interrupt" fn breakpoint_exception(stack_frame: InterruptStackFrame) {
|
||||||
|
/*
|
||||||
// cover the screen in a nice communist red (:
|
// cover the screen in a nice communist red (:
|
||||||
let mut fb = FACEBOOK.fb_mutex.lock();
|
let mut fb = FACEBOOK.fb_mutex.lock();
|
||||||
let fb_width = FACEBOOK.fb_width.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_width);
|
||||||
drop(fb_height);
|
drop(fb_height);
|
||||||
drop(fb);
|
drop(fb);
|
||||||
|
*/
|
||||||
}
|
}
|
|
@ -3,27 +3,28 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
use alloc::format;
|
||||||
|
use alloc::sync::Arc;
|
||||||
use allocator::*;
|
use allocator::*;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
extern crate rlibc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
use core::ops::Deref;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
|
|
||||||
use crate::serial::potential_serial_ports;
|
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
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 font;
|
||||||
mod serial;
|
mod serial;
|
||||||
mod internals;
|
mod internals;
|
||||||
mod allocator;
|
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! {
|
lazy_static! {
|
||||||
static ref IDT: InterruptDescriptorTable = {
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
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]
|
#[panic_handler]
|
||||||
fn panic(_info: &PanicInfo) -> ! { loop {} }
|
fn panic(_info: &PanicInfo) -> ! { loop {} }
|
||||||
|
|
||||||
fn KernelPanic(msg: KernelError, fb: &mut FrameBuffer) {
|
#[no_mangle]
|
||||||
// cover the screen in red
|
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]
|
if let Some(i) = console_port {
|
||||||
fn kernel_main() -> ! {
|
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 {}
|
loop {}
|
||||||
}
|
}
|
|
@ -5,6 +5,8 @@ use core::borrow::{Borrow, BorrowMut};
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
pub mod ps2;
|
pub mod ps2;
|
||||||
|
pub mod terminal_helpers;
|
||||||
|
pub mod terminal;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum potential_serial_ports {
|
pub enum potential_serial_ports {
|
||||||
|
@ -84,6 +86,12 @@ impl Port {
|
||||||
command(self.base as u16 + serial_offsets::DATA as u16, data);
|
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 {
|
fn is_recv_full(&self) -> bool {
|
||||||
let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);
|
let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);
|
||||||
status & 0x01 == 0x01
|
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