From aef1325ce90377188d8358b1031f7c4ec398382b Mon Sep 17 00:00:00 2001 From: Kitsu Date: Fri, 10 Sep 2021 17:32:09 +0300 Subject: [PATCH] Impl --- .cargo/config.toml | 6 ++ .gitignore | 4 ++ Cargo.toml | 14 +++++ i686-kolibri.json | 33 +++++++++++ link.x | 35 +++++++++++ rust-toolchain | 1 + src/lib.rs | 142 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 51 ++++++++++++++++ 8 files changed, 286 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 i686-kolibri.json create mode 100644 link.x create mode 100644 rust-toolchain create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..b155c62 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,6 @@ +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] + +[build] +target = "i686-kolibri.json" +rustflags = ["-C", "link-arg=-Tlink.x"] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0cccdf0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +**/*.rs.bk +/Cargo.lock +/rust_dos.com diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..06e081f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "hw_kolibri" +version = "0.1.0" +authors = ["Kitsu "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[profile.release] +opt-level = "z" +lto = "thin" + +[dependencies] +cstr_core = { version = "0.2.4", default-features = false, features = ["nightly"] } diff --git a/i686-kolibri.json b/i686-kolibri.json new file mode 100644 index 0000000..1b76fbd --- /dev/null +++ b/i686-kolibri.json @@ -0,0 +1,33 @@ +{ + "arch": "x86", + "cpu": "pentium", + "data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128", + "dynamic-linking": false, + "executables": true, + "has-elf-tls": false, + "has-rpath": true, + "is-builtin": false, + "linker-flavor": "gcc", + "linker": "gcc", + "llvm-target": "i686-unknown-none-code32", + "pre-link-args": { + "gcc": [ + "-nostdlib", + "-Wl,--build-id=none", + "-Wl,--as-needed", + "-Wl,-z,noexecstack", + "-m32" + ] + }, + "max-atomic-width": 32, + "os": "none", + "relocation-model": "static", + "position-independent-executables": false, + "relro-level": "off", + "target-c-int-width": "32", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "unknown", + "panic-strategy": "abort", + "disable-redzone": true +} diff --git a/link.x b/link.x new file mode 100644 index 0000000..b60ee55 --- /dev/null +++ b/link.x @@ -0,0 +1,35 @@ +PATH_SIZE = 1024; +PARAMS_SIZE = 256; +STACK_SIZE = 1024; + +OUTPUT_FORMAT("binary") + +SECTIONS +{ +. = 0x24; + .text : { + *(.text) + *(.text.*) + } +END = .; + .hdr : AT(0){ + LONG(0x554e454D); + LONG(0x31305445); + LONG(1); + LONG(kol_main); + LONG(END); + LONG(FILE_END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); + LONG(FILE_END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); + LONG(FILE_END + PATH_SIZE); + LONG(FILE_END); + } + .dat ALIGN(16) : { + *(.rdata) + *(const) + *(CONST) + *(.data) + *(data) + } + .bss ALIGN(16) : {*(.bss)} +FILE_END = .; +} diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..bf867e0 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..fe69ae6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,142 @@ +#![feature(asm)] +#![no_std] + +macro_rules! syscall { + ($fn_no:literal) => {{ + let mut res: i32 = $fn_no; + + asm!("int 0x40", inout("eax") res); + res + }}; + ($fn_no:literal, $($reg:tt)*) => {{ + let mut res: i32 = $fn_no; + asm!("int 0x40", + $($reg)*, + inout("eax") res, + ); + res + }} +} + +#[derive(Clone, Copy)] +pub struct Color(u8, u8, u8); + +impl Color { + pub fn rgb(r: u8, g: u8, b: u8) -> Self { + Self(r, g, b) + } + + pub fn r(&self) -> u8 { + self.0 + } + pub fn g(&self) -> u8 { + self.1 + } + pub fn b(&self) -> u8 { + self.2 + } + + pub fn as_rgb_val(self) -> u32 { + (self.0 as u32) << 16 | (self.1 as u32) << 8 | (self.0 as u32) + } +} + +#[inline] +pub unsafe fn start_window_draw() { + syscall!(12, in("ebx") 1); +} + +pub struct Dot { + pub x: u32, + pub y: u32, +} + +#[repr(u32)] +pub enum WindowKind { + Fixed = 0, + NoDraw = 1, + Resizable = 2, + Themed = 3, + FixedThemed = 4, +} + +pub struct WindowParams<'a> { + pub color: Color, + pub kind: WindowKind, + pub title: Option<&'a cstr_core::CStr>, +} + +#[inline] +pub unsafe fn define_window(start: Dot, width: u32, height: u32, params: WindowParams<'_>) { + const RELATIVE_FLAG: u32 = 0x20; + syscall!( + 0, + in("ebx") start.x * 65536 + width, + in("ecx") start.y * 65536 + height, + in("edx") params.color.as_rgb_val() | + (RELATIVE_FLAG | (params.title.is_some() as u32) << 4 | params.kind as u32) << 24, + in("edi") params.title.map(|s| s.as_ptr()).unwrap_or_else(core::ptr::null) + ); +} + +pub struct WindowTextParams<'a> { + pub color: Color, + pub text: &'a str, + pub bg_color: Option, +} + +#[inline] +pub unsafe fn display_message(start: Dot, params: WindowTextParams<'_>) { + const UTF8_FLAG: u32 = 0b0011_0000 << 24; + const BG_FLAG: u32 = 0b0100_0000 << 24; + // XXX: llvm uses esi internally for x86-32 + // hope we're lucky enough so it won't be overwritten. + asm!("mov esi, {}", in(reg) params.text.len()); + syscall!( + 4, + in("ebx") start.x * 65536 + start.y, + in("ecx") params.color.as_rgb_val() | BG_FLAG * params.bg_color.is_some() as u32 | UTF8_FLAG, + in("edx") params.text.as_ptr() + ); +} + +#[inline] +pub unsafe fn end_window_draw() { + syscall!(12, in("ebx") 2); +} + +pub fn exit() -> ! { + unsafe { syscall!(-1) }; + + unsafe { core::hint::unreachable_unchecked() } +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + exit(); +} + +#[non_exhaustive] +pub enum Event { + Redraw, + KeyPress, +} + +#[inline] +pub fn fetch_event() -> Option { + match unsafe { syscall!(10) } { + 1 => Some(Event::Redraw), + 2 => Some(Event::KeyPress), + _ => None, + } +} + +#[inline] +pub fn fetch_key() -> Option { + let res = unsafe { syscall!(2) }; + if res == 1 { + None + } else { + Some(((res >> 8) & 0xff) as u8) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..2f045cf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,51 @@ +#![feature(asm)] +#![no_std] +#![no_main] + +use cstr_core::{cstr, CStr}; + +use hw_kolibri::{Color, Dot, Event, WindowKind, WindowParams, WindowTextParams}; + +const HEADER: &CStr = cstr!("Hey Kolibri"); +const MSG: &str = "Hello from Rust!"; + +#[inline(always)] // for some reason function removed otherwise +fn draw_window() { + unsafe { + hw_kolibri::start_window_draw(); + hw_kolibri::define_window( + Dot { x: 50, y: 50 }, + 300, + 400, + WindowParams { + color: Color::rgb(0xff, 0xff, 0xff), + kind: WindowKind::Themed, + title: Some(HEADER), + }, + ); + hw_kolibri::display_message( + Dot { x: 0, y: 10 }, + WindowTextParams { + color: Color::rgb(0x66, 0x22, 0x22), + text: MSG, + bg_color: None, + }, + ); + hw_kolibri::end_window_draw(); + } +} + +#[no_mangle] +fn kol_main() -> ! { + draw_window(); + + while let Some(ev) = hw_kolibri::fetch_event() { + match ev { + Event::Redraw => draw_window(), + Event::KeyPress => drop(hw_kolibri::fetch_key()), + _ => break, + } + } + + hw_kolibri::exit(); +}