mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-12 23:24:41 +08:00
内存缓存和ext4完整支持
This commit is contained in:
@@ -8,6 +8,8 @@ members = ["boot"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
use std::{env, path::PathBuf, process::Command};
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
if target != "x86_64-unknown-uefi" {
|
||||
return;
|
||||
}
|
||||
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let lwext4_dir = manifest_dir.join("third_party/lwext4");
|
||||
let config_dir = manifest_dir.join("third_party/lwext4_config/include/generated");
|
||||
let shim = manifest_dir.join("src/fs/lwext4_shim.c");
|
||||
|
||||
println!("cargo:rerun-if-changed={}", shim.display());
|
||||
println!(
|
||||
"cargo:rerun-if-changed={}",
|
||||
lwext4_dir.join("src").display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rerun-if-changed={}",
|
||||
manifest_dir
|
||||
.join("third_party/lwext4_config/include/generated/ext4_config.h")
|
||||
.display()
|
||||
);
|
||||
|
||||
let sources = [
|
||||
"ext4.c",
|
||||
"ext4_balloc.c",
|
||||
"ext4_bitmap.c",
|
||||
"ext4_bcache.c",
|
||||
"ext4_block_group.c",
|
||||
"ext4_blockdev.c",
|
||||
"ext4_crc32.c",
|
||||
"ext4_debug.c",
|
||||
"ext4_dir.c",
|
||||
"ext4_dir_idx.c",
|
||||
"ext4_extent.c",
|
||||
"ext4_fs.c",
|
||||
"ext4_hash.c",
|
||||
"ext4_ialloc.c",
|
||||
"ext4_inode.c",
|
||||
"ext4_journal.c",
|
||||
"ext4_mbr.c",
|
||||
"ext4_super.c",
|
||||
"ext4_trans.c",
|
||||
"ext4_xattr.c",
|
||||
];
|
||||
|
||||
let clang = env::var("CLANG").unwrap_or_else(|_| "clang".to_string());
|
||||
let ar = env::var("AR").unwrap_or_else(|_| "llvm-ar".to_string());
|
||||
let mut objects = Vec::new();
|
||||
|
||||
for source in sources {
|
||||
let input = lwext4_dir.join("src").join(source);
|
||||
let output = out_dir.join(format!("{source}.obj"));
|
||||
compile_c(&clang, &input, &output, &lwext4_dir, &config_dir);
|
||||
objects.push(output);
|
||||
}
|
||||
|
||||
let shim_obj = out_dir.join("zeroos_lwext4_shim.obj");
|
||||
compile_c(&clang, &shim, &shim_obj, &lwext4_dir, &config_dir);
|
||||
objects.push(shim_obj);
|
||||
|
||||
let lib = out_dir.join("libzeroos_lwext4.a");
|
||||
let status = Command::new(&ar)
|
||||
.arg("crs")
|
||||
.arg(&lib)
|
||||
.args(&objects)
|
||||
.status()
|
||||
.unwrap_or_else(|error| panic!("failed to run {ar}: {error}"));
|
||||
assert!(status.success(), "{ar} failed while archiving lwext4");
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", out_dir.display());
|
||||
println!("cargo:rustc-link-lib=static=zeroos_lwext4");
|
||||
}
|
||||
|
||||
fn compile_c(
|
||||
clang: &str,
|
||||
input: &PathBuf,
|
||||
output: &PathBuf,
|
||||
lwext4_dir: &PathBuf,
|
||||
config_dir: &PathBuf,
|
||||
) {
|
||||
let status = Command::new(clang)
|
||||
.arg("-target")
|
||||
.arg("x86_64-unknown-windows")
|
||||
.arg("-ffreestanding")
|
||||
.arg("-fno-stack-protector")
|
||||
.arg("-fno-builtin")
|
||||
.arg("-mno-red-zone")
|
||||
.arg("-O2")
|
||||
.arg("-Wall")
|
||||
.arg("-Wno-unused-parameter")
|
||||
.arg("-Wno-missing-braces")
|
||||
.arg("-DCONFIG_USE_DEFAULT_CFG=0")
|
||||
.arg("-I")
|
||||
.arg(lwext4_dir.join("include"))
|
||||
.arg("-I")
|
||||
.arg(config_dir.parent().unwrap())
|
||||
.arg("-c")
|
||||
.arg(input)
|
||||
.arg("-o")
|
||||
.arg(output)
|
||||
.status()
|
||||
.unwrap_or_else(|error| panic!("failed to run {clang}: {error}"));
|
||||
assert!(
|
||||
status.success(),
|
||||
"{clang} failed while compiling {}",
|
||||
input.display()
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::drivers::storage::{
|
||||
ahci::AhciDisk,
|
||||
block::{BlockDevice, BlockError},
|
||||
|
||||
@@ -0,0 +1,706 @@
|
||||
use crate::drivers::storage::{
|
||||
ahci::AhciDisk,
|
||||
block::{BlockDevice, BlockError},
|
||||
partition::PartitionBlockDevice,
|
||||
};
|
||||
use crate::fs::uefi::LoadedFile;
|
||||
use crate::memory::{PAGE_SIZE, PhysicalMemoryManager};
|
||||
use core::ffi::c_void;
|
||||
|
||||
const EIO: isize = 5;
|
||||
const ENOENT: isize = 2;
|
||||
const ENODEV: isize = 19;
|
||||
const EFBIG: isize = 27;
|
||||
const EXT4_DE_REG_FILE: u8 = 1;
|
||||
const EXT4_DE_DIR: u8 = 2;
|
||||
const MAX_PATH: usize = 256;
|
||||
const CACHE_SLOTS: usize = 64;
|
||||
const EXEC_CACHE_SLOTS: usize = 8;
|
||||
|
||||
static mut ROOT_DEVICE: Option<PartitionBlockDevice<AhciDisk>> = None;
|
||||
static mut MOUNTED: bool = false;
|
||||
static mut MEMORY_MANAGER: *mut PhysicalMemoryManager = core::ptr::null_mut();
|
||||
static mut CACHE: [CacheEntry; CACHE_SLOTS] = [CacheEntry::empty(); CACHE_SLOTS];
|
||||
static mut CACHE_CLOCK: u64 = 0;
|
||||
static mut EXEC_CACHE: [ExecCacheEntry; EXEC_CACHE_SLOTS] =
|
||||
[ExecCacheEntry::empty(); EXEC_CACHE_SLOTS];
|
||||
|
||||
unsafe extern "C" {
|
||||
fn zeroos_lwext4_mount(block_count: u64) -> i32;
|
||||
fn zeroos_lwext4_read(
|
||||
path: *const u8,
|
||||
offset: u64,
|
||||
buf: *mut u8,
|
||||
len: usize,
|
||||
done: *mut usize,
|
||||
) -> i32;
|
||||
fn zeroos_lwext4_write(
|
||||
path: *const u8,
|
||||
offset: u64,
|
||||
buf: *const u8,
|
||||
len: usize,
|
||||
done: *mut usize,
|
||||
) -> i32;
|
||||
fn zeroos_lwext4_truncate(path: *const u8, size: u64) -> i32;
|
||||
fn zeroos_lwext4_size(path: *const u8, size: *mut u64) -> i32;
|
||||
fn zeroos_lwext4_create_file(path: *const u8) -> i32;
|
||||
fn zeroos_lwext4_mkdir(path: *const u8) -> i32;
|
||||
fn ext4_dir_open(dir: *mut Ext4Dir, path: *const u8) -> i32;
|
||||
fn ext4_dir_close(dir: *mut Ext4Dir) -> i32;
|
||||
fn ext4_dir_entry_next(dir: *mut Ext4Dir) -> *const Ext4DirEntry;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Ext4File {
|
||||
mp: *mut c_void,
|
||||
inode: u32,
|
||||
flags: u32,
|
||||
fsize: u64,
|
||||
fpos: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Ext4DirEntry {
|
||||
inode: u32,
|
||||
entry_length: u16,
|
||||
name_length: u8,
|
||||
inode_type: u8,
|
||||
name: [u8; 255],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Ext4Dir {
|
||||
f: Ext4File,
|
||||
de: Ext4DirEntry,
|
||||
next_off: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct CacheEntry {
|
||||
valid: bool,
|
||||
dirty: bool,
|
||||
stamp: u64,
|
||||
page_index: u64,
|
||||
path: [u8; MAX_PATH],
|
||||
data: [u8; PAGE_SIZE],
|
||||
}
|
||||
|
||||
impl CacheEntry {
|
||||
const fn empty() -> Self {
|
||||
Self {
|
||||
valid: false,
|
||||
dirty: false,
|
||||
stamp: 0,
|
||||
page_index: 0,
|
||||
path: [0; MAX_PATH],
|
||||
data: [0; PAGE_SIZE],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct ExecCacheEntry {
|
||||
valid: bool,
|
||||
hits: u64,
|
||||
stamp: u64,
|
||||
path: [u8; MAX_PATH],
|
||||
ptr: *const u8,
|
||||
len: usize,
|
||||
pages: usize,
|
||||
}
|
||||
|
||||
impl ExecCacheEntry {
|
||||
const fn empty() -> Self {
|
||||
Self {
|
||||
valid: false,
|
||||
hits: 0,
|
||||
stamp: 0,
|
||||
path: [0; MAX_PATH],
|
||||
ptr: core::ptr::null(),
|
||||
len: 0,
|
||||
pages: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn mount_root(
|
||||
device: PartitionBlockDevice<AhciDisk>,
|
||||
sector_count: u64,
|
||||
) -> Result<(), isize> {
|
||||
unsafe {
|
||||
ROOT_DEVICE = Some(device);
|
||||
let rc = zeroos_lwext4_mount(sector_count);
|
||||
if rc == 0 {
|
||||
MOUNTED = true;
|
||||
Ok(())
|
||||
} else {
|
||||
ROOT_DEVICE = None;
|
||||
Err(map_error(rc))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_mounted() -> bool {
|
||||
unsafe { MOUNTED }
|
||||
}
|
||||
|
||||
pub fn init_cache(memory: *mut PhysicalMemoryManager) {
|
||||
unsafe {
|
||||
MEMORY_MANAGER = memory;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_path_at(
|
||||
path: &[u8],
|
||||
offset: usize,
|
||||
buffer: *mut u8,
|
||||
len: usize,
|
||||
) -> Result<usize, isize> {
|
||||
if !is_mounted() {
|
||||
return Err(-ENODEV);
|
||||
}
|
||||
if buffer.is_null() {
|
||||
return Err(-EIO);
|
||||
}
|
||||
let path = c_path(path)?;
|
||||
cache_read(&path, offset, buffer, len)
|
||||
}
|
||||
|
||||
pub fn write_path_at(
|
||||
path: &[u8],
|
||||
offset: usize,
|
||||
buffer: *const u8,
|
||||
len: usize,
|
||||
) -> Result<usize, isize> {
|
||||
if !is_mounted() {
|
||||
return Err(-ENODEV);
|
||||
}
|
||||
if buffer.is_null() {
|
||||
return Err(-EIO);
|
||||
}
|
||||
let Some(end) = offset.checked_add(len) else {
|
||||
return Err(-EFBIG);
|
||||
};
|
||||
if end as u64 > u64::MAX {
|
||||
return Err(-EFBIG);
|
||||
}
|
||||
let path = c_path(path)?;
|
||||
invalidate_exec_cache(&path);
|
||||
cache_write(&path, offset, buffer, len)
|
||||
}
|
||||
|
||||
pub fn truncate_path(path: &[u8], size: usize) -> Result<(), isize> {
|
||||
if !is_mounted() {
|
||||
return Err(-ENODEV);
|
||||
}
|
||||
let path = c_path(path)?;
|
||||
flush_path_cache(&path)?;
|
||||
invalidate_exec_cache(&path);
|
||||
let rc = unsafe { zeroos_lwext4_truncate(path.as_ptr(), size as u64) };
|
||||
if rc == 0 {
|
||||
invalidate_path_cache(&path);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(map_error(rc))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size_path(path: &[u8]) -> Result<usize, isize> {
|
||||
if !is_mounted() {
|
||||
return Err(-ENODEV);
|
||||
}
|
||||
let path = c_path(path)?;
|
||||
let mut size = 0u64;
|
||||
let rc = unsafe { zeroos_lwext4_size(path.as_ptr(), &mut size) };
|
||||
if rc == 0 {
|
||||
usize::try_from(size).map_err(|_| -EFBIG)
|
||||
} else {
|
||||
Err(map_error(rc))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_path(memory: &mut PhysicalMemoryManager, path: &[u8]) -> Result<LoadedFile, isize> {
|
||||
let path = c_path(path)?;
|
||||
if let Some(image) = exec_cache_get(&path) {
|
||||
return Ok(image);
|
||||
}
|
||||
|
||||
let len = size_path(&path)?;
|
||||
let pages = len.div_ceil(PAGE_SIZE).max(1);
|
||||
let Some(buffer) = memory.alloc_pages(pages) else {
|
||||
return Err(-EIO);
|
||||
};
|
||||
let slice = unsafe { core::slice::from_raw_parts_mut(buffer, pages * PAGE_SIZE) };
|
||||
slice[..len].fill(0);
|
||||
match cache_read(&path, 0, slice.as_mut_ptr(), len) {
|
||||
Ok(_) => {
|
||||
let image = LoadedFile {
|
||||
ptr: buffer as *const u8,
|
||||
len,
|
||||
};
|
||||
exec_cache_insert(&path, image.ptr, image.len, pages);
|
||||
Ok(image)
|
||||
}
|
||||
Err(error) => {
|
||||
unsafe {
|
||||
memory.free_pages(buffer, pages);
|
||||
}
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_file(path: &[u8]) -> Result<(), isize> {
|
||||
if !is_mounted() {
|
||||
return Err(-ENODEV);
|
||||
}
|
||||
let path = c_path(path)?;
|
||||
flush_path_cache(&path)?;
|
||||
invalidate_exec_cache(&path);
|
||||
let rc = unsafe { zeroos_lwext4_create_file(path.as_ptr()) };
|
||||
if rc == 0 {
|
||||
invalidate_path_cache(&path);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(map_error(rc))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_dir(path: &[u8]) -> Result<(), isize> {
|
||||
if !is_mounted() {
|
||||
return Err(-ENODEV);
|
||||
}
|
||||
let path = c_path(path)?;
|
||||
let rc = unsafe { zeroos_lwext4_mkdir(path.as_ptr()) };
|
||||
if rc == 0 { Ok(()) } else { Err(map_error(rc)) }
|
||||
}
|
||||
|
||||
pub fn mount_vfs_tree() -> Result<(), isize> {
|
||||
let mut root = [0u8; MAX_PATH];
|
||||
root[0] = b'/';
|
||||
mount_vfs_dir(&root, 0)
|
||||
}
|
||||
|
||||
pub fn flush_cache() -> Result<(), isize> {
|
||||
for index in 0..CACHE_SLOTS {
|
||||
flush_entry(index)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn zeroos_lwext4_read_blocks(
|
||||
buffer: *mut u8,
|
||||
block_id: u64,
|
||||
block_count: u32,
|
||||
) -> i32 {
|
||||
if buffer.is_null() {
|
||||
return EIO as i32;
|
||||
}
|
||||
let byte_count = block_count as usize * 512;
|
||||
let offset = block_id.saturating_mul(512);
|
||||
unsafe {
|
||||
let Some(mut device) = ROOT_DEVICE else {
|
||||
return ENODEV as i32;
|
||||
};
|
||||
let slice = core::slice::from_raw_parts_mut(buffer, byte_count);
|
||||
let result = device.read_at(offset, slice);
|
||||
ROOT_DEVICE = Some(device);
|
||||
block_result(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn zeroos_lwext4_write_blocks(
|
||||
buffer: *const u8,
|
||||
block_id: u64,
|
||||
block_count: u32,
|
||||
) -> i32 {
|
||||
if buffer.is_null() {
|
||||
return EIO as i32;
|
||||
}
|
||||
let byte_count = block_count as usize * 512;
|
||||
let offset = block_id.saturating_mul(512);
|
||||
unsafe {
|
||||
let Some(mut device) = ROOT_DEVICE else {
|
||||
return ENODEV as i32;
|
||||
};
|
||||
let slice = core::slice::from_raw_parts(buffer, byte_count);
|
||||
let result = device.write_at(offset, slice);
|
||||
ROOT_DEVICE = Some(device);
|
||||
block_result(result)
|
||||
}
|
||||
}
|
||||
|
||||
fn block_result(result: Result<(), BlockError>) -> i32 {
|
||||
match result {
|
||||
Ok(()) => 0,
|
||||
Err(_) => EIO as i32,
|
||||
}
|
||||
}
|
||||
|
||||
fn cache_read(
|
||||
path: &[u8; MAX_PATH],
|
||||
offset: usize,
|
||||
buffer: *mut u8,
|
||||
len: usize,
|
||||
) -> Result<usize, isize> {
|
||||
if len == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let mut copied = 0usize;
|
||||
while copied < len {
|
||||
let absolute = offset + copied;
|
||||
let page_index = (absolute / PAGE_SIZE) as u64;
|
||||
let page_offset = absolute % PAGE_SIZE;
|
||||
let chunk = (PAGE_SIZE - page_offset).min(len - copied);
|
||||
let slot = cache_get_page_slot(path, page_index, true)?;
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
CACHE[slot].data.as_ptr().add(page_offset),
|
||||
buffer.add(copied),
|
||||
chunk,
|
||||
);
|
||||
}
|
||||
copied += chunk;
|
||||
}
|
||||
Ok(copied)
|
||||
}
|
||||
|
||||
fn cache_write(
|
||||
path: &[u8; MAX_PATH],
|
||||
offset: usize,
|
||||
buffer: *const u8,
|
||||
len: usize,
|
||||
) -> Result<usize, isize> {
|
||||
if len == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let mut written = 0usize;
|
||||
while written < len {
|
||||
let absolute = offset + written;
|
||||
let page_index = (absolute / PAGE_SIZE) as u64;
|
||||
let page_offset = absolute % PAGE_SIZE;
|
||||
let chunk = (PAGE_SIZE - page_offset).min(len - written);
|
||||
let slot = cache_get_page_slot(path, page_index, true)?;
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
buffer.add(written),
|
||||
CACHE[slot].data.as_mut_ptr().add(page_offset),
|
||||
chunk,
|
||||
);
|
||||
CACHE[slot].dirty = true;
|
||||
CACHE[slot].stamp = next_stamp();
|
||||
}
|
||||
written += chunk;
|
||||
}
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
fn cache_get_page_slot(path: &[u8; MAX_PATH], page_index: u64, load: bool) -> Result<usize, isize> {
|
||||
unsafe {
|
||||
let mut free_slot = None;
|
||||
let mut lru_slot = 0usize;
|
||||
let mut lru_stamp = u64::MAX;
|
||||
|
||||
for index in 0..CACHE_SLOTS {
|
||||
let entry = &mut CACHE[index];
|
||||
if entry.valid {
|
||||
if entry.page_index == page_index && entry.path == *path {
|
||||
entry.stamp = next_stamp();
|
||||
return Ok(index);
|
||||
}
|
||||
if entry.stamp < lru_stamp {
|
||||
lru_stamp = entry.stamp;
|
||||
lru_slot = index;
|
||||
}
|
||||
} else if free_slot.is_none() {
|
||||
free_slot = Some(index);
|
||||
}
|
||||
}
|
||||
|
||||
let slot = free_slot.unwrap_or(lru_slot);
|
||||
if CACHE[slot].valid && CACHE[slot].dirty {
|
||||
flush_entry(slot)?;
|
||||
}
|
||||
let entry = &mut CACHE[slot];
|
||||
entry.valid = true;
|
||||
entry.dirty = false;
|
||||
entry.stamp = next_stamp();
|
||||
entry.page_index = page_index;
|
||||
entry.path = *path;
|
||||
entry.data.fill(0);
|
||||
|
||||
if load {
|
||||
load_page(slot, path, page_index)?;
|
||||
}
|
||||
|
||||
Ok(slot)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_page(slot: usize, path: &[u8; MAX_PATH], page_index: u64) -> Result<(), isize> {
|
||||
let mut done = 0usize;
|
||||
let offset = page_index as usize * PAGE_SIZE;
|
||||
let rc = unsafe {
|
||||
zeroos_lwext4_read(
|
||||
path.as_ptr(),
|
||||
offset as u64,
|
||||
CACHE[slot].data.as_mut_ptr(),
|
||||
PAGE_SIZE,
|
||||
&mut done,
|
||||
)
|
||||
};
|
||||
if rc == 0 {
|
||||
if done < PAGE_SIZE {
|
||||
unsafe {
|
||||
CACHE[slot].data[done..].fill(0);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(map_error(rc))
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_path_cache(path: &[u8; MAX_PATH]) -> Result<(), isize> {
|
||||
unsafe {
|
||||
for index in 0..CACHE_SLOTS {
|
||||
if CACHE[index].valid && CACHE[index].path == *path && CACHE[index].dirty {
|
||||
flush_entry(index)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn invalidate_path_cache(path: &[u8; MAX_PATH]) {
|
||||
unsafe {
|
||||
for index in 0..CACHE_SLOTS {
|
||||
if CACHE[index].valid && CACHE[index].path == *path {
|
||||
CACHE[index] = CacheEntry::empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_entry(index: usize) -> Result<(), isize> {
|
||||
unsafe {
|
||||
let entry = &mut CACHE[index];
|
||||
if !entry.valid || !entry.dirty {
|
||||
return Ok(());
|
||||
}
|
||||
let mut done = 0usize;
|
||||
let rc = zeroos_lwext4_write(
|
||||
entry.path.as_ptr(),
|
||||
entry.page_index * PAGE_SIZE as u64,
|
||||
entry.data.as_ptr(),
|
||||
PAGE_SIZE,
|
||||
&mut done,
|
||||
);
|
||||
if rc == 0 {
|
||||
entry.dirty = false;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(map_error(rc))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_cache_get(path: &[u8; MAX_PATH]) -> Option<LoadedFile> {
|
||||
unsafe {
|
||||
for index in 0..EXEC_CACHE_SLOTS {
|
||||
let entry = &mut *core::ptr::addr_of_mut!(EXEC_CACHE[index]);
|
||||
if entry.valid && entry.path == *path {
|
||||
entry.hits = entry.hits.saturating_add(1);
|
||||
entry.stamp = next_stamp();
|
||||
return Some(LoadedFile {
|
||||
ptr: entry.ptr,
|
||||
len: entry.len,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn exec_cache_insert(path: &[u8; MAX_PATH], ptr: *const u8, len: usize, pages: usize) {
|
||||
unsafe {
|
||||
let mut free_slot = None;
|
||||
let mut lru_slot = 0usize;
|
||||
let mut lru_score = u64::MAX;
|
||||
for index in 0..EXEC_CACHE_SLOTS {
|
||||
let entry = EXEC_CACHE[index];
|
||||
if !entry.valid {
|
||||
free_slot = Some(index);
|
||||
break;
|
||||
}
|
||||
let score = entry.stamp.saturating_sub(entry.hits.min(64));
|
||||
if score < lru_score {
|
||||
lru_score = score;
|
||||
lru_slot = index;
|
||||
}
|
||||
}
|
||||
let slot = free_slot.unwrap_or(lru_slot);
|
||||
if EXEC_CACHE[slot].valid {
|
||||
free_exec_entry(slot);
|
||||
}
|
||||
let entry = &mut EXEC_CACHE[slot];
|
||||
entry.valid = true;
|
||||
entry.hits = 1;
|
||||
entry.stamp = next_stamp();
|
||||
entry.path = *path;
|
||||
entry.ptr = ptr;
|
||||
entry.len = len;
|
||||
entry.pages = pages;
|
||||
}
|
||||
}
|
||||
|
||||
fn invalidate_exec_cache(path: &[u8; MAX_PATH]) {
|
||||
unsafe {
|
||||
for index in 0..EXEC_CACHE_SLOTS {
|
||||
if EXEC_CACHE[index].valid && EXEC_CACHE[index].path == *path {
|
||||
free_exec_entry(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn free_exec_entry(index: usize) {
|
||||
unsafe {
|
||||
let entry = &mut *core::ptr::addr_of_mut!(EXEC_CACHE[index]);
|
||||
if entry.valid && !entry.ptr.is_null() && !MEMORY_MANAGER.is_null() && entry.pages > 0 {
|
||||
(*MEMORY_MANAGER).free_pages(entry.ptr as *mut u8, entry.pages);
|
||||
}
|
||||
EXEC_CACHE[index] = ExecCacheEntry::empty();
|
||||
}
|
||||
}
|
||||
|
||||
fn next_stamp() -> u64 {
|
||||
unsafe {
|
||||
CACHE_CLOCK = CACHE_CLOCK.wrapping_add(1);
|
||||
CACHE_CLOCK
|
||||
}
|
||||
}
|
||||
|
||||
fn map_error(error: i32) -> isize {
|
||||
if error == 0 {
|
||||
return 0;
|
||||
}
|
||||
let errno = error.unsigned_abs() as isize;
|
||||
match errno {
|
||||
2 => -ENOENT,
|
||||
5 => -EIO,
|
||||
19 => -ENODEV,
|
||||
27 => -EFBIG,
|
||||
_ => -EIO,
|
||||
}
|
||||
}
|
||||
|
||||
fn mount_vfs_dir(path: &[u8], depth: usize) -> Result<(), isize> {
|
||||
if depth > 16 {
|
||||
return Ok(());
|
||||
}
|
||||
let mut dir = Ext4Dir {
|
||||
f: Ext4File {
|
||||
mp: core::ptr::null_mut(),
|
||||
inode: 0,
|
||||
flags: 0,
|
||||
fsize: 0,
|
||||
fpos: 0,
|
||||
},
|
||||
de: Ext4DirEntry {
|
||||
inode: 0,
|
||||
entry_length: 0,
|
||||
name_length: 0,
|
||||
inode_type: 0,
|
||||
name: [0; 255],
|
||||
},
|
||||
next_off: 0,
|
||||
};
|
||||
let c_path = c_path(path)?;
|
||||
let rc = unsafe { ext4_dir_open(&mut dir, c_path.as_ptr()) };
|
||||
if rc != 0 {
|
||||
return Err(map_error(rc));
|
||||
}
|
||||
|
||||
loop {
|
||||
let entry = unsafe { ext4_dir_entry_next(&mut dir) };
|
||||
if entry.is_null() {
|
||||
break;
|
||||
}
|
||||
let entry = unsafe { &*entry };
|
||||
let name_len = entry.name_length as usize;
|
||||
if name_len == 0 || name_len > entry.name.len() {
|
||||
continue;
|
||||
}
|
||||
let name = &entry.name[..name_len];
|
||||
if name == b"." || name == b".." {
|
||||
continue;
|
||||
}
|
||||
let mut child_path = [0u8; MAX_PATH];
|
||||
if !join_path(path, name, &mut child_path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match entry.inode_type {
|
||||
EXT4_DE_DIR => {
|
||||
let _ = crate::fs::vfs::mount_ext4_node(
|
||||
&child_path,
|
||||
crate::fs::vfs::NodeKind::Directory,
|
||||
);
|
||||
let _ = mount_vfs_dir(&child_path, depth + 1);
|
||||
}
|
||||
EXT4_DE_REG_FILE => {
|
||||
let _ =
|
||||
crate::fs::vfs::mount_ext4_node(&child_path, crate::fs::vfs::NodeKind::Regular);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let _ = ext4_dir_close(&mut dir);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn c_path(path: &[u8]) -> Result<[u8; MAX_PATH], isize> {
|
||||
let len = nul_len(path);
|
||||
if len == 0 || len >= MAX_PATH {
|
||||
return Err(-ENOENT);
|
||||
}
|
||||
let mut out = [0u8; MAX_PATH];
|
||||
out[..len].copy_from_slice(&path[..len]);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn join_path(parent: &[u8], name: &[u8], out: &mut [u8; MAX_PATH]) -> bool {
|
||||
let parent_len = nul_len(parent);
|
||||
if parent_len == 0 || name.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let mut pos = 0;
|
||||
while pos < parent_len && pos < MAX_PATH - 1 {
|
||||
out[pos] = parent[pos];
|
||||
pos += 1;
|
||||
}
|
||||
if !(pos == 1 && out[0] == b'/') {
|
||||
if pos >= MAX_PATH - 1 {
|
||||
return false;
|
||||
}
|
||||
out[pos] = b'/';
|
||||
pos += 1;
|
||||
}
|
||||
if pos + name.len() >= MAX_PATH {
|
||||
return false;
|
||||
}
|
||||
out[pos..pos + name.len()].copy_from_slice(name);
|
||||
true
|
||||
}
|
||||
|
||||
fn nul_len(path: &[u8]) -> usize {
|
||||
path.iter()
|
||||
.position(|byte| *byte == 0)
|
||||
.unwrap_or(path.len())
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
#include <ext4.h>
|
||||
#include <ext4_blockdev.h>
|
||||
#include <ext4_oflags.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int zeroos_lwext4_read_blocks(void *buf, uint64_t blk_id, uint32_t blk_cnt);
|
||||
extern int zeroos_lwext4_write_blocks(const void *buf, uint64_t blk_id, uint32_t blk_cnt);
|
||||
|
||||
#define ZEROOS_LWEXT4_HEAP_SIZE (4u * 1024u * 1024u)
|
||||
#define ZEROOS_LWEXT4_ALIGN 16u
|
||||
|
||||
struct zeroos_alloc_header {
|
||||
size_t size;
|
||||
int free;
|
||||
struct zeroos_alloc_header *next;
|
||||
};
|
||||
|
||||
static uint8_t zeroos_lwext4_heap[ZEROOS_LWEXT4_HEAP_SIZE];
|
||||
static struct zeroos_alloc_header *zeroos_heap_head;
|
||||
static uint8_t zeroos_bbuf[512];
|
||||
static struct ext4_blockdev zeroos_bdev;
|
||||
static struct ext4_blockdev_iface zeroos_bdev_iface;
|
||||
static int zeroos_mounted;
|
||||
|
||||
static size_t zeroos_align_up(size_t value) {
|
||||
return (value + ZEROOS_LWEXT4_ALIGN - 1u) & ~(ZEROOS_LWEXT4_ALIGN - 1u);
|
||||
}
|
||||
|
||||
static void zeroos_heap_init(void) {
|
||||
if (zeroos_heap_head) {
|
||||
return;
|
||||
}
|
||||
zeroos_heap_head = (struct zeroos_alloc_header *)zeroos_lwext4_heap;
|
||||
zeroos_heap_head->size = ZEROOS_LWEXT4_HEAP_SIZE - sizeof(struct zeroos_alloc_header);
|
||||
zeroos_heap_head->free = 1;
|
||||
zeroos_heap_head->next = 0;
|
||||
}
|
||||
|
||||
void *ext4_user_malloc(size_t size) {
|
||||
zeroos_heap_init();
|
||||
size = zeroos_align_up(size);
|
||||
struct zeroos_alloc_header *node = zeroos_heap_head;
|
||||
while (node) {
|
||||
if (node->free && node->size >= size) {
|
||||
size_t remaining = node->size - size;
|
||||
if (remaining > sizeof(struct zeroos_alloc_header) + ZEROOS_LWEXT4_ALIGN) {
|
||||
struct zeroos_alloc_header *next =
|
||||
(struct zeroos_alloc_header *)((uint8_t *)(node + 1) + size);
|
||||
next->size = remaining - sizeof(struct zeroos_alloc_header);
|
||||
next->free = 1;
|
||||
next->next = node->next;
|
||||
node->next = next;
|
||||
node->size = size;
|
||||
}
|
||||
node->free = 0;
|
||||
return node + 1;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *ext4_user_calloc(size_t count, size_t size) {
|
||||
size_t total = count * size;
|
||||
void *ptr = ext4_user_malloc(total);
|
||||
if (ptr) {
|
||||
memset(ptr, 0, total);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ext4_user_free(void *ptr) {
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
struct zeroos_alloc_header *node = ((struct zeroos_alloc_header *)ptr) - 1;
|
||||
node->free = 1;
|
||||
while (node->next && node->next->free) {
|
||||
node->size += sizeof(struct zeroos_alloc_header) + node->next->size;
|
||||
node->next = node->next->next;
|
||||
}
|
||||
}
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n) {
|
||||
uint8_t *d = (uint8_t *)dest;
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
uint8_t *d = (uint8_t *)dest;
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
if (d < s) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
} else {
|
||||
while (n > 0) {
|
||||
n--;
|
||||
d[n] = s[n];
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n) {
|
||||
uint8_t *d = (uint8_t *)dest;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
d[i] = (uint8_t)c;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memcmp(const void *a, const void *b, size_t n) {
|
||||
const uint8_t *pa = (const uint8_t *)a;
|
||||
const uint8_t *pb = (const uint8_t *)b;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (pa[i] != pb[i]) {
|
||||
return (int)pa[i] - (int)pb[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
size_t len = 0;
|
||||
while (s[len]) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int strcmp(const char *a, const char *b) {
|
||||
while (*a && *a == *b) {
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return (int)(uint8_t)*a - (int)(uint8_t)*b;
|
||||
}
|
||||
|
||||
int strncmp(const char *a, const char *b, size_t n) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (a[i] != b[i] || a[i] == 0 || b[i] == 0) {
|
||||
return (int)(uint8_t)a[i] - (int)(uint8_t)b[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strcpy(char *dest, const char *src) {
|
||||
char *out = dest;
|
||||
while ((*dest++ = *src++)) {
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
|
||||
uint8_t *items = (uint8_t *)base;
|
||||
uint8_t *tmp = (uint8_t *)ext4_user_malloc(size);
|
||||
if (!tmp) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 1; i < nmemb; i++) {
|
||||
memcpy(tmp, items + i * size, size);
|
||||
size_t j = i;
|
||||
while (j > 0 && compar(items + (j - 1) * size, tmp) > 0) {
|
||||
memmove(items + j * size, items + (j - 1) * size, size);
|
||||
j--;
|
||||
}
|
||||
memcpy(items + j * size, tmp, size);
|
||||
}
|
||||
ext4_user_free(tmp);
|
||||
}
|
||||
|
||||
static int zeroos_bdev_open(struct ext4_blockdev *bdev) {
|
||||
(void)bdev;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int zeroos_bdev_close(struct ext4_blockdev *bdev) {
|
||||
(void)bdev;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int zeroos_bdev_lock(struct ext4_blockdev *bdev) {
|
||||
(void)bdev;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int zeroos_bdev_unlock(struct ext4_blockdev *bdev) {
|
||||
(void)bdev;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int zeroos_bdev_bread(
|
||||
struct ext4_blockdev *bdev,
|
||||
void *buf,
|
||||
uint64_t blk_id,
|
||||
uint32_t blk_cnt
|
||||
) {
|
||||
(void)bdev;
|
||||
return zeroos_lwext4_read_blocks(buf, blk_id, blk_cnt);
|
||||
}
|
||||
|
||||
static int zeroos_bdev_bwrite(
|
||||
struct ext4_blockdev *bdev,
|
||||
const void *buf,
|
||||
uint64_t blk_id,
|
||||
uint32_t blk_cnt
|
||||
) {
|
||||
(void)bdev;
|
||||
return zeroos_lwext4_write_blocks(buf, blk_id, blk_cnt);
|
||||
}
|
||||
|
||||
int zeroos_lwext4_mount(uint64_t block_count) {
|
||||
if (zeroos_mounted) {
|
||||
return EOK;
|
||||
}
|
||||
|
||||
zeroos_bdev_iface.open = zeroos_bdev_open;
|
||||
zeroos_bdev_iface.bread = zeroos_bdev_bread;
|
||||
zeroos_bdev_iface.bwrite = zeroos_bdev_bwrite;
|
||||
zeroos_bdev_iface.close = zeroos_bdev_close;
|
||||
zeroos_bdev_iface.lock = zeroos_bdev_lock;
|
||||
zeroos_bdev_iface.unlock = zeroos_bdev_unlock;
|
||||
zeroos_bdev_iface.ph_bsize = 512;
|
||||
zeroos_bdev_iface.ph_bcnt = block_count;
|
||||
zeroos_bdev_iface.ph_bbuf = zeroos_bbuf;
|
||||
zeroos_bdev_iface.ph_refctr = 0;
|
||||
zeroos_bdev_iface.bread_ctr = 0;
|
||||
zeroos_bdev_iface.bwrite_ctr = 0;
|
||||
zeroos_bdev_iface.p_user = 0;
|
||||
|
||||
memset(&zeroos_bdev, 0, sizeof(zeroos_bdev));
|
||||
zeroos_bdev.bdif = &zeroos_bdev_iface;
|
||||
zeroos_bdev.part_offset = 0;
|
||||
zeroos_bdev.part_size = block_count * 512u;
|
||||
|
||||
int rc = ext4_device_register(&zeroos_bdev, "zeroos");
|
||||
if (rc != EOK) {
|
||||
return rc;
|
||||
}
|
||||
rc = ext4_mount("zeroos", "/", false);
|
||||
if (rc != EOK) {
|
||||
return rc;
|
||||
}
|
||||
ext4_cache_write_back("/", false);
|
||||
zeroos_mounted = 1;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
int zeroos_lwext4_read(const char *path, uint64_t offset, void *buf, size_t len, size_t *done) {
|
||||
ext4_file file;
|
||||
*done = 0;
|
||||
int rc = ext4_fopen2(&file, path, O_RDONLY);
|
||||
if (rc != EOK) {
|
||||
return rc;
|
||||
}
|
||||
rc = ext4_fseek(&file, (int64_t)offset, SEEK_SET);
|
||||
if (rc == EOK) {
|
||||
rc = ext4_fread(&file, buf, len, done);
|
||||
}
|
||||
ext4_fclose(&file);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int zeroos_lwext4_write(const char *path, uint64_t offset, const void *buf, size_t len, size_t *done) {
|
||||
ext4_file file;
|
||||
*done = 0;
|
||||
int rc = ext4_fopen2(&file, path, O_RDWR | O_CREAT);
|
||||
if (rc != EOK) {
|
||||
return rc;
|
||||
}
|
||||
rc = ext4_fseek(&file, (int64_t)offset, SEEK_SET);
|
||||
if (rc == EOK) {
|
||||
rc = ext4_fwrite(&file, buf, len, done);
|
||||
}
|
||||
ext4_fclose(&file);
|
||||
ext4_cache_flush("/");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int zeroos_lwext4_truncate(const char *path, uint64_t size) {
|
||||
ext4_file file;
|
||||
int rc = ext4_fopen2(&file, path, O_RDWR | O_CREAT);
|
||||
if (rc != EOK) {
|
||||
return rc;
|
||||
}
|
||||
rc = ext4_ftruncate(&file, size);
|
||||
ext4_fclose(&file);
|
||||
ext4_cache_flush("/");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int zeroos_lwext4_size(const char *path, uint64_t *size) {
|
||||
ext4_file file;
|
||||
*size = 0;
|
||||
int rc = ext4_fopen2(&file, path, O_RDONLY);
|
||||
if (rc != EOK) {
|
||||
return rc;
|
||||
}
|
||||
*size = ext4_fsize(&file);
|
||||
ext4_fclose(&file);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
int zeroos_lwext4_create_file(const char *path) {
|
||||
ext4_file file;
|
||||
int rc = ext4_fopen2(&file, path, O_RDWR | O_CREAT);
|
||||
if (rc == EOK) {
|
||||
ext4_fclose(&file);
|
||||
ext4_cache_flush("/");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int zeroos_lwext4_mkdir(const char *path) {
|
||||
int rc = ext4_dir_mk(path);
|
||||
if (rc == EEXIST) {
|
||||
return EOK;
|
||||
}
|
||||
ext4_cache_flush("/");
|
||||
return rc;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod ext4;
|
||||
pub mod lwext4;
|
||||
pub mod uefi;
|
||||
pub mod vfs;
|
||||
|
||||
+106
-19
@@ -15,7 +15,6 @@ const EINVAL: isize = 22;
|
||||
const ENOENT: isize = 2;
|
||||
const ENOTDIR: isize = 20;
|
||||
const EMFILE: isize = 24;
|
||||
const EIO: isize = 5;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Color {
|
||||
@@ -226,12 +225,25 @@ impl Vfs {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
let offset = self.fds[fd].offset.min(node.len);
|
||||
let available = node.len - offset;
|
||||
if node.data.is_null() {
|
||||
let count =
|
||||
match crate::fs::lwext4::read_path_at(&node.path, self.fds[fd].offset, buffer, len)
|
||||
{
|
||||
Ok(count) => count,
|
||||
Err(error) => return error,
|
||||
};
|
||||
self.fds[fd].offset = self.fds[fd].offset.saturating_add(count);
|
||||
return count as isize;
|
||||
}
|
||||
|
||||
let node_len = self.node_len(node_index);
|
||||
let offset = self.fds[fd].offset.min(node_len);
|
||||
let available = node_len - offset;
|
||||
let count = len.min(available);
|
||||
if count > 0 {
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(node.data.add(offset), buffer, count);
|
||||
let source = node.data.add(offset);
|
||||
core::ptr::copy_nonoverlapping(source, buffer, count);
|
||||
}
|
||||
}
|
||||
self.fds[fd].offset = offset + count;
|
||||
@@ -245,6 +257,9 @@ impl Vfs {
|
||||
let Some(node_index) = self.fds[fd].node else {
|
||||
return -EBADF;
|
||||
};
|
||||
if self.nodes[node_index].kind == NodeKind::Regular {
|
||||
return self.write_regular_fd(fd, node_index, buffer, len);
|
||||
}
|
||||
if self.nodes[node_index].kind != NodeKind::CharDevice {
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -253,6 +268,31 @@ impl Vfs {
|
||||
crate::console::write(buffer) as isize
|
||||
}
|
||||
|
||||
fn write_regular_fd(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
node_index: usize,
|
||||
buffer: *const u8,
|
||||
len: usize,
|
||||
) -> isize {
|
||||
let offset = self.fds[fd].offset;
|
||||
let count = match crate::fs::lwext4::write_path_at(
|
||||
&self.nodes[node_index].path,
|
||||
offset,
|
||||
buffer,
|
||||
len,
|
||||
) {
|
||||
Ok(count) => count,
|
||||
Err(error) => return error,
|
||||
};
|
||||
let end = offset.saturating_add(count);
|
||||
self.fds[fd].offset = end;
|
||||
if end > self.nodes[node_index].len {
|
||||
self.nodes[node_index].len = end;
|
||||
}
|
||||
count as isize
|
||||
}
|
||||
|
||||
fn close_fd(&mut self, fd: usize) -> isize {
|
||||
if fd < 3 || fd >= MAX_FDS || self.fds[fd].node.is_none() {
|
||||
return -EBADF;
|
||||
@@ -298,7 +338,7 @@ impl Vfs {
|
||||
let Some(node_index) = self.fds[fd].node else {
|
||||
return -EBADF;
|
||||
};
|
||||
let len = self.nodes[node_index].len as isize;
|
||||
let len = self.node_len(node_index) as isize;
|
||||
let current = self.fds[fd].offset as isize;
|
||||
let next = match whence {
|
||||
0 => offset,
|
||||
@@ -323,6 +363,24 @@ impl Vfs {
|
||||
write_stat(stat, self.nodes[node_index])
|
||||
}
|
||||
|
||||
fn ftruncate_fd(&mut self, fd: usize, size: usize) -> isize {
|
||||
if fd >= MAX_FDS {
|
||||
return -EBADF;
|
||||
}
|
||||
let Some(node_index) = self.fds[fd].node else {
|
||||
return -EBADF;
|
||||
};
|
||||
if self.nodes[node_index].kind != NodeKind::Regular {
|
||||
return -EINVAL;
|
||||
}
|
||||
match crate::fs::lwext4::truncate_path(&self.nodes[node_index].path, size) {
|
||||
Ok(()) => {}
|
||||
Err(error) => return error,
|
||||
}
|
||||
self.nodes[node_index].len = size;
|
||||
0
|
||||
}
|
||||
|
||||
fn is_tty_fd(&self, fd: usize) -> bool {
|
||||
if fd >= MAX_FDS {
|
||||
return false;
|
||||
@@ -387,6 +445,22 @@ impl Vfs {
|
||||
write_stat(stat, self.nodes[node_index])
|
||||
}
|
||||
|
||||
fn truncate_path(&mut self, path: &[u8], size: usize) -> isize {
|
||||
let Some(node_index) = self.find(path) else {
|
||||
return -ENOENT;
|
||||
};
|
||||
if self.nodes[node_index].kind != NodeKind::Regular {
|
||||
return -EINVAL;
|
||||
}
|
||||
match crate::fs::lwext4::truncate_path(&self.nodes[node_index].path, size) {
|
||||
Ok(()) => {
|
||||
self.nodes[node_index].len = size;
|
||||
0
|
||||
}
|
||||
Err(error) => error,
|
||||
}
|
||||
}
|
||||
|
||||
fn chdir_path(&mut self, path: &[u8]) -> isize {
|
||||
let Some(node_index) = self.find(path) else {
|
||||
return -ENOENT;
|
||||
@@ -414,6 +488,15 @@ impl Vfs {
|
||||
}
|
||||
}
|
||||
|
||||
fn node_len(&self, node_index: usize) -> usize {
|
||||
let node = self.nodes[node_index];
|
||||
if node.kind == NodeKind::Regular && node.data.is_null() {
|
||||
crate::fs::lwext4::size_path(&node.path).unwrap_or(node.len)
|
||||
} else {
|
||||
node.len
|
||||
}
|
||||
}
|
||||
|
||||
fn getcwd(&self, buffer: *mut u8, len: usize) -> isize {
|
||||
if buffer.is_null() {
|
||||
return -EFAULT;
|
||||
@@ -576,10 +659,7 @@ pub unsafe fn init() {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn mount_static_file(path: &'static [u8], data: *const u8, len: usize) -> Option<()> {
|
||||
unsafe { vfs_mut().insert(path, NodeKind::Regular, data, len) }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn mount_ext4_node(path: &[u8], kind: NodeKind) -> Option<()> {
|
||||
unsafe { vfs_mut().insert(path, kind, core::ptr::null(), 0) }
|
||||
}
|
||||
@@ -655,6 +735,10 @@ pub fn fstat(fd: usize, stat: *mut u8) -> isize {
|
||||
unsafe { vfs_ref().stat_fd(fd, stat) }
|
||||
}
|
||||
|
||||
pub fn ftruncate(fd: usize, size: usize) -> isize {
|
||||
unsafe { vfs_mut().ftruncate_fd(fd, size) }
|
||||
}
|
||||
|
||||
pub fn is_tty(fd: usize) -> bool {
|
||||
unsafe { vfs_ref().is_tty_fd(fd) }
|
||||
}
|
||||
@@ -684,6 +768,13 @@ pub fn stat_user_path(path: *const u8, stat: *mut u8) -> isize {
|
||||
unsafe { vfs_ref().stat_path(&path, stat) }
|
||||
}
|
||||
|
||||
pub fn truncate_user_path(path: *const u8, size: usize) -> isize {
|
||||
let Some(path) = (unsafe { read_user_path(path) }) else {
|
||||
return -EFAULT;
|
||||
};
|
||||
unsafe { vfs_mut().truncate_path(&path, size) }
|
||||
}
|
||||
|
||||
pub fn statat_user_path(dirfd: isize, path: *const u8, stat: *mut u8) -> isize {
|
||||
if unsafe { path_starts_with_slash(path) } || dirfd == AT_FDCWD {
|
||||
return stat_user_path(path, stat);
|
||||
@@ -761,9 +852,9 @@ fn create_directory_path(path: &[u8]) -> isize {
|
||||
if unsafe { vfs_ref().find(path).is_some() } {
|
||||
return 0;
|
||||
}
|
||||
match crate::fs::ext4::create_dir(path) {
|
||||
match crate::fs::lwext4::create_dir(path) {
|
||||
Ok(()) => unsafe { vfs_mut().create_path(path, NodeKind::Directory) },
|
||||
Err(_) => -EIO,
|
||||
Err(error) => error,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,9 +862,9 @@ fn create_regular_path(path: &[u8]) -> isize {
|
||||
if unsafe { vfs_ref().find(path).is_some() } {
|
||||
return 0;
|
||||
}
|
||||
match crate::fs::ext4::create_file(path) {
|
||||
match crate::fs::lwext4::create_file(path) {
|
||||
Ok(()) => unsafe { vfs_mut().create_path(path, NodeKind::Regular) },
|
||||
Err(_) => -EIO,
|
||||
Err(error) => error,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,15 +872,11 @@ pub fn getcwd(buffer: *mut u8, len: usize) -> isize {
|
||||
unsafe { vfs_ref().getcwd(buffer, len) }
|
||||
}
|
||||
|
||||
pub fn file_data_user_path(path: *const u8) -> Option<(*const u8, usize)> {
|
||||
pub fn exec_path_user(path: *const u8) -> Option<[u8; MAX_PATH]> {
|
||||
let path = unsafe { read_user_path(path) }?;
|
||||
unsafe {
|
||||
let index = vfs_ref().resolve_executable_path(&path)?;
|
||||
let node = &vfs_ref().nodes[index];
|
||||
if node.kind != NodeKind::Regular {
|
||||
return None;
|
||||
}
|
||||
Some((node.data, node.len))
|
||||
Some(vfs_ref().nodes[index].path)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
-114
@@ -84,87 +84,48 @@ extern "efiapi" fn efi_main(
|
||||
let _ = (stats.total_pages, stats.free_pages, stats.used_pages);
|
||||
logger.ok(b"physical memory manager");
|
||||
|
||||
fs::vfs::init();
|
||||
services::vfs::init();
|
||||
logger.ok(b"vfs");
|
||||
ipc::init();
|
||||
logger.ok(b"ipc");
|
||||
|
||||
let ahci_disks = drivers::storage::ahci::init(memory);
|
||||
let mut ext4_user_image = None;
|
||||
let mut ext4_user_path = None;
|
||||
if ahci_disks > 0 {
|
||||
let storage = services::storage::init(memory);
|
||||
if storage.ahci_disks > 0 {
|
||||
logger.ok(b"ahci");
|
||||
if let Some(mut disk) = drivers::storage::ahci::first_disk() {
|
||||
match drivers::storage::partition::find_linux_partition(&mut disk) {
|
||||
Ok(partition) => {
|
||||
let mut root =
|
||||
drivers::storage::partition::PartitionBlockDevice::new(disk, partition);
|
||||
match fs::ext4::mount(&mut root) {
|
||||
Ok(ext4) => {
|
||||
logger.ok(b"ext4");
|
||||
let _ = fs::ext4::mount_vfs_tree(&mut root, &ext4);
|
||||
fs::ext4::register_root(root, ext4);
|
||||
match fs::ext4::load_path(
|
||||
&mut root,
|
||||
&ext4,
|
||||
memory,
|
||||
b"/usr/bin/busybox",
|
||||
) {
|
||||
Ok(image) => {
|
||||
ext4_user_image = Some(image);
|
||||
ext4_user_path = Some(b"/usr/bin/busybox" as &'static [u8]);
|
||||
logger.ok(b"ext4 /usr/bin/busybox");
|
||||
}
|
||||
Err(_) => match fs::ext4::load_path(
|
||||
&mut root,
|
||||
&ext4,
|
||||
memory,
|
||||
b"/usr/bin/sh",
|
||||
) {
|
||||
Ok(image) => {
|
||||
ext4_user_image = Some(image);
|
||||
ext4_user_path = Some(b"/usr/bin/sh" as &'static [u8]);
|
||||
logger.ok(b"ext4 /usr/bin/sh");
|
||||
}
|
||||
Err(_) => logger.info(b"ext4 userspace not loaded"),
|
||||
},
|
||||
}
|
||||
}
|
||||
Err(_) => logger.info(b"ext4 not mounted"),
|
||||
}
|
||||
}
|
||||
Err(_) => logger.info(b"no linux gpt partition"),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.info(b"no ahci disk");
|
||||
}
|
||||
if storage.ext4_mounted {
|
||||
logger.ok(b"ext4");
|
||||
} else if storage.ahci_disks > 0 {
|
||||
logger.info(b"ext4 not mounted");
|
||||
}
|
||||
if storage.userspace_path == Some(b"/usr/bin/busybox" as &'static [u8]) {
|
||||
logger.ok(b"ext4 /usr/bin/busybox");
|
||||
} else if storage.userspace_path == Some(b"/usr/bin/sh" as &'static [u8]) {
|
||||
logger.ok(b"ext4 /usr/bin/sh");
|
||||
} else if storage.ext4_mounted {
|
||||
logger.info(b"ext4 userspace not loaded");
|
||||
}
|
||||
|
||||
let (loaded_user_image, loaded_user_path) = if let Some(image) = ext4_user_image {
|
||||
(Some(image), ext4_user_path)
|
||||
} else if let Some(image) =
|
||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::BASH_PATH)
|
||||
{
|
||||
(Some(image), Some(b"/bin/bash" as &'static [u8]))
|
||||
} else if let Some(image) =
|
||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::SH_PATH)
|
||||
{
|
||||
(Some(image), Some(b"/bin/sh" as &'static [u8]))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let userspace_image_found = loaded_user_image.is_some();
|
||||
if loaded_user_image.is_some() {
|
||||
if let (Some(image), Some(path)) = (&loaded_user_image, loaded_user_path) {
|
||||
let _ = fs::vfs::mount_static_file(path, image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/usr/bin/busybox", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/bin/busybox", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/usr/bin/sh", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/usr/bin/bash", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/bin/sh", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/bin/bash", image.ptr, image.len);
|
||||
let (loaded_user_image, loaded_user_path) = match storage.userspace_image {
|
||||
Some(image) => (Some(image), storage.userspace_path),
|
||||
None => {
|
||||
if let Some(image) =
|
||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::BASH_PATH)
|
||||
{
|
||||
(Some(image), Some(b"/bin/bash" as &'static [u8]))
|
||||
} else if let Some(image) =
|
||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::SH_PATH)
|
||||
{
|
||||
(Some(image), Some(b"/bin/sh" as &'static [u8]))
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
logger.ok(b"userspace image loaded from esp");
|
||||
};
|
||||
if loaded_user_image.is_some() {
|
||||
logger.ok(b"userspace image loaded");
|
||||
} else {
|
||||
logger.info(b"no /bin/bash or /bin/sh on esp, using built-in user program");
|
||||
}
|
||||
@@ -189,8 +150,8 @@ extern "efiapi" fn efi_main(
|
||||
logger.ok(b"address space");
|
||||
|
||||
let mut userspace_program = None;
|
||||
let user_entry = if let Some(image) = loaded_user_image {
|
||||
match elf::load_user_elf(&image, memory) {
|
||||
let user_entry = if let Some(ref image) = loaded_user_image {
|
||||
match elf::load_user_elf(image, memory) {
|
||||
Some(program) => {
|
||||
logger.ok(b"elf userspace program");
|
||||
userspace_program = Some(user::UserAux {
|
||||
@@ -209,6 +170,13 @@ extern "efiapi" fn efi_main(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let user_args: &[&[u8]] = match loaded_user_path {
|
||||
Some(b"/usr/bin/busybox") => &[b"/usr/bin/busybox", b"sh"],
|
||||
Some(b"/usr/bin/sh") => &[b"/usr/bin/sh"],
|
||||
Some(b"/usr/bin/bash") => &[b"/usr/bin/bash"],
|
||||
Some(b"/bin/sh") => &[b"/bin/sh"],
|
||||
_ => &[b"/bin/bash"],
|
||||
};
|
||||
|
||||
let Some(test_page) = memory.alloc_page() else {
|
||||
halt_forever();
|
||||
@@ -251,16 +219,10 @@ extern "efiapi" fn efi_main(
|
||||
logger.ok(b"cr3");
|
||||
tty.clear();
|
||||
if user_entry.is_some() {
|
||||
if loaded_user_path == Some(b"/usr/bin/busybox" as &'static [u8]) {
|
||||
console::write(b"enter userspace: /usr/bin/busybox sh\r\n");
|
||||
} else if loaded_user_path == Some(b"/usr/bin/sh" as &'static [u8]) {
|
||||
console::write(b"enter userspace: /usr/bin/sh\r\n");
|
||||
} else if loaded_user_path == Some(b"/usr/bin/bash" as &'static [u8]) {
|
||||
console::write(b"enter userspace: /usr/bin/bash\r\n");
|
||||
} else {
|
||||
console::write(b"enter userspace: /bin/bash\r\n");
|
||||
}
|
||||
} else if userspace_image_found {
|
||||
console::write(b"enter userspace: ");
|
||||
console::write(user_args[0]);
|
||||
console::write(b"\r\n");
|
||||
} else if loaded_user_image.is_some() {
|
||||
console::write(b"/bin/bash found but ELF load failed; enter built-in userspace\r\n");
|
||||
} else {
|
||||
console::write(b"/bin/bash not found on ESP; enter built-in userspace\r\n");
|
||||
@@ -268,37 +230,11 @@ extern "efiapi" fn efi_main(
|
||||
syscall::init(memory, &raw mut address_space);
|
||||
io::enable_interrupts();
|
||||
if let Some(entry) = user_entry {
|
||||
if loaded_user_path == Some(b"/usr/bin/busybox" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/usr/bin/busybox", b"sh"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else if loaded_user_path == Some(b"/usr/bin/sh" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/usr/bin/sh"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else if loaded_user_path == Some(b"/usr/bin/bash" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/usr/bin/bash"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else if loaded_user_path == Some(b"/bin/sh" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/bin/sh"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/bin/bash"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
}
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
user_args,
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else {
|
||||
user::enter();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod storage;
|
||||
pub mod tty;
|
||||
pub mod vfs;
|
||||
|
||||
pub const SERVICE_VFS: usize = 1;
|
||||
pub const SERVICE_TTY: usize = 2;
|
||||
pub const SERVICE_STORAGE: usize = 3;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ServiceRequest {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
use crate::{drivers, fs, memory::PhysicalMemoryManager};
|
||||
|
||||
pub struct StorageInitResult {
|
||||
pub ahci_disks: usize,
|
||||
pub ext4_mounted: bool,
|
||||
pub userspace_image: Option<fs::uefi::LoadedFile>,
|
||||
pub userspace_path: Option<&'static [u8]>,
|
||||
}
|
||||
|
||||
pub fn init(memory: &mut PhysicalMemoryManager) -> StorageInitResult {
|
||||
let ahci_disks = unsafe { drivers::storage::ahci::init(memory) };
|
||||
let mut result = StorageInitResult {
|
||||
ahci_disks,
|
||||
ext4_mounted: false,
|
||||
userspace_image: None,
|
||||
userspace_path: None,
|
||||
};
|
||||
|
||||
if ahci_disks == 0 {
|
||||
return result;
|
||||
}
|
||||
|
||||
let Some(mut disk) = drivers::storage::ahci::first_disk() else {
|
||||
return result;
|
||||
};
|
||||
let Ok(partition) = drivers::storage::partition::find_linux_partition(&mut disk) else {
|
||||
return result;
|
||||
};
|
||||
|
||||
let root = drivers::storage::partition::PartitionBlockDevice::new(disk, partition);
|
||||
let root_sector_count = partition.last_lba - partition.first_lba + 1;
|
||||
if unsafe { fs::lwext4::mount_root(root, root_sector_count) }.is_err() {
|
||||
return result;
|
||||
}
|
||||
fs::lwext4::init_cache(memory as *mut PhysicalMemoryManager);
|
||||
|
||||
result.ext4_mounted = true;
|
||||
let _ = fs::lwext4::mount_vfs_tree();
|
||||
|
||||
match fs::lwext4::load_path(memory, b"/usr/bin/busybox") {
|
||||
Ok(image) => {
|
||||
result.userspace_image = Some(image);
|
||||
result.userspace_path = Some(b"/usr/bin/busybox");
|
||||
}
|
||||
Err(_) => {
|
||||
if let Ok(image) = fs::lwext4::load_path(memory, b"/usr/bin/sh") {
|
||||
result.userspace_image = Some(image);
|
||||
result.userspace_path = Some(b"/usr/bin/sh");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
+63
-3
@@ -1,9 +1,69 @@
|
||||
use crate::ipc::Message;
|
||||
use crate::{console, fs::vfs, ipc::Message};
|
||||
|
||||
pub const OP_READ: u16 = 1;
|
||||
pub const OP_WRITE: u16 = 2;
|
||||
pub const OP_IOCTL: u16 = 3;
|
||||
pub const OP_RESET: u16 = 4;
|
||||
pub const OP_SET_RAW: u16 = 5;
|
||||
pub const OP_SIZE: u16 = 6;
|
||||
pub const OP_IS_TTY: u16 = 7;
|
||||
|
||||
pub fn dispatch(_message: Message) -> isize {
|
||||
-38
|
||||
pub fn dispatch(message: Message) -> isize {
|
||||
match message.opcode {
|
||||
OP_WRITE => console::write(unsafe {
|
||||
core::slice::from_raw_parts(message.args[0] as *const u8, message.args[1])
|
||||
}) as isize,
|
||||
OP_RESET => {
|
||||
console::reset_terminal();
|
||||
0
|
||||
}
|
||||
OP_SET_RAW => {
|
||||
console::set_raw_mode(message.args[0] != 0);
|
||||
0
|
||||
}
|
||||
OP_SIZE => {
|
||||
let (columns, rows) = console::size();
|
||||
((rows & 0xffff) << 16 | (columns & 0xffff)) as isize
|
||||
}
|
||||
OP_IS_TTY => {
|
||||
if message.args[0] <= 2 || vfs::is_tty(message.args[0]) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => -38,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(bytes: &[u8]) -> usize {
|
||||
dispatch(message(
|
||||
OP_WRITE,
|
||||
[bytes.as_ptr() as usize, bytes.len(), 0, 0, 0, 0],
|
||||
)) as usize
|
||||
}
|
||||
|
||||
pub fn reset_terminal() {
|
||||
let _ = dispatch(message(OP_RESET, [0, 0, 0, 0, 0, 0]));
|
||||
}
|
||||
|
||||
pub fn set_raw_mode(enabled: bool) {
|
||||
let _ = dispatch(message(OP_SET_RAW, [enabled as usize, 0, 0, 0, 0, 0]));
|
||||
}
|
||||
|
||||
pub fn size() -> (usize, usize) {
|
||||
let packed = dispatch(message(OP_SIZE, [0, 0, 0, 0, 0, 0])) as usize;
|
||||
(packed & 0xffff, (packed >> 16) & 0xffff)
|
||||
}
|
||||
|
||||
pub fn is_tty(fd: usize) -> bool {
|
||||
dispatch(message(OP_IS_TTY, [fd, 0, 0, 0, 0, 0])) != 0
|
||||
}
|
||||
|
||||
fn message(opcode: u16, args: [usize; 6]) -> Message {
|
||||
Message {
|
||||
sender: crate::task::current_pid(),
|
||||
opcode,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
+181
-3
@@ -1,10 +1,188 @@
|
||||
use crate::ipc::Message;
|
||||
use crate::{fs::vfs, ipc::Message};
|
||||
|
||||
pub const OP_OPEN: u16 = 1;
|
||||
pub const OP_READ: u16 = 2;
|
||||
pub const OP_WRITE: u16 = 3;
|
||||
pub const OP_CLOSE: u16 = 4;
|
||||
pub const OP_OPENAT: u16 = 5;
|
||||
pub const OP_ACCESS: u16 = 6;
|
||||
pub const OP_FSTAT: u16 = 7;
|
||||
pub const OP_LSEEK: u16 = 8;
|
||||
pub const OP_DUP: u16 = 9;
|
||||
pub const OP_DUP_MIN: u16 = 10;
|
||||
pub const OP_DUP2: u16 = 11;
|
||||
pub const OP_GETCWD: u16 = 12;
|
||||
pub const OP_CHDIR: u16 = 13;
|
||||
pub const OP_MKDIR: u16 = 14;
|
||||
pub const OP_MKDIRAT: u16 = 15;
|
||||
pub const OP_TOUCH: u16 = 16;
|
||||
pub const OP_GETDENTS64: u16 = 17;
|
||||
pub const OP_STAT: u16 = 18;
|
||||
pub const OP_STATAT: u16 = 19;
|
||||
pub const OP_FTRUNCATE: u16 = 20;
|
||||
pub const OP_TRUNCATE: u16 = 21;
|
||||
|
||||
pub fn dispatch(_message: Message) -> isize {
|
||||
-38
|
||||
pub fn dispatch(message: Message) -> isize {
|
||||
match message.opcode {
|
||||
OP_OPEN => vfs::open_user_path_with_flags(message.args[0] as *const u8, message.args[1]),
|
||||
OP_OPENAT => vfs::openat_user_path(
|
||||
message.args[0] as isize,
|
||||
message.args[1] as *const u8,
|
||||
message.args[2],
|
||||
),
|
||||
OP_ACCESS => vfs::access_user_path(message.args[0] as *const u8),
|
||||
OP_READ => vfs::read(message.args[0], message.args[1] as *mut u8, message.args[2]),
|
||||
OP_WRITE => vfs::write(
|
||||
message.args[0],
|
||||
message.args[1] as *const u8,
|
||||
message.args[2],
|
||||
),
|
||||
OP_CLOSE => vfs::close(message.args[0]),
|
||||
OP_FSTAT => vfs::fstat(message.args[0], message.args[1] as *mut u8),
|
||||
OP_LSEEK => vfs::lseek(message.args[0], message.args[1] as isize, message.args[2]),
|
||||
OP_DUP => vfs::dup(message.args[0]),
|
||||
OP_DUP_MIN => vfs::dup_min(message.args[0], message.args[1]),
|
||||
OP_DUP2 => vfs::dup2(message.args[0], message.args[1]),
|
||||
OP_GETCWD => vfs::getcwd(message.args[0] as *mut u8, message.args[1]),
|
||||
OP_CHDIR => vfs::chdir_user_path(message.args[0] as *const u8),
|
||||
OP_MKDIR => vfs::mkdir_user_path(message.args[0] as *const u8),
|
||||
OP_MKDIRAT => {
|
||||
vfs::mkdirat_user_path(message.args[0] as isize, message.args[1] as *const u8)
|
||||
}
|
||||
OP_TOUCH => vfs::touch_user_path(message.args[0] as isize, message.args[1] as *const u8),
|
||||
OP_GETDENTS64 => {
|
||||
vfs::getdents64(message.args[0], message.args[1] as *mut u8, message.args[2])
|
||||
}
|
||||
OP_STAT => vfs::stat_user_path(message.args[0] as *const u8, message.args[1] as *mut u8),
|
||||
OP_STATAT => vfs::statat_user_path(
|
||||
message.args[0] as isize,
|
||||
message.args[1] as *const u8,
|
||||
message.args[2] as *mut u8,
|
||||
),
|
||||
OP_FTRUNCATE => vfs::ftruncate(message.args[0], message.args[1]),
|
||||
OP_TRUNCATE => vfs::truncate_user_path(message.args[0] as *const u8, message.args[1]),
|
||||
_ => -38,
|
||||
}
|
||||
}
|
||||
|
||||
pub const AT_FDCWD: isize = vfs::AT_FDCWD;
|
||||
|
||||
pub unsafe fn init() {
|
||||
unsafe { vfs::init() }
|
||||
}
|
||||
|
||||
pub fn open_user_path_with_flags(path: *const u8, flags: usize) -> isize {
|
||||
dispatch(message(OP_OPEN, [path as usize, flags, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn openat_user_path(dirfd: isize, path: *const u8, flags: usize) -> isize {
|
||||
dispatch(message(
|
||||
OP_OPENAT,
|
||||
[dirfd as usize, path as usize, flags, 0, 0, 0],
|
||||
))
|
||||
}
|
||||
|
||||
pub fn access_user_path(path: *const u8) -> isize {
|
||||
dispatch(message(OP_ACCESS, [path as usize, 0, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn is_tty(fd: usize) -> bool {
|
||||
vfs::is_tty(fd)
|
||||
}
|
||||
|
||||
pub fn read(fd: usize, buffer: *mut u8, len: usize) -> isize {
|
||||
dispatch(message(OP_READ, [fd, buffer as usize, len, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn write(fd: usize, buffer: *const u8, len: usize) -> isize {
|
||||
dispatch(message(OP_WRITE, [fd, buffer as usize, len, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn poll(fd: usize, events: i16) -> Option<i16> {
|
||||
vfs::poll(fd, events)
|
||||
}
|
||||
|
||||
pub fn close(fd: usize) -> isize {
|
||||
dispatch(message(OP_CLOSE, [fd, 0, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn fstat(fd: usize, stat: *mut u8) -> isize {
|
||||
dispatch(message(OP_FSTAT, [fd, stat as usize, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn ftruncate(fd: usize, size: usize) -> isize {
|
||||
dispatch(message(OP_FTRUNCATE, [fd, size, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn truncate_user_path(path: *const u8, size: usize) -> isize {
|
||||
dispatch(message(OP_TRUNCATE, [path as usize, size, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn lseek(fd: usize, offset: isize, whence: usize) -> isize {
|
||||
dispatch(message(OP_LSEEK, [fd, offset as usize, whence, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn dup(fd: usize) -> isize {
|
||||
dispatch(message(OP_DUP, [fd, 0, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn dup_min(fd: usize, min_newfd: usize) -> isize {
|
||||
dispatch(message(OP_DUP_MIN, [fd, min_newfd, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn dup2(oldfd: usize, newfd: usize) -> isize {
|
||||
dispatch(message(OP_DUP2, [oldfd, newfd, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn exec_path_user(path: *const u8) -> Option<[u8; 256]> {
|
||||
vfs::exec_path_user(path)
|
||||
}
|
||||
|
||||
pub fn getcwd(buffer: *mut u8, len: usize) -> isize {
|
||||
dispatch(message(OP_GETCWD, [buffer as usize, len, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn chdir_user_path(path: *const u8) -> isize {
|
||||
dispatch(message(OP_CHDIR, [path as usize, 0, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn mkdir_user_path(path: *const u8) -> isize {
|
||||
dispatch(message(OP_MKDIR, [path as usize, 0, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn mkdirat_user_path(dirfd: isize, path: *const u8) -> isize {
|
||||
dispatch(message(
|
||||
OP_MKDIRAT,
|
||||
[dirfd as usize, path as usize, 0, 0, 0, 0],
|
||||
))
|
||||
}
|
||||
|
||||
pub fn touch_user_path(dirfd: isize, path: *const u8) -> isize {
|
||||
dispatch(message(
|
||||
OP_TOUCH,
|
||||
[dirfd as usize, path as usize, 0, 0, 0, 0],
|
||||
))
|
||||
}
|
||||
|
||||
pub fn getdents64(fd: usize, buffer: *mut u8, len: usize) -> isize {
|
||||
dispatch(message(OP_GETDENTS64, [fd, buffer as usize, len, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn stat_user_path(path: *const u8, stat: *mut u8) -> isize {
|
||||
dispatch(message(OP_STAT, [path as usize, stat as usize, 0, 0, 0, 0]))
|
||||
}
|
||||
|
||||
pub fn statat_user_path(dirfd: isize, path: *const u8, stat: *mut u8) -> isize {
|
||||
dispatch(message(
|
||||
OP_STATAT,
|
||||
[dirfd as usize, path as usize, stat as usize, 0, 0, 0],
|
||||
))
|
||||
}
|
||||
|
||||
fn message(opcode: u16, args: [usize; 6]) -> Message {
|
||||
Message {
|
||||
sender: crate::task::current_pid(),
|
||||
opcode,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
+65
-36
@@ -1,13 +1,11 @@
|
||||
use core::arch::{asm, global_asm};
|
||||
|
||||
use crate::{
|
||||
console,
|
||||
drivers::platform::timer,
|
||||
elf,
|
||||
fs::vfs,
|
||||
gdt, ipc,
|
||||
elf, gdt, ipc,
|
||||
memory::{PAGE_SIZE, PhysicalMemoryManager},
|
||||
paging::{AddressSpace, PageFlags},
|
||||
services::{tty as tty_service, vfs},
|
||||
task, user,
|
||||
};
|
||||
|
||||
@@ -48,12 +46,17 @@ pub const SYS_FORK: usize = 57;
|
||||
pub const SYS_VFORK: usize = 58;
|
||||
pub const SYS_EXECVE: usize = 59;
|
||||
pub const SYS_WAIT4: usize = 61;
|
||||
pub const SYS_FSYNC: usize = 74;
|
||||
pub const SYS_FDATASYNC: usize = 75;
|
||||
pub const SYS_TRUNCATE: usize = 76;
|
||||
pub const SYS_FTRUNCATE: usize = 77;
|
||||
pub const SYS_FCNTL: usize = 72;
|
||||
pub const SYS_DUP: usize = 32;
|
||||
pub const SYS_DUP2: usize = 33;
|
||||
pub const SYS_GETDENTS64: usize = 217;
|
||||
pub const SYS_GETRANDOM: usize = 318;
|
||||
pub const SYS_PRLIMIT64: usize = 302;
|
||||
pub const SYS_SYNCFS: usize = 306;
|
||||
pub const SYS_GETPGID: usize = 121;
|
||||
pub const SYS_SETPGID: usize = 109;
|
||||
pub const SYS_GETSID: usize = 124;
|
||||
@@ -63,6 +66,7 @@ pub const SYS_CHDIR: usize = 80;
|
||||
pub const SYS_MKDIR: usize = 83;
|
||||
pub const SYS_READLINK: usize = 89;
|
||||
pub const SYS_PRCTL: usize = 157;
|
||||
pub const SYS_SYNC: usize = 162;
|
||||
pub const SYS_TIME: usize = 201;
|
||||
pub const SYS_GETUID: usize = 102;
|
||||
pub const SYS_GETGID: usize = 104;
|
||||
@@ -401,11 +405,15 @@ pub extern "C" fn zeroos_syscall_dispatch(
|
||||
SYS_VFORK => sys_vfork(frame),
|
||||
SYS_EXECVE => sys_execve(arg0 as *const u8, arg1 as *const *const u8, frame),
|
||||
SYS_WAIT4 => sys_wait4(arg0 as isize, arg1 as *mut i32),
|
||||
SYS_FSYNC | SYS_FDATASYNC => sys_sync(),
|
||||
SYS_TRUNCATE => vfs::truncate_user_path(arg0 as *const u8, arg1),
|
||||
SYS_FTRUNCATE => vfs::ftruncate(arg0, arg1),
|
||||
SYS_FCNTL => sys_fcntl(arg0, arg1, arg2),
|
||||
SYS_GETCWD => sys_getcwd(arg0 as *mut u8, arg1),
|
||||
SYS_CHDIR => sys_chdir(arg0 as *const u8),
|
||||
SYS_READLINK => -ENOENT,
|
||||
SYS_PRCTL => 0,
|
||||
SYS_SYNC => sys_sync(),
|
||||
SYS_TIME => sys_time(arg0 as *mut u64),
|
||||
SYS_UNAME => sys_uname(arg0 as *mut u8),
|
||||
SYS_GETUID | SYS_GETGID | SYS_GETEUID | SYS_GETEGID => 0,
|
||||
@@ -424,6 +432,7 @@ pub extern "C" fn zeroos_syscall_dispatch(
|
||||
SYS_RSEQ => sys_rseq(arg0, arg1, arg2),
|
||||
SYS_GETRANDOM => sys_getrandom(arg0 as *mut u8, arg1, arg2),
|
||||
SYS_PRLIMIT64 => sys_prlimit64(arg0, arg1, arg2 as *const u8, arg3 as *mut u8),
|
||||
SYS_SYNCFS => sys_sync(),
|
||||
SYS_GETDENTS64 => trace_fs_result(
|
||||
b"getdents",
|
||||
arg0,
|
||||
@@ -464,9 +473,9 @@ fn trace_syscall(number: usize) {
|
||||
}
|
||||
SYSCALL_TRACE_COUNT += 1;
|
||||
}
|
||||
console::write(b"sys ");
|
||||
tty_service::write(b"sys ");
|
||||
write_usize(number);
|
||||
console::write(b"\n");
|
||||
tty_service::write(b"\n");
|
||||
}
|
||||
|
||||
fn sys_read(fd: usize, buffer: *mut u8, len: usize) -> isize {
|
||||
@@ -477,6 +486,16 @@ fn sys_read(fd: usize, buffer: *mut u8, len: usize) -> isize {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if vfs::is_tty(fd) {
|
||||
loop {
|
||||
let read = vfs::read(fd, buffer, len);
|
||||
if read != 0 {
|
||||
return read;
|
||||
}
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if let Some(read) = ipc::read(fd, buffer, len) {
|
||||
if read != -EAGAIN {
|
||||
@@ -710,9 +729,9 @@ fn sys_fcntl(fd: usize, command: usize, arg: usize) -> isize {
|
||||
F_GETFL => 0,
|
||||
F_SETFL => 0,
|
||||
_ => {
|
||||
console::write(b"unsupported fcntl ");
|
||||
tty_service::write(b"unsupported fcntl ");
|
||||
write_usize(command);
|
||||
console::write(b"\n");
|
||||
tty_service::write(b"\n");
|
||||
-EINVAL
|
||||
}
|
||||
}
|
||||
@@ -726,7 +745,7 @@ fn sys_execve(path: *const u8, argv: *const *const u8, frame: *mut TrapFrame) ->
|
||||
if path.is_null() || frame.is_null() {
|
||||
return -EFAULT;
|
||||
}
|
||||
let Some((ptr, len)) = vfs::file_data_user_path(path) else {
|
||||
let Some(exec_path) = vfs::exec_path_user(path) else {
|
||||
return -ENOENT;
|
||||
};
|
||||
|
||||
@@ -738,11 +757,13 @@ fn sys_execve(path: *const u8, argv: *const *const u8, frame: *mut TrapFrame) ->
|
||||
args[index] = &arg_storage[index][..arg_lens[index]];
|
||||
}
|
||||
|
||||
let image = crate::fs::uefi::LoadedFile { ptr, len };
|
||||
unsafe {
|
||||
if MEMORY.is_null() {
|
||||
return -ENODEV;
|
||||
}
|
||||
let Ok(image) = crate::fs::lwext4::load_path(&mut *MEMORY, &exec_path) else {
|
||||
return -ENOENT;
|
||||
};
|
||||
let Some(program) = elf::load_user_elf(&image, &mut *MEMORY) else {
|
||||
return -ENOENT;
|
||||
};
|
||||
@@ -973,7 +994,7 @@ fn sys_ioctl(fd: usize, request: usize, arg: *mut u8, frame: *mut TrapFrame) ->
|
||||
if arg.is_null() {
|
||||
return -EBADF;
|
||||
}
|
||||
if fd > STDERR_FILENO && !vfs::is_tty(fd) {
|
||||
if fd > STDERR_FILENO && !tty_service::is_tty(fd) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
@@ -1000,7 +1021,7 @@ fn sys_ioctl(fd: usize, request: usize, arg: *mut u8, frame: *mut TrapFrame) ->
|
||||
0
|
||||
}
|
||||
TIOCGWINSZ => {
|
||||
let (columns, rows) = console::size();
|
||||
let (columns, rows) = tty_service::size();
|
||||
let winsize = arg as *mut u16;
|
||||
winsize.add(0).write(rows as u16);
|
||||
winsize.add(1).write(columns as u16);
|
||||
@@ -1034,7 +1055,7 @@ unsafe fn set_termios_mode(arg: *mut u8, _termios2: bool) {
|
||||
unsafe {
|
||||
let lflag = (arg as *const u32).add(3).read();
|
||||
const ICANON: u32 = 0o0000002;
|
||||
crate::console::set_raw_mode(lflag & ICANON == 0);
|
||||
tty_service::set_raw_mode(lflag & ICANON == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1134,7 +1155,7 @@ fn sys_arch_prctl(code: usize, addr: usize) -> isize {
|
||||
}
|
||||
|
||||
fn sys_isatty(fd: usize) -> isize {
|
||||
if fd <= STDERR_FILENO || vfs::is_tty(fd) {
|
||||
if fd <= STDERR_FILENO || tty_service::is_tty(fd) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@@ -1316,7 +1337,8 @@ fn sys_prlimit64(
|
||||
}
|
||||
|
||||
fn sys_exit(code: isize, frame: *mut TrapFrame) -> isize {
|
||||
crate::console::reset_terminal();
|
||||
let _ = crate::fs::lwext4::flush_cache();
|
||||
tty_service::reset_terminal();
|
||||
if !frame.is_null() && task::exit_current(code, unsafe { &mut *frame }) {
|
||||
restore_user_heap();
|
||||
return unsafe { (*frame).rax as isize };
|
||||
@@ -1329,6 +1351,13 @@ fn sys_exit(code: isize, frame: *mut TrapFrame) -> isize {
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_sync() -> isize {
|
||||
match crate::fs::lwext4::flush_cache() {
|
||||
Ok(()) => 0,
|
||||
Err(error) => error,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snapshot_user_heap() {
|
||||
unsafe {
|
||||
snapshot_user_elf_image();
|
||||
@@ -1426,9 +1455,9 @@ fn trace_unsupported_syscall(number: usize) {
|
||||
LAST_UNSUPPORTED_SYSCALL = number;
|
||||
}
|
||||
|
||||
console::write(b"unsupported syscall ");
|
||||
tty_service::write(b"unsupported syscall ");
|
||||
write_usize(number);
|
||||
console::write(b"\n");
|
||||
tty_service::write(b"\n");
|
||||
}
|
||||
|
||||
fn write_usize(mut value: usize) {
|
||||
@@ -1436,7 +1465,7 @@ fn write_usize(mut value: usize) {
|
||||
let mut index = buffer.len();
|
||||
|
||||
if value == 0 {
|
||||
console::write(b"0");
|
||||
tty_service::write(b"0");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1446,19 +1475,19 @@ fn write_usize(mut value: usize) {
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
console::write(&buffer[index..]);
|
||||
tty_service::write(&buffer[index..]);
|
||||
}
|
||||
|
||||
fn trace_alloc(name: &[u8], addr: usize, len: usize) {
|
||||
if !TRACE_ALLOC {
|
||||
return;
|
||||
}
|
||||
console::write(name);
|
||||
console::write(b" ");
|
||||
tty_service::write(name);
|
||||
tty_service::write(b" ");
|
||||
write_hex_usize(addr);
|
||||
console::write(b" ");
|
||||
tty_service::write(b" ");
|
||||
write_hex_usize(len);
|
||||
console::write(b"\n");
|
||||
tty_service::write(b"\n");
|
||||
}
|
||||
|
||||
fn trace_ioctl(request: usize, arg: usize, frame: *mut TrapFrame) {
|
||||
@@ -1471,42 +1500,42 @@ fn trace_ioctl(request: usize, arg: usize, frame: *mut TrapFrame) {
|
||||
}
|
||||
IOCTL_TRACE_COUNT += 1;
|
||||
}
|
||||
console::write(b"ioctl req=");
|
||||
tty_service::write(b"ioctl req=");
|
||||
write_hex_usize(request);
|
||||
console::write(b" arg=");
|
||||
tty_service::write(b" arg=");
|
||||
write_hex_usize(arg);
|
||||
if !frame.is_null() {
|
||||
let frame = unsafe { &*frame };
|
||||
console::write(b" ret=");
|
||||
tty_service::write(b" ret=");
|
||||
write_hex_usize(frame.rcx);
|
||||
console::write(b" rsp=");
|
||||
tty_service::write(b" rsp=");
|
||||
write_hex_usize(frame.rsp);
|
||||
}
|
||||
console::write(b"\n");
|
||||
tty_service::write(b"\n");
|
||||
}
|
||||
|
||||
fn trace_fs_result(name: &[u8], arg0: usize, arg1: usize, result: isize) -> isize {
|
||||
if !TRACE_FS_FDS {
|
||||
return result;
|
||||
}
|
||||
console::write(name);
|
||||
console::write(b" a0=");
|
||||
tty_service::write(name);
|
||||
tty_service::write(b" a0=");
|
||||
write_hex_usize(arg0);
|
||||
console::write(b" a1=");
|
||||
tty_service::write(b" a1=");
|
||||
write_hex_usize(arg1);
|
||||
console::write(b" -> ");
|
||||
tty_service::write(b" -> ");
|
||||
if result < 0 {
|
||||
console::write(b"-");
|
||||
tty_service::write(b"-");
|
||||
write_usize((-result) as usize);
|
||||
} else {
|
||||
write_usize(result as usize);
|
||||
}
|
||||
console::write(b"\n");
|
||||
tty_service::write(b"\n");
|
||||
result
|
||||
}
|
||||
|
||||
fn write_hex_usize(value: usize) {
|
||||
console::write(b"0x");
|
||||
tty_service::write(b"0x");
|
||||
let mut shift = usize::BITS as usize;
|
||||
let mut started = false;
|
||||
while shift > 0 {
|
||||
@@ -1519,7 +1548,7 @@ fn write_hex_usize(value: usize) {
|
||||
} else {
|
||||
b'a' + digit - 10
|
||||
};
|
||||
console::write(&[ch]);
|
||||
tty_service::write(&[ch]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
Submodule third_party/lwext4 added at 58bcf89a12
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef ZEROOS_ASSERT_H_
|
||||
#define ZEROOS_ASSERT_H_
|
||||
|
||||
#define assert(x) ((void)(x))
|
||||
|
||||
#endif
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef ZEROOS_ERRNO_H_
|
||||
#define ZEROOS_ERRNO_H_
|
||||
|
||||
#include <ext4_errno.h>
|
||||
|
||||
#endif
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef ZEROOS_FCNTL_H_
|
||||
#define ZEROOS_FCNTL_H_
|
||||
|
||||
#include <ext4_oflags.h>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef ZEROOS_LWEXT4_GENERATED_CONFIG_H_
|
||||
#define ZEROOS_LWEXT4_GENERATED_CONFIG_H_
|
||||
|
||||
#define CONFIG_EXT_FEATURE_SET_LVL F_SET_EXT4
|
||||
#define CONFIG_JOURNALING_ENABLE 0
|
||||
#define CONFIG_XATTR_ENABLE 1
|
||||
#define CONFIG_EXTENTS_ENABLE 1
|
||||
#define CONFIG_HAVE_OWN_ERRNO 1
|
||||
#define CONFIG_DEBUG_PRINTF 0
|
||||
#define CONFIG_DEBUG_ASSERT 0
|
||||
#define CONFIG_HAVE_OWN_ASSERT 1
|
||||
#define CONFIG_BLOCK_DEV_ENABLE_STATS 0
|
||||
#define CONFIG_BLOCK_DEV_CACHE_SIZE 16
|
||||
#define CONFIG_EXT4_MAX_BLOCKDEV_NAME 32
|
||||
#define CONFIG_EXT4_BLOCKDEVS_COUNT 2
|
||||
#define CONFIG_EXT4_MAX_MP_NAME 32
|
||||
#define CONFIG_EXT4_MOUNTPOINTS_COUNT 2
|
||||
#define CONFIG_HAVE_OWN_OFLAGS 1
|
||||
#define CONFIG_MAX_TRUNCATE_SIZE (16ul * 1024ul * 1024ul)
|
||||
#define CONFIG_UNALIGNED_ACCESS 0
|
||||
#define CONFIG_USE_USER_MALLOC 1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef ZEROOS_INTTYPES_H_
|
||||
#define ZEROOS_INTTYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PRIu64 "llu"
|
||||
#define PRId64 "lld"
|
||||
|
||||
#endif
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#ifndef ZEROOS_STDARG_H_
|
||||
#define ZEROOS_STDARG_H_
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||
#define va_end(ap) __builtin_va_end(ap)
|
||||
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||
|
||||
#endif
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#ifndef ZEROOS_STDBOOL_H_
|
||||
#define ZEROOS_STDBOOL_H_
|
||||
|
||||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#endif
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#ifndef ZEROOS_STDDEF_H_
|
||||
#define ZEROOS_STDDEF_H_
|
||||
|
||||
#define NULL ((void *)0)
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#ifndef ZEROOS_STDINT_H_
|
||||
#define ZEROOS_STDINT_H_
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
|
||||
#define UINT32_MAX 0xffffffffu
|
||||
#define UINT64_MAX 0xffffffffffffffffull
|
||||
|
||||
#endif
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#ifndef ZEROOS_STDIO_H_
|
||||
#define ZEROOS_STDIO_H_
|
||||
|
||||
#define stdout ((void *)0)
|
||||
int printf(const char *fmt, ...);
|
||||
int fflush(void *stream);
|
||||
|
||||
#endif
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#ifndef ZEROOS_STDLIB_H_
|
||||
#define ZEROOS_STDLIB_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void *ext4_user_malloc(size_t size);
|
||||
void *ext4_user_calloc(size_t count, size_t size);
|
||||
void ext4_user_free(void *ptr);
|
||||
void qsort(
|
||||
void *base,
|
||||
size_t nmemb,
|
||||
size_t size,
|
||||
int (*compar)(const void *, const void *)
|
||||
);
|
||||
|
||||
#endif
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#ifndef ZEROOS_STRING_H_
|
||||
#define ZEROOS_STRING_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
void *memset(void *dest, int c, size_t n);
|
||||
int memcmp(const void *a, const void *b, size_t n);
|
||||
size_t strlen(const char *s);
|
||||
int strcmp(const char *a, const char *b);
|
||||
int strncmp(const char *a, const char *b, size_t n);
|
||||
char *strcpy(char *dest, const char *src);
|
||||
|
||||
#endif
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef ZEROOS_UNISTD_H_
|
||||
#define ZEROOS_UNISTD_H_
|
||||
|
||||
#include <ext4_oflags.h>
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user