Make Doom run by improving and fixing libc stubs, adding proper heap

allocation, adding a timer, a framebuffer swap, rectangle and buffer
draw syscall, moving the header files to the correct directory,
disabling stack protection, AVX and MMX, while enabling SSE, fix
interrupt handler popping in the wrong order, improve
load_segment_to_memory alignment, add load_from_ptr to framebuffer for
very quick drawing, serial_print as well as render font in
consolewriter, zero the memory in sbrk, add a fake file system and
methods to libxunil for DOOM, add correct printf, vsnprintf add _start
which calls the main function in libxunil, mark all registers as used
inside syscalls for no memory corruption, add build_helloworld.sh script
This commit is contained in:
csd4ni3l
2026-04-07 18:06:52 +02:00
parent ae3915147a
commit 9e8090c736
29 changed files with 980 additions and 256 deletions

View File

@@ -213,7 +213,7 @@ ifeq ($(KARCH),loongarch64)
iso_root -o $(IMAGE_NAME).iso
endif
rm -rf iso_root
qemu-system-$(KARCH) -cdrom $(IMAGE_NAME).iso -m 512M -serial stdio
qemu-system-$(KARCH) -cdrom $(IMAGE_NAME).iso -m 1G -serial stdio
$(IMAGE_NAME).hdd: limine/limine kernel
rm -f $(IMAGE_NAME).hdd

BIN
assets/doom1.wad Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,6 @@
bash build_libxunil.sh
cd user/apps/doomgeneric/doomgeneric
rm -r ./build
make -f Makefile.xunil
make -j16 -f Makefile.xunil
cp doomgeneric ../../../../assets/doomgeneric
cd ../../../..

4
build_helloworld.sh Normal file
View File

@@ -0,0 +1,4 @@
bash build_libxunil.sh
cd user/apps/helloworld
bash compile.sh
cd ../../../

View File

