From 59d825577a7f5c2d244f8267126898c1eb37a753 Mon Sep 17 00:00:00 2001 From: sweetbread Date: Sat, 13 Jan 2024 13:51:44 +0300 Subject: [PATCH] feat: Buttons + events wip: malloc feat: Buttons --- Makefile.toml | 2 +- build.rs | 17 ++-- example/hwa.rs | 76 ++++++++++++++--- i686-kolibri.json | 3 +- link.x | 41 ++++----- src/allocation.rs | 184 +++++++++++++++++++++++++++++++++++++++++ src/func_constants.inc | 8 ++ src/lib.rs | 26 +++++- src/modules.rs | 1 + src/modules/system.rs | 33 ++++++++ src/modules/threads.rs | 12 +++ src/modules/windows.rs | 67 +++++++++++++++ src/sys.rs | 24 ++++++ src/syscalls.S | 50 +++++++++++ 14 files changed, 502 insertions(+), 42 deletions(-) create mode 100644 src/allocation.rs create mode 100644 src/modules/system.rs diff --git a/Makefile.toml b/Makefile.toml index 06c4b9e..6be534b 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -21,6 +21,6 @@ args = ["build"] [tasks.objcopy] command = "cargo" -args = ["objcopy", "@@remove-empty(RELEASE_FLAG)", "--", "-Obinary"] +args = ["objcopy", "@@remove-empty(RELEASE_FLAG)", "--", "-O binary", "--strip-all"] dependencies = ["build-1"] install_crate = { crate_name = "cargo-binutils", binary = "rust-objcopy", test_arg = ["--help"] } diff --git a/build.rs b/build.rs index b42244f..3bc9533 100644 --- a/build.rs +++ b/build.rs @@ -1,19 +1,20 @@ -use std::{process::Command, env}; +use std::{env, process::Command}; fn main() { println!("cargo:rerun-if-changed=src/syscalls.S"); let out_dir = env::var("OUT_DIR").unwrap(); - + Command::new("fasm") .arg("src/syscalls.S") .arg(&format!("{}/libsyscalls.a", out_dir)) - .status().unwrap(); - Command::new("ar") - .arg("crus") - .arg(&format!("{}/libsyscalls.a", out_dir)) - .arg(&format!("{}/libsyscalls.o", out_dir)) - .status().unwrap(); + .status() + .unwrap(); + // Command::new("ar") + // .arg("crus") + // .arg(&format!("{}/libsyscalls.a", out_dir)) + // .arg(&format!("{}/libsyscalls.o", out_dir)) + // .status().unwrap(); println!("cargo:rustc-link-search={}", out_dir) } diff --git a/example/hwa.rs b/example/hwa.rs index dd62107..8c0fcc5 100644 --- a/example/hwa.rs +++ b/example/hwa.rs @@ -3,17 +3,26 @@ use cstr_core::{cstr, CStr}; -use kos::graphics::{display_message, Color, Dot, Size}; -use kos::input::fetch_key; -use kos::threads::{exit, fetch_event, Event}; -use kos::windows::{define_window, end_window_draw, start_window_draw, WindowKind, WindowParams}; +use kos::{ + graphics::{display_message, Color, Dot, Size}, + input::fetch_key, + threads::{exit, fetch_event, Event}, + windows::{ + define_button, define_window, end_window_draw, get_button_id, start_window_draw, + WindowKind, WindowParams, CLOSE_BUTTON, + }, +}; const HEADER: &CStr = cstr!("Hey Kolibri"); const MSG: &CStr = cstr!("Hello from Rust!"); +const BTN: u32 = 42; -#[inline(always)] // for some reason function removed otherwise -fn draw_window() { +#[macro_use] +extern crate alloc; + +fn draw_window(c: usize) { start_window_draw(); + define_window( Dot { x: 50, y: 50 }, Size { @@ -26,21 +35,64 @@ fn draw_window() { title: Some(HEADER), }, ); - display_message(Dot { x: 0, y: 10 }, Color::rgb(0x66, 0x22, 0x22), MSG, None); + + display_message( + Dot { x: 10, y: 10 }, + Color::rgb(0x66, 0x22, 0x22), + MSG, + None, + ); + + display_message( + Dot { x: 10, y: 30 }, + Color::rgb(0, 0, 0), + CStr::from_bytes_with_nul(format!("Button pressed: {} times\0", c).as_bytes()) + .unwrap_or(cstr!("String error")), + None, + ); + + define_button( + Dot { x: 10, y: 70 }, + Size { + width: 70, + height: 15, + }, + BTN, + true, + true, + Some(Color::rgb(128, 255, 128)), + ); + end_window_draw(); + + return; +} + +fn button_handler(c: &mut usize) { + let btn_id = get_button_id(); + + if btn_id.is_some() { + match btn_id.unwrap() { + CLOSE_BUTTON => exit(), + BTN => { + *c += 1; + draw_window(*c); + } + _ => {} + } + } } #[no_mangle] -fn kol_main() -> ! { - draw_window(); +fn kol_main() { + let mut c = 0; while let Some(ev) = fetch_event() { match ev { - Event::Redraw => draw_window(), + Event::Redraw => draw_window(c), Event::KeyPress => drop(fetch_key()), + Event::BtnPress => button_handler(&mut c), _ => break, } } - - exit(); } diff --git a/i686-kolibri.json b/i686-kolibri.json index e9acf65..763b2fb 100644 --- a/i686-kolibri.json +++ b/i686-kolibri.json @@ -18,6 +18,7 @@ "target-endian": "little", "target-pointer-width": "32", "vendor": "unknown", + "disable-redzone": true, "panic-strategy": "abort", - "disable-redzone": true + "singlethread": true } diff --git a/link.x b/link.x index 75b506f..feef1c9 100644 --- a/link.x +++ b/link.x @@ -1,33 +1,36 @@ PATH_SIZE = 1024; PARAMS_SIZE = 256; -STACK_SIZE = 1024; +STACK_SIZE = 1024*4; + +SECTIONS { + hdr : { + LONG(0x554e454D); + LONG(0x31305445); + LONG(1); // Header version + LONG(kol_main); // Program start + LONG(END); // Image size + LONG(FILE_END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); // Required amount of memory + LONG(FILE_END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); // Stack + LONG(FILE_END + PATH_SIZE); // Boot params + LONG(FILE_END); // Application path + } -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) + + END = .; + + .data ALIGN(16) : { + *(.rodata.*) *(const) *(CONST) *(.data) *(data) } + .bss ALIGN(16) : {*(.bss)} -FILE_END = .; + + FILE_END = .; } diff --git a/src/allocation.rs b/src/allocation.rs new file mode 100644 index 0000000..68a72e2 --- /dev/null +++ b/src/allocation.rs @@ -0,0 +1,184 @@ +use crate::system::debug_write; +use crate::{sys, throw_new}; +use core::alloc::Layout; +use core::mem::size_of; +use core::ptr::null_mut; +use core::sync::atomic::{AtomicBool, Ordering}; + +extern crate alloc; + +const PAGE_SIZE: usize = 4096; +static mut MAIN_SECTOR: usize = 0; + +#[derive(Clone, Copy)] +enum Sign { + Dead = 0, + Active = 1, + Free = 2, +} + +#[derive(Clone, Copy)] +struct SectorHeader { + pub size: usize, + pub size_left: usize, +} + +#[derive(Clone, Copy)] +struct BlockHeader { + pub sign: Sign, + pub size: usize, +} + +static HEAP_INIT: AtomicBool = AtomicBool::new(false); + +pub fn init() { + if !HEAP_INIT.swap(true, Ordering::Relaxed) { + unsafe { + sys::init_heap(); + MAIN_SECTOR = sys::alloc(PAGE_SIZE) as usize; + } + } +} + +pub fn malloc(size: usize) -> *mut u8 { + unsafe { + for i in 0..PAGE_SIZE / 4 { + let addr = *((MAIN_SECTOR + i * 4) as *const u32) as *const u8; + + if (addr as usize) != 0 { + let sec = addr; + let mut hdr = *(addr as *const SectorHeader); + let sec_start_blocks = (sec as usize) + size_of::(); + if hdr.size_left >= size { + let mut j = sec_start_blocks; + let mut first_found_block_addr = 0; + + while j <= sec_start_blocks + hdr.size { + let mut block = *(j as *const BlockHeader); + match block.sign { + Sign::Active => { + // If block is occupated - pass + first_found_block_addr = 0; + j += size_of::() + block.size; + } + + Sign::Free => { + if first_found_block_addr != 0 { + first_found_block_addr = j; + } + + let sum_size = j - first_found_block_addr + block.size; + if sum_size < size { + // if not enough size - pass and find next block + j += (size_of::()) + block.size; + } else if size - sum_size < size_of::() { + // Create 2 blocks + let mut main_block = + *(first_found_block_addr as *const BlockHeader); + main_block.sign = Sign::Active; + main_block.size = size; + + let mut secondary_block = *(first_found_block_addr + as *const BlockHeader) + .add(size_of::() + size); + secondary_block.sign = Sign::Free; + secondary_block.size = + sum_size - size - size_of::(); + + return (first_found_block_addr as *mut u8) + .add(size_of::()); + } else { + // Create 1 block + let mut main_block = + *(first_found_block_addr as *const BlockHeader); + main_block.sign = Sign::Active; + main_block.size = sum_size - size_of::(); + return (first_found_block_addr as *mut u8) + .add(size_of::()); + } + } + + Sign::Dead => { + // We found \0 - dead zone. There are no further blocks + if j + size + size_of::() + <= sec_start_blocks + hdr.size + { + // There is enough space for creating new block + block.sign = Sign::Active; + block.size = size; + hdr.size_left -= size + size_of::(); + return (j + size_of::()) as *mut u8; + } else { + // There is not enough space, go to next sector + break; + } + } + } + } + } + } else { + let sec_size = size + PAGE_SIZE - size % PAGE_SIZE; + let new_sec = sys::alloc(sec_size); + let sec_hdr = new_sec as *mut SectorHeader; + *sec_hdr = SectorHeader { + size: sec_size, + size_left: sec_size - size_of::(), + }; + let new_block = new_sec.add(size_of::()) as *mut BlockHeader; + (*new_block).sign = Sign::Active; + (*new_block).size = size; + (*sec_hdr).size_left -= size + size_of::(); + return new_block.add(1) as *mut u8; + } + } + } + + panic!("Malloc error: end of the loop") +} + +fn free(block: *const u8) { + unsafe { + let mut block_hdr = *(block.sub(size_of::()) as *mut BlockHeader); + + for i in 0..PAGE_SIZE / 4 { + let addr = *((MAIN_SECTOR + i * 4) as *const u32) as *const u8; + let mut hdr = *(addr as *const SectorHeader); + + if addr < block && (block as usize) < (addr as usize) + hdr.size { + hdr.size_left += block_hdr.size; + if hdr.size_left == hdr.size - size_of::() { + free(addr) + } else { + block_hdr.sign = Sign::Free; + } + break; + } + } + + if !sys::free(block) { + panic!("Free failed"); + } + } +} + +struct GlobalAlloc; + +unsafe impl alloc::alloc::GlobalAlloc for GlobalAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() != 1 { + throw_new!("Only byte aligned available now"); + return null_mut(); + } + + init(); + malloc(layout.size()) + } + + unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) { + // free keeps track of layout presumably???? + free(ptr) + } +} + +#[global_allocator] +static ALLOC: GlobalAlloc = GlobalAlloc; diff --git a/src/func_constants.inc b/src/func_constants.inc index 76359f3..e9fff2c 100644 --- a/src/func_constants.inc +++ b/src/func_constants.inc @@ -4,7 +4,15 @@ SF_PUT_PIXEL = 1 SF_GET_KEY = 2 SF_GET_SYS_TIME = 3 SF_DRAW_TEXT = 4 +SF_DEFINE_BUTTON = 8 SF_WAIT_EVENT = 10 SF_REDRAW = 12 SSF_BEGIN_DRAW = 1 SSF_END_DRAW = 2 +SF_GET_BUTTON = 17 +SF_BOARD = 63 + SSF_DEBUG_WRITE = 1 +SF_SYS_MISC = 68 + SSF_HEAP_INIT = 11 + SSF_MEM_ALLOC = 12 + SSF_MEM_FREE = 13 diff --git a/src/lib.rs b/src/lib.rs index 838fe2e..fac55f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,30 @@ mod modules; mod nanolibc; -mod sys; +pub mod sys; +pub mod allocation; pub use modules::*; + +#[macro_use] +extern crate alloc; + +#[macro_export] +macro_rules! throw_new { + ($text:expr) => { + debug_write(&format!( + "{}:{}\nAn error raised:\n{}\n", + file!(), + line!(), + $text + )); + }; +} + +#[macro_export] +macro_rules! panic { + ($text:expr) => { + debug_write(cstr_core::cstr!("Panic!\n" + $text + "\n")); + sys::exit(); + }; +} diff --git a/src/modules.rs b/src/modules.rs index 8321061..759d7a5 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -1,4 +1,5 @@ pub mod graphics; pub mod input; +pub mod system; pub mod threads; pub mod windows; diff --git a/src/modules/system.rs b/src/modules/system.rs new file mode 100644 index 0000000..d500d25 --- /dev/null +++ b/src/modules/system.rs @@ -0,0 +1,33 @@ +use crate::sys; +use alloc::string::String; +use cstr_core::CStr; + +trait Debuggable { + fn data_iter(self) -> impl Iterator; +} + +impl Debuggable for &str { + fn data_iter(self) -> impl Iterator { + self.bytes() + } +} + +impl Debuggable for &String { + fn data_iter(self) -> impl Iterator { + self.as_bytes().iter().copied() + } +} + +impl Debuggable for &CStr { + fn data_iter(self) -> impl Iterator { + self.to_bytes().iter().copied() + } +} + +pub fn debug_write(text: Str) { + for byte in text.data_iter() { + unsafe { + sys::_debug_write(byte); + } + } +} diff --git a/src/modules/threads.rs b/src/modules/threads.rs index fd70a19..02d4547 100644 --- a/src/modules/threads.rs +++ b/src/modules/threads.rs @@ -8,12 +8,24 @@ pub fn exit() -> ! { pub enum Event { Redraw, KeyPress, + BtnPress, + BgRedraw, + Mouse, + IPC, + Network, + Debug, } pub fn fetch_event() -> Option { match unsafe { sys::wait_event() } { 1 => Some(Event::Redraw), 2 => Some(Event::KeyPress), + 3 => Some(Event::BtnPress), + 5 => Some(Event::BgRedraw), + 6 => Some(Event::Mouse), + 7 => Some(Event::IPC), + 8 => Some(Event::Network), + 9 => Some(Event::Debug), _ => None, } } diff --git a/src/modules/windows.rs b/src/modules/windows.rs index e042844..d6e5785 100644 --- a/src/modules/windows.rs +++ b/src/modules/windows.rs @@ -1,5 +1,8 @@ use crate::graphics::{Color, Dot, Size}; use crate::sys; +use crate::system::debug_write; +use crate::throw_new; +use cstr_core::{cstr, CStr}; #[repr(u32)] pub enum WindowKind { @@ -16,6 +19,8 @@ pub struct WindowParams<'a> { pub title: Option<&'a cstr_core::CStr>, } +pub const CLOSE_BUTTON: u32 = 1; + pub fn define_window(start: Dot, size: Size, params: WindowParams<'_>) { const RELATIVE_FLAG: u32 = 0x20; @@ -34,6 +39,68 @@ pub fn define_window(start: Dot, size: Size, params: WindowParams<'_>) { } } +pub fn define_button( + start: Dot, + size: Size, + id: u32, + draw: bool, + border: bool, + color: Option, +) { + if 0 >= size.width || size.width >= 0x8000 || 0 >= size.height || size.height >= 0x8000 { + crate::graphics::display_message( + Dot { x: 10, y: 200 }, + Color::rgb(255, 0, 0), + CStr::from_bytes_with_nul( + format!( + "x:{:?} y:{:?} w:{:?} h:{:?}\n\0", + start.x, start.y, size.width, size.height + ) + .as_bytes(), + ) + .unwrap_or(cstr!("String error")), + None, + ); + throw_new!(format!( + "x:{:?} y:{:?} w:{:?} h:{:?}\n", + start.x, start.y, size.width, size.height + )); + return; + } + if id > 0xFFFFFF { + throw_new!("Invalid button ID"); + return; + } + + let mut flags = 0; + if !draw { + flags += 1 << 30 + }; + if !border { + flags += 1 << 29 + }; + + unsafe { + sys::define_button( + start.x << 16 | size.width, + start.y << 16 | size.height, + flags << 29 | id, + color.unwrap_or(Color::rgb(255, 255, 255)).as_rgb_val(), + ); + } +} + +// TODO: mouse button info +pub fn get_button_id() -> Option { + unsafe { + let eax = sys::get_button_id(); + if eax == 1 { + return None; + } + return Some(eax >> 8); + } +} + pub fn start_window_draw() { unsafe { sys::start_window_draw() } } diff --git a/src/sys.rs b/src/sys.rs index c5b4eb2..9489c35 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -16,6 +16,10 @@ extern "C" { #[link_name = "_display_message"] pub fn display_message(ebx: u32, ecx: u32, edx: u32, edi: u32); + // 8 + #[link_name = "_define_button"] + pub fn define_button(ebx: u32, ecx: u32, edx: u32, esi: u32); + // 10 #[link_name = "_wait_event"] pub fn wait_event() -> u32; @@ -27,4 +31,24 @@ extern "C" { // 12.2 #[link_name = "_end_window_draw"] pub fn end_window_draw(); + + // 17 + #[link_name = "_get_button_id"] + pub fn get_button_id() -> u32; + + // 63.1 + #[link_name = "_debug_write"] + pub fn _debug_write(cl: u8); + + // 68.11 + #[link_name = "_init_heap"] + pub fn init_heap(); + + // 68.12 + #[link_name = "_alloc"] + pub fn alloc(size: usize) -> *const u8; + + // 68.13 + #[link_name = "_free"] + pub fn free(block: *const u8) -> bool; } diff --git a/src/syscalls.S b/src/syscalls.S index 2ffe630..2db1a6d 100644 --- a/src/syscalls.S +++ b/src/syscalls.S @@ -10,6 +10,12 @@ section '.text' public _display_message public _wait_event public _pressed_key + public _define_button + public _debug_write + public _get_button_id + public _init_heap + public _alloc + public _free _exit: mov eax, SF_TERMINATE_PROCESS @@ -61,3 +67,47 @@ _pressed_key: mov eax, SF_GET_KEY int 0x40 ret + +_define_button: + push esi edi + mov eax, SF_DEFINE_BUTTON + mov ebx, dword [esp + 4 * 3] + mov ecx, dword [esp + 4 * 4] + mov edx, dword [esp + 4 * 5] + mov esi, dword [esp + 4 * 6] + int 0x40 + pop edi esi + ret + +_debug_write: + mov eax, SF_BOARD + mov ebx, SSF_DEBUG_WRITE + mov cl , byte [esp + 4 * 1] + int 0x40 + ret + +_get_button_id: + mov eax, SF_GET_BUTTON + int 0x40 + ret + +_init_heap: + mov eax, SF_SYS_MISC + mov ebx, SSF_HEAP_INIT + int 0x40 + ret + +_alloc: + mov eax, SF_SYS_MISC + mov ebx, SSF_MEM_ALLOC + mov ecx, [esp + 4 * 1] + int 0x40 + ret + +_free: + mov eax, SF_SYS_MISC + mov ebx, SSF_MEM_FREE + mov ecx, [esp + 4 * 1] + int 0x40 + ret +