mirror of
https://github.com/XunilGroup/libxunil.git
synced 2026-04-25 11:39:02 +02:00
Upload current libxunil, to be used as a submodule
This commit is contained in:
4
.cargo/config.toml
Normal file
4
.cargo/config.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[unstable]
|
||||||
|
json-target-spec = true
|
||||||
|
build-std-features = ["compiler-builtins-mem"]
|
||||||
|
build-std = ["core", "compiler_builtins", "alloc"]
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
34
Cargo.lock
generated
Normal file
34
Cargo.lock
generated
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libxunil"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
18
Cargo.toml
Normal file
18
Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "libxunil"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "xunil"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
opt-level = "s"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
spin = "0.10.0"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
1
include/inttypes.h
Normal file
1
include/inttypes.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include <stdint.h>
|
||||||
44
include/stdio.h
Normal file
44
include/stdio.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
typedef struct FILE FILE;
|
||||||
|
|
||||||
|
extern FILE *stdin;
|
||||||
|
extern FILE *stdout;
|
||||||
|
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);
|
||||||
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);
|
||||||
|
int fseek(FILE *fp, long offset, int whence);
|
||||||
|
long ftell(FILE *fp);
|
||||||
|
int fflush(FILE *fp);
|
||||||
|
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);
|
||||||
|
ssize_t write(int fd, const void *buf, size_t count);
|
||||||
|
void exit(int code);
|
||||||
|
|
||||||
|
int sscanf(const char *str, const char *format, ...);
|
||||||
24
include/stdlib.h
Normal file
24
include/stdlib.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *malloc(size_t size);
|
||||||
|
void *calloc(size_t nmemb, size_t size);
|
||||||
|
void *realloc(void *ptr, size_t size);
|
||||||
|
void free(void *ptr);
|
||||||
|
|
||||||
|
void exit(int status);
|
||||||
|
void abort(void);
|
||||||
|
|
||||||
|
int atoi(const char *s);
|
||||||
|
long atol(const char *s);
|
||||||
|
double atof(const char *s);
|
||||||
|
long strtol(const char *s, char **endptr, int base);
|
||||||
|
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();
|
||||||
22
include/string.h
Normal file
22
include/string.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *memset(void *s, int c, size_t n);
|
||||||
|
void *memcpy(void *dst, const void *src, size_t n);
|
||||||
|
void *memmove(void *dst, const void *src, size_t n);
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
|
void *memchr(const void *s, int c, size_t n);
|
||||||
|
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
char *strcpy(char *dst, const char *src);
|
||||||
|
char *strncpy(char *dst, const char *src, size_t n);
|
||||||
|
char *strcat(char *dst, const char *src);
|
||||||
|
char *strncat(char *dst, const char *src, size_t n);
|
||||||
|
int strcmp(const char *s1, const char *s2);
|
||||||
|
int strncmp(const char *s1, const char *s2, size_t n);
|
||||||
|
char *strchr(const char *s, int c);
|
||||||
|
char *strrchr(const char *s, int c);
|
||||||
|
char *strstr(const char *haystack, const char *needle);
|
||||||
|
char *strtok(char *str, const char *delim);
|
||||||
|
char *strdup(const char *s);
|
||||||
|
char *strerror(int errnum);
|
||||||
8
include/strings.h
Normal file
8
include/strings.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
int strcasecmp(const char *s1, const char *s2);
|
||||||
|
int strncasecmp(const char *s1, const char *s2, size_t n);
|
||||||
|
void bzero(void *s, size_t n);
|
||||||
|
void bcopy(const void *src, void *dest, size_t n);
|
||||||
|
int bcmp(const void *s1, const void *s2, size_t n);
|
||||||
8
rust-toolchain.toml
Normal file
8
rust-toolchain.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
|
targets = [
|
||||||
|
"x86_64-unknown-none",
|
||||||
|
# "aarch64-unknown-none",
|
||||||
|
# "riscv64gc-unknown-none-elf",
|
||||||
|
# "loongarch64-unknown-none",
|
||||||
|
]
|
||||||
255
src/file.rs
Normal file
255
src/file.rs
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
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)]
|
||||||
|
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 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)]
|
||||||
|
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: 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: 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 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 fflush(file_ptr: *mut FILE) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn mkdir(path: *const u8, mode: *const u8) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn remove(path: *const i8) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn rename(path: *const u8, new_path: *const u8) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
unsafe extern "C" fn vfprintf(stream: *const u8, format: *const u8, args: ...) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
109
src/heap.rs
Normal file
109
src/heap.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use spin::mutex::Mutex;
|
||||||
|
|
||||||
|
use crate::util::align_up;
|
||||||
|
|
||||||
|
pub struct LinkedNode {
|
||||||
|
pub size: usize,
|
||||||
|
pub next: Option<&'static mut LinkedNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinkedNode {
|
||||||
|
pub const fn new(size: usize) -> LinkedNode {
|
||||||
|
LinkedNode { size, next: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_addr(&self) -> usize {
|
||||||
|
self as *const Self as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_addr(&self) -> usize {
|
||||||
|
self.start_addr() + self.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
head: LinkedNode::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn add_free_memory_region(&mut self, start: usize, size: usize) {
|
||||||
|
unsafe {
|
||||||
|
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) -> Option<Allocation> {
|
||||||
|
let mut current = &mut self.head;
|
||||||
|
|
||||||
|
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) -> 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(());
|
||||||
|
}
|
||||||
|
Ok(Allocation { start, end })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static ALLOCATOR: Mutex<LinkedListAllocator> = Mutex::new(LinkedListAllocator::new());
|
||||||
662
src/lib.rs
Normal file
662
src/lib.rs
Normal file
@@ -0,0 +1,662 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![feature(c_variadic)]
|
||||||
|
use core::{
|
||||||
|
ffi::VaList,
|
||||||
|
fmt::{Error, Result, Write},
|
||||||
|
ptr::{addr_of_mut, null, null_mut},
|
||||||
|
usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
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: 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: 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 = 0usize;
|
||||||
|
while unsafe { *s.add(len) } != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
len
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
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(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: i32) -> i32 {
|
||||||
|
n.abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
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)]
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*c) == b'+' || (*c) == b'-' {
|
||||||
|
if *c == b'-' {
|
||||||
|
sign = -1;
|
||||||
|
}
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
while (*c).is_ascii_digit() {
|
||||||
|
value *= 10;
|
||||||
|
value += ((*c) - b'0') as i32;
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value * sign
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn pow10_i32(exp: i32) -> f64 {
|
||||||
|
let mut e = exp;
|
||||||
|
let mut scale: f64 = 1.0;
|
||||||
|
|
||||||
|
if e > 0 {
|
||||||
|
while e > 0 {
|
||||||
|
scale *= 10.0;
|
||||||
|
e -= 1;
|
||||||
|
}
|
||||||
|
} else if e < 0 {
|
||||||
|
while e < 0 {
|
||||||
|
scale *= 0.1;
|
||||||
|
e += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scale
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn atof(mut c: *const u8) -> f64 {
|
||||||
|
let mut sign: f64 = 1.0;
|
||||||
|
unsafe {
|
||||||
|
while (*c).is_ascii_whitespace() {
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*c) == b'+' || (*c) == b'-' {
|
||||||
|
if *c == b'-' {
|
||||||
|
sign = -1.0;
|
||||||
|
}
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut int_part: i64 = 0;
|
||||||
|
while (*c).is_ascii_digit() {
|
||||||
|
int_part = int_part * 10 + ((*c) - b'0') as i64;
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result: f64 = int_part as f64;
|
||||||
|
|
||||||
|
if *c == b'.' {
|
||||||
|
c = c.add(1);
|
||||||
|
let mut factor = 0.1;
|
||||||
|
while (*c).is_ascii_digit() {
|
||||||
|
result += ((*c) - b'0') as f64 * factor;
|
||||||
|
factor *= 0.1;
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if *c == b'e' || *c == b'E' {
|
||||||
|
c = c.add(1);
|
||||||
|
|
||||||
|
let mut exp_sign = 1;
|
||||||
|
let mut exp_value = 0;
|
||||||
|
|
||||||
|
if (*c) == b'+' || (*c) == b'-' {
|
||||||
|
if *c == b'-' {
|
||||||
|
exp_sign = -1;
|
||||||
|
}
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*c).is_ascii_digit() {
|
||||||
|
exp_value *= 10;
|
||||||
|
exp_value += ((*c) - b'0') as i64;
|
||||||
|
c = c.add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result *= pow10_i32((exp_sign * exp_value) as i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
sign * result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ignore_case {
|
||||||
|
c_1 = c_1.to_ascii_lowercase();
|
||||||
|
c_2 = c_2.to_ascii_lowercase();
|
||||||
|
}
|
||||||
|
if c_1 != c_2 {
|
||||||
|
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, 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, usize::MAX)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
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: usize) -> i32 {
|
||||||
|
compare_str(str_1, str_2, false, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
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 = unsafe { *source.add(i) };
|
||||||
|
unsafe { *dest.add(i) = b };
|
||||||
|
|
||||||
|
if b == 0 {
|
||||||
|
let mut j = i + 1;
|
||||||
|
while j < n {
|
||||||
|
unsafe { *dest.add(j) = 0 };
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
unsafe extern "C" fn strdup(s: *const u8) -> *mut u8 {
|
||||||
|
let len = strlen(s);
|
||||||
|
let memory = malloc((len + 1) as u64);
|
||||||
|
if memory.is_null() {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
unsafe { memcpy(memory, s, len + 1) };
|
||||||
|
memory
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
unsafe extern "C" fn strstr(haystack: *const u8, needle: *const u8) -> *const u8 {
|
||||||
|
if haystack.is_null() || needle.is_null() {
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut h = haystack;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if *needle == 0 {
|
||||||
|
return haystack;
|
||||||
|
}
|
||||||
|
|
||||||
|
while *h != 0 {
|
||||||
|
if *h == *needle {
|
||||||
|
let mut h2 = h;
|
||||||
|
let mut n2 = needle;
|
||||||
|
|
||||||
|
while *n2 != 0 && *h2 != 0 && *h2 == *n2 {
|
||||||
|
h2 = h2.add(1);
|
||||||
|
n2 = n2.add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if *n2 == 0 {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h = h.add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
null()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
unsafe extern "C" fn strchr(s: *const u8, ch: i32) -> *const u8 {
|
||||||
|
if s.is_null() {
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = 0usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
while *s.add(i) != 0 {
|
||||||
|
if *s.add(i) == ch as u8 {
|
||||||
|
return s.add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
null()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
unsafe extern "C" fn strrchr(s: *const u8, ch: u8) -> *const u8 {
|
||||||
|
let mut n = 0;
|
||||||
|
let mut last: *const u8 = null();
|
||||||
|
|
||||||
|
if ch == 0 {
|
||||||
|
while unsafe { *s.add(n) } != 0 {
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
return unsafe { s.add(n + 1) };
|
||||||
|
} else {
|
||||||
|
while unsafe { *s.add(n) } != 0 {
|
||||||
|
let cur_ch = unsafe { s.add(n) };
|
||||||
|
if unsafe { *cur_ch == ch } {
|
||||||
|
last = cur_ch;
|
||||||
|
}
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
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: 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(error: &core::panic::PanicInfo) -> ! {
|
||||||
|
exit(-1)
|
||||||
|
}
|
||||||
258
src/mem.rs
Normal file
258
src/mem.rs
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
use core::{ffi::c_int, mem, ptr::null_mut, usize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
heap::{ALLOCATOR, LinkedNode},
|
||||||
|
syscall::{BRK, syscall1},
|
||||||
|
util::align_up,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sbrk(increment: i64) -> isize {
|
||||||
|
unsafe { syscall1(BRK, increment as isize) as isize }
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_SIZE: u64 = 18446744073709551615;
|
||||||
|
|
||||||
|
const HEADER_MAGIC_ALLOC: u64 = 0xBADC0FFEE0DDF00D;
|
||||||
|
const HEADER_MAGIC_FREE: u64 = 0xFEE1DEADCAFEBABE;
|
||||||
|
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
struct Header {
|
||||||
|
magic: u64,
|
||||||
|
_pad: u64,
|
||||||
|
alloc_size: usize,
|
||||||
|
region_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn calloc(count: u64, size: u64) -> *mut u8 {
|
||||||
|
if count != 0 && size > MAX_SIZE / count {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut total = count * size;
|
||||||
|
if total == 0 {
|
||||||
|
total = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr = malloc(total);
|
||||||
|
if ptr.is_null() {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { memset(ptr, 0, total as usize) };
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn free(ptr: *mut u8) {
|
||||||
|
if ptr.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let header_ptr = (ptr as usize - mem::size_of::<Header>()) as *mut Header;
|
||||||
|
if (header_ptr as usize) & 0xF != 0 {
|
||||||
|
core::hint::unreachable_unchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*header_ptr).magic != HEADER_MAGIC_ALLOC {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let region_size = (*header_ptr).region_size;
|
||||||
|
(*header_ptr).magic = HEADER_MAGIC_FREE;
|
||||||
|
let mut allocator = ALLOCATOR.lock();
|
||||||
|
allocator.add_free_memory_region(header_ptr as usize, region_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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(needed) {
|
||||||
|
unsafe {
|
||||||
|
let header_ptr = region.start as *mut Header;
|
||||||
|
header_ptr.write(Header {
|
||||||
|
magic: HEADER_MAGIC_ALLOC,
|
||||||
|
_pad: 0,
|
||||||
|
alloc_size: (region.end - region.start).saturating_sub(hdr),
|
||||||
|
region_size: region.end - region.start,
|
||||||
|
});
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
|
||||||
|
if size == 0 {
|
||||||
|
free(ptr);
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
return malloc(size as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let hdr = mem::size_of::<Header>();
|
||||||
|
let header_ptr = (ptr as usize - hdr) as *mut Header;
|
||||||
|
|
||||||
|
if (*header_ptr).magic != HEADER_MAGIC_ALLOC {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let old_alloc_size = (*header_ptr).alloc_size;
|
||||||
|
|
||||||
|
if size <= old_alloc_size {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_ptr = malloc(size as u64);
|
||||||
|
if new_ptr.is_null() {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
core::ptr::copy_nonoverlapping(ptr, new_ptr, old_alloc_size);
|
||||||
|
free(ptr);
|
||||||
|
new_ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, n: usize) -> *mut u8 {
|
||||||
|
if n == 0 {
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
if dest.is_null() {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let byte = c as u8;
|
||||||
|
let mut i = 0usize;
|
||||||
|
while i < n {
|
||||||
|
unsafe { core::ptr::write_volatile(dest.add(i), byte) };
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
|
||||||
|
if n == 0 {
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
if dest.is_null() || src.is_null() {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = 0usize;
|
||||||
|
while i < n {
|
||||||
|
let v = unsafe { core::ptr::read_volatile(src.add(i)) };
|
||||||
|
unsafe { core::ptr::write_volatile(dest.add(i), v) };
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
|
||||||
|
if n == 0 {
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
if dest.is_null() || src.is_null() {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let dest_addr = dest as usize;
|
||||||
|
let src_addr = src as usize;
|
||||||
|
|
||||||
|
if dest_addr == src_addr {
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if dest_addr < src_addr || dest_addr >= src_addr.saturating_add(n) {
|
||||||
|
let mut i = 0usize;
|
||||||
|
while i < n {
|
||||||
|
let v = unsafe { core::ptr::read_volatile(src.add(i)) };
|
||||||
|
unsafe { core::ptr::write_volatile(dest.add(i), v) };
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut i = n;
|
||||||
|
while i != 0 {
|
||||||
|
i -= 1;
|
||||||
|
let v = unsafe { core::ptr::read_volatile(src.add(i)) };
|
||||||
|
unsafe { core::ptr::write_volatile(dest.add(i), v) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn memcmp(a: *const u8, b: *const u8, n: usize) -> i32 {
|
||||||
|
if n == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if a.is_null() || b.is_null() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = 0usize;
|
||||||
|
while i < n {
|
||||||
|
let av = unsafe { core::ptr::read_volatile(a.add(i)) };
|
||||||
|
let bv = unsafe { core::ptr::read_volatile(b.add(i)) };
|
||||||
|
if av != bv {
|
||||||
|
return av as i32 - bv as i32;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
77
src/syscall.rs
Normal file
77
src/syscall.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
pub const READ: usize = 0;
|
||||||
|
pub const WRITE: usize = 1;
|
||||||
|
pub const OPEN: usize = 2;
|
||||||
|
pub const CLOSE: usize = 3;
|
||||||
|
pub const STAT: usize = 4;
|
||||||
|
pub const LSEEK: usize = 8;
|
||||||
|
pub const MMAP: usize = 9;
|
||||||
|
pub const MUNMAP: usize = 9;
|
||||||
|
pub const BRK: usize = 12;
|
||||||
|
pub const GETPID: usize = 39;
|
||||||
|
pub const FORK: usize = 57;
|
||||||
|
pub const EXECVE: usize = 59;
|
||||||
|
pub const EXIT: usize = 60;
|
||||||
|
pub const WAIT4: usize = 61;
|
||||||
|
pub const KILL: usize = 62;
|
||||||
|
pub const CHDIR: usize = 80;
|
||||||
|
pub const MKDIR: usize = 83;
|
||||||
|
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 {
|
||||||
|
let ret: isize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"int 0x80",
|
||||||
|
in("rax") num,
|
||||||
|
lateout("rax") ret,
|
||||||
|
clobber_abi("sysv64"),
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn syscall1(num: usize, arg0: isize) -> isize {
|
||||||
|
let ret: isize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"int 0x80",
|
||||||
|
in("rax") num,
|
||||||
|
in("rdi") arg0,
|
||||||
|
lateout("rax") ret,
|
||||||
|
clobber_abi("sysv64"),
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn syscall3(num: usize, arg0: isize, arg1: isize, arg2: isize) -> isize {
|
||||||
|
let ret: isize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"int 0x80",
|
||||||
|
in("rax") num,
|
||||||
|
in("rdi") arg0,
|
||||||
|
in("rsi") arg1,
|
||||||
|
in("rdx") arg2,
|
||||||
|
lateout("rax") ret,
|
||||||
|
clobber_abi("sysv64"),
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
38
src/time.rs
Normal file
38
src/time.rs
Normal 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
|
||||||
|
}
|
||||||
20
src/util.rs
Normal file
20
src/util.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#[inline]
|
||||||
|
pub const fn align_down(addr: usize, align: usize) -> usize {
|
||||||
|
assert!(align.is_power_of_two(), "`align` must be a power of two");
|
||||||
|
addr & !(align - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn align_up(addr: usize, align: usize) -> usize {
|
||||||
|
assert!(align.is_power_of_two(), "`align` must be a power of two");
|
||||||
|
let align_mask = align - 1;
|
||||||
|
if addr & align_mask == 0 {
|
||||||
|
addr
|
||||||
|
} else {
|
||||||
|
if let Some(aligned) = (addr | align_mask).checked_add(1) {
|
||||||
|
aligned
|
||||||
|
} else {
|
||||||
|
panic!("attempt to add with overflow")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user