7 Commits

Author SHA1 Message Date
Sanya Kapoor
5723950f42 build: fix alloc 2026-03-11 02:41:10 +05:30
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
16 changed files with 210 additions and 69 deletions

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,10 @@ path = "examples/hwa.rs"
name = "con"
path = "examples/con.rs"
[[example]]
name = "dark"
path = "examples/dark.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,
);

View File

@@ -1,7 +1,7 @@
{
"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,

View File

@@ -36,6 +36,7 @@ pub fn init() {
unsafe {
sys::init_heap();
MAIN_SECTOR = sys::alloc(PAGE_SIZE) as usize;
core::ptr::write_bytes(MAIN_SECTOR as *mut u8, 0, PAGE_SIZE); // make sector table start clean
}
}
}
@@ -47,14 +48,14 @@ pub fn malloc(size: usize) -> *mut u8 {
if (addr as usize) != 0 {
let sec = addr;
let mut hdr = *(addr as *const SectorHeader);
let hdr = &mut *(addr as *mut SectorHeader);
let sec_start_blocks = (sec as usize) + size_of::<SectorHeader>();
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);
let block = &mut *(j as *mut BlockHeader);
match block.sign {
Sign::Active => {
// If block is occupated - pass
@@ -63,7 +64,7 @@ pub fn malloc(size: usize) -> *mut u8 {
}
Sign::Free => {
if first_found_block_addr != 0 {
if first_found_block_addr == 0 {
first_found_block_addr = j;
}
@@ -73,26 +74,32 @@ pub fn malloc(size: usize) -> *mut u8 {
j += (size_of::<BlockHeader>()) + block.size;
} else if size - sum_size < size_of::<BlockHeader>() {
// Create 2 blocks
let mut main_block =
*(first_found_block_addr as *const BlockHeader);
let main_block =
&mut *(first_found_block_addr as *mut BlockHeader);
main_block.sign = Sign::Active;
main_block.size = size;
let mut secondary_block = *(first_found_block_addr
as *const BlockHeader)
.add(size_of::<BlockHeader>() + size);
secondary_block.sign = Sign::Free;
secondary_block.size =
let secondary_block = (first_found_block_addr
+ size_of::<BlockHeader>()
+ size)
as *mut BlockHeader;
(*secondary_block).sign = Sign::Free;
(*secondary_block).size =
sum_size - size - size_of::<BlockHeader>();
hdr.size_left -= size + size_of::<BlockHeader>();
return (first_found_block_addr as *mut u8)
.add(size_of::<BlockHeader>());
} else {
// Create 1 block
let mut main_block =
*(first_found_block_addr as *const BlockHeader);
let main_block =
&mut *(first_found_block_addr as *mut BlockHeader);
main_block.sign = Sign::Active;
main_block.size = sum_size - size_of::<BlockHeader>();
hdr.size_left -= main_block.size + size_of::<BlockHeader>();
return (first_found_block_addr as *mut u8)
.add(size_of::<BlockHeader>());
}
@@ -117,9 +124,11 @@ pub fn malloc(size: usize) -> *mut u8 {
}
}
} else {
let sec_size = size + PAGE_SIZE - size % PAGE_SIZE;
// round requested size up to whole pages
let sec_size = (size + PAGE_SIZE - 1) & !(PAGE_SIZE - 1);
let new_sec = sys::alloc(sec_size);
let sec_hdr = new_sec as *mut SectorHeader;
*((MAIN_SECTOR + i * 4) as *mut u32) = new_sec as u32; // remember this sector in the table
*sec_hdr = SectorHeader {
size: sec_size,
size_left: sec_size - size_of::<SectorHeader>(),
@@ -138,26 +147,26 @@ pub fn malloc(size: usize) -> *mut u8 {
fn free(block: *const u8) {
unsafe {
let mut block_hdr = *(block.sub(size_of::<BlockHeader>()) as *mut BlockHeader);
let block_hdr = &mut *(block.sub(size_of::<BlockHeader>()) 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.is_null() {
continue;
}
let hdr = &mut *(addr as *mut SectorHeader);
if addr < block && (block as usize) < (addr as usize) + hdr.size {
hdr.size_left += block_hdr.size;
hdr.size_left += block_hdr.size + size_of::<BlockHeader>();
if hdr.size_left == hdr.size - size_of::<SectorHeader>() {
free(addr)
sys::free(addr); // whole sector is free, hand it back to OS
*((MAIN_SECTOR + i * 4) as *mut u32) = 0; // and drop from the table
} else {
block_hdr.sign = Sign::Free;
}
break;
}
}
if !sys::free(block) {
panic!("Free failed");
}
}
}
@@ -181,4 +190,4 @@ unsafe impl alloc::alloc::GlobalAlloc for GlobalAlloc {
}
#[global_allocator]
static ALLOC: GlobalAlloc = GlobalAlloc;
static ALLOC: GlobalAlloc = GlobalAlloc;

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

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

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

@@ -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;

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
@@ -50,6 +51,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