@@ -1,8 +1,9 @@
#[cfg(target_arch = "x86_64")]
pub use crate::arch::x86_64::paging::FRAME_ALLOCATOR_X86_64 as FRAME_ALLOCATOR;
use crate::driver::timer::TIMER;
use core::{alloc::GlobalAlloc, arch::asm};
use crate::{driver::timer::TIMER, util::serial_print};
use alloc::string::ToString;
use core::{alloc::GlobalAlloc, arch::asm, sync::atomic::Ordering};
use limine::response::{HhdmResponse, MemoryMapResponse};
#[cfg(target_arch = "x86_64")]
@@ -50,10 +51,11 @@ pub fn idle() {
}
pub fn sleep(ticks: u64) {
let start = TIMER.now();
while (TIMER.now() - start).elapsed() <= ticks {
idle();
}
// let start = TIMER.now();
// while start.ticks_since() < ticks {
// serial_print(start.ticks_since().to_string().as_str());
// core::hint::spin_loop();
// }
}
pub fn infinite_idle() -> ! {

View File

@@ -16,7 +16,7 @@ use crate::{
pub fn run_elf_x86_64(entry_point: *const u8, heap_base: u64) {
let stack_base: u64 = 0x0000_7fff_0000_0000;
let page_count = 3;
let page_count = 4096; // 16 mib
let page_size = 0x1000u64;
let stack_top = stack_base + (page_count as u64 * page_size);

View File

@@ -20,7 +20,7 @@ fn align_up(addr: usize, align: usize) -> usize {
pub static ALLOCATOR: Locked<LinkedListAllocator> = Locked::new(LinkedListAllocator::new());
pub const HEAP_START: usize = 0x_4444_4444_0000;
pub const HEAP_SIZE: usize = 256 * 1024 * 1024; // 256 MiB
pub const HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MiB
pub struct LinkedNode {
pub size: usize,
@@ -54,7 +54,7 @@ impl LinkedListAllocator {
fn size_align(layout: Layout) -> (usize, usize) {
let layout = layout
.align_to(core::mem::align_of::<LinkedNode>())
.align_to(16)
.expect("Align to LinkedNode failed")
.pad_to_align();
@@ -70,7 +70,7 @@ impl LinkedListAllocator {
}
unsafe fn add_free_memory_region(&mut self, start: usize, size: usize) {
assert_eq!(align_up(start, core::mem::align_of::<LinkedNode>()), start); // Check if we are up at least 1 LinkedNode size
assert_eq!(align_up(start, 16), start); // Check if we are up at least 1 LinkedNode size
assert!(size >= core::mem::size_of::<LinkedNode>()); // check if we have enough space for a LinkedNode
let mut linked_node = LinkedNode::new(size);

View File

@@ -8,8 +8,14 @@ use crate::{
util::serial_print,
};
use limine::response::{HhdmResponse, MemoryMapResponse};
use x86_64::instructions::interrupts::without_interrupts;
use x86_64::instructions::{interrupts, port::Port};
use x86_64::{
instructions::interrupts::without_interrupts,
registers::control::{Cr0, Cr0Flags},
};
use x86_64::{
instructions::{interrupts, port::Port},
registers::control::{Cr4, Cr4Flags},
};
const TIMER_PRECISION_HZ: u32 = 1000;
const PIT_DIVISOR: u16 = (1_193_182_u32 / TIMER_PRECISION_HZ) as u16;
@@ -53,6 +59,19 @@ pub fn init_x86_64<'a>(
memory_map_response: &'a MemoryMapResponse,
) -> OffsetPageTable<'static> {
load_gdt_x86_64();
unsafe {
let mut cr0 = Cr0::read();
cr0.remove(Cr0Flags::EMULATE_COPROCESSOR);
cr0.insert(Cr0Flags::MONITOR_COPROCESSOR);
Cr0::write(cr0);
let mut cr4 = Cr4::read();
cr4.insert(Cr4Flags::OSFXSR);
cr4.insert(Cr4Flags::OSXMMEXCPT_ENABLE);
Cr4::write(cr4);
}
init_idt_x86_64();
unsafe {

View File

@@ -6,6 +6,7 @@ use crate::{
timer::TIMER,
},
println,
util::serial_print,
};
use lazy_static::lazy_static;
use pc_keyboard::DecodedKey;
@@ -182,11 +183,11 @@ unsafe extern "C" fn syscall_interrupt_handler() {
"add rsp, 8",
"add rsp, 8",
// pop them in reverse orser
"pop rbx",
"pop rcx",
"pop rdx",
"pop rsi",
"pop rdi",
"pop rsi",
"pop rdx",
"pop rcx",
"pop rbx",
"pop rbp",
"pop r8",
"pop r9",

View File

@@ -291,27 +291,26 @@ pub fn load_segment_to_memory(
let p_offset: u64 = unsafe { (*phdr).p_offset };
let file_size: u64 = unsafe { (*phdr).p_filesz };
let vaddr: *mut u8 = get_vaddr(phdr, load_bias);
if p_offset > elf_bytes.len() as u64
|| file_size > elf_bytes.len() as u64
|| p_offset + file_size > elf_bytes.len() as u64
|| file_size > mem_size
{
return;
} // invalid, could read past it's memory
if file_size > mem_size {
return;
}
let vaddr: u64 = get_vaddr(phdr, load_bias) as u64;
let mem_page: u64 = align_down(vaddr, PAGE_SIZE);
let file_page: u64 = align_down(p_offset, PAGE_SIZE);
let page_off: u64 = vaddr - mem_page;
let seg_start = align_down(vaddr as u64, PAGE_SIZE);
let seg_end = align_up(vaddr as u64 + mem_size, PAGE_SIZE);
let seg_start = mem_page;
let seg_end = align_up(vaddr + mem_size, PAGE_SIZE);
let mut flags =
PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::WRITABLE;
if unsafe { ((*phdr).p_flags & PF_X) != 0 } {
} else {
if unsafe { ((*phdr).p_flags & PF_X) == 0 } {
flags |= PageTableFlags::NO_EXECUTE;
}
@@ -337,19 +336,18 @@ pub fn load_segment_to_memory(
drop(frame_allocator);
let dst = (mem_page + page_off) as *mut u8;
let src = unsafe { elf_bytes.as_ptr().add(p_offset as usize) };
unsafe {
core::ptr::copy_nonoverlapping(
elf_bytes.as_ptr().add(p_offset as usize),
vaddr,
file_size as usize,
);
core::ptr::copy_nonoverlapping(src, dst, file_size as usize);
if mem_size > file_size {
memset(
vaddr.add(file_size as usize),
dst.add(file_size as usize),
0,
(mem_size - file_size) as usize,
);
}
};
}
}

View File

@@ -70,6 +70,22 @@ impl Framebuffer {
}
}
pub unsafe fn load_from_ptr(
&mut self,
src_ptr: *const u32,
src_width: usize,
src_height: usize,
) {
let h = core::cmp::min(src_height, self.height);
let w = core::cmp::min(src_width, self.width);
for y in 0..h {
let src_row = src_ptr.add(y * src_width);
let dst_row = self.back_buffer.as_mut_ptr().add(y * self.pitch);
core::ptr::copy_nonoverlapping(src_row, dst_row, w);
}
}
pub fn clear(&mut self, color: u32) {
self.back_buffer.fill(color);
}

View File

@@ -1,6 +1,6 @@
use crate::driver::graphics::base::rgb;
use crate::driver::graphics::font_render::render_text;
use crate::driver::graphics::framebuffer::Framebuffer;
use crate::{driver::graphics::base::rgb, util::serial_print};
use core::fmt::{self, Write};
use spin::Mutex;
@@ -15,6 +15,7 @@ pub struct ConsoleWriter<'a> {
impl Write for ConsoleWriter<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
serial_print(s);
self.console.render_text(self.fb, s, 2, false);
Ok(())
}

View File

@@ -3,15 +3,19 @@ use core::{
ptr::null_mut,
};
use alloc::string::ToString;
use x86_64::{
VirtAddr,
structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB},
};
use crate::{
arch::arch::{FRAME_ALLOCATOR, get_allocator, infinite_idle},
driver::graphics::framebuffer::with_framebuffer,
println,
arch::arch::{FRAME_ALLOCATOR, get_allocator, infinite_idle, sleep},
driver::{
graphics::{framebuffer::with_framebuffer, primitives::rectangle_filled},
timer::TIMER,
},
print, println,
task::scheduler::SCHEDULER,
util::{align_up, serial_print},
};
@@ -37,6 +41,10 @@ const UNLINK: usize = 87;
const GETDENTS64: usize = 217;
const CLOCK_GETTIME: usize = 228;
const EXIT_GROUP: usize = 231;
const SLEEP: usize = 909090; // zzz haha
const DRAW_PIXEL: usize = 5555;
const FRAMEBUFFER_SWAP: usize = 6666;
pub const DRAW_BUFFER: usize = 7777;
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
let align = if align < 1 {
@@ -74,7 +82,6 @@ pub unsafe fn memset(ptr: *mut u8, val: u8, count: usize) {
}
pub unsafe fn sbrk(increment: isize) -> isize {
serial_print("sbrk called");
let mut scheduler = SCHEDULER.lock();
if scheduler.current_process == -1 {
return -1;
@@ -100,16 +107,17 @@ pub unsafe fn sbrk(increment: isize) -> isize {
if new < heap_base {
return -1;
}
if new > stack_top - 3 * 4096 {
if new > stack_top - 16384 * 4096 {
// 67 mib max
return -1;
}
if new > old {
let map_start = align_up(old, 4096);
let map_end = align_up(new, 4096);
for addr in (map_start..map_end).step_by(4096) {
let frame = frame_allocator.allocate_frame().unwrap();
if let Some(frame) = frame_allocator.allocate_frame() {
// TODO: do not use x86_64 only
let virt_addr = VirtAddr::new(addr);
let page = Page::<Size4KiB>::containing_address(virt_addr);
@@ -128,6 +136,11 @@ pub unsafe fn sbrk(increment: isize) -> isize {
)
.unwrap()
.flush();
core::ptr::write_bytes(virt_addr.as_mut_ptr::<u8>(), 0, 4096);
}
} else {
return -1;
}
}
}
@@ -135,8 +148,6 @@ pub unsafe fn sbrk(increment: isize) -> isize {
process.heap_end = new;
serial_print("sbrk finished");
return old as isize;
})
.unwrap_or(-1);
@@ -150,21 +161,58 @@ pub unsafe extern "C" fn syscall_dispatch(
arg2: isize,
) -> isize {
match num {
SYS_BRK => sbrk(arg0),
SYS_WRITE => {
BRK => sbrk(arg0),
WRITE => {
let buf_ptr = arg1 as *const u8;
let len = arg2 as usize;
let bytes: &[u8] = unsafe { core::slice::from_raw_parts(buf_ptr, len) };
let s = core::str::from_utf8(bytes).unwrap_or("<non-utf8>");
println!("SYS_WRITE called: {:?} {:?}", s, len);
if let Ok(s) = core::str::from_utf8(bytes) {
print!("{}", s);
} else {
for byte in bytes {
if *byte == b'\0' {
continue;
}
print!("{}", *byte as char);
}
}
with_framebuffer(|fb| fb.swap());
0
}
SYS_EXIT => {
println!("Program exit.");
EXIT => {
println!("Program exit: {}", arg0);
with_framebuffer(|fb| fb.swap());
infinite_idle();
}
67 => {
println!("{:?}", arg1);
0
}
SLEEP => {
sleep(arg0 as u64);
0
}
CLOCK_GETTIME => TIMER.now().elapsed() as isize,
DRAW_PIXEL => {
with_framebuffer(|mut fb| {
rectangle_filled(&mut fb, arg0 as usize, arg1 as usize, 4, 4, arg2 as u32);
});
0
}
DRAW_BUFFER => {
with_framebuffer(|mut fb| {
fb.load_from_ptr(arg0 as *const u32, arg1 as usize, arg2 as usize);
fb.swap();
});
0
}
FRAMEBUFFER_SWAP => {
with_framebuffer(|fb| {
fb.swap();
});
0
}
_ => -38, // syscall not found
}
}

View File

@@ -3,6 +3,8 @@ use core::{
sync::atomic::{AtomicU64, Ordering},
};
use crate::util::serial_print;
pub static TIMER: Timer = Timer::new();
pub struct Timer {
@@ -50,6 +52,11 @@ impl Time {
pub fn elapsed(&self) -> u64 {
self.interrupt_count
}
pub fn ticks_since(&self) -> u64 {
let now = TIMER.interrupt_count.load(Ordering::Relaxed);
now.saturating_sub(self.interrupt_count)
}
}
impl Add for Time {

View File

@@ -39,6 +39,8 @@ impl Locked<Scheduler> {
let stack_top = guard.processes[&pid].stack_top;
guard.current_process = pid as i64;
drop(guard);
enter_usermode(entry_point as u64, (stack_top & !0xF) - 8);
}

View File

@@ -26,7 +26,7 @@ use crate::{
static CURSOR_BYTES: &[u8] = include_bytes!("../../assets/cursors/default.bmp");
#[repr(C, align(8))]
#[repr(C, align(16))]
struct AlignedElf([u8; include_bytes!("../../assets/doomgeneric").len()]);
static TEST_ELF: AlignedElf = AlignedElf(*include_bytes!("../../assets/doomgeneric"));
static TEST_ELF_BYTES: &[u8] = &TEST_ELF.0;
@@ -86,8 +86,6 @@ fn boot_animation() {
pub fn userspace_init(mapper: &mut OffsetPageTable) -> ! {
// this is just a stub
boot_animation();
let (entry_point, heap_base) = load_file(mapper, TEST_ELF_BYTES);
println!("Entry point: {:?}", entry_point);

View File

@@ -1,4 +1,3 @@
gcc -nostdlib -nostdinc -static -static-pie \
-o $1 $1.c \
-L../../libxunil/target/release -l:libxunil.a
mv $1 ../../../assets/$1.elf
GCC_INCLUDES=$(gcc -print-file-name=include)
SYS_INCLUDES=/usr/include
gcc -w -static -D__NO_INLINE__ -O0 -mno-mmx -mno-avx -fno-stack-protector -fno-inline -fno-inline-small-functions -fno-indirect-inlining -fno-builtin -fcompare-debug-second -nostdlib -nostdinc helloworld.c -Wl,--gc-sections -L../../libxunil/target/release -l:libxunil.a -I../../libxunil/include -I"$GCC_INCLUDES" -I"$SYS_INCLUDES" -o ../../../assets/helloworld.elf

View File

@@ -1,2 +1 @@
#include <stddef.h>
#include <stdint.h>

View File

@@ -1,18 +1,9 @@
#pragma once
#include <sys/types.h>
#include <stddef.h>
#include <stdarg.h>
typedef struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
typedef struct FILE FILE;
extern FILE *stdin;
extern FILE *stdout;
@@ -20,6 +11,10 @@ extern FILE *stderr;
#define EOF (-1)
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
FILE *fopen(const char *path, const char *mode);
int fclose(FILE *fp);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp);
@@ -31,12 +26,19 @@ char *fgets(char *s, int size, FILE *fp);
int fputs(const char *s, FILE *fp);
int feof(FILE *fp);
int ferror(FILE *fp);
int remove(const char *path);
int rename(const char *path, const char *new_path);
int printf(const char *fmt, ...);
int puts(const char *s);
int putchar(int c);
int fprintf(FILE *fp, const char *fmt, ...);
int sprintf(char *buf, const char *fmt, ...);
int snprintf(char *buf, size_t size, const char *fmt, ...);
int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap);
int vfprintf(FILE *fp, const char *fmt, va_list ap);
void write(int fd, const char* buf, unsigned long count);
ssize_t write(int fd, const void *buf, size_t count);
void exit(int code);
int sscanf(const char *str, const char *format, ...);

View File

@@ -1,4 +1,5 @@
#pragma once
#include <inttypes.h>
#include <stddef.h>
void *malloc(size_t size);
@@ -18,3 +19,6 @@ double strtod(const char *s, char **endptr);
char *getenv(const char *name);
void qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void *));
int abs(int x);
int system(const char *cmd);
int draw_pixel(uint32_t x, uint32_t y, uint32_t color);
int framebuffer_swap();

View File

@@ -1,40 +1,236 @@
use core::{
ffi::CStr,
ptr::{null, null_mut},
};
use crate::{mem::free, printf, puts};
#[repr(C)]
#[derive(Clone, Copy)]
pub struct FILE {
pub data: *const u8, // pointer to the file's data
pub size: usize, // total size
pub cursor: usize, // current position
pub writable: bool, // is this a write buffer?
pub write_buf: *mut u8, // for writable fake files
pub write_cap: usize,
pub fd: i64,
}
impl FILE {
pub const fn zeroed() -> FILE {
FILE {
data: null(),
size: 0,
cursor: 0,
writable: false,
write_buf: null_mut(),
write_cap: 0,
fd: -1,
}
}
}
struct FakeFileEntry {
name: &'static str,
data: &'static [u8],
}
#[repr(C, align(8))]
struct AlignedWAD([u8; include_bytes!("../../../assets/doom1.wad").len()]);
static TEST_WAD: AlignedWAD = AlignedWAD(*include_bytes!("../../../assets/doom1.wad"));
static TEST_WAD_BYTES: &[u8] = &TEST_WAD.0;
static FILES: &[FakeFileEntry] = &[
FakeFileEntry {
name: "doom1.wad",
data: TEST_WAD_BYTES,
},
FakeFileEntry {
name: "default.cfg",
data: b"",
},
FakeFileEntry {
name: "doom.cfg",
data: b"",
},
];
static mut FILE_POOL: [FILE; 16] = [FILE::zeroed(); 16];
static mut FILE_POOL_USED: [bool; 16] = [false; 16];
static mut STDERR_FILE: FILE = FILE::zeroed();
static mut STDOUT_FILE: FILE = FILE::zeroed();
static mut STDIN_FILE: FILE = FILE::zeroed();
#[unsafe(no_mangle)]
extern "C" fn fopen(path: *const u8, mode: *const u8) -> *mut u8 {
0x10 as *mut u8
pub static mut stderr: *mut FILE = unsafe { &raw mut STDERR_FILE };
#[unsafe(no_mangle)]
pub static mut stdin: *mut FILE = unsafe { &raw mut STDIN_FILE };
#[unsafe(no_mangle)]
pub static mut stdout: *mut FILE = unsafe { &raw mut STDOUT_FILE };
pub unsafe fn get_file_pool_slot() -> (*mut FILE, i64) {
unsafe {
for i in 0..16 {
if !FILE_POOL_USED[i] {
FILE_POOL_USED[i] = true;
return (&mut FILE_POOL[i], i as i64);
}
}
(null_mut(), -1)
}
}
#[unsafe(no_mangle)]
extern "C" fn fclose(file_ptr: *mut u8) -> i32 {
extern "C" fn fopen(path: *const i8, mode: *const i8) -> *mut FILE {
if path.is_null() || mode.is_null() {
return null_mut();
}
unsafe {
let name = CStr::from_ptr(path).to_str().unwrap_or("");
for entry in FILES {
if name.contains(entry.name) {
let (slot, fd) = get_file_pool_slot();
if slot.is_null() {
return null_mut();
}
(*slot).data = entry.data.as_ptr();
(*slot).size = entry.data.len();
(*slot).cursor = 0;
(*slot).writable = false;
(*slot).write_buf = null_mut();
(*slot).write_cap = 0;
(*slot).fd = fd;
return slot;
}
}
}
null_mut()
}
#[unsafe(no_mangle)]
extern "C" fn fclose(file_ptr: *mut FILE) -> i32 {
if file_ptr.is_null() || unsafe { (*file_ptr).fd < 0 || (*file_ptr).fd >= 16 } {
return -1;
}
unsafe { FILE_POOL_USED[(*file_ptr).fd as usize] = false };
unsafe { *file_ptr = FILE::zeroed() };
0
}
#[unsafe(no_mangle)]
extern "C" fn fprintf(file_ptr: *mut u8, s: *const u8) -> i32 {
unsafe extern "C" fn fprintf(file_ptr: *mut FILE, fmt: *const u8, args: ...) -> i32 {
if fmt.is_null() || file_ptr.is_null() || unsafe { (*file_ptr).fd < 0 || (*file_ptr).fd >= 16 }
{
return -1;
}
0
}
#[unsafe(no_mangle)]
extern "C" fn fread(ptr: *mut u8, size: i32, nmemb: *const u8, fp: *const u8) -> i32 {
extern "C" fn fread(ptr: *mut u8, size: usize, nmemb: usize, fp: *mut FILE) -> usize {
if size == 0
|| nmemb == 0
|| ptr.is_null()
|| fp.is_null()
|| unsafe { (*fp).fd < 0 || (*fp).fd >= 16 }
{
return 0;
}
let total = match size.checked_mul(nmemb) {
Some(t) => t,
None => return 0,
};
unsafe {
let f = &mut *fp;
if f.cursor > f.size {
puts(b"failed to read\0".as_ptr());
return 0;
}
let available = f.size - f.cursor;
let to_read = total.min(available);
if to_read > 0 {
core::ptr::copy_nonoverlapping(f.data.add(f.cursor), ptr, to_read);
f.cursor = f.cursor.saturating_add(to_read);
}
to_read / size
}
}
#[unsafe(no_mangle)]
extern "C" fn fseek(stream: *mut FILE, offset: i64, whence: i32) -> i32 {
if stream.is_null() || unsafe { (*stream).fd } == -1 {
return -1;
}
let f = unsafe { &mut *stream };
let new_pos = match whence {
0 => {
if offset < 0 {
return -1;
}
offset as usize
}
1 => {
let cur = f.cursor as i64;
let pos = cur.saturating_add(offset);
if pos < 0 {
return -1;
}
pos as usize
}
2 => {
let end = f.size as i64;
let pos = end.saturating_add(offset);
if pos < 0 {
return -1;
}
pos as usize
}
_ => return -1,
};
if new_pos > f.size {
return -1;
}
f.cursor = new_pos;
0
}
#[unsafe(no_mangle)]
extern "C" fn fwrite(ptr: *mut u8, size: i32, nmemb: *const u8, fp: *const u8) -> i32 {
0
extern "C" fn fwrite(ptr: *mut u8, size: usize, count: usize, fp: *mut FILE) -> usize {
if ptr.is_null() || fp.is_null() || unsafe { (*fp).fd < 0 || (*fp).fd >= 16 } {
return 0;
}
count
}
#[unsafe(no_mangle)]
extern "C" fn fseek(s: *const u8, size: i32, fp: *const u8) -> i32 {
0
extern "C" fn ftell(stream: *mut FILE) -> i64 {
if stream.is_null() || unsafe { (*stream).fd < 0 || (*stream).fd >= 16 } {
return -1;
}
unsafe { (*stream).cursor as i64 }
}
#[unsafe(no_mangle)]
extern "C" fn ftell(fp: *const u8) -> i64 {
0
}
#[unsafe(no_mangle)]
extern "C" fn fflush(file_ptr: *mut u8) -> i32 {
extern "C" fn fflush(file_ptr: *mut FILE) -> i32 {
0
}
@@ -44,7 +240,7 @@ extern "C" fn mkdir(path: *const u8, mode: *const u8) -> i32 {
}
#[unsafe(no_mangle)]
extern "C" fn remove(path: *const u8) -> i32 {
extern "C" fn remove(path: *const i8) -> i32 {
0
}
@@ -57,8 +253,3 @@ extern "C" fn rename(path: *const u8, new_path: *const u8) -> i32 {
unsafe extern "C" fn vfprintf(stream: *const u8, format: *const u8, args: ...) -> i32 {
0
}
#[unsafe(no_mangle)]
unsafe extern "C" fn vsnprintf(s: *mut u8, n: i32, format: *const u8, args: ...) -> i32 {
0
}

View File

@@ -2,9 +2,6 @@ use spin::mutex::Mutex;
use crate::util::align_up;
pub const HEAP_START: usize = 0x_4444_4444_0000;
pub const HEAP_SIZE: usize = 256 * 1024 * 1024; // 256 MiB
pub struct LinkedNode {
pub size: usize,
pub next: Option<&'static mut LinkedNode>,
@@ -28,6 +25,12 @@ pub struct LinkedListAllocator {
head: LinkedNode,
}
#[derive(Clone, Copy)]
pub struct Allocation {
pub start: usize,
pub end: usize,
}
impl LinkedListAllocator {
pub const fn new() -> LinkedListAllocator {
Self {
@@ -36,58 +39,70 @@ impl LinkedListAllocator {
}
pub unsafe fn add_free_memory_region(&mut self, start: usize, size: usize) {
assert_eq!(align_up(start, core::mem::align_of::<LinkedNode>()), start); // Check if we are up at least 1 LinkedNode size
assert!(size >= core::mem::size_of::<LinkedNode>()); // check if we have enough space for a LinkedNode
let mut linked_node = LinkedNode::new(size);
linked_node.next = self.head.next.take();
let linked_node_ptr = start as *mut LinkedNode; // Treat the start memory region as a LinkedNode type
unsafe {
linked_node_ptr.write(linked_node); // write the data, very risky
self.head.next = Some(&mut *linked_node_ptr);
assert_eq!(align_up(start, 16), start);
assert!(size >= core::mem::size_of::<LinkedNode>());
let mut node = LinkedNode::new(size);
node.next = self.head.next.take();
let node_ptr = start as *mut LinkedNode;
node_ptr.write(node);
self.head.next = Some(&mut *node_ptr);
}
}
pub fn find_region(
&mut self,
size: usize,
align: usize,
) -> Option<(&'static mut LinkedNode, usize)> {
pub fn find_region(&mut self, size: usize) -> Option<Allocation> {
let mut current = &mut self.head;
while let Some(ref mut region) = current.next {
if let Ok(alloc_start) = Self::alloc_from_region(&region, size, align) {
let next = region.next.take();
let ret = Some((current.next.take().unwrap(), alloc_start));
current.next = next;
return ret;
} else {
while let Some(ref region) = current.next {
let mut alloc = match Self::alloc_from_region(region, size) {
Ok(a) => a,
Err(()) => {
current = current.next.as_mut().unwrap();
continue;
}
};
let taken = current.next.take().unwrap();
let region_end = taken.end_addr();
let old_next = unsafe {
let node_ptr = taken as *mut LinkedNode;
let next_ptr = core::ptr::addr_of_mut!((*node_ptr).next);
core::ptr::read(next_ptr)
};
let excess_size = region_end - alloc.end;
if excess_size >= core::mem::size_of::<LinkedNode>() {
unsafe {
let remainder_ptr = alloc.end as *mut LinkedNode;
remainder_ptr.write(LinkedNode {
size: excess_size,
next: old_next,
});
current.next = Some(&mut *remainder_ptr);
}
} else {
alloc.end = region_end;
current.next = old_next;
}
return Some(alloc);
}
None
}
fn alloc_from_region(region: &LinkedNode, size: usize, align: usize) -> Result<usize, ()> {
let alloc_start = align_up(region.start_addr() + core::mem::size_of::<usize>(), align);
let alloc_end = (alloc_start - core::mem::size_of::<usize>())
.checked_add(size)
.ok_or(())?; // check for overflows
if alloc_end > region.end_addr() {
fn alloc_from_region(region: &LinkedNode, size: usize) -> Result<Allocation, ()> {
let start = region.start_addr();
let end_unaligned = start.checked_add(size).ok_or(())?;
let end = align_up(end_unaligned, 16);
if end > region.end_addr() {
return Err(());
}
let excess_size = region.end_addr() - alloc_end;
if excess_size > 0 && excess_size < core::mem::size_of::<LinkedNode>() {
// if the remaining space is not enough for another LinkedNode, skip this region.
return Err(());
}
Ok(alloc_start)
Ok(Allocation { start, end })
}
}

View File

@@ -1,33 +1,57 @@
#![no_std]
#![feature(c_variadic)]
use core::ptr::{null, null_mut};
use core::{
ffi::VaList,
fmt::{Error, Result, Write},
ptr::{addr_of_mut, null, null_mut},
usize,
};
use crate::{
mem::{malloc, memcpy, memset},
syscall::{EXIT, WRITE, syscall3},
mem::{malloc, memcpy},
syscall::{DRAW_BUFFER, DRAW_PIXEL, EXIT, FRAMEBUFFER_SWAP, WRITE, syscall0, syscall3},
};
pub mod file;
pub mod heap;
pub mod mem;
pub mod syscall;
pub mod time;
pub mod util;
static mut ERRNO: core::ffi::c_int = 0;
static TOUPPER_TABLE: [i32; 384] = {
let mut table = [0i32; 384];
let mut i = 0usize;
while i < 384 {
let c = i.wrapping_sub(128) as u8;
table[i] = if c.is_ascii_lowercase() {
(c - 0x20) as i32
} else {
c as i32
};
i += 1;
}
table
};
#[unsafe(no_mangle)]
extern "C" fn write(fd: i64, buf: *const u8, count: usize) -> isize {
unsafe { syscall3(WRITE, fd as usize, buf as usize, count) }
extern "C" fn write(fd: i32, buf: *const u8, count: usize) -> isize {
unsafe { syscall3(WRITE, fd as isize, buf as isize, count as isize) }
}
#[unsafe(no_mangle)]
extern "C" fn exit(code: i64) -> ! {
unsafe { syscall3(EXIT, code as usize, 0, 0) };
loop {}
extern "C" fn exit(code: i32) -> ! {
unsafe { syscall3(EXIT, code as isize, 0, 0) };
loop {
unsafe { core::arch::asm!("nop") };
}
}
#[unsafe(no_mangle)]
extern "C" fn strlen(s: *const u8) -> usize {
let mut len = 0;
let mut len = 0usize;
while unsafe { *s.add(len) } != 0 {
len += 1;
}
@@ -35,33 +59,292 @@ extern "C" fn strlen(s: *const u8) -> usize {
}
#[unsafe(no_mangle)]
extern "C" fn puts(s: *const u8) -> isize {
extern "C" fn puts(s: *const u8) -> i32 {
write(1, s, strlen(s));
write(1, b"\n\0".as_ptr(), 1);
0
}
#[unsafe(no_mangle)]
extern "C" fn putchar(s: i32) -> isize {
write(1, (s as u8 + b'0') as *const u8, 1);
extern "C" fn putchar(c: i32) -> i32 {
let b = c as u8;
write(1, core::ptr::addr_of!(b), 1);
0
}
#[unsafe(no_mangle)]
extern "C" fn abs(n: i64) -> i64 {
extern "C" fn abs(n: i32) -> i32 {
n.abs()
}
#[unsafe(no_mangle)]
unsafe extern "C" fn printf(format: *const u8, args: ...) {
unsafe { syscall3(WRITE, 1, format as usize, strlen(format)) };
struct BufWriter {
buf: *mut u8,
max: usize,
pos: usize,
}
impl Write for BufWriter {
fn write_str(&mut self, s: &str) -> Result {
for byte in s.bytes() {
if self.pos >= self.max {
return Err(Error);
}
unsafe {
*self.buf.add(self.pos) = byte;
}
self.pos += 1;
}
Ok(())
}
}
struct StdoutWriter {
size: usize,
}
impl Write for StdoutWriter {
fn write_str(&mut self, s: &str) -> Result {
self.size += s.len();
write(1, s.as_ptr(), s.len());
Ok(())
}
}
pub unsafe fn write_c_formatted(fmt: *const u8, args: &mut VaList, writer: &mut impl Write) {
let mut fi = 0usize;
loop {
let ch = unsafe { *fmt.add(fi) };
fi += 1;
if ch == 0 {
break;
}
if ch != b'%' {
let _ = writer.write_char(ch as char);
continue;
}
let mut precision: Option<usize> = None;
let mut next_byte = unsafe { *fmt.add(fi) };
if next_byte == b'.' {
fi += 1;
let mut p_val = 0usize;
loop {
let digit = unsafe { *fmt.add(fi) };
if digit >= b'0' && digit <= b'9' {
p_val = p_val * 10 + (digit - b'0') as usize;
fi += 1;
} else {
break;
}
}
precision = Some(p_val);
next_byte = unsafe { *fmt.add(fi) };
}
let spec = next_byte;
fi += 1;
unsafe {
match spec {
b'd' | b'i' => {
let v: i32 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:01$}", v, p);
} else {
let _ = write!(writer, "{}", v);
}
}
b'u' => {
let v: u32 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:01$}", v, p);
} else {
let _ = write!(writer, "{}", v);
}
}
b'x' => {
let v: u32 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:01$x}", v, p);
} else {
let _ = write!(writer, "{:x}", v);
}
}
b'X' => {
let v: u32 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:01$X}", v, p);
} else {
let _ = write!(writer, "{:X}", v);
}
}
b'o' => {
let v: u32 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:01$o}", v, p);
} else {
let _ = write!(writer, "{:o}", v);
}
}
b'p' => {
let v: *const u8 = args.arg();
if v.is_null() {
let _ = writer.write_str("(null)");
} else {
let _ = write!(writer, "0x{:x}", v as usize);
}
}
b'c' => {
let v: i32 = args.arg();
let _ = writer.write_char((v as u8) as char);
}
b's' => {
let ptr: *const u8 = args.arg();
if ptr.is_null() {
let _ = writer.write_str("(null)");
} else {
let mut si = 0usize;
loop {
let c = *ptr.add(si);
if c == 0 {
break;
}
if let Some(p) = precision {
if si >= p {
break;
}
}
let _ = writer.write_char(c as char);
si += 1;
}
}
}
b'f' | b'F' | b'g' | b'G' => {
let v: f64 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:.*}", p, v);
} else {
let _ = write!(writer, "{}", v);
}
}
b'l' => {
let next_spec = *fmt.add(fi);
fi += 1;
match next_spec {
b'd' | b'i' => {
let v: i64 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:01$}", v, p);
} else {
let _ = write!(writer, "{}", v);
}
}
b'u' => {
let v: u64 = args.arg();
if let Some(p) = precision {
let _ = write!(writer, "{:01$}", v, p);
} else {
let _ = write!(writer, "{}", v);
}
}
_ => {
let _ = writer.write_char('%');
let _ = writer.write_char('l');
let _ = writer.write_char(next_spec as char);
}
}
}
b'%' => {
let _ = writer.write_char('%');
}
_ => {
let _ = writer.write_char('%');
let _ = writer.write_char(spec as char);
}
}
}
}
}
#[unsafe(no_mangle)]
extern "C" fn atoi(mut c: *const u8) -> i64 {
let mut value: i64 = 0;
let mut sign: i64 = 1;
pub unsafe extern "C" fn printf(fmt: *const u8, mut args: ...) -> i32 {
let mut writer = StdoutWriter { size: 0 };
unsafe { write_c_formatted(fmt, &mut args, &mut writer) };
writer.size as i32
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn vsnprintf(
buf: *mut u8,
size: usize,
fmt: *const u8,
mut args: VaList,
) -> i32 {
if buf.is_null() || size == 0 || fmt.is_null() {
return -1;
}
let max = size - 1;
let mut writer = BufWriter { buf, max, pos: 0 };
unsafe { write_c_formatted(fmt, &mut args, &mut writer) };
unsafe {
*buf.add(writer.pos) = 0;
}
writer.pos as i32
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn snprintf(buf: *mut u8, size: usize, fmt: *const u8, mut args: ...) -> i32 {
if buf.is_null() || size == 0 || fmt.is_null() {
return -1;
}
let max = size - 1;
let mut writer = BufWriter { buf, max, pos: 0 };
unsafe { write_c_formatted(fmt, &mut args, &mut writer) };
unsafe {
*buf.add(writer.pos) = 0;
}
writer.pos as i32
}
unsafe extern "C" {
fn main(argc: i32, argv: *const *const u8) -> i32;
}
#[unsafe(no_mangle)]
pub extern "C" fn __stack_chk_fail() -> ! {
exit(127)
}
#[unsafe(no_mangle)]
pub extern "C" fn __stack_chk_fail_local() -> ! {
__stack_chk_fail()
}
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
let code = unsafe { main(0, null()) };
exit(code as i32);
}
#[unsafe(no_mangle)]
extern "C" fn atoi(mut c: *const u8) -> i32 {
let mut value: i32 = 0;
let mut sign: i32 = 1;
unsafe {
while (*c).is_ascii_whitespace() {
c = c.add(1);
@@ -75,7 +358,7 @@ extern "C" fn atoi(mut c: *const u8) -> i64 {
}
while (*c).is_ascii_digit() {
value *= 10;
value += ((*c) - b'0') as i64;
value += ((*c) - b'0') as i32;
c = c.add(1);
}
}
@@ -162,69 +445,88 @@ extern "C" fn atof(mut c: *const u8) -> f64 {
}
}
pub fn compare_str(str_1: *const u8, str_2: *const u8, case: bool, n: usize) -> i32 {
pub fn compare_str(str_1: *const u8, str_2: *const u8, ignore_case: bool, n: usize) -> i32 {
let mut len = 0;
while len < n {
let mut c_1 = unsafe { *str_1.add(len) };
let mut c_2 = unsafe { *str_2.add(len) };
if case {
if ignore_case {
c_1 = c_1.to_ascii_lowercase();
c_2 = c_2.to_ascii_lowercase();
}
if c_1 != c_2 {
return (c_1 - c_2) as i32;
return (c_1 as i32) - (c_2 as i32);
}
if c_1 == 0 {
return 0;
}
len += 1;
}
0
}
#[unsafe(no_mangle)]
unsafe extern "C" fn strcasecmp(str_1: *const u8, str_2: *const u8) -> i32 {
compare_str(str_1, str_2, true, 999999999999999)
compare_str(str_1, str_2, true, usize::MAX)
}
#[unsafe(no_mangle)]
unsafe extern "C" fn strcmp(str_1: *const u8, str_2: *const u8) -> i32 {
compare_str(str_1, str_2, false, 999999999999999)
compare_str(str_1, str_2, false, usize::MAX)
}
#[unsafe(no_mangle)]
unsafe extern "C" fn strncasecmp(str_1: *const u8, str_2: *const u8, n: i32) -> i32 {
compare_str(str_1, str_2, true, n as usize)
unsafe extern "C" fn strncasecmp(str_1: *const u8, str_2: *const u8, n: usize) -> i32 {
compare_str(str_1, str_2, true, n)
}
#[unsafe(no_mangle)]
unsafe extern "C" fn strncmp(str_1: *const u8, str_2: *const u8, n: i32) -> i32 {
compare_str(str_1, str_2, false, n as usize)
unsafe extern "C" fn strncmp(str_1: *const u8, str_2: *const u8, n: usize) -> i32 {
compare_str(str_1, str_2, false, n)
}
#[unsafe(no_mangle)]
unsafe extern "C" fn strncpy(dest: *mut u8, source: *const u8, n: usize) -> *mut u8 {
let mut i = 0usize;
unsafe extern "C" fn draw_pixel(x: u32, y: u32, color: u32) -> i32 {
unsafe {
return syscall3(DRAW_PIXEL, x as isize, y as isize, color as isize) as i32;
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn draw_buffer(buffer: *const u32, width: u32, height: u32) -> i32 {
unsafe {
return syscall3(
DRAW_BUFFER,
buffer as isize,
width as isize,
height as isize,
) as i32;
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn framebuffer_swap() -> i32 {
unsafe {
return syscall0(FRAMEBUFFER_SWAP) as i32;
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strncpy(dest: *mut u8, source: *const u8, n: usize) -> *mut u8 {
let mut i = 0usize;
while i < n {
let b = *source.add(i);
*dest.add(i) = b;
i += 1;
let b = unsafe { *source.add(i) };
unsafe { *dest.add(i) = b };
if b == 0 {
while i < n {
*dest.add(i) = 0;
i += 1;
let mut j = i + 1;
while j < n {
unsafe { *dest.add(j) = 0 };
j += 1;
}
break;
}
}
i += 1;
}
dest
@@ -277,7 +579,7 @@ unsafe extern "C" fn strstr(haystack: *const u8, needle: *const u8) -> *const u8
}
#[unsafe(no_mangle)]
unsafe extern "C" fn strchr(s: *const u8, ch: u8) -> *const u8 {
unsafe extern "C" fn strchr(s: *const u8, ch: i32) -> *const u8 {
if s.is_null() {
return null();
}
@@ -286,7 +588,7 @@ unsafe extern "C" fn strchr(s: *const u8, ch: u8) -> *const u8 {
unsafe {
while *s.add(i) != 0 {
if *s.add(i) == ch {
if *s.add(i) == ch as u8 {
return s.add(i);
}
@@ -321,21 +623,40 @@ unsafe extern "C" fn strrchr(s: *const u8, ch: u8) -> *const u8 {
}
#[unsafe(no_mangle)]
unsafe extern "C" fn toupper(char: u8) -> u8 {
char.to_ascii_uppercase()
unsafe extern "C" fn toupper(char: i32) -> i32 {
(char as u8).to_ascii_uppercase() as i32
}
#[unsafe(no_mangle)]
unsafe extern "C" fn tolower(char: u8) -> u8 {
char.to_ascii_lowercase()
unsafe extern "C" fn tolower(char: i32) -> i32 {
(char as u8).to_ascii_lowercase() as i32
}
#[unsafe(no_mangle)]
extern "C" fn system(cmd: *const u8) -> i32 {
0
}
#[unsafe(no_mangle)]
extern "C" fn __ctype_toupper_loc() -> *const u8 {
TOUPPER_TABLE.as_ptr() as *const u8
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn __isoc23_sscanf() -> ! {
panic!("sscanf not implemented");
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sscanf(str: *mut u8, fmt: *const u8, args: ...) -> i32 {
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn __errno_location() -> *mut core::ffi::c_int {
addr_of_mut!(ERRNO)
}
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
fn panic(error: &core::panic::PanicInfo) -> ! {
exit(-1)
}

View File

@@ -1,17 +1,23 @@
use core::ptr::null_mut;
use core::{mem, ptr::null_mut, usize};
use crate::{
heap::ALLOCATOR,
heap::{ALLOCATOR, LinkedNode},
syscall::{BRK, syscall1},
util::align_up,
};
#[unsafe(no_mangle)]
pub extern "C" fn sbrk(increment: i64) -> i64 {
unsafe { syscall1(BRK, increment as usize) as i64 }
pub fn sbrk(increment: i64) -> isize {
unsafe { syscall1(BRK, increment as isize) as isize }
}
const MAX_SIZE: u64 = 18446744073709551615;
#[repr(C, align(16))]
struct Header {
size: usize,
_pad: usize,
}
#[unsafe(no_mangle)]
pub extern "C" fn calloc(count: u64, size: u64) -> *mut u8 {
if count != 0 && size > MAX_SIZE / count {
@@ -19,19 +25,16 @@ pub extern "C" fn calloc(count: u64, size: u64) -> *mut u8 {
}
let mut total = count * size;
if total == 0 {
total = 1;
}
let ptr = malloc(total);
if ptr.is_null() {
return null_mut();
}
memset(ptr, 0, total as usize);
ptr
}
@@ -40,78 +43,126 @@ pub extern "C" fn free(ptr: *mut u8) {
if ptr.is_null() {
return;
}
unsafe {
let size = *(((ptr as usize) - core::mem::size_of::<usize>()) as *const usize);
unsafe {
let header_ptr = (ptr as usize - mem::size_of::<Header>()) as *mut Header;
let total = (*header_ptr).size;
let mut allocator = ALLOCATOR.lock();
allocator
.add_free_memory_region(ptr as usize - core::mem::size_of::<usize>(), size as usize);
allocator.add_free_memory_region(header_ptr as usize, total);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn malloc(size: u64) -> *mut u8 {
let req = size as usize;
let req = if req == 0 { 1 } else { req };
let hdr = mem::size_of::<Header>();
let needed_unaligned = match hdr.checked_add(req) {
Some(v) => v,
None => return null_mut(),
};
let align_req = 16;
let needed = align_up(needed_unaligned, align_req);
let mut allocator = ALLOCATOR.lock();
if let Some(region) = allocator.find_region(size as usize, 16) {
return region.1 as *mut u8;
} else {
let start_addr: i64 = sbrk(size as i64);
if start_addr == -1 {
if let Some(region) = allocator.find_region(needed) {
unsafe {
let header_ptr = region.start as *mut Header;
header_ptr.write(Header {
size: region.end - region.start,
_pad: 0,
});
return (region.start + hdr) as *mut u8;
}
}
let min_region = mem::size_of::<LinkedNode>();
let req_region = core::cmp::max(needed, min_region);
let align = align_req;
let over = match req_region.checked_add(align) {
Some(v) => v,
None => return null_mut(),
};
if over > i64::MAX as usize {
return null_mut();
}
unsafe { allocator.add_free_memory_region(start_addr as usize, size as usize) };
let raw_start = sbrk(over as i64);
if raw_start == -1 {
return null_mut();
}
let raw_start = raw_start as usize;
let aligned_start = align_up(raw_start, align);
let usable = over - (aligned_start - raw_start);
if usable < min_region {
return null_mut();
}
unsafe {
allocator.add_free_memory_region(aligned_start, usable);
}
drop(allocator);
malloc(size)
}
}
#[unsafe(no_mangle)]
pub extern "C" fn memcpy(dest_str: *mut u8, src_str: *const u8, n: usize) -> *mut u8 {
unsafe { core::ptr::copy(src_str, dest_str, n) };
dest_str
}
#[unsafe(no_mangle)]
pub extern "C" fn memset(str: *mut u8, c: i64, n: usize) -> *mut u8 {
unsafe {
core::ptr::write_bytes(str, c as u8, n);
pub extern "C" fn memset(dst: *mut u8, c: i64, n: usize) -> *mut u8 {
if dst.is_null() || n == 0 {
return dst;
}
str
unsafe {
let val = c as u8;
let mut i = 0usize;
while i < n {
*dst.add(i) = val;
i += 1;
}
}
dst
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
unsafe {
if size == 0 {
free(ptr);
return null_mut();
}
let header = ((ptr as usize) - core::mem::size_of::<usize>()) as *mut usize;
let old_size = *header;
if ptr.is_null() {
return malloc(size as u64);
}
if old_size == size {
unsafe {
let hdr = mem::size_of::<Header>();
let header_ptr = (ptr as usize - hdr) as *mut Header;
let total = (*header_ptr).size;
let old_payload = total.saturating_sub(hdr);
if size <= old_payload {
return ptr;
} else if size < old_size {
let mut allocator = ALLOCATOR.lock();
let difference = old_size.abs_diff(size);
let start = (ptr as usize) + size;
*header = size;
allocator.add_free_memory_region(start as usize, difference as usize);
return ptr;
} else {
}
let new_ptr = malloc(size as u64);
if new_ptr.is_null() {
return null_mut();
}
core::ptr::copy_nonoverlapping(ptr, new_ptr, old_size);
core::ptr::copy_nonoverlapping(ptr, new_ptr, old_payload);
free(ptr);
return new_ptr;
}
new_ptr
}
}

View File

@@ -19,6 +19,10 @@ pub const UNLINK: usize = 87;
pub const GETDENTS64: usize = 217;
pub const CLOCK_GETTIME: usize = 228;
pub const EXIT_GROUP: usize = 231;
pub const SLEEP: usize = 909090; // zzz haha
pub const DRAW_PIXEL: usize = 5555;
pub const DRAW_BUFFER: usize = 7777;
pub const FRAMEBUFFER_SWAP: usize = 6666;
#[inline(always)]
pub unsafe fn syscall0(num: usize) -> isize {
@@ -28,6 +32,8 @@ pub unsafe fn syscall0(num: usize) -> isize {
"int 0x80",
in("rax") num,
lateout("rax") ret,
out("rdi") _, out("rcx") _, out("rdx") _, out("rsi") _,
out("r8") _, out("r9") _, out("r10") _, out("r11") _,
options(nostack)
);
}
@@ -36,7 +42,7 @@ pub unsafe fn syscall0(num: usize) -> isize {
}
#[inline(always)]
pub unsafe fn syscall1(num: usize, arg0: usize) -> isize {
pub unsafe fn syscall1(num: usize, arg0: isize) -> isize {
let ret: isize;
unsafe {
core::arch::asm!(
@@ -44,6 +50,8 @@ pub unsafe fn syscall1(num: usize, arg0: usize) -> isize {
in("rax") num,
in("rdi") arg0,
lateout("rax") ret,
out("rcx") _, out("rdx") _, out("rsi") _,
out("r8") _, out("r9") _, out("r10") _, out("r11") _,
options(nostack)
);
}
@@ -52,7 +60,7 @@ pub unsafe fn syscall1(num: usize, arg0: usize) -> isize {
}
#[inline(always)]
pub unsafe fn syscall3(num: usize, arg0: usize, arg1: usize, arg2: usize) -> isize {
pub unsafe fn syscall3(num: usize, arg0: isize, arg1: isize, arg2: isize) -> isize {
let ret: isize;
unsafe {
core::arch::asm!(

38
user/libxunil/src/time.rs Normal file
View File

@@ -0,0 +1,38 @@
use crate::syscall::{CLOCK_GETTIME, SLEEP, syscall0, syscall1};
#[repr(C)]
pub struct Timeval {
pub tv_sec: i64,
pub tv_usec: i64,
}
#[repr(C)]
pub struct Timezone {
pub tz_minuteswest: i32,
pub tz_dsttime: i32,
}
pub const TICKS_PER_SECOND: u64 = 1000;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sleep_ms(ms: i32) -> i32 {
unsafe { syscall1(SLEEP, ms as isize) };
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gettimeofday(tv: *mut Timeval, _tz: *mut Timezone) -> i32 {
unsafe {
if !tv.is_null() {
let ticks = syscall0(CLOCK_GETTIME) as u64;
let seconds = ticks / TICKS_PER_SECOND;
let microseconds = (ticks % TICKS_PER_SECOND) * (1_000_000 / TICKS_PER_SECOND);
(*tv).tv_sec = seconds as i64;
(*tv).tv_usec = microseconds as i64;
}
}
0
}