├── Cargo.lock ├── Cargo.toml ├── Makefile.toml ├── README.md ├── build.rs ├── examples ├── bf.rs ├── con.rs ├── dark.rs └── hwa.rs ├── i686-kolibri.json ├── link.x ├── rust-toolchain └── src ├── allocation.rs ├── dll.rs ├── dll └── console.rs ├── func_constants.inc ├── lib.rs ├── modules.rs ├── modules ├── graphics.rs ├── input.rs ├── system.rs ├── threads.rs ├── vec.rs └── windows.rs ├── nanolibc.rs ├── sys.rs └── syscalls.S /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "kos" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kos" 3 | version = "0.1.0" 4 | authors = ["Kitsu ", "Sweetbread"] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [[example]] 10 | name = "hwa" 11 | path = "examples/hwa.rs" 12 | 13 | [[example]] 14 | name = "con" 15 | path = "examples/con.rs" 16 | 17 | [[example]] 18 | name = "dark" 19 | path = "examples/dark.rs" 20 | 21 | [profile.release] 22 | opt-level = "z" 23 | lto = "thin" 24 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [env.production] 2 | RELEASE_FLAG = "--release" 3 | 4 | [tasks.default] 5 | alias = "all" 6 | 7 | [tasks.all] 8 | dependencies = ["build"] 9 | 10 | [tasks.clean] 11 | command = "cargo" 12 | args = ["clean"] 13 | 14 | [tasks.build] 15 | command = "cargo" 16 | args = ["build", "@@remove-empty(RELEASE_FLAG)"] 17 | 18 | [tasks.example] 19 | command = "cargo" 20 | args = ["objcopy", "@@remove-empty(RELEASE_FLAG)", "--example", "${@}", "--", "-O", "binary", "--strip-all", "${@}.kex"] 21 | # install_crate = { crate_name = "cargo-binutils", binary = "rust-objcopy", test_arg = ["--help"] } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust library for KolibriOS 2 | 3 | Project uses cargo-make for building steps. You need to install cargo-binutils: 4 | `cargo install cargo-binutils` and llvm-tools-preview: `rustup component add llvm-tools-preview` 5 | to make it work. Also you need a working FASM. 6 | 7 | Once installed building is trivial then: 8 | `cargo make --profile production example ` 9 | produces a ready-to-use binary at root. 10 | 11 | ## Star History 12 | 13 | [![Star History Chart](https://api.star-history.com/svg?repos=paulcodeman/rust-kolibrios&type=Date)](https://star-history.com/#paulcodeman/rust-kolibrios&Date) 14 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, process::Command}; 2 | 3 | fn main() { 4 | println!("cargo:rerun-if-changed=src/syscalls.S"); 5 | 6 | let out_dir = env::var("OUT_DIR").unwrap(); 7 | 8 | Command::new("fasm") 9 | .arg("src/syscalls.S") 10 | .arg(&format!("{}/libsyscalls.a", out_dir)) 11 | .status() 12 | .unwrap(); 13 | // Command::new("ar") 14 | // .arg("crus") 15 | // .arg(&format!("{}/libsyscalls.a", out_dir)) 16 | // .arg(&format!("{}/libsyscalls.o", out_dir)) 17 | // .status().unwrap(); 18 | 19 | println!("cargo:rustc-link-search={}", out_dir) 20 | } 21 | -------------------------------------------------------------------------------- /examples/bf.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use kos::{dll::Console, threads::exit}; 5 | extern crate alloc; 6 | 7 | const TAPE_SIZE: usize = 30000; 8 | 9 | fn interpret_bf(code: &str) { 10 | let mut tape = [0u8; TAPE_SIZE]; 11 | let mut ptr = 0; 12 | let mut pc = 0; 13 | let mut loop_stack = [0usize; 16]; 14 | let mut loop_stack_ptr = 0; 15 | 16 | while pc < code.len() { 17 | match code.as_bytes()[pc] as char { 18 | '>' => ptr = (ptr + 1) % TAPE_SIZE, 19 | '<' => ptr = (ptr + TAPE_SIZE - 1) % TAPE_SIZE, 20 | '+' => tape[ptr] = tape[ptr].wrapping_add(1), 21 | '-' => tape[ptr] = tape[ptr].wrapping_sub(1), 22 | '.' => { 23 | let con_lib = Console::import(None).unwrap(); 24 | con_lib.write_char(tape[ptr] as char); 25 | } 26 | ',' => { 27 | let con_lib = Console::import(None).unwrap(); 28 | tape[ptr] = con_lib.gets().as_bytes()[0]; 29 | } 30 | '[' => { 31 | if tape[ptr] == 0 { 32 | let mut open_brackets = 1; 33 | while open_brackets > 0 { 34 | pc += 1; 35 | if code.as_bytes()[pc] as char == '[' { 36 | open_brackets += 1; 37 | } else if code.as_bytes()[pc] as char == ']' { 38 | open_brackets -= 1; 39 | } 40 | } 41 | } else { 42 | loop_stack[loop_stack_ptr] = pc; 43 | loop_stack_ptr += 1; 44 | } 45 | } 46 | ']' => { 47 | if tape[ptr] != 0 { 48 | pc = loop_stack[loop_stack_ptr - 1]; 49 | } else { 50 | loop_stack_ptr -= 1; 51 | } 52 | } 53 | _ => {} 54 | } 55 | pc += 1; 56 | } 57 | } 58 | 59 | #[no_mangle] 60 | pub fn kol_main() { 61 | let con_lib = Console::import(None).unwrap(); 62 | con_lib.init(u32::MAX, u32::MAX, u32::MAX, u32::MAX, c"BrainF*ck"); 63 | 64 | loop { 65 | con_lib.write_string("Enter BF code: "); 66 | let code = con_lib.gets(); 67 | interpret_bf(&code); 68 | con_lib.write_string("\n"); 69 | } 70 | 71 | con_lib.exit(false); 72 | exit(); 73 | } -------------------------------------------------------------------------------- /examples/con.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use kos::{dll::Console, threads::exit}; 5 | 6 | extern crate alloc; 7 | 8 | #[no_mangle] 9 | pub fn kol_main() { 10 | let con_lib = Console::import(None).unwrap(); 11 | con_lib.init(u32::MAX, u32::MAX, u32::MAX, u32::MAX, c"Rust!"); 12 | con_lib.write_string("Hi from Rust!"); 13 | con_lib.exit(false); 14 | 15 | exit(); 16 | } 17 | -------------------------------------------------------------------------------- /examples/dark.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use kos::{ 5 | graphics::{display_message, Color, Dot, Size}, 6 | input::fetch_key, 7 | threads::{exit, fetch_event, Event}, 8 | windows::{ 9 | define_button, define_window, end_window_draw, get_button_id, invert_pixel, 10 | start_window_draw, WindowKind, WindowParams, CLOSE_BUTTON, 11 | }, 12 | }; 13 | 14 | const HEADER: &'static CStr = c"Dark Mode Demo"; 15 | const TEXT: [&'static CStr; 6] = [ 16 | c"Lorem ipsum dolor sit amet,", 17 | c"semper et rutrum placerat,", 18 | c"Integer sed diam commodo quam varius", 19 | c"Sed finibus urna sit amet felis", 20 | c"vestibulum elementum. Maecenas at feugiat lacus", 21 | c"tristique et sit amet tortor.", 22 | ]; 23 | const BTN: u32 = 42; 24 | const WINDOW_SIZE: Size = Size { 25 | width: 400, 26 | height: 400, 27 | }; 28 | 29 | extern crate alloc; 30 | 31 | fn draw_window(invert: bool) { 32 | start_window_draw(); 33 | 34 | define_window( 35 | Dot { x: 50, y: 50 }, 36 | WINDOW_SIZE, 37 | WindowParams { 38 | color: Color::rgb(0xff, 0xff, 0xff), 39 | kind: WindowKind::FixedThemed, 40 | title: Some(HEADER), 41 | }, 42 | ); 43 | 44 | display_message(Dot { x: 10, y: 10 }, Color::rgb(0, 0, 0), TEXT[0], None); 45 | display_message(Dot { x: 10, y: 50 }, Color::rgb(0, 0, 0), TEXT[1], None); 46 | display_message(Dot { x: 10, y: 90 }, Color::rgb(0, 0, 0), TEXT[2], None); 47 | display_message(Dot { x: 10, y: 130 }, Color::rgb(0, 0, 0), TEXT[3], None); 48 | display_message(Dot { x: 10, y: 170 }, Color::rgb(0, 0, 0), TEXT[4], None); 49 | display_message(Dot { x: 10, y: 210 }, Color::rgb(0, 0, 0), TEXT[5], None); 50 | 51 | define_button( 52 | Dot { x: 10, y: 300 }, 53 | Size { 54 | width: 100, 55 | height: 30, 56 | }, 57 | BTN, 58 | true, 59 | true, 60 | Some(Color::rgb(147, 112, 219)), 61 | ); 62 | 63 | display_message( 64 | Dot { x: 20, y: 310 }, 65 | Color::rgb(255, 255, 255), 66 | if invert { 67 | c"Light mode" 68 | } else { 69 | c"Dark mode" 70 | }, 71 | None, 72 | ); 73 | 74 | if invert { 75 | for x in 0..WINDOW_SIZE.width { 76 | for y in 0..WINDOW_SIZE.height { 77 | invert_pixel(Dot { x, y }) 78 | } 79 | } 80 | } 81 | 82 | end_window_draw(); 83 | 84 | return; 85 | } 86 | 87 | fn button_handler(invert: &mut bool) { 88 | let btn_id = get_button_id(); 89 | 90 | if btn_id.is_some() { 91 | match btn_id.unwrap() { 92 | CLOSE_BUTTON => exit(), 93 | BTN => { 94 | *invert = !*invert; 95 | draw_window(*invert); 96 | } 97 | _ => {} 98 | } 99 | } 100 | } 101 | 102 | #[no_mangle] 103 | fn kol_main() { 104 | let mut invert = false; 105 | 106 | while let Some(ev) = 107 | fetch_event((Event::Redraw as u32) | (Event::KeyPress as u32) | (Event::BtnPress as u32)) 108 | { 109 | match ev { 110 | Event::Redraw => draw_window(invert), 111 | Event::KeyPress => drop(fetch_key()), 112 | Event::BtnPress => button_handler(&mut invert), 113 | _ => break, 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /examples/hwa.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use alloc::ffi::CString; 5 | use core::ffi::CStr; 6 | use kos::{ 7 | graphics::{display_message, Color, Dot, Size}, 8 | input::fetch_key, 9 | system::{get_lang, Lang}, 10 | threads::{exit, fetch_event, Event}, 11 | windows::{ 12 | define_button, define_window, end_window_draw, get_button_id, start_window_draw, 13 | WindowKind, WindowParams, CLOSE_BUTTON, 14 | }, 15 | }; 16 | 17 | const HEADER: &CStr = c"Hey Kolibri"; 18 | const MSG: &CStr = c"Hello from Rust!"; 19 | const BTN: u32 = 42; 20 | 21 | #[macro_use] 22 | extern crate alloc; 23 | 24 | fn draw_window(c: usize) { 25 | start_window_draw(); 26 | 27 | define_window( 28 | Dot { x: 50, y: 50 }, 29 | Size { 30 | width: 300, 31 | height: 400, 32 | }, 33 | WindowParams { 34 | color: Color::rgb(0xff, 0xff, 0xff), 35 | kind: WindowKind::Themed, 36 | title: Some(HEADER), 37 | }, 38 | ); 39 | 40 | display_message( 41 | Dot { x: 10, y: 10 }, 42 | Color::rgb(0x66, 0x22, 0x22), 43 | MSG, 44 | None, 45 | ); 46 | 47 | let btn_str = match get_lang() { 48 | Lang::German => format!("Taste gedrückt: {} mal", c), 49 | Lang::Russian => format!("Кнопка нажата: {} раз", c), 50 | Lang::French => format!("Button enfoncé : {} fois", c), 51 | _ => format!("Button pressed: {} times", c), 52 | }; 53 | 54 | display_message( 55 | Dot { x: 10, y: 30 }, 56 | Color::rgb(0, 0, 0), 57 | CString::new(btn_str.as_bytes()) 58 | .expect("CString error") 59 | .as_c_str(), 60 | None, 61 | ); 62 | 63 | define_button( 64 | Dot { x: 10, y: 70 }, 65 | Size { 66 | width: 70, 67 | height: 15, 68 | }, 69 | BTN, 70 | true, 71 | true, 72 | Some(Color::rgb(128, 255, 128)), 73 | ); 74 | 75 | end_window_draw(); 76 | 77 | return; 78 | } 79 | 80 | fn button_handler(c: &mut usize) { 81 | let btn_id = get_button_id(); 82 | 83 | if btn_id.is_some() { 84 | match btn_id.unwrap() { 85 | CLOSE_BUTTON => exit(), 86 | BTN => { 87 | *c += 1; 88 | draw_window(*c); 89 | } 90 | _ => {} 91 | } 92 | } 93 | } 94 | 95 | #[no_mangle] 96 | fn kol_main() { 97 | let mut c = 0; 98 | 99 | while let Some(ev) = 100 | fetch_event((Event::Redraw as u32) | (Event::KeyPress as u32) | (Event::BtnPress as u32)) 101 | { 102 | match ev { 103 | Event::Redraw => draw_window(c), 104 | Event::KeyPress => drop(fetch_key()), 105 | Event::BtnPress => button_handler(&mut c), 106 | _ => break, 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /i686-kolibri.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "x86", 3 | "cpu": "pentium", 4 | "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", 5 | "dynamic-linking": false, 6 | "executables": true, 7 | "has-rpath": true, 8 | "is-builtin": false, 9 | "linker-flavor": "ld.lld", 10 | "linker": "rust-lld", 11 | "llvm-target": "i686-unknown-none-code32", 12 | "max-atomic-width": 32, 13 | "os": "none", 14 | "relocation-model": "static", 15 | "position-independent-executables": false, 16 | "relro-level": "off", 17 | "target-c-int-width": "32", 18 | "target-endian": "little", 19 | "target-pointer-width": "32", 20 | "vendor": "unknown", 21 | "disable-redzone": true, 22 | "panic-strategy": "abort", 23 | "singlethread": true 24 | } 25 | -------------------------------------------------------------------------------- /link.x: -------------------------------------------------------------------------------- 1 | PATH_SIZE = 1024; 2 | PARAMS_SIZE = 256; 3 | STACK_SIZE = 1024*64; 4 | 5 | SECTIONS { 6 | hdr : { 7 | LONG(0x554e454D); 8 | LONG(0x31305445); 9 | LONG(1); // Header version 10 | LONG(kol_main); // Program start 11 | LONG(END); // Image size 12 | LONG(FILE_END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); // Required amount of memory 13 | LONG(FILE_END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); // Stack 14 | LONG(FILE_END + PATH_SIZE); // Boot params 15 | LONG(FILE_END); // Application path 16 | } 17 | 18 | .text : { 19 | *(.text) 20 | *(.text.*) 21 | } 22 | 23 | END = .; 24 | 25 | .data ALIGN(16) : { 26 | *(.rodata.*) 27 | *(const) 28 | *(CONST) 29 | *(.data) 30 | *(data) 31 | } 32 | 33 | .bss ALIGN(16) : {*(.bss)} 34 | 35 | FILE_END = .; 36 | } 37 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly 2 | -------------------------------------------------------------------------------- /src/allocation.rs: -------------------------------------------------------------------------------- 1 | use crate::system::debug_write; 2 | use crate::{sys, throw_new}; 3 | use core::alloc::Layout; 4 | use core::mem::size_of; 5 | use core::ptr::null_mut; 6 | use core::sync::atomic::{AtomicBool, Ordering}; 7 | 8 | extern crate alloc; 9 | 10 | const PAGE_SIZE: usize = 4096; 11 | static mut MAIN_SECTOR: usize = 0; 12 | 13 | #[derive(Clone, Copy, PartialEq)] // Добавлено PartialEq для сравнения в дальнейшем 14 | enum Sign { 15 | Dead = 0, 16 | Active = 1, 17 | Free = 2, 18 | } 19 | 20 | #[derive(Clone, Copy)] 21 | struct SectorHeader { 22 | pub size: usize, 23 | pub size_left: usize, 24 | } 25 | 26 | #[derive(Clone, Copy)] 27 | struct BlockHeader { 28 | pub sign: Sign, 29 | pub size: usize, 30 | } 31 | 32 | static HEAP_INIT: AtomicBool = AtomicBool::new(false); 33 | 34 | pub fn init() { 35 | if !HEAP_INIT.swap(true, Ordering::Relaxed) { 36 | unsafe { 37 | sys::init_heap(); 38 | MAIN_SECTOR = sys::alloc(PAGE_SIZE) as usize; 39 | // Инициализация первого сектора 40 | let sec_hdr = MAIN_SECTOR as *mut SectorHeader; 41 | *sec_hdr = SectorHeader { 42 | size: PAGE_SIZE, 43 | size_left: PAGE_SIZE - size_of::(), 44 | }; 45 | } 46 | } 47 | } 48 | 49 | pub fn malloc(layout: Layout) -> *mut u8 { 50 | let size = layout.size(); 51 | let align = layout.align(); // Использование align из layout 52 | 53 | unsafe { 54 | let mut found_block: *mut BlockHeader = null_mut(); 55 | let mut found_block_size = 0; 56 | 57 | for i in 0..PAGE_SIZE / 4 { 58 | let addr = *((MAIN_SECTOR + i * 4) as *const u32) as *const u8; 59 | 60 | if (addr as usize) != 0 { 61 | let sec = addr; 62 | let hdr = *(addr as *const SectorHeader); // Убрано лишнее mut 63 | let sec_start_blocks = (sec as usize) + size_of::(); 64 | 65 | if hdr.size_left >= size { 66 | let mut j = sec_start_blocks; 67 | 68 | while j <= sec_start_blocks + hdr.size - size_of::() { 69 | let block = *(j as *const BlockHeader); 70 | 71 | match block.sign { 72 | Sign::Active => { 73 | j += size_of::() + block.size; 74 | } 75 | 76 | Sign::Free => { 77 | // Проверяем выравнивание блока 78 | let aligned_addr = (j + size_of::()) as *mut u8; 79 | let aligned_addr_value = aligned_addr as usize; 80 | if aligned_addr_value % align == 0 && block.size >= size && (found_block_size == 0 || block.size < found_block_size) { 81 | found_block = j as *mut BlockHeader; 82 | found_block_size = block.size; 83 | } 84 | j += size_of::() + block.size; 85 | } 86 | 87 | Sign::Dead => { 88 | if j + size + size_of::() 89 | <= sec_start_blocks + hdr.size 90 | && (found_block_size == 0 || (sec_start_blocks + hdr.size - j) < found_block_size) 91 | { 92 | found_block = j as *mut BlockHeader; 93 | found_block_size = sec_start_blocks + hdr.size - j; 94 | } 95 | break; 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | if found_block_size > 0 { 104 | if found_block_size >= size + size_of::() { 105 | let new_block = (found_block as *mut u8).add(size + size_of::()) as *mut BlockHeader; 106 | *new_block = BlockHeader { 107 | sign: Sign::Free, 108 | size: found_block_size - size - size_of::(), 109 | }; 110 | (*found_block).size = size; 111 | } 112 | 113 | (*found_block).sign = Sign::Active; 114 | let addr = (found_block as *mut u8).add(size_of::()); 115 | 116 | for i in 0..PAGE_SIZE / 4 { 117 | let sec_addr = *((MAIN_SECTOR + i * 4) as *const u32) as *const u8; 118 | if (sec_addr as usize) != 0 { 119 | let sec = sec_addr; 120 | let mut hdr = *(sec as *const SectorHeader); 121 | if (sec as usize) < (addr as usize) && (addr as usize) < (sec as usize) + hdr.size { 122 | hdr.size_left -= size + size_of::(); 123 | break; 124 | } 125 | } 126 | } 127 | 128 | return addr; 129 | } else { 130 | // Выделение новой страницы 131 | let sec_size = size + PAGE_SIZE - size % PAGE_SIZE; 132 | let new_sec = sys::alloc(sec_size) as *mut u8; 133 | if new_sec == null_mut() { 134 | return null_mut(); 135 | } 136 | let sec_hdr = new_sec as *mut SectorHeader; 137 | *sec_hdr = SectorHeader { 138 | size: sec_size, 139 | size_left: sec_size - size_of::(), 140 | }; 141 | 142 | // Добавление адреса новой страницы в таблицу страниц 143 | for i in 0..PAGE_SIZE / 4 { 144 | let addr = (MAIN_SECTOR + i * 4) as *mut u32; 145 | if *addr == 0 { 146 | *addr = new_sec as u32; 147 | break; 148 | } 149 | } 150 | 151 | let new_block = new_sec.add(size_of::()) as *mut BlockHeader; 152 | *new_block = BlockHeader { 153 | sign: Sign::Active, 154 | size: size, 155 | }; 156 | (*sec_hdr).size_left -= size + size_of::(); 157 | return new_block.add(size_of::()) as *mut u8; // Возвращаем адрес данных, а не заголовка 158 | } 159 | } 160 | } 161 | 162 | fn free(block: *const u8) { 163 | unsafe { 164 | let block_hdr = (block.sub(size_of::())) as *mut BlockHeader; 165 | (*block_hdr).sign = Sign::Free; 166 | 167 | // Поиск соседних свободных блоков и объединение 168 | let current_block = block_hdr; // Убрано лишнее объявление переменной 169 | loop { 170 | let next_block = (current_block as *mut u8) 171 | .add(size_of::() + (*current_block).size) 172 | as *mut BlockHeader; 173 | if (*next_block).sign == Sign::Free { 174 | (*current_block).size += size_of::() + (*next_block).size; 175 | (*next_block).sign = Sign::Dead; // Помечаем следующий блок как неиспользуемый 176 | } else { 177 | break; 178 | } 179 | } 180 | 181 | // Обновление size_left в заголовке сектора 182 | for i in 0..PAGE_SIZE / 4 { 183 | let sec_addr = *((MAIN_SECTOR + i * 4) as *const u32) as *const u8; 184 | if (sec_addr as usize) != 0 { 185 | let sec = sec_addr; 186 | let mut hdr = *(sec as *const SectorHeader); 187 | if (sec as usize) < (block as usize) && (block as usize) < (sec as usize) + hdr.size { 188 | hdr.size_left += (*block_hdr).size + size_of::(); 189 | break; 190 | } 191 | } 192 | } 193 | 194 | // Освобождение страницы, если она полностью свободна 195 | for i in 0..PAGE_SIZE / 4 { 196 | let sec_addr = *((MAIN_SECTOR + i * 4) as *const u32) as *const u8; 197 | if (sec_addr as usize) != 0 { 198 | let sec = sec_addr; 199 | let hdr = *(sec as *const SectorHeader); 200 | if hdr.size_left == hdr.size - size_of::() { 201 | sys::free(sec as *mut u8); 202 | *((MAIN_SECTOR + i * 4) as *mut u32) = 0; // Удаляем адрес сектора из таблицы 203 | break; 204 | } 205 | } 206 | } 207 | } 208 | } 209 | 210 | struct GlobalAlloc; 211 | 212 | unsafe impl alloc::alloc::GlobalAlloc for GlobalAlloc { 213 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 214 | if layout.align() > PAGE_SIZE { 215 | throw_new!("Align is too big"); 216 | return null_mut(); 217 | } 218 | 219 | init(); 220 | malloc(layout) // Передаем layout в malloc 221 | } 222 | 223 | unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) { 224 | free(ptr) 225 | } 226 | } 227 | 228 | #[global_allocator] 229 | static ALLOC: GlobalAlloc = GlobalAlloc; -------------------------------------------------------------------------------- /src/dll.rs: -------------------------------------------------------------------------------- 1 | use crate::sys; 2 | use core::ffi::CStr; 3 | 4 | mod console; 5 | pub use console::Console; 6 | 7 | #[repr(C)] 8 | struct ImportTableEl { 9 | pub func_name: *const u8, 10 | pub func_addr: fn(), 11 | } 12 | 13 | pub struct DLL { 14 | table: *const ImportTableEl, 15 | } 16 | 17 | impl DLL { 18 | pub fn load_dll(name: &CStr) -> Result { 19 | unsafe { 20 | let table = sys::load_dll(name.as_ptr() as *const u8); 21 | if table.is_null() { 22 | return Err("Library load error"); 23 | } 24 | 25 | Ok(DLL { 26 | table: table as *const ImportTableEl, 27 | }) 28 | } 29 | } 30 | 31 | pub fn get_func(&self, name: &CStr) -> Result<*const (), &'static str> { 32 | unsafe { 33 | let mut i = 0; 34 | loop { 35 | let el = self.table.add(i); 36 | 37 | // Ensure we don't dereference a null pointer 38 | if el.is_null() { 39 | return Err("Function not found"); 40 | } 41 | 42 | let cur_name = CStr::from_ptr((*el).func_name as *const i8); 43 | if cur_name == name { 44 | return Ok((*el).func_addr as *const ()); 45 | } 46 | 47 | i += 1; 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/dll/console.rs: -------------------------------------------------------------------------------- 1 | use crate::dll::DLL; 2 | use core::ffi::CStr; 3 | use core::mem::transmute; 4 | 5 | extern "C" { 6 | fn strlen(s: *const u8) -> usize; 7 | } 8 | 9 | static mut BUFFER: [u8; 1000] = [0u8; 1000]; 10 | 11 | pub struct Console { 12 | con_init: extern "stdcall" fn(u32, u32, u32, u32, *const u8), 13 | con_gets: extern "stdcall" fn(*const u8, u32), 14 | con_write_string: extern "stdcall" fn(*const u8, u32), 15 | con_exit: extern "stdcall" fn(bool), 16 | } 17 | 18 | impl Console { 19 | pub fn import(path: Option<&CStr>) -> Result { 20 | let lib = DLL::load_dll(path.unwrap_or(c"/sys/lib/console.obj")); 21 | match lib { 22 | Err(e) => return Err(e), 23 | Ok(dll) => unsafe { 24 | Ok(Console { 25 | con_init: transmute(dll.get_func(c"con_init").ok().unwrap()), 26 | con_gets: transmute(dll.get_func(c"con_gets").ok().unwrap()), 27 | con_write_string: transmute(dll.get_func(c"con_write_string").ok().unwrap()), 28 | con_exit: transmute(dll.get_func(c"con_exit").ok().unwrap()), 29 | }) 30 | }, 31 | } 32 | } 33 | 34 | pub fn init(&self, x: u32, y: u32, width: u32, height: u32, title: &CStr) { 35 | (self.con_init)(x, y, width, height, title.as_ptr() as *const u8); 36 | } 37 | 38 | pub fn gets(&self) -> &str { 39 | unsafe { 40 | (self.con_gets)(BUFFER.as_mut_ptr(), BUFFER.len() as u32); 41 | let length = strlen(BUFFER.as_ptr()); 42 | core::str::from_utf8(&BUFFER[..length]).unwrap_or("") 43 | } 44 | } 45 | 46 | pub fn write_string(&self, text: &str) { 47 | (self.con_write_string)(text.as_ptr(), text.len() as u32); 48 | } 49 | 50 | pub fn exit(self, close_window: bool) { 51 | (self.con_exit)(close_window); 52 | } 53 | 54 | pub fn write_char(&self, c: char) { 55 | let mut buf = [0u8; 4]; 56 | let s = c.encode_utf8(&mut buf); 57 | self.write_string(s); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/func_constants.inc: -------------------------------------------------------------------------------- 1 | SF_TERMINATE_PROCESS = -1 2 | SF_CREATE_WINDOW = 0 3 | SF_PUT_PIXEL = 1 4 | SF_GET_KEY = 2 5 | SF_GET_SYS_TIME = 3 6 | SF_DRAW_TEXT = 4 7 | SF_DEFINE_BUTTON = 8 8 | SF_WAIT_EVENT = 10 9 | SF_REDRAW = 12 10 | SSF_BEGIN_DRAW = 1 11 | SSF_END_DRAW = 2 12 | SF_GET_BUTTON = 17 13 | SF_SYSTEM_GET = 26 14 | SSF_SYS_LANG = 5 15 | SF_SET_EVENTS_MASK = 40 16 | SF_BOARD = 63 17 | SSF_DEBUG_WRITE = 1 18 | SF_SYS_MISC = 68 19 | SSF_HEAP_INIT = 11 20 | SSF_MEM_ALLOC = 12 21 | SSF_MEM_FREE = 13 22 | SSF_LOAD_DLL = 19 23 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | mod modules; 4 | mod nanolibc; 5 | 6 | pub mod allocation; 7 | pub mod dll; 8 | pub mod sys; 9 | 10 | pub use modules::*; 11 | 12 | #[macro_use] 13 | extern crate alloc; 14 | 15 | #[macro_export] 16 | macro_rules! throw_new { 17 | ($text:expr) => { 18 | debug_write(&format!( 19 | "{}:{}\nAn error raised:\n{}\n", 20 | file!(), 21 | line!(), 22 | $text 23 | )); 24 | }; 25 | } 26 | 27 | #[macro_export] 28 | macro_rules! panic { 29 | ($text:expr) => { 30 | debug_write(cstr_core::cstr!(concat!("Panic!\n", $text, "\n"))); 31 | unsafe { 32 | sys::exit(); 33 | } 34 | }; 35 | } -------------------------------------------------------------------------------- /src/modules.rs: -------------------------------------------------------------------------------- 1 | pub mod graphics; 2 | pub mod input; 3 | pub mod system; 4 | pub mod threads; 5 | pub mod windows; 6 | pub mod vec; -------------------------------------------------------------------------------- /src/modules/graphics.rs: -------------------------------------------------------------------------------- 1 | use crate::sys; 2 | use core::ffi::CStr; 3 | 4 | #[derive(Clone, Copy)] 5 | pub struct Color(u8, u8, u8); 6 | 7 | impl Color { 8 | pub fn rgb(r: u8, g: u8, b: u8) -> Self { 9 | Self(r, g, b) 10 | } 11 | 12 | pub fn r(&self) -> u8 { 13 | self.0 14 | } 15 | 16 | pub fn g(&self) -> u8 { 17 | self.1 18 | } 19 | 20 | pub fn b(&self) -> u8 { 21 | self.2 22 | } 23 | 24 | pub fn as_rgb_val(self) -> u32 { 25 | (self.0 as u32) << 16 | (self.1 as u32) << 8 | (self.2 as u32) 26 | } 27 | } 28 | 29 | pub struct Dot { 30 | pub x: u32, 31 | pub y: u32, 32 | } 33 | 34 | pub struct Size { 35 | pub width: u32, 36 | pub height: u32, 37 | } 38 | 39 | pub fn display_message<'a>(start: Dot, color: Color, text: &'a CStr, bg_color: Option) { 40 | // XX=ABFFCSSS 41 | const UTF8_FLAG: u32 = (3 << 4) << 24; // FF 42 | const BG_FLAG: u32 = (1 << 6) << 24; // B 43 | const ASCIIZ_FLAG: u32 = (1 << 7) << 24; // A 44 | 45 | unsafe { 46 | sys::display_message( 47 | start.x << 16 | start.y, 48 | color.as_rgb_val() | BG_FLAG * bg_color.is_some() as u32 | UTF8_FLAG | ASCIIZ_FLAG, 49 | text.as_ptr() as u32, 50 | 0, 51 | bg_color.unwrap_or(Color(0, 0, 0)).as_rgb_val(), 52 | ); 53 | } 54 | } 55 | 56 | pub fn display_message_str<'a>(start: Dot, color: Color, text: &'a str, bg_color: Option) { 57 | // XX=ABFFCSSS 58 | const UTF8_FLAG: u32 = (3 << 4) << 24; // FF 59 | const BG_FLAG: u32 = (1 << 6) << 24; // B 60 | 61 | unsafe { 62 | sys::display_message( 63 | start.x << 16 | start.y, 64 | color.as_rgb_val() | BG_FLAG * bg_color.is_some() as u32 | UTF8_FLAG, 65 | text.as_ptr() as u32, 66 | text.len() as u32, 67 | bg_color.unwrap_or(Color(0, 0, 0)).as_rgb_val(), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/modules/input.rs: -------------------------------------------------------------------------------- 1 | use crate::sys; 2 | 3 | pub fn fetch_key() -> Option { 4 | let res = unsafe { sys::pressed_key() }; 5 | if res == 1 { 6 | None 7 | } else { 8 | Some(((res >> 8) & 0xff) as u8) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/modules/system.rs: -------------------------------------------------------------------------------- 1 | use crate::sys; 2 | use crate::throw_new; 3 | use alloc::string::String; 4 | use core::ffi::CStr; 5 | 6 | // Сделаем трейт публичным 7 | pub trait Debuggable { 8 | fn data_iter(self) -> impl Iterator; 9 | } 10 | 11 | impl Debuggable for &str { 12 | fn data_iter(self) -> impl Iterator { 13 | self.bytes() 14 | } 15 | } 16 | 17 | impl Debuggable for &String { 18 | fn data_iter(self) -> impl Iterator { 19 | self.as_bytes().iter().copied() 20 | } 21 | } 22 | 23 | impl Debuggable for &CStr { 24 | fn data_iter(self) -> impl Iterator { 25 | self.to_bytes().iter().copied() 26 | } 27 | } 28 | 29 | pub enum Lang { 30 | English, 31 | Finnish, 32 | German, 33 | Russian, 34 | French, 35 | Estonian, 36 | Spanish, 37 | Italian, 38 | } 39 | 40 | pub fn get_lang() -> Lang { 41 | unsafe { 42 | let l = sys::get_lang(); 43 | return match l { 44 | 1 => Lang::English, 45 | 2 => Lang::Finnish, 46 | 3 => Lang::German, 47 | 4 => Lang::Russian, 48 | 5 => Lang::French, 49 | 6 => Lang::Estonian, 50 | 7 => Lang::Spanish, 51 | 8 => Lang::Italian, 52 | _ => { 53 | throw_new!(format!("Unknown lang: {}", l)); 54 | Lang::English 55 | } 56 | }; 57 | } 58 | } 59 | 60 | pub fn debug_write(text: Str) { 61 | for byte in text.data_iter() { 62 | unsafe { 63 | sys::_debug_write(byte); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/modules/threads.rs: -------------------------------------------------------------------------------- 1 | use crate::sys::{self, set_event_mask}; 2 | 3 | pub fn exit() -> ! { 4 | unsafe { sys::exit() } 5 | } 6 | 7 | #[non_exhaustive] 8 | pub enum Event { 9 | Redraw = 1 << 0, 10 | KeyPress = 1 << 1, 11 | BtnPress = 1 << 2, 12 | BgRedraw = 1 << 4, 13 | Mouse = 1 << 5, 14 | IPC = 1 << 6, 15 | Network = 1 << 7, 16 | Debug = 1 << 8, 17 | } 18 | 19 | pub fn fetch_event(flags: u32) -> Option { 20 | let old_mask = unsafe { sys::set_event_mask(flags as u32) }; 21 | let e = match unsafe { sys::wait_event() } { 22 | 1 => Some(Event::Redraw), 23 | 2 => Some(Event::KeyPress), 24 | 3 => Some(Event::BtnPress), 25 | 5 => Some(Event::BgRedraw), 26 | 6 => Some(Event::Mouse), 27 | 7 => Some(Event::IPC), 28 | 8 => Some(Event::Network), 29 | 9 => Some(Event::Debug), 30 | _ => None, 31 | }; 32 | unsafe { set_event_mask(old_mask) }; 33 | e 34 | } 35 | -------------------------------------------------------------------------------- /src/modules/vec.rs: -------------------------------------------------------------------------------- 1 | use core::ptr::{self, null_mut}; 2 | use core::alloc::Layout; 3 | use crate::sys::{alloc, free}; 4 | extern crate alloc; 5 | 6 | const INITIAL_CAPACITY: usize = 4; 7 | 8 | pub struct Vec { 9 | ptr: *mut T, 10 | len: usize, 11 | capacity: usize, 12 | } 13 | 14 | impl Vec { 15 | pub fn new() -> Self { 16 | Self { 17 | ptr: null_mut(), 18 | len: 0, 19 | capacity: 0, 20 | } 21 | } 22 | 23 | pub fn push(&mut self, value: T) { 24 | if self.len == self.capacity { 25 | self.grow(); 26 | } 27 | 28 | unsafe { 29 | let end = self.ptr.add(self.len); 30 | ptr::write(end, value); 31 | self.len += 1; 32 | } 33 | } 34 | 35 | fn grow(&mut self) { 36 | let new_capacity = if self.capacity == 0 { 37 | INITIAL_CAPACITY 38 | } else { 39 | self.capacity * 2 40 | }; 41 | 42 | let new_layout = Layout::array::(new_capacity).expect("Layout creation failed"); 43 | 44 | unsafe { 45 | let new_ptr = alloc(new_layout.size()) as *mut T; 46 | 47 | if new_ptr.is_null() { 48 | alloc::alloc::handle_alloc_error(new_layout); 49 | } 50 | 51 | if !self.ptr.is_null() { 52 | ptr::copy_nonoverlapping(self.ptr, new_ptr, self.len); 53 | free(self.ptr as *mut u8); 54 | } 55 | 56 | self.ptr = new_ptr; 57 | self.capacity = new_capacity; 58 | } 59 | } 60 | 61 | pub fn len(&self) -> usize { 62 | self.len 63 | } 64 | 65 | pub fn capacity(&self) -> usize { 66 | self.capacity 67 | } 68 | 69 | pub fn as_ptr(&self) -> *const T { 70 | self.ptr 71 | } 72 | 73 | pub fn as_mut_ptr(&mut self) -> *mut T { 74 | self.ptr 75 | } 76 | } 77 | 78 | impl Drop for Vec { 79 | fn drop(&mut self) { 80 | unsafe { 81 | if !self.ptr.is_null() { 82 | for i in 0..self.len { 83 | let element_ptr = self.ptr.add(i); 84 | ptr::drop_in_place(element_ptr); 85 | } 86 | free(self.ptr as *mut u8); 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /src/modules/windows.rs: -------------------------------------------------------------------------------- 1 | use crate::graphics::{Color, Dot, Size}; 2 | use crate::sys; 3 | use crate::system::debug_write; 4 | use crate::throw_new; 5 | use alloc::ffi::CString; 6 | use core::ffi::CStr; 7 | 8 | #[repr(u32)] 9 | pub enum WindowKind { 10 | Fixed = 0, 11 | NoDraw = 1, 12 | Resizable = 2, 13 | Themed = 3, 14 | FixedThemed = 4, 15 | } 16 | 17 | pub struct WindowParams<'a> { 18 | pub color: Color, 19 | pub kind: WindowKind, 20 | pub title: Option<&'a CStr>, 21 | } 22 | 23 | pub const CLOSE_BUTTON: u32 = 1; 24 | 25 | pub fn define_window(start: Dot, size: Size, params: WindowParams) { 26 | const RELATIVE_FLAG: u32 = 0x20; 27 | 28 | unsafe { 29 | sys::define_window( 30 | start.x << 16 | size.width, 31 | start.y << 16 | size.height, 32 | params.color.as_rgb_val() 33 | | (RELATIVE_FLAG | (params.title.is_some() as u32) << 4 | params.kind as u32) << 24, 34 | 0, 35 | params 36 | .title 37 | .map(|s| s.as_ptr()) 38 | .unwrap_or_else(core::ptr::null) as u32, 39 | ); 40 | } 41 | } 42 | 43 | pub fn put_pixel(pos: Dot, color: Option) { 44 | let color: u32 = color.unwrap_or(Color::rgb(255, 255, 255)).as_rgb_val(); 45 | unsafe { sys::put_pixel(pos.x, pos.y, color) } 46 | } 47 | 48 | pub fn invert_pixel(pos: Dot) { 49 | unsafe { sys::put_pixel(pos.x, pos.y, 1 << 24) } 50 | } 51 | 52 | pub fn define_button( 53 | start: Dot, 54 | size: Size, 55 | id: u32, 56 | draw: bool, 57 | border: bool, 58 | color: Option, 59 | ) { 60 | if 0 >= size.width || size.width >= 0x8000 || 0 >= size.height || size.height >= 0x8000 { 61 | crate::graphics::display_message( 62 | Dot { x: 10, y: 200 }, 63 | Color::rgb(255, 0, 0), 64 | CString::new(format!( 65 | "x:{:?} y:{:?} w:{:?} h:{:?}\n", 66 | start.x, start.y, size.width, size.height 67 | )) 68 | .expect("CString error") 69 | .as_c_str(), 70 | None, 71 | ); 72 | throw_new!(format!( 73 | "x:{:?} y:{:?} w:{:?} h:{:?}\n", 74 | start.x, start.y, size.width, size.height 75 | )); 76 | return; 77 | } 78 | if id > 0xFFFFFF { 79 | throw_new!("Invalid button ID"); 80 | return; 81 | } 82 | 83 | let mut flags = 0; 84 | if !draw { 85 | flags += 1 << 30 86 | }; 87 | if !border { 88 | flags += 1 << 29 89 | }; 90 | 91 | unsafe { 92 | sys::define_button( 93 | start.x << 16 | size.width, 94 | start.y << 16 | size.height, 95 | flags << 29 | id, 96 | color.unwrap_or(Color::rgb(255, 255, 255)).as_rgb_val(), 97 | ); 98 | } 99 | } 100 | 101 | // TODO: mouse button info 102 | pub fn get_button_id() -> Option { 103 | unsafe { 104 | let eax = sys::get_button_id(); 105 | if eax == 1 { 106 | return None; 107 | } 108 | return Some(eax >> 8); 109 | } 110 | } 111 | 112 | pub fn start_window_draw() { 113 | unsafe { sys::start_window_draw() } 114 | } 115 | 116 | pub fn end_window_draw() { 117 | unsafe { sys::end_window_draw() } 118 | } 119 | 120 | #[panic_handler] 121 | fn panic(_info: &core::panic::PanicInfo) -> ! { 122 | unsafe { 123 | sys::exit(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/nanolibc.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { 3 | if n == 0 || dest.is_null() || src.is_null() { 4 | return dest; 5 | } 6 | 7 | let mut i = 0; 8 | while i < n { 9 | *dest.add(i) = *src.add(i); 10 | i += 1; 11 | } 12 | 13 | dest 14 | } 15 | 16 | #[no_mangle] 17 | pub unsafe extern "C" fn memset(s: *mut u8, x: i32, n: usize) -> *mut u8 { 18 | if n == 0 || s.is_null() { 19 | return s; 20 | } 21 | 22 | let mut i = 0; 23 | while i < n { 24 | *s.add(i) = x as u8; 25 | i += 1; 26 | } 27 | 28 | s 29 | } 30 | 31 | #[no_mangle] 32 | pub unsafe extern "C" fn memcmp(s1: *mut u8, s2: *const u8, n: usize) -> i32 { 33 | if n == 0 || s1.is_null() || s2.is_null() { 34 | return 0; 35 | } 36 | 37 | let mut i = 0; 38 | while i < n { 39 | let x = *s1.add(i); 40 | let y = *s2.add(i); 41 | if x != y { 42 | return i32::from(x) - i32::from(y); 43 | } 44 | i += 1; 45 | } 46 | 47 | 0 48 | } 49 | 50 | #[no_mangle] 51 | pub unsafe extern "C" fn strlen(str: *mut u8) -> usize { 52 | if str.is_null() { 53 | return 0; 54 | } 55 | 56 | let mut len = 0; 57 | while *str.add(len) != 0 { 58 | len += 1; 59 | } 60 | 61 | len 62 | } -------------------------------------------------------------------------------- /src/sys.rs: -------------------------------------------------------------------------------- 1 | #[link(name = "syscalls")] 2 | extern "C" { 3 | // Системный вызов для завершения программы 4 | #[link_name = "_exit"] 5 | pub fn exit() -> !; 6 | 7 | // Системный вызов для создания окна 8 | #[link_name = "_define_window"] 9 | pub fn define_window(ebx: u32, ecx: u32, edx: u32, esi: u32, edi: u32); 10 | 11 | // Системный вызов для установки пикселя 12 | #[link_name = "_put_pixel"] 13 | pub fn put_pixel(ebx: u32, ecx: u32, edx: u32); 14 | 15 | // Системный вызов для получения нажатой клавиши 16 | #[link_name = "_pressed_key"] 17 | pub fn pressed_key() -> u32; 18 | 19 | // Системный вызов для отображения сообщения 20 | #[link_name = "_display_message"] 21 | pub fn display_message(ebx: u32, ecx: u32, edx: u32, esi: u32, edi: u32); 22 | 23 | // Системный вызов для создания кнопки 24 | #[link_name = "_define_button"] 25 | pub fn define_button(ebx: u32, ecx: u32, edx: u32, esi: u32); 26 | 27 | // Системный вызов для ожидания события 28 | #[link_name = "_wait_event"] 29 | pub fn wait_event() -> u32; 30 | 31 | // Системные вызовы для начала и конца отрисовки окна 32 | #[link_name = "_start_window_draw"] 33 | pub fn start_window_draw(); 34 | 35 | #[link_name = "_end_window_draw"] 36 | pub fn end_window_draw(); 37 | 38 | // Системный вызов для получения ID кнопки 39 | #[link_name = "_get_button_id"] 40 | pub fn get_button_id() -> u32; 41 | 42 | // Системный вызов для получения языка системы 43 | #[link_name = "_get_lang"] 44 | pub fn get_lang() -> u32; 45 | 46 | // Системный вызов для установки маски событий 47 | #[link_name = "_set_event_mask"] 48 | pub fn set_event_mask(mask: u32) -> u32; 49 | 50 | // Системный вызов для записи отладочной информации 51 | #[link_name = "_debug_write"] 52 | pub fn _debug_write(cl: u8); 53 | 54 | // Системные вызовы для управления кучей 55 | #[link_name = "_init_heap"] 56 | pub fn init_heap(); 57 | 58 | #[link_name = "_alloc"] 59 | pub fn alloc(size: usize) -> *const u8; 60 | 61 | #[link_name = "_free"] 62 | pub fn free(block: *const u8) -> bool; 63 | 64 | // Системный вызов для загрузки динамической библиотеки 65 | #[link_name = "_load_dll"] 66 | pub fn load_dll(name: *const u8) -> *const u32; 67 | } -------------------------------------------------------------------------------- /src/syscalls.S: -------------------------------------------------------------------------------- 1 | format ELF 2 | 3 | include "src/func_constants.inc" 4 | 5 | section '.text' 6 | public _exit 7 | public _start_window_draw 8 | public _end_window_draw 9 | public _define_window 10 | public _put_pixel 11 | public _display_message 12 | public _wait_event 13 | public _pressed_key 14 | public _define_button 15 | public _debug_write 16 | public _get_button_id 17 | public _init_heap 18 | public _alloc 19 | public _free 20 | public _get_lang 21 | public _load_dll 22 | public _set_event_mask 23 | 24 | _exit: 25 | mov eax, SF_TERMINATE_PROCESS 26 | int 0x40 27 | 28 | _start_window_draw: 29 | mov eax, SF_REDRAW 30 | mov ebx, SSF_BEGIN_DRAW 31 | int 0x40 32 | ret 33 | 34 | _end_window_draw: 35 | mov eax, SF_REDRAW 36 | mov ebx, SSF_END_DRAW 37 | int 0x40 38 | ret 39 | 40 | _define_window: 41 | push edi 42 | push esi 43 | mov eax, SF_CREATE_WINDOW 44 | mov ebx, dword [esp + 4 * 3] 45 | mov ecx, dword [esp + 4 * 4] 46 | mov edx, dword [esp + 4 * 5] 47 | mov esi, dword [esp + 4 * 6] 48 | mov edi, dword [esp + 4 * 7] 49 | int 0x40 50 | pop esi 51 | pop edi 52 | ret 53 | 54 | _put_pixel: 55 | mov eax, SF_PUT_PIXEL 56 | mov ebx, dword [esp + 4 * 1] 57 | mov ecx, dword [esp + 4 * 2] 58 | mov edx, dword [esp + 4 * 3] 59 | int 0x40 60 | ret 61 | 62 | _display_message: 63 | push esi edi 64 | mov eax, SF_DRAW_TEXT 65 | mov ebx, dword [esp + 4 * 3] 66 | mov ecx, dword [esp + 4 * 4] 67 | mov edx, dword [esp + 4 * 5] 68 | mov esi, dword [esp + 4 * 6] 69 | mov edi, dword [esp + 4 * 7] 70 | int 0x40 71 | pop edi esi 72 | ret 73 | 74 | _wait_event: 75 | mov eax, SF_WAIT_EVENT 76 | int 0x40 77 | ret 78 | 79 | _pressed_key: 80 | mov eax, SF_GET_KEY 81 | int 0x40 82 | ret 83 | 84 | _define_button: 85 | push esi edi 86 | mov eax, SF_DEFINE_BUTTON 87 | mov ebx, dword [esp + 4 * 3] 88 | mov ecx, dword [esp + 4 * 4] 89 | mov edx, dword [esp + 4 * 5] 90 | mov esi, dword [esp + 4 * 6] 91 | int 0x40 92 | pop edi esi 93 | ret 94 | 95 | _debug_write: 96 | mov eax, SF_BOARD 97 | mov ebx, SSF_DEBUG_WRITE 98 | mov cl , byte [esp + 4 * 1] 99 | int 0x40 100 | ret 101 | 102 | _get_button_id: 103 | mov eax, SF_GET_BUTTON 104 | int 0x40 105 | ret 106 | 107 | _init_heap: 108 | mov eax, SF_SYS_MISC 109 | mov ebx, SSF_HEAP_INIT 110 | int 0x40 111 | ret 112 | 113 | _alloc: 114 | mov eax, SF_SYS_MISC 115 | mov ebx, SSF_MEM_ALLOC 116 | mov ecx, [esp + 4 * 1] 117 | int 0x40 118 | ret 119 | 120 | _free: 121 | mov eax, SF_SYS_MISC 122 | mov ebx, SSF_MEM_FREE 123 | mov ecx, [esp + 4 * 1] 124 | int 0x40 125 | ret 126 | 127 | _get_lang: 128 | mov eax, SF_SYSTEM_GET 129 | mov ebx, SSF_SYS_LANG 130 | int 0x40 131 | ret 132 | 133 | _load_dll: 134 | mov eax, SF_SYS_MISC 135 | mov ebx, SSF_LOAD_DLL 136 | mov ecx, [esp + 4 * 1] 137 | int 0x40 138 | ret 139 | 140 | _set_event_mask: 141 | mov eax, SF_SET_EVENTS_MASK 142 | mov ebx, [esp + 4 * 1] 143 | int 0x40 144 | ret 145 | 146 | --------------------------------------------------------------------------------