1
0
forked from Rust/Core

Use C for syscalls

This commit is contained in:
Kitsu 2021-12-09 02:18:30 +03:00
parent aef1325ce9
commit 17ca59abe0
7 changed files with 112 additions and 54 deletions

View File

@ -12,3 +12,6 @@ lto = "thin"
[dependencies] [dependencies]
cstr_core = { version = "0.2.4", default-features = false, features = ["nightly"] } cstr_core = { version = "0.2.4", default-features = false, features = ["nightly"] }
[build-dependencies]
cc = "1.0.72"

8
build.rs Normal file
View File

@ -0,0 +1,8 @@
fn main() {
println!("cargo:rerun-if-changed=src/syscalls.c");
cc::Build::new()
.file("src/syscalls.c")
.flag("-fno-PIC") // for some reason `pic(false)` doesn't work
.static_flag(true)
.compile("syscalls");
}

View File

@ -1,22 +1,8 @@
#![feature(asm)]
#![no_std] #![no_std]
macro_rules! syscall { mod sys;
($fn_no:literal) => {{
let mut res: i32 = $fn_no;
asm!("int 0x40", inout("eax") res); pub use sys::*;
res
}};
($fn_no:literal, $($reg:tt)*) => {{
let mut res: i32 = $fn_no;
asm!("int 0x40",
$($reg)*,
inout("eax") res,
);
res
}}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Color(u8, u8, u8); pub struct Color(u8, u8, u8);
@ -29,9 +15,11 @@ impl Color {
pub fn r(&self) -> u8 { pub fn r(&self) -> u8 {
self.0 self.0
} }
pub fn g(&self) -> u8 { pub fn g(&self) -> u8 {
self.1 self.1
} }
pub fn b(&self) -> u8 { pub fn b(&self) -> u8 {
self.2 self.2
} }
@ -41,11 +29,6 @@ impl Color {
} }
} }
#[inline]
pub unsafe fn start_window_draw() {
syscall!(12, in("ebx") 1);
}
pub struct Dot { pub struct Dot {
pub x: u32, pub x: u32,
pub y: u32, pub y: u32,
@ -66,17 +49,21 @@ pub struct WindowParams<'a> {
pub title: Option<&'a cstr_core::CStr>, pub title: Option<&'a cstr_core::CStr>,
} }
#[inline] pub fn define_window(start: Dot, width: u32, height: u32, params: WindowParams<'_>) {
pub unsafe fn define_window(start: Dot, width: u32, height: u32, params: WindowParams<'_>) {
const RELATIVE_FLAG: u32 = 0x20; const RELATIVE_FLAG: u32 = 0x20;
syscall!(
0, unsafe {
in("ebx") start.x * 65536 + width, sys::define_window(
in("ecx") start.y * 65536 + height, start.x * 65536 + width,
in("edx") params.color.as_rgb_val() | start.y * 65536 + height,
(RELATIVE_FLAG | (params.title.is_some() as u32) << 4 | params.kind as u32) << 24, params.color.as_rgb_val()
in("edi") params.title.map(|s| s.as_ptr()).unwrap_or_else(core::ptr::null) | (RELATIVE_FLAG | (params.title.is_some() as u32) << 4 | params.kind as u32) << 24,
); params
.title
.map(|s| s.as_ptr())
.unwrap_or_else(core::ptr::null) as u32,
);
}
} }
pub struct WindowTextParams<'a> { pub struct WindowTextParams<'a> {
@ -85,30 +72,23 @@ pub struct WindowTextParams<'a> {
pub bg_color: Option<Color>, pub bg_color: Option<Color>,
} }
#[inline] pub fn display_message(start: Dot, params: WindowTextParams<'_>) {
pub unsafe fn display_message(start: Dot, params: WindowTextParams<'_>) {
const UTF8_FLAG: u32 = 0b0011_0000 << 24; const UTF8_FLAG: u32 = 0b0011_0000 << 24;
const BG_FLAG: u32 = 0b0100_0000 << 24; const BG_FLAG: u32 = 0b0100_0000 << 24;
// XXX: llvm uses esi internally for x86-32
// hope we're lucky enough so it won't be overwritten.
asm!("mov esi, {}", in(reg) params.text.len());
syscall!(
4,
in("ebx") start.x * 65536 + start.y,
in("ecx") params.color.as_rgb_val() | BG_FLAG * params.bg_color.is_some() as u32 | UTF8_FLAG,
in("edx") params.text.as_ptr()
);
}
#[inline] unsafe {
pub unsafe fn end_window_draw() { sys::display_message(
syscall!(12, in("ebx") 2); start.x * 65536 + start.y,
params.color.as_rgb_val() | BG_FLAG * params.bg_color.is_some() as u32 | UTF8_FLAG,
params.text.as_ptr() as u32,
0,
params.text.len() as u32,
);
}
} }
pub fn exit() -> ! { pub fn exit() -> ! {
unsafe { syscall!(-1) }; unsafe { sys::exit() }
unsafe { core::hint::unreachable_unchecked() }
} }
#[panic_handler] #[panic_handler]
@ -122,18 +102,16 @@ pub enum Event {
KeyPress, KeyPress,
} }
#[inline]
pub fn fetch_event() -> Option<Event> { pub fn fetch_event() -> Option<Event> {
match unsafe { syscall!(10) } { match unsafe { sys::wait_event() } {
1 => Some(Event::Redraw), 1 => Some(Event::Redraw),
2 => Some(Event::KeyPress), 2 => Some(Event::KeyPress),
_ => None, _ => None,
} }
} }
#[inline]
pub fn fetch_key() -> Option<u8> { pub fn fetch_key() -> Option<u8> {
let res = unsafe { syscall!(2) }; let res = unsafe { sys::pressed_key() };
if res == 1 { if res == 1 {
None None
} else { } else {

View File

@ -1,4 +1,3 @@
#![feature(asm)]
#![no_std] #![no_std]
#![no_main] #![no_main]

16
src/sys.rs Normal file
View File

@ -0,0 +1,16 @@
#[link(name = "syscalls")]
extern "C" {
pub fn start_window_draw();
pub fn end_window_draw();
#[link_name = "exit0"]
pub fn exit() -> !;
pub fn define_window(ebx: u32, ecx: u32, edx: u32, edi: u32);
pub fn display_message(ebx: u32, ecx: u32, edx: u32, edi: u32, esi: u32);
pub fn wait_event() -> u32;
pub fn pressed_key() -> u32;
}

54
src/syscalls.c Normal file
View File

@ -0,0 +1,54 @@
void start_window_draw() {
__asm__ volatile (
"int $0x40;"
:: "a"(12), "b"(1)
);
}
void end_window_draw() {
__asm__ volatile (
"int $0x40;"
:: "a"(12), "b"(2)
);
}
void exit0() {
__asm__ volatile (
"int $0x40;"
:: "a"(-1)
);
}
void define_window(unsigned ebx, unsigned ecx, unsigned edx, unsigned edi) {
__asm__ volatile (
"int $0x40;"
:: "a"(0), "b"(ebx), "c"(ecx), "d"(edx), "D"(edi)
: "memory"
);
}
void display_message(unsigned ebx, unsigned ecx, unsigned edx, unsigned edi, unsigned esi) {
__asm__ volatile (
"int $0x40;"
:: "a"(4), "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi)
: "memory"
);
}
unsigned wait_event() {
unsigned res;
__asm__ volatile (
"int $0x40;"
: "=r"(res) : "a"(10)
);
return res;
}
unsigned pressed_key() {
unsigned res;
__asm__ volatile (
"int $0x40;"
: "=r"(res) : "a"(2)
);
return res;
}

BIN
src/syscalls.o Normal file

Binary file not shown.