9 Commits

Author SHA1 Message Date
Sanya Kapoor
5487f52028 feat: network syscall 74 wrapper 2026-03-15 11:18:38 +05:30
5ca63e7afb fix: Add strlen func 2026-03-14 22:29:39 +03:00
3e8244f686 config: update things and add shell.nix 2026-03-14 22:29:24 +03:00
21c90abd44 refactor: Change to Rust's CStr 2024-05-08 20:42:41 +03:00
78f050e20c feat: put_pixel
dark example
2024-05-07 22:20:44 +03:00
20f46098ec Update .gitignore 2024-03-23 14:55:48 +03:00
c9a9df5746 Modify README.md a little
Add info about requirements
2024-03-23 14:55:48 +03:00
49b37f37c8 config: Update Cargo.toml
Bump cstr_core
2024-03-23 14:55:48 +03:00
30cc19fb3c build: Update layout 2024-03-23 14:55:48 +03:00
23 changed files with 516 additions and 51 deletions

View File

@@ -1,5 +1,6 @@
[unstable]
build-std = ["core", "compiler_builtins", "alloc"]
json-target-spec = true
[build]
target = "i686-kolibri.json"

2
.gitignore vendored
View File

@@ -2,4 +2,4 @@
**/*.rs.bk
/Cargo.lock
/rust_dos.com
rust.kex
*.kex

View File

@@ -2,7 +2,7 @@
name = "kos"
version = "0.1.0"
authors = ["Kitsu <mail@kitsu.me>", "Sweetbread"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -14,11 +14,14 @@ path = "examples/hwa.rs"
name = "con"
path = "examples/con.rs"
[[example]]
name = "dark"
path = "examples/dark.rs"
[[example]]
name = "net"
path = "examples/net.rs"
[profile.release]
opt-level = "z"
lto = "thin"
[dependencies]
cstr_core = { version = "0.2.4", default-features = false, features = ["nightly"] }
[build-dependencies]

View File

@@ -18,4 +18,4 @@ args = ["build", "@@remove-empty(RELEASE_FLAG)"]
[tasks.example]
command = "cargo"
args = ["objcopy", "@@remove-empty(RELEASE_FLAG)", "--example", "${@}", "--", "-O", "binary", "--strip-all", "${@}.kex"]
#install_crate = { crate_name = "cargo-binutils", binary = "rust-objcopy", test_arg = ["--help"] }
# install_crate = { crate_name = "cargo-binutils", binary = "rust-objcopy", test_arg = ["--help"] }

View File

@@ -1,7 +1,8 @@
# Rust library for KolibriOS
Project uses [cargo-make](https://github.com/sagiegurari/cargo-make) for building steps.
You need to install cargo-binutils: `cargo install cargo-binutils` and llvm-tools-preview: `rustup component add llvm-tools-preview` to make it work.
Also you need a working [FASM](https://flatassembler.net/download.php).
Once installed building is trivial then: `cargo make --profile production <example name>` produces
Once installed building is trivial then: `cargo make --profile production example <example name>` produces
a ready-to-use binary at root.

View File

@@ -1,19 +1,15 @@
#![no_std]
#![no_main]
use cstr_core::cstr;
use kos::{dll::Console, threads::exit};
extern crate alloc;
#[no_mangle]
pub fn kol_main() {
let header = cstr!("Rust!");
let string = "Hi from Rust!";
let con_lib = Console::import(None).unwrap();
con_lib.init(u32::MAX, u32::MAX, u32::MAX, u32::MAX, header);
con_lib.write_string(string);
con_lib.init(u32::MAX, u32::MAX, u32::MAX, u32::MAX, c"Rust!");
con_lib.write_string("Hi from Rust!");
con_lib.exit(false);
exit();

116
examples/dark.rs Normal file
View File

@@ -0,0 +1,116 @@
#![no_std]
#![no_main]
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, invert_pixel,
start_window_draw, WindowKind, WindowParams, CLOSE_BUTTON,
},
};
const HEADER: &'static CStr = c"Dark Mode Demo";
const TEXT: [&'static CStr; 6] = [
c"Lorem ipsum dolor sit amet,",
c"semper et rutrum placerat,",
c"Integer sed diam commodo quam varius",
c"Sed finibus urna sit amet felis",
c"vestibulum elementum. Maecenas at feugiat lacus",
c"tristique et sit amet tortor.",
];
const BTN: u32 = 42;
const WINDOW_SIZE: Size = Size {
width: 400,
height: 400,
};
extern crate alloc;
fn draw_window(invert: bool) {
start_window_draw();
define_window(
Dot { x: 50, y: 50 },
WINDOW_SIZE,
WindowParams {
color: Color::rgb(0xff, 0xff, 0xff),
kind: WindowKind::FixedThemed,
title: Some(HEADER),
},
);
display_message(Dot { x: 10, y: 10 }, Color::rgb(0, 0, 0), TEXT[0], None);
display_message(Dot { x: 10, y: 50 }, Color::rgb(0, 0, 0), TEXT[1], None);
display_message(Dot { x: 10, y: 90 }, Color::rgb(0, 0, 0), TEXT[2], None);
display_message(Dot { x: 10, y: 130 }, Color::rgb(0, 0, 0), TEXT[3], None);
display_message(Dot { x: 10, y: 170 }, Color::rgb(0, 0, 0), TEXT[4], None);
display_message(Dot { x: 10, y: 210 }, Color::rgb(0, 0, 0), TEXT[5], None);
define_button(
Dot { x: 10, y: 300 },
Size {
width: 100,
height: 30,
},
BTN,
true,
true,
Some(Color::rgb(147, 112, 219)),
);
display_message(
Dot { x: 20, y: 310 },
Color::rgb(255, 255, 255),
if invert {
c"Light mode"
} else {
c"Dark mode"
},
None,
);
if invert {
for x in 0..WINDOW_SIZE.width {
for y in 0..WINDOW_SIZE.height {
invert_pixel(Dot { x, y })
}
}
}
end_window_draw();
return;
}
fn button_handler(invert: &mut bool) {
let btn_id = get_button_id();
if btn_id.is_some() {
match btn_id.unwrap() {
CLOSE_BUTTON => exit(),
BTN => {
*invert = !*invert;
draw_window(*invert);
}
_ => {}
}
}
}
#[no_mangle]
fn kol_main() {
let mut invert = false;
while let Some(ev) =
fetch_event((Event::Redraw as u32) | (Event::KeyPress as u32) | (Event::BtnPress as u32))
{
match ev {
Event::Redraw => draw_window(invert),
Event::KeyPress => drop(fetch_key()),
Event::BtnPress => button_handler(&mut invert),
_ => break,
}
}
}

View File

@@ -1,8 +1,8 @@
#![no_std]
#![no_main]
use cstr_core::{cstr, CStr};
use alloc::ffi::CString;
use core::ffi::CStr;
use kos::{
graphics::{display_message, Color, Dot, Size},
input::fetch_key,
@@ -14,8 +14,8 @@ use kos::{
},
};
const HEADER: &CStr = cstr!("Hey Kolibri");
const MSG: &CStr = cstr!("Hello from Rust!");
const HEADER: &CStr = c"Hey Kolibri";
const MSG: &CStr = c"Hello from Rust!";
const BTN: u32 = 42;
#[macro_use]
@@ -45,16 +45,18 @@ fn draw_window(c: usize) {
);
let btn_str = match get_lang() {
Lang::German => format!("Taste gedrückt: {} mal\0", c),
Lang::Russian => format!("Кнопка нажата: {} раз\0", c),
Lang::French => format!("Button enfoncé : {} fois\0", c),
_ => format!("Button pressed: {} times\0", c),
Lang::German => format!("Taste gedrückt: {} mal", c),
Lang::Russian => format!("Кнопка нажата: {} раз", c),
Lang::French => format!("Button enfoncé : {} fois", c),
_ => format!("Button pressed: {} times", c),
};
display_message(
Dot { x: 10, y: 30 },
Color::rgb(0, 0, 0),
CStr::from_bytes_with_nul(btn_str.as_bytes()).unwrap_or(cstr!("String error")),
CString::new(btn_str.as_bytes())
.expect("CString error")
.as_c_str(),
None,
);

65
examples/net.rs Normal file
View File

@@ -0,0 +1,65 @@
#![no_std]
#![no_main]
extern crate alloc;
use alloc::format;
use kos::{
dll::Console,
network::{self, DeviceType},
threads::exit,
};
#[no_mangle]
pub fn kol_main() {
let con_lib = Console::import(None).expect("Failed to load /sys/lib/console.obj");
con_lib.init(u32::MAX, u32::MAX, u32::MAX, u32::MAX, c"Network Diagnostics");
let count = network::device_count();
con_lib.write_string("Network Subsystem Diagnostics\n");
con_lib.write_string("=============================\n");
con_lib.write_string(&format!("Discovered Devices: {}\n\n", count));
for i in 0..(count as u8) {
if let Ok(name) = network::device_name(i) {
con_lib.write_string(&format!("INTERFACE [{}]\n", i));
con_lib.write_string(&format!(" Name: {}\n", name));
if let Ok(info) = network::device_info(i) {
let dev_type = match info.device_type {
DeviceType::Ethernet => "Ethernet",
DeviceType::Loopback => "Loopback",
DeviceType::Unknown(_id) => "Unknown Hardware",
};
con_lib.write_string(&format!(" Type: {}\n", dev_type));
let up = if info.link.is_up() { "UP" } else { "DOWN" };
let mbps = info.link.speed_mbps().unwrap_or(0);
let duplex = if info.link.is_full_duplex() { "Full" } else { "Half" };
con_lib.write_string(&format!(" State: {} (Speed: {} Mbps, {} Duplex)\n", up, mbps, duplex));
}
if let Ok(stats) = network::device_stats(i) {
con_lib.write_string(&format!(" Stats: RX {} bytes | TX {} bytes\n", stats.rx_bytes, stats.tx_bytes));
con_lib.write_string(&format!(" RX {} pkts | TX {} pkts\n", stats.rx_packets, stats.tx_packets));
if stats.rx_errors > 0 || stats.tx_errors > 0 || stats.tx_dropped > 0 {
con_lib.write_string(&format!(" [!] Errors detected: RX={} TX={} Drops={}\n",
stats.rx_errors, stats.tx_errors, stats.tx_dropped));
}
}
con_lib.write_string("\n");
} else {
con_lib.write_string(&format!("INTERFACE [{}]\n [!] Failed to pull hardware state.\n\n", i));
}
}
con_lib.write_string("Diagnostics complete.");
con_lib.exit(false);
exit();
}

View File

@@ -1,11 +1,10 @@
{
"arch": "x86",
"cpu": "pentium",
"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128",
"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",
"dynamic-linking": false,
"executables": true,
"has-rpath": true,
"is-builtin": false,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"llvm-target": "i686-unknown-none-code32",
@@ -14,9 +13,9 @@
"relocation-model": "static",
"position-independent-executables": false,
"relro-level": "off",
"target-c-int-width": "32",
"target-c-int-width": 32,
"target-endian": "little",
"target-pointer-width": "32",
"target-pointer-width": 32,
"vendor": "unknown",
"disable-redzone": true,
"panic-strategy": "abort",

View File

@@ -1 +1,4 @@
nightly
[toolchain]
channel = "nightly"
components = ["rust-src", "llvm-tools-preview"]
profile = "default"

14
shell.nix Normal file
View File

@@ -0,0 +1,14 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
packages = with pkgs; [
rustup
cargo-make
cargo-binutils
fasm
];
shellHook = ''
export PATH="$HOME/.cargo/bin:$PATH"
'';
}

View File

@@ -1,5 +1,5 @@
use crate::sys;
use cstr_core::CStr;
use core::ffi::CStr;
mod console;
pub use console::Console;

View File

@@ -1,7 +1,6 @@
use crate::dll::DLL;
use core::ffi::CStr;
use core::mem::transmute;
use cstr_core::cstr;
use cstr_core::CStr;
pub struct Console {
con_init: extern "stdcall" fn(u32, u32, u32, u32, *const u8),
@@ -11,16 +10,14 @@ pub struct Console {
impl Console {
pub fn import(path: Option<&CStr>) -> Result<Self, &str> {
let lib = DLL::load_dll(path.unwrap_or(cstr!("/sys/lib/console.obj")));
let lib = DLL::load_dll(path.unwrap_or(c"/sys/lib/console.obj"));
match lib {
Err(e) => return Err(e),
Ok(dll) => unsafe {
Ok(Console {
con_init: transmute(dll.get_func(cstr!("con_init")).ok().unwrap()),
con_write_string: transmute(
dll.get_func(cstr!("con_write_string")).ok().unwrap(),
),
con_exit: transmute(dll.get_func(cstr!("con_exit")).ok().unwrap()),
con_init: transmute(dll.get_func(c"con_init").ok().unwrap()),
con_write_string: transmute(dll.get_func(c"con_write_string").ok().unwrap()),
con_exit: transmute(dll.get_func(c"con_exit").ok().unwrap()),
})
},
}

View File

@@ -20,3 +20,21 @@ SF_SYS_MISC = 68
SSF_MEM_ALLOC = 12
SSF_MEM_FREE = 13
SSF_LOAD_DLL = 19
SF_NETWORK_GET = 74
SSF_DEVICE_COUNT = -1
SSF_DEVICE_TYPE = 0
SSF_DEVICE_NAME = 1
SSF_RESET_DEVICE = 2
SSF_STOP_DEVICE = 3
SSF_DEVICE_POINTER = 4
SSF_TX_PACKET_COUNT = 6
SSF_RX_PACKET_COUNT = 7
SSF_TX_BYTE_COUNT = 8
SSF_RX_BYTE_COUNT = 9
SSF_LINK_STATUS = 10
SSF_TX_PACKET_ERROR_COUNT = 11
SSF_TX_PACKET_DROP_COUNT = 12
SSF_TX_PACKET_MISS_COUNT = 13
SSF_RX_PACKET_ERROR_COUNT = 14
SSF_RX_PACKET_DROP_COUNT = 15
SSF_RX_PACKET_MISS_COUNT = 16

View File

@@ -1,5 +1,6 @@
pub mod graphics;
pub mod input;
pub mod network;
pub mod system;
pub mod threads;
pub mod windows;

View File

@@ -1,5 +1,5 @@
use crate::sys;
use cstr_core::CStr;
use core::ffi::CStr;
#[derive(Clone, Copy)]
pub struct Color(u8, u8, u8);

186
src/modules/network.rs Normal file
View File

@@ -0,0 +1,186 @@
use crate::sys;
use alloc::string::String;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NetworkError {
NoDevice,
KernelError(i32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeviceType {
Loopback,
Ethernet,
Unknown(u32),
}
impl DeviceType {
fn from_raw(v: u32) -> Self {
match v {
0 => DeviceType::Loopback,
1 => DeviceType::Ethernet,
other => DeviceType::Unknown(other),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LinkStatus(u32);
impl LinkStatus {
pub fn is_up(&self) -> bool {
self.0 & 0b0001 != 0
}
pub fn is_full_duplex(&self) -> bool {
self.0 & 0b0010 != 0
}
pub fn speed_mbps(&self) -> Option<u32> {
match self.0 & 0b1100 {
0b0100 => Some(10),
0b1000 => Some(100),
0b1100 => Some(1000),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct DeviceStats {
pub tx_packets: u32,
pub rx_packets: u32,
pub tx_bytes: u64,
pub rx_bytes: u64,
pub tx_errors: u32,
pub tx_dropped: u32,
pub tx_missed: u32,
pub rx_errors: u32,
pub rx_dropped: u32,
pub rx_missed: u32,
}
#[derive(Debug, Clone, Copy)]
pub struct DeviceInfo {
pub device_type: DeviceType,
pub link: LinkStatus,
}
fn raw_get(subfunc: u8, device: u8) -> Result<i32, NetworkError> {
let r = unsafe { sys::network_get(subfunc, device, 0) };
if r == -1 {
Err(NetworkError::NoDevice)
} else {
Ok(r)
}
}
fn raw_get_u64(subfunc: u8, device: u8) -> Result<u64, NetworkError> {
let mut hi: u32 = 0;
let lo = unsafe { sys::network_get_u64(subfunc, device, &mut hi as *mut u32) };
if lo == -1 {
Err(NetworkError::NoDevice)
} else {
Ok((hi as u64) << 32 | (lo as u32) as u64)
}
}
pub fn device_count() -> u32 {
let r = unsafe { sys::network_get(0xFFu8, 0, 0) };
if r < 0 {
0
} else {
r as u32
}
}
pub fn device_type(device: u8) -> Result<DeviceType, NetworkError> {
raw_get(0, device).map(|v| DeviceType::from_raw(v as u32))
}
pub fn device_name(device: u8) -> Result<String, NetworkError> {
let mut buf = [0u8; 64];
let r = unsafe { sys::network_get(1, device, buf.as_mut_ptr() as u32) };
if r == -1 {
return Err(NetworkError::NoDevice);
}
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
Ok(String::from(core::str::from_utf8(&buf[..len]).unwrap_or("?")))
}
pub fn reset_device(device: u8) -> Result<(), NetworkError> {
raw_get(2, device).map(|_| ())
}
pub fn stop_device(device: u8) -> Result<(), NetworkError> {
raw_get(3, device).map(|_| ())
}
pub fn device_pointer(device: u8) -> Result<u32, NetworkError> {
raw_get(4, device).map(|v| v as u32)
}
pub fn tx_packet_count(device: u8) -> Result<u32, NetworkError> {
raw_get(6, device).map(|v| v as u32)
}
pub fn rx_packet_count(device: u8) -> Result<u32, NetworkError> {
raw_get(7, device).map(|v| v as u32)
}
pub fn tx_byte_count(device: u8) -> Result<u64, NetworkError> {
raw_get_u64(8, device)
}
pub fn rx_byte_count(device: u8) -> Result<u64, NetworkError> {
raw_get_u64(9, device)
}
pub fn link_status(device: u8) -> Result<LinkStatus, NetworkError> {
raw_get(10, device).map(|v| LinkStatus(v as u32))
}
pub fn tx_error_count(device: u8) -> Result<u32, NetworkError> {
raw_get(11, device).map(|v| v as u32)
}
pub fn tx_drop_count(device: u8) -> Result<u32, NetworkError> {
raw_get(12, device).map(|v| v as u32)
}
pub fn tx_miss_count(device: u8) -> Result<u32, NetworkError> {
raw_get(13, device).map(|v| v as u32)
}
pub fn rx_error_count(device: u8) -> Result<u32, NetworkError> {
raw_get(14, device).map(|v| v as u32)
}
pub fn rx_drop_count(device: u8) -> Result<u32, NetworkError> {
raw_get(15, device).map(|v| v as u32)
}
pub fn rx_miss_count(device: u8) -> Result<u32, NetworkError> {
raw_get(16, device).map(|v| v as u32)
}
pub fn device_info(device: u8) -> Result<DeviceInfo, NetworkError> {
let device_type = device_type(device)?;
let link = link_status(device)?;
Ok(DeviceInfo { device_type, link })
}
pub fn device_stats(device: u8) -> Result<DeviceStats, NetworkError> {
Ok(DeviceStats {
tx_packets: tx_packet_count(device)?,
rx_packets: rx_packet_count(device)?,
tx_bytes: tx_byte_count(device)?,
rx_bytes: rx_byte_count(device)?,
tx_errors: tx_error_count(device)?,
tx_dropped: tx_drop_count(device)?,
tx_missed: tx_miss_count(device)?,
rx_errors: rx_error_count(device)?,
rx_dropped: rx_drop_count(device)?,
rx_missed: rx_miss_count(device)?,
})
}

View File

@@ -1,7 +1,7 @@
use crate::sys;
use crate::throw_new;
use alloc::string::String;
use cstr_core::CStr;
use core::ffi::CStr;
trait Debuggable {
fn data_iter(self) -> impl Iterator<Item = u8>;

View File

@@ -2,7 +2,8 @@ use crate::graphics::{Color, Dot, Size};
use crate::sys;
use crate::system::debug_write;
use crate::throw_new;
use cstr_core::{cstr, CStr};
use alloc::ffi::CString;
use core::ffi::CStr;
#[repr(u32)]
pub enum WindowKind {
@@ -16,12 +17,12 @@ pub enum WindowKind {
pub struct WindowParams<'a> {
pub color: Color,
pub kind: WindowKind,
pub title: Option<&'a cstr_core::CStr>,
pub title: Option<&'a CStr>,
}
pub const CLOSE_BUTTON: u32 = 1;
pub fn define_window(start: Dot, size: Size, params: WindowParams<'_>) {
pub fn define_window(start: Dot, size: Size, params: WindowParams) {
const RELATIVE_FLAG: u32 = 0x20;
unsafe {
@@ -39,6 +40,15 @@ pub fn define_window(start: Dot, size: Size, params: WindowParams<'_>) {
}
}
pub fn put_pixel(pos: Dot, color: Option<Color>) {
let color: u32 = color.unwrap_or(Color::rgb(255, 255, 255)).as_rgb_val();
unsafe { sys::put_pixel(pos.x, pos.y, color) }
}
pub fn invert_pixel(pos: Dot) {
unsafe { sys::put_pixel(pos.x, pos.y, 1 << 24) }
}
pub fn define_button(
start: Dot,
size: Size,
@@ -51,14 +61,12 @@ pub fn define_button(
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")),
CString::new(format!(
"x:{:?} y:{:?} w:{:?} h:{:?}\n",
start.x, start.y, size.width, size.height
))
.expect("CString error")
.as_c_str(),
None,
);
throw_new!(format!(

View File

@@ -31,3 +31,12 @@ pub unsafe extern "C" fn memcmp(s1: *mut u8, s2: *const u8, n: usize) -> i32 {
0
}
#[no_mangle]
pub unsafe extern "C" fn strlen(str: *mut u8) -> usize {
let mut len = 0usize;
loop {
if *str.add(len) == 0 { return len; }
len += 1;
}
}

View File

@@ -8,6 +8,10 @@ extern "C" {
#[link_name = "_define_window"]
pub fn define_window(ebx: u32, ecx: u32, edx: u32, esi: u32, edi: u32);
// 1
#[link_name = "_put_pixel"]
pub fn put_pixel(ebx: u32, ecx: u32, edx: u32);
// 2
#[link_name = "_pressed_key"]
pub fn pressed_key() -> u32;
@@ -63,4 +67,12 @@ extern "C" {
// 68.19
#[link_name = "_load_dll"]
pub fn load_dll(name: *const u8) -> *const u32;
// 74
#[link_name = "_network_get"]
pub fn network_get(subfunc: u8, device: u8, ecx: u32) -> i32;
// 74 (u64 return: eax=lo, ebx=hi via out-ptr)
#[link_name = "_network_get_u64"]
pub fn network_get_u64(subfunc: u8, device: u8, ebx_out: *mut u32) -> i32;
}

View File

@@ -7,6 +7,7 @@ section '.text'
public _start_window_draw
public _end_window_draw
public _define_window
public _put_pixel
public _display_message
public _wait_event
public _pressed_key
@@ -19,6 +20,8 @@ section '.text'
public _get_lang
public _load_dll
public _set_event_mask
public _network_get
public _network_get_u64
_exit:
mov eax, SF_TERMINATE_PROCESS
@@ -50,6 +53,14 @@ _define_window:
pop edi
ret
_put_pixel:
mov eax, SF_PUT_PIXEL
mov ebx, dword [esp + 4 * 1]
mov ecx, dword [esp + 4 * 2]
mov edx, dword [esp + 4 * 3]
int 0x40
ret
_display_message:
push esi edi
mov eax, SF_DRAW_TEXT
@@ -134,3 +145,26 @@ _set_event_mask:
int 0x40
ret
_network_get:
push ebx
mov eax, SF_NETWORK_GET
movzx ebx, byte [esp + 4 * 2]
mov bh, byte [esp + 4 * 3]
mov ecx, [esp + 4 * 4]
int 0x40
pop ebx
ret
_network_get_u64:
push ebx
push edi
mov eax, SF_NETWORK_GET
movzx ebx, byte [esp + 4 * 3]
mov bh, byte [esp + 4 * 4]
xor ecx, ecx
mov edi, [esp + 4 * 5]
int 0x40
mov [edi], ebx
pop edi
pop ebx
ret