springboard to rust; VGA text mode driver and basics of TTY system
This commit is contained in:
commit
b5aea81535
|
@ -0,0 +1,6 @@
|
||||||
|
[build]
|
||||||
|
target = "x86_64-unknown-shadeos-gnu.json"
|
||||||
|
|
||||||
|
[unstable]
|
||||||
|
build-std = ["core", "compiler_builtins"]
|
||||||
|
build-std-features = ["compiler-builtins-mem"]
|
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?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="modules">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
<option name="version" value="2" />
|
||||||
|
</MakefileProjectSettings>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
<component name="MarkdownSettingsMigration">
|
||||||
|
<option name="stateVersion" value="1" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="Python" name="Python facet">
|
||||||
|
<configuration sdkName="Python 3.10" />
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
</module>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "shadeos"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lazy_static = {version = "1.4.0", features = ["spin_no_std"]}
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
|
@ -0,0 +1,45 @@
|
||||||
|
ASM := nasm
|
||||||
|
ASMARGS := -f elf64
|
||||||
|
|
||||||
|
LD := x86_64-elf-ld
|
||||||
|
LDARGS := --nmagic
|
||||||
|
|
||||||
|
CARGO_ENV := debug
|
||||||
|
CARGO_EXTRA_ARG := #--release
|
||||||
|
|
||||||
|
.PHONY = target clean run rustc build debug
|
||||||
|
default: build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
cargo clean
|
||||||
|
|
||||||
|
build: target/shade.iso
|
||||||
|
|
||||||
|
rustc:
|
||||||
|
RUST_TARGET_PATH=$(shell pwd) cargo build $(CARGO_EXTRA_ARG)
|
||||||
|
|
||||||
|
run: target/shade.iso
|
||||||
|
qemu-system-x86_64 -cdrom target/shade.iso
|
||||||
|
debug: target/shade.iso
|
||||||
|
qemu-system-x86_64 -cdrom target/shade.iso -s -S
|
||||||
|
|
||||||
|
target/shade.iso: target/shade.bin iso/boot/grub/grub.cfg
|
||||||
|
cp -r iso target
|
||||||
|
cp target/shade.bin target/iso/boot/shade.bin
|
||||||
|
cd target
|
||||||
|
cd target && grub-mkrescue -o shade.iso iso
|
||||||
|
|
||||||
|
|
||||||
|
target/shade.bin: target/llb/entry32.o target/llb/mb2_header.o rustc
|
||||||
|
$(LD) $(LDARGS) --output=target/shade.bin --script=linker.ld target/llb/entry32.o target/llb/mb2_header.o target/x86_64-unknown-shadeos-gnu/$(CARGO_ENV)/libshadeos.a
|
||||||
|
|
||||||
|
target/llb.a: target/llb/mb2_header.o target/llb/entry32.o
|
||||||
|
mkdir -p target/llb
|
||||||
|
ar rvs target/llb.a target/llb/mb2_header.o target/llb/entry32.o
|
||||||
|
|
||||||
|
target/llb/mb2_header.o: src/llb/mb2_header.asm
|
||||||
|
mkdir -p target/llb
|
||||||
|
$(ASM) $(ASMARGS) src/llb/mb2_header.asm -o target/llb/mb2_header.o
|
||||||
|
target/llb/entry32.o: src/llb/entry32.asm
|
||||||
|
mkdir -p target/llb
|
||||||
|
$(ASM) $(ASMARGS) src/llb/entry32.asm -o target/llb/entry32.o
|
|
@ -0,0 +1,7 @@
|
||||||
|
set timeout=0
|
||||||
|
set default=0
|
||||||
|
|
||||||
|
menuentry "shadeOS" {
|
||||||
|
multiboot2 /boot/shade.bin
|
||||||
|
boot
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 1M;
|
||||||
|
|
||||||
|
.boot :
|
||||||
|
{
|
||||||
|
*(.mb2_header)
|
||||||
|
}
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod tty;
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod vga;
|
|
@ -0,0 +1,28 @@
|
||||||
|
use crate::tty::{TTYCharacter, TTYDriver, TTYDriverError};
|
||||||
|
use crate::unsafe_utils::writes::write_dword;
|
||||||
|
|
||||||
|
/// Implementation of TTYDriver for 0xb8000 VGA Text Mode
|
||||||
|
|
||||||
|
pub struct VGATTYDriver {}
|
||||||
|
impl TTYDriver for VGATTYDriver {
|
||||||
|
fn set_char(&self, row: usize, col: usize, char: TTYCharacter) -> Result<(), TTYDriverError> {
|
||||||
|
if row > 25 {
|
||||||
|
return Err(TTYDriverError::RowOutOfBounds { got: row })
|
||||||
|
}
|
||||||
|
if col > 80 {
|
||||||
|
return Err(TTYDriverError::ColOutOfBounds { got: col })
|
||||||
|
}
|
||||||
|
// calculate the memory offset
|
||||||
|
let write_location = 0xb8000 + (row * 80 + col) * 2;
|
||||||
|
|
||||||
|
// convert the TTYCharacter into a raw u16 to be written to memory
|
||||||
|
let raw_char = (char.format as u16) << 8 | char.char as u16;
|
||||||
|
|
||||||
|
// and then write it using unsafe_utils
|
||||||
|
unsafe {
|
||||||
|
write_dword(raw_char, write_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(error_in_core)]
|
||||||
|
#![feature(panic_info_message)]
|
||||||
|
|
||||||
|
pub mod tty;
|
||||||
|
pub mod drivers;
|
||||||
|
pub mod unsafe_utils;
|
||||||
|
|
||||||
|
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
use crate::drivers::tty::vga::VGATTYDriver;
|
||||||
|
use crate::tty::{Color, TTY, TTYCharacter, TTYDriver, TTYDriverError};
|
||||||
|
|
||||||
|
/// This is our kpanic function. This will eventually use any functioning video driver to dump the kernel, but for now it just hangs
|
||||||
|
#[panic_handler]
|
||||||
|
fn kpanic(_info: &PanicInfo) -> ! {
|
||||||
|
let panic_str = _info.location().unwrap();
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn kmain() -> ! {
|
||||||
|
// initialize ttys and the kernel buffer
|
||||||
|
// just one for now
|
||||||
|
let vga_driver = VGATTYDriver {};
|
||||||
|
let mut ttys: TTY<2> = TTY::new();
|
||||||
|
ttys.select(0);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][0] = TTYCharacter::new('s', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][1] = TTYCharacter::new('h', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][2] = TTYCharacter::new('a', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][3] = TTYCharacter::new('d', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][4] = TTYCharacter::new('e', Color::White, Color::Black);
|
||||||
|
|
||||||
|
ttys.select(1);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][0] = TTYCharacter::new('o', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][1] = TTYCharacter::new('s', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][2] = TTYCharacter::new(' ', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][3] = TTYCharacter::new(':', Color::White, Color::Black);
|
||||||
|
ttys.ttys[ttys.selected].screen_buffer[0][4] = TTYCharacter::new(')', Color::White, Color::Black);
|
||||||
|
|
||||||
|
match ttys.select_and_update(0, &vga_driver) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
match e {
|
||||||
|
TTYDriverError::ColOutOfBounds { got } => {
|
||||||
|
vga_driver.set_char(0, 5, TTYCharacter::new('y', Color::Red, Color::Black)).unwrap();
|
||||||
|
loop {}
|
||||||
|
},
|
||||||
|
TTYDriverError::RowOutOfBounds { got } => {
|
||||||
|
vga_driver.set_char(0, 5, TTYCharacter::new('y', Color::Red, Color::Black)).unwrap();
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..2000000 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ttys.select_and_update(1, &vga_driver).unwrap();
|
||||||
|
|
||||||
|
//vga_driver.set_char(0, 0, TTYCharacter::new('s', Color::White, Color::Black)).unwrap();
|
||||||
|
//vga_driver.set_char(0, 1, TTYCharacter::new('h', Color::White, Color::Black)).unwrap();
|
||||||
|
|
||||||
|
loop{}
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
global _start
|
||||||
|
extern kmain
|
||||||
|
|
||||||
|
section .text
|
||||||
|
bits 32
|
||||||
|
|
||||||
|
; LLB MESSAGE CODES:
|
||||||
|
; llb:01 - llb execution started
|
||||||
|
; llb:02 - llb got execution back, system panic
|
||||||
|
; llb:03 - configuring page tables
|
||||||
|
; llb:04 - page tables configured with no issues
|
||||||
|
; llb:05 - gdt loaded, handoff to rbt
|
||||||
|
; llb:6 - handoff to long mode successful
|
||||||
|
|
||||||
|
_start:
|
||||||
|
; llb:01
|
||||||
|
mov word [0xb8000], 0x026c
|
||||||
|
mov word [0xb8002], 0x026c
|
||||||
|
mov word [0xb8004], 0x0262
|
||||||
|
mov word [0xb8006], 0x023a
|
||||||
|
mov word [0xb8008], 0x0230
|
||||||
|
mov word [0xb800a], 0x0231
|
||||||
|
|
||||||
|
; llb:03
|
||||||
|
mov word [0xb8010], 0x026c
|
||||||
|
mov word [0xb8012], 0x026c
|
||||||
|
mov word [0xb8014], 0x0262
|
||||||
|
mov word [0xb8016], 0x023a
|
||||||
|
mov word [0xb8018], 0x0230
|
||||||
|
mov word [0xb801a], 0x0233
|
||||||
|
|
||||||
|
; Point the first entry of the level 4 page table to the first entry in the
|
||||||
|
; p3 table
|
||||||
|
mov eax, p3_table
|
||||||
|
or eax, 0b11
|
||||||
|
mov dword [p4_table + 0], eax
|
||||||
|
|
||||||
|
mov eax, p2_table
|
||||||
|
or eax, 0b11
|
||||||
|
mov dword [p3_table + 0], eax
|
||||||
|
|
||||||
|
mov ecx, 0 ; loop counter
|
||||||
|
.map_p2_table:
|
||||||
|
mov eax, 0x200000 ; 2 MiB huge pages
|
||||||
|
mul ecx
|
||||||
|
or eax, 0b10000011 ; huge pages
|
||||||
|
mov [p2_table + ecx * 8], eax ; mark in the page table
|
||||||
|
inc ecx
|
||||||
|
cmp ecx, 512 ; 512 2 MiB pages = 1024 MiB paged memory; 1 GiB usable memory
|
||||||
|
jne .map_p2_table
|
||||||
|
|
||||||
|
; put address of page table in cr3
|
||||||
|
mov eax, p4_table
|
||||||
|
mov cr3, eax
|
||||||
|
|
||||||
|
; enable pae
|
||||||
|
mov eax, cr4
|
||||||
|
or eax, 1 << 5
|
||||||
|
mov cr4, eax
|
||||||
|
|
||||||
|
; set long mode bit
|
||||||
|
mov ecx, 0xc0000080
|
||||||
|
rdmsr
|
||||||
|
or eax, 1 << 8
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
; enable paging
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 1 << 31
|
||||||
|
or eax, 1 << 16
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; llb:04
|
||||||
|
mov word [0xb8020], 0x026c
|
||||||
|
mov word [0xb8022], 0x026c
|
||||||
|
mov word [0xb8024], 0x0262
|
||||||
|
mov word [0xb8026], 0x023a
|
||||||
|
mov word [0xb8028], 0x0230
|
||||||
|
mov word [0xb802a], 0x0234
|
||||||
|
|
||||||
|
lgdt [gdt64.pointer]
|
||||||
|
|
||||||
|
; update selectors
|
||||||
|
mov ax, gdt64.data
|
||||||
|
mov ss, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
|
||||||
|
; llb:05
|
||||||
|
mov word [0xb8030], 0x026c
|
||||||
|
mov word [0xb8032], 0x026c
|
||||||
|
mov word [0xb8034], 0x0262
|
||||||
|
mov word [0xb8036], 0x023a
|
||||||
|
mov word [0xb8038], 0x0230
|
||||||
|
mov word [0xb803a], 0x0235
|
||||||
|
|
||||||
|
jmp gdt64.code:rbt_entry
|
||||||
|
|
||||||
|
; llb:02
|
||||||
|
mov word [0xb8200], 0x026c
|
||||||
|
mov word [0xb8202], 0x026c
|
||||||
|
mov word [0xb8204], 0x0262
|
||||||
|
mov word [0xb8206], 0x023a
|
||||||
|
mov word [0xb8208], 0x0230
|
||||||
|
mov word [0xb820a], 0x0232
|
||||||
|
hlt
|
||||||
|
|
||||||
|
section .bss
|
||||||
|
align 4096
|
||||||
|
|
||||||
|
p4_table:
|
||||||
|
resb 4096
|
||||||
|
p3_table:
|
||||||
|
resb 4096
|
||||||
|
p2_table:
|
||||||
|
resb 4096
|
||||||
|
|
||||||
|
section .rodata
|
||||||
|
section .rodata
|
||||||
|
gdt64:
|
||||||
|
dq 0
|
||||||
|
.code: equ $ - gdt64
|
||||||
|
dq (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
|
||||||
|
.data: equ $ - gdt64
|
||||||
|
dq (1<<44) | (1<<47) | (1<<41)
|
||||||
|
.pointer:
|
||||||
|
dw .pointer - gdt64 - 1
|
||||||
|
dq gdt64
|
||||||
|
|
||||||
|
section .text
|
||||||
|
bits 64
|
||||||
|
rbt_entry:
|
||||||
|
|
||||||
|
; llb:06
|
||||||
|
mov word [0xb8040], 0x026c
|
||||||
|
mov word [0xb8042], 0x026c
|
||||||
|
mov word [0xb8044], 0x0262
|
||||||
|
mov word [0xb8046], 0x023a
|
||||||
|
mov word [0xb8048], 0x0230
|
||||||
|
mov word [0xb804a], 0x0236
|
||||||
|
|
||||||
|
jmp kmain
|
||||||
|
|
||||||
|
hlt
|
|
@ -0,0 +1,14 @@
|
||||||
|
section .mb2_header
|
||||||
|
header_start:
|
||||||
|
dd 0xe85250d6 ; magic number
|
||||||
|
dd 0 ; protected mode code
|
||||||
|
dd header_end - header_start ; header length
|
||||||
|
|
||||||
|
; checksum
|
||||||
|
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
|
||||||
|
|
||||||
|
; required end tag
|
||||||
|
dw 0 ; type
|
||||||
|
dw 0 ; flags
|
||||||
|
dd 8 ; size
|
||||||
|
header_end:
|
|
@ -0,0 +1,121 @@
|
||||||
|
use core::error::Error;
|
||||||
|
use core::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
pub struct TTY<const C: usize> {
|
||||||
|
pub ttys: [VirtualTTY; C],
|
||||||
|
pub selected: usize
|
||||||
|
}
|
||||||
|
impl<const C: usize> TTY<C> {
|
||||||
|
pub fn new() -> TTY<C> {
|
||||||
|
Self {
|
||||||
|
ttys: [
|
||||||
|
VirtualTTY::new(); C
|
||||||
|
],
|
||||||
|
selected: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select(&mut self, new: usize) { self.selected = new; }
|
||||||
|
|
||||||
|
pub fn update(&self, driver: &impl TTYDriver) -> Result<(), TTYDriverError> {
|
||||||
|
let selected_tty = &self.ttys[self.selected];
|
||||||
|
for (row_num, row) in selected_tty.screen_buffer.iter().enumerate() {
|
||||||
|
for (col_num, col) in row.iter().enumerate() {
|
||||||
|
driver.set_char(row_num, col_num, *col)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_and_update(&mut self, new: usize, driver: &impl TTYDriver) -> Result<(), TTYDriverError> {
|
||||||
|
self.select(new);
|
||||||
|
self.update(driver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[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(Copy, Clone)]
|
||||||
|
pub struct TTYCharacter {
|
||||||
|
pub format: u8,
|
||||||
|
pub char: char
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TTYCharacter {
|
||||||
|
pub fn blank() -> Self { Self { format: 0u8, char: ' ' } }
|
||||||
|
pub fn from(char: char) -> Self { Self { format: 0x0fu8, char }}
|
||||||
|
pub fn new(char: char, fg: Color, bg: Color) -> Self {
|
||||||
|
Self {
|
||||||
|
format: (fg as u8) << 4 | bg as u8,
|
||||||
|
char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ROWS_ON_SCREEN: usize = 25;
|
||||||
|
pub const COLS: usize = 80;
|
||||||
|
|
||||||
|
pub const ROWS_IN_TTY: usize = 80;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct VirtualTTY {
|
||||||
|
pub full_buffer: VirtualTTYBuffer<ROWS_IN_TTY, COLS>,
|
||||||
|
pub screen_buffer: VirtualTTYBuffer<ROWS_ON_SCREEN, COLS>,
|
||||||
|
pub line_offset: usize
|
||||||
|
}
|
||||||
|
impl Default for VirtualTTY {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
full_buffer: [[TTYCharacter::blank(); COLS]; ROWS_IN_TTY],
|
||||||
|
screen_buffer: [[TTYCharacter::blank(); COLS]; ROWS_ON_SCREEN],
|
||||||
|
line_offset: ROWS_IN_TTY - ROWS_ON_SCREEN, // assume we are scrolled all the way down
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl VirtualTTY {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type VirtualTTYBuffer<const R: usize, const C: usize> = [[TTYCharacter; C]; R];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TTYDriverError {
|
||||||
|
RowOutOfBounds { got: usize },
|
||||||
|
ColOutOfBounds { got: usize }
|
||||||
|
}
|
||||||
|
impl Display for TTYDriverError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::RowOutOfBounds { got } => write!(f, "Character write out of bounds: row {} too high", got),
|
||||||
|
Self::ColOutOfBounds { got } => write!(f, "Character write out of bounds: col {} too high", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Error for TTYDriverError {}
|
||||||
|
|
||||||
|
pub trait TTYDriver {
|
||||||
|
fn set_char(&self, row: usize, col: usize, char: TTYCharacter) -> Result<(), TTYDriverError>;
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
/// Unsafe utility functions
|
||||||
|
pub mod writes;
|
|
@ -0,0 +1,5 @@
|
||||||
|
/// Write the given dword to any arbitrary memory location. This is an inherently unsafe operation; hence the function is unsafe
|
||||||
|
pub unsafe fn write_dword(dword: u16, at: usize) {
|
||||||
|
let ptr = at as *mut u16;
|
||||||
|
*ptr = dword;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def help():
|
||||||
|
print('Usage: mkasmmsg.py -b<32/64> <format> <message>')
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
format = sys.argv[2]
|
||||||
|
msg = sys.argv[3]
|
||||||
|
base = 0xb8000
|
||||||
|
|
||||||
|
index = {
|
||||||
|
'1': 'word',
|
||||||
|
'2': 'dword',
|
||||||
|
'4': 'qword'
|
||||||
|
}
|
||||||
|
|
||||||
|
command = 'mov {} [{}], 0x{}'
|
||||||
|
|
||||||
|
if sys.argv[1] == '-b32':
|
||||||
|
groupsize = 2
|
||||||
|
elif sys.argv[1] == '-b64':
|
||||||
|
groupsize = 4
|
||||||
|
else:
|
||||||
|
help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def chunk(iterator, n):
|
||||||
|
for i in range(0, len(iterator), n):
|
||||||
|
yield iterator[i:i + n]
|
||||||
|
|
||||||
|
|
||||||
|
raw_nums = []
|
||||||
|
|
||||||
|
for char in list(msg):
|
||||||
|
raw_nums.append(format + hex(ord(char))[2:])
|
||||||
|
|
||||||
|
total = 0
|
||||||
|
|
||||||
|
for num, block in enumerate(list(chunk(raw_nums, groupsize))):
|
||||||
|
if len(block) == 3:
|
||||||
|
total += 2
|
||||||
|
print(command.format('word', hex(base + total), block[0]))
|
||||||
|
total += 4
|
||||||
|
print(command.format('dword', hex(base + total), ''.join(block[1:])))
|
||||||
|
continue
|
||||||
|
total += len(block) * groupsize
|
||||||
|
print(command.format(index[str(len(block))], hex(base + total), ''.join(block)))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"arch": "x86_64",
|
||||||
|
"cpu": "x86-64",
|
||||||
|
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||||
|
"llvm-target": "x86_64-unknown-none-gnu",
|
||||||
|
"linker-flavor": "gcc",
|
||||||
|
"no-compiler-rt": true,
|
||||||
|
"os": "intermezzos",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"target-c-int-width": "32",
|
||||||
|
"features": "-mmx,-fxsr,-sse,-sse2,+soft-float",
|
||||||
|
"disable-redzone": true,
|
||||||
|
"eliminate-frame-pointer": false
|
||||||
|
}
|
Loading…
Reference in New Issue