mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-13 00:24:41 +08:00
内存缓存和ext4完整支持
This commit is contained in:
@@ -8,6 +8,8 @@ members = ["boot"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
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::{
|
use crate::drivers::storage::{
|
||||||
ahci::AhciDisk,
|
ahci::AhciDisk,
|
||||||
block::{BlockDevice, BlockError},
|
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 ext4;
|
||||||
|
pub mod lwext4;
|
||||||
pub mod uefi;
|
pub mod uefi;
|
||||||
pub mod vfs;
|
pub mod vfs;
|
||||||
|
|||||||
+106
-19
@@ -15,7 +15,6 @@ const EINVAL: isize = 22;
|
|||||||
const ENOENT: isize = 2;
|
const ENOENT: isize = 2;
|
||||||
const ENOTDIR: isize = 20;
|
const ENOTDIR: isize = 20;
|
||||||
const EMFILE: isize = 24;
|
const EMFILE: isize = 24;
|
||||||
const EIO: isize = 5;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum Color {
|
enum Color {
|
||||||
@@ -226,12 +225,25 @@ impl Vfs {
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
let offset = self.fds[fd].offset.min(node.len);
|
if node.data.is_null() {
|
||||||
let available = node.len - offset;
|
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);
|
let count = len.min(available);
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
unsafe {
|
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;
|
self.fds[fd].offset = offset + count;
|
||||||
@@ -245,6 +257,9 @@ impl Vfs {
|
|||||||
let Some(node_index) = self.fds[fd].node else {
|
let Some(node_index) = self.fds[fd].node else {
|
||||||
return -EBADF;
|
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 {
|
if self.nodes[node_index].kind != NodeKind::CharDevice {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -253,6 +268,31 @@ impl Vfs {
|
|||||||
crate::console::write(buffer) as isize
|
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 {
|
fn close_fd(&mut self, fd: usize) -> isize {
|
||||||
if fd < 3 || fd >= MAX_FDS || self.fds[fd].node.is_none() {
|
if fd < 3 || fd >= MAX_FDS || self.fds[fd].node.is_none() {
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
@@ -298,7 +338,7 @@ impl Vfs {
|
|||||||
let Some(node_index) = self.fds[fd].node else {
|
let Some(node_index) = self.fds[fd].node else {
|
||||||
return -EBADF;
|
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 current = self.fds[fd].offset as isize;
|
||||||
let next = match whence {
|
let next = match whence {
|
||||||
0 => offset,
|
0 => offset,
|
||||||
@@ -323,6 +363,24 @@ impl Vfs {
|
|||||||
write_stat(stat, self.nodes[node_index])
|
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 {
|
fn is_tty_fd(&self, fd: usize) -> bool {
|
||||||
if fd >= MAX_FDS {
|
if fd >= MAX_FDS {
|
||||||
return false;
|
return false;
|
||||||
@@ -387,6 +445,22 @@ impl Vfs {
|
|||||||
write_stat(stat, self.nodes[node_index])
|
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 {
|
fn chdir_path(&mut self, path: &[u8]) -> isize {
|
||||||
let Some(node_index) = self.find(path) else {
|
let Some(node_index) = self.find(path) else {
|
||||||
return -ENOENT;
|
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 {
|
fn getcwd(&self, buffer: *mut u8, len: usize) -> isize {
|
||||||
if buffer.is_null() {
|
if buffer.is_null() {
|
||||||
return -EFAULT;
|
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<()> {
|
#[allow(dead_code)]
|
||||||
unsafe { vfs_mut().insert(path, NodeKind::Regular, data, len) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mount_ext4_node(path: &[u8], kind: NodeKind) -> Option<()> {
|
pub fn mount_ext4_node(path: &[u8], kind: NodeKind) -> Option<()> {
|
||||||
unsafe { vfs_mut().insert(path, kind, core::ptr::null(), 0) }
|
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) }
|
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 {
|
pub fn is_tty(fd: usize) -> bool {
|
||||||
unsafe { vfs_ref().is_tty_fd(fd) }
|
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) }
|
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 {
|
pub fn statat_user_path(dirfd: isize, path: *const u8, stat: *mut u8) -> isize {
|
||||||
if unsafe { path_starts_with_slash(path) } || dirfd == AT_FDCWD {
|
if unsafe { path_starts_with_slash(path) } || dirfd == AT_FDCWD {
|
||||||
return stat_user_path(path, stat);
|
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() } {
|
if unsafe { vfs_ref().find(path).is_some() } {
|
||||||
return 0;
|
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) },
|
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() } {
|
if unsafe { vfs_ref().find(path).is_some() } {
|
||||||
return 0;
|
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) },
|
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) }
|
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) }?;
|
let path = unsafe { read_user_path(path) }?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let index = vfs_ref().resolve_executable_path(&path)?;
|
let index = vfs_ref().resolve_executable_path(&path)?;
|
||||||
let node = &vfs_ref().nodes[index];
|
Some(vfs_ref().nodes[index].path)
|
||||||
if node.kind != NodeKind::Regular {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some((node.data, node.len))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+50
-114
@@ -84,87 +84,48 @@ extern "efiapi" fn efi_main(
|
|||||||
let _ = (stats.total_pages, stats.free_pages, stats.used_pages);
|
let _ = (stats.total_pages, stats.free_pages, stats.used_pages);
|
||||||
logger.ok(b"physical memory manager");
|
logger.ok(b"physical memory manager");
|
||||||
|
|
||||||
fs::vfs::init();
|
services::vfs::init();
|
||||||
logger.ok(b"vfs");
|
logger.ok(b"vfs");
|
||||||
ipc::init();
|
ipc::init();
|
||||||
logger.ok(b"ipc");
|
logger.ok(b"ipc");
|
||||||
|
|
||||||
let ahci_disks = drivers::storage::ahci::init(memory);
|
let storage = services::storage::init(memory);
|
||||||
let mut ext4_user_image = None;
|
if storage.ahci_disks > 0 {
|
||||||
let mut ext4_user_path = None;
|
|
||||||
if ahci_disks > 0 {
|
|
||||||
logger.ok(b"ahci");
|
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 {
|
} else {
|
||||||
logger.info(b"no ahci disk");
|
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 {
|
let (loaded_user_image, loaded_user_path) = match storage.userspace_image {
|
||||||
(Some(image), ext4_user_path)
|
Some(image) => (Some(image), storage.userspace_path),
|
||||||
} else if let Some(image) =
|
None => {
|
||||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::BASH_PATH)
|
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) =
|
(Some(image), Some(b"/bin/bash" as &'static [u8]))
|
||||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::SH_PATH)
|
} 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 {
|
(Some(image), Some(b"/bin/sh" as &'static [u8]))
|
||||||
(None, None)
|
} 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);
|
|
||||||
}
|
}
|
||||||
logger.ok(b"userspace image loaded from esp");
|
};
|
||||||
|
if loaded_user_image.is_some() {
|
||||||
|
logger.ok(b"userspace image loaded");
|
||||||
} else {
|
} else {
|
||||||
logger.info(b"no /bin/bash or /bin/sh on esp, using built-in user program");
|
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");
|
logger.ok(b"address space");
|
||||||
|
|
||||||
let mut userspace_program = None;
|
let mut userspace_program = None;
|
||||||
let user_entry = if let Some(image) = loaded_user_image {
|
let user_entry = if let Some(ref image) = loaded_user_image {
|
||||||
match elf::load_user_elf(&image, memory) {
|
match elf::load_user_elf(image, memory) {
|
||||||
Some(program) => {
|
Some(program) => {
|
||||||
logger.ok(b"elf userspace program");
|
logger.ok(b"elf userspace program");
|
||||||
userspace_program = Some(user::UserAux {
|
userspace_program = Some(user::UserAux {
|
||||||
@@ -209,6 +170,13 @@ extern "efiapi" fn efi_main(
|
|||||||
} else {
|
} else {
|
||||||
None
|
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 {
|
let Some(test_page) = memory.alloc_page() else {
|
||||||
halt_forever();
|
halt_forever();
|
||||||
@@ -251,16 +219,10 @@ extern "efiapi" fn efi_main(
|
|||||||
logger.ok(b"cr3");
|
logger.ok(b"cr3");
|
||||||
tty.clear();
|
tty.clear();
|
||||||
if user_entry.is_some() {
|
if user_entry.is_some() {
|
||||||
if loaded_user_path == Some(b"/usr/bin/busybox" as &'static [u8]) {
|
console::write(b"enter userspace: ");
|
||||||
console::write(b"enter userspace: /usr/bin/busybox sh\r\n");
|
console::write(user_args[0]);
|
||||||
} else if loaded_user_path == Some(b"/usr/bin/sh" as &'static [u8]) {
|
console::write(b"\r\n");
|
||||||
console::write(b"enter userspace: /usr/bin/sh\r\n");
|
} else if loaded_user_image.is_some() {
|
||||||
} 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"/bin/bash found but ELF load failed; enter built-in userspace\r\n");
|
console::write(b"/bin/bash found but ELF load failed; enter built-in userspace\r\n");
|
||||||
} else {
|
} else {
|
||||||
console::write(b"/bin/bash not found on ESP; enter built-in userspace\r\n");
|
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);
|
syscall::init(memory, &raw mut address_space);
|
||||||
io::enable_interrupts();
|
io::enable_interrupts();
|
||||||
if let Some(entry) = user_entry {
|
if let Some(entry) = user_entry {
|
||||||
if loaded_user_path == Some(b"/usr/bin/busybox" as &'static [u8]) {
|
user::enter_elf_with_args(
|
||||||
user::enter_elf_with_args(
|
entry,
|
||||||
entry,
|
user_args,
|
||||||
&[b"/usr/bin/busybox", b"sh"],
|
user_program_or_default(user_entry, userspace_program),
|
||||||
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),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
user::enter();
|
user::enter();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
pub mod storage;
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
pub mod vfs;
|
pub mod vfs;
|
||||||
|
|
||||||
pub const SERVICE_VFS: usize = 1;
|
pub const SERVICE_VFS: usize = 1;
|
||||||
pub const SERVICE_TTY: usize = 2;
|
pub const SERVICE_TTY: usize = 2;
|
||||||
|
pub const SERVICE_STORAGE: usize = 3;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ServiceRequest {
|
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_READ: u16 = 1;
|
||||||
pub const OP_WRITE: u16 = 2;
|
pub const OP_WRITE: u16 = 2;
|
||||||
pub const OP_IOCTL: u16 = 3;
|
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 {
|
pub fn dispatch(message: Message) -> isize {
|
||||||
-38
|
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_OPEN: u16 = 1;
|
||||||
pub const OP_READ: u16 = 2;
|
pub const OP_READ: u16 = 2;
|
||||||
pub const OP_WRITE: u16 = 3;
|
pub const OP_WRITE: u16 = 3;
|
||||||
pub const OP_CLOSE: u16 = 4;
|
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 {
|
pub fn dispatch(message: Message) -> isize {
|
||||||
-38
|
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 core::arch::{asm, global_asm};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
console,
|
|
||||||
drivers::platform::timer,
|
drivers::platform::timer,
|
||||||
elf,
|
elf, gdt, ipc,
|
||||||
fs::vfs,
|
|
||||||
gdt, ipc,
|
|
||||||
memory::{PAGE_SIZE, PhysicalMemoryManager},
|
memory::{PAGE_SIZE, PhysicalMemoryManager},
|
||||||
paging::{AddressSpace, PageFlags},
|
paging::{AddressSpace, PageFlags},
|
||||||
|
services::{tty as tty_service, vfs},
|
||||||
task, user,
|
task, user,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,12 +46,17 @@ pub const SYS_FORK: usize = 57;
|
|||||||
pub const SYS_VFORK: usize = 58;
|
pub const SYS_VFORK: usize = 58;
|
||||||
pub const SYS_EXECVE: usize = 59;
|
pub const SYS_EXECVE: usize = 59;
|
||||||
pub const SYS_WAIT4: usize = 61;
|
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_FCNTL: usize = 72;
|
||||||
pub const SYS_DUP: usize = 32;
|
pub const SYS_DUP: usize = 32;
|
||||||
pub const SYS_DUP2: usize = 33;
|
pub const SYS_DUP2: usize = 33;
|
||||||
pub const SYS_GETDENTS64: usize = 217;
|
pub const SYS_GETDENTS64: usize = 217;
|
||||||
pub const SYS_GETRANDOM: usize = 318;
|
pub const SYS_GETRANDOM: usize = 318;
|
||||||
pub const SYS_PRLIMIT64: usize = 302;
|
pub const SYS_PRLIMIT64: usize = 302;
|
||||||
|
pub const SYS_SYNCFS: usize = 306;
|
||||||
pub const SYS_GETPGID: usize = 121;
|
pub const SYS_GETPGID: usize = 121;
|
||||||
pub const SYS_SETPGID: usize = 109;
|
pub const SYS_SETPGID: usize = 109;
|
||||||
pub const SYS_GETSID: usize = 124;
|
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_MKDIR: usize = 83;
|
||||||
pub const SYS_READLINK: usize = 89;
|
pub const SYS_READLINK: usize = 89;
|
||||||
pub const SYS_PRCTL: usize = 157;
|
pub const SYS_PRCTL: usize = 157;
|
||||||
|
pub const SYS_SYNC: usize = 162;
|
||||||
pub const SYS_TIME: usize = 201;
|
pub const SYS_TIME: usize = 201;
|
||||||
pub const SYS_GETUID: usize = 102;
|
pub const SYS_GETUID: usize = 102;
|
||||||
pub const SYS_GETGID: usize = 104;
|
pub const SYS_GETGID: usize = 104;
|
||||||
@@ -401,11 +405,15 @@ pub extern "C" fn zeroos_syscall_dispatch(
|
|||||||
SYS_VFORK => sys_vfork(frame),
|
SYS_VFORK => sys_vfork(frame),
|
||||||
SYS_EXECVE => sys_execve(arg0 as *const u8, arg1 as *const *const u8, 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_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_FCNTL => sys_fcntl(arg0, arg1, arg2),
|
||||||
SYS_GETCWD => sys_getcwd(arg0 as *mut u8, arg1),
|
SYS_GETCWD => sys_getcwd(arg0 as *mut u8, arg1),
|
||||||
SYS_CHDIR => sys_chdir(arg0 as *const u8),
|
SYS_CHDIR => sys_chdir(arg0 as *const u8),
|
||||||
SYS_READLINK => -ENOENT,
|
SYS_READLINK => -ENOENT,
|
||||||
SYS_PRCTL => 0,
|
SYS_PRCTL => 0,
|
||||||
|
SYS_SYNC => sys_sync(),
|
||||||
SYS_TIME => sys_time(arg0 as *mut u64),
|
SYS_TIME => sys_time(arg0 as *mut u64),
|
||||||
SYS_UNAME => sys_uname(arg0 as *mut u8),
|
SYS_UNAME => sys_uname(arg0 as *mut u8),
|
||||||
SYS_GETUID | SYS_GETGID | SYS_GETEUID | SYS_GETEGID => 0,
|
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_RSEQ => sys_rseq(arg0, arg1, arg2),
|
||||||
SYS_GETRANDOM => sys_getrandom(arg0 as *mut u8, 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_PRLIMIT64 => sys_prlimit64(arg0, arg1, arg2 as *const u8, arg3 as *mut u8),
|
||||||
|
SYS_SYNCFS => sys_sync(),
|
||||||
SYS_GETDENTS64 => trace_fs_result(
|
SYS_GETDENTS64 => trace_fs_result(
|
||||||
b"getdents",
|
b"getdents",
|
||||||
arg0,
|
arg0,
|
||||||
@@ -464,9 +473,9 @@ fn trace_syscall(number: usize) {
|
|||||||
}
|
}
|
||||||
SYSCALL_TRACE_COUNT += 1;
|
SYSCALL_TRACE_COUNT += 1;
|
||||||
}
|
}
|
||||||
console::write(b"sys ");
|
tty_service::write(b"sys ");
|
||||||
write_usize(number);
|
write_usize(number);
|
||||||
console::write(b"\n");
|
tty_service::write(b"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sys_read(fd: usize, buffer: *mut u8, len: usize) -> isize {
|
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;
|
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 {
|
loop {
|
||||||
if let Some(read) = ipc::read(fd, buffer, len) {
|
if let Some(read) = ipc::read(fd, buffer, len) {
|
||||||
if read != -EAGAIN {
|
if read != -EAGAIN {
|
||||||
@@ -710,9 +729,9 @@ fn sys_fcntl(fd: usize, command: usize, arg: usize) -> isize {
|
|||||||
F_GETFL => 0,
|
F_GETFL => 0,
|
||||||
F_SETFL => 0,
|
F_SETFL => 0,
|
||||||
_ => {
|
_ => {
|
||||||
console::write(b"unsupported fcntl ");
|
tty_service::write(b"unsupported fcntl ");
|
||||||
write_usize(command);
|
write_usize(command);
|
||||||
console::write(b"\n");
|
tty_service::write(b"\n");
|
||||||
-EINVAL
|
-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() {
|
if path.is_null() || frame.is_null() {
|
||||||
return -EFAULT;
|
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;
|
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]];
|
args[index] = &arg_storage[index][..arg_lens[index]];
|
||||||
}
|
}
|
||||||
|
|
||||||
let image = crate::fs::uefi::LoadedFile { ptr, len };
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if MEMORY.is_null() {
|
if MEMORY.is_null() {
|
||||||
return -ENODEV;
|
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 {
|
let Some(program) = elf::load_user_elf(&image, &mut *MEMORY) else {
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
};
|
};
|
||||||
@@ -973,7 +994,7 @@ fn sys_ioctl(fd: usize, request: usize, arg: *mut u8, frame: *mut TrapFrame) ->
|
|||||||
if arg.is_null() {
|
if arg.is_null() {
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
}
|
}
|
||||||
if fd > STDERR_FILENO && !vfs::is_tty(fd) {
|
if fd > STDERR_FILENO && !tty_service::is_tty(fd) {
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,7 +1021,7 @@ fn sys_ioctl(fd: usize, request: usize, arg: *mut u8, frame: *mut TrapFrame) ->
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
TIOCGWINSZ => {
|
TIOCGWINSZ => {
|
||||||
let (columns, rows) = console::size();
|
let (columns, rows) = tty_service::size();
|
||||||
let winsize = arg as *mut u16;
|
let winsize = arg as *mut u16;
|
||||||
winsize.add(0).write(rows as u16);
|
winsize.add(0).write(rows as u16);
|
||||||
winsize.add(1).write(columns as u16);
|
winsize.add(1).write(columns as u16);
|
||||||
@@ -1034,7 +1055,7 @@ unsafe fn set_termios_mode(arg: *mut u8, _termios2: bool) {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let lflag = (arg as *const u32).add(3).read();
|
let lflag = (arg as *const u32).add(3).read();
|
||||||
const ICANON: u32 = 0o0000002;
|
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 {
|
fn sys_isatty(fd: usize) -> isize {
|
||||||
if fd <= STDERR_FILENO || vfs::is_tty(fd) {
|
if fd <= STDERR_FILENO || tty_service::is_tty(fd) {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
@@ -1316,7 +1337,8 @@ fn sys_prlimit64(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sys_exit(code: isize, frame: *mut TrapFrame) -> isize {
|
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 }) {
|
if !frame.is_null() && task::exit_current(code, unsafe { &mut *frame }) {
|
||||||
restore_user_heap();
|
restore_user_heap();
|
||||||
return unsafe { (*frame).rax as isize };
|
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() {
|
pub fn snapshot_user_heap() {
|
||||||
unsafe {
|
unsafe {
|
||||||
snapshot_user_elf_image();
|
snapshot_user_elf_image();
|
||||||
@@ -1426,9 +1455,9 @@ fn trace_unsupported_syscall(number: usize) {
|
|||||||
LAST_UNSUPPORTED_SYSCALL = number;
|
LAST_UNSUPPORTED_SYSCALL = number;
|
||||||
}
|
}
|
||||||
|
|
||||||
console::write(b"unsupported syscall ");
|
tty_service::write(b"unsupported syscall ");
|
||||||
write_usize(number);
|
write_usize(number);
|
||||||
console::write(b"\n");
|
tty_service::write(b"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_usize(mut value: usize) {
|
fn write_usize(mut value: usize) {
|
||||||
@@ -1436,7 +1465,7 @@ fn write_usize(mut value: usize) {
|
|||||||
let mut index = buffer.len();
|
let mut index = buffer.len();
|
||||||
|
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
console::write(b"0");
|
tty_service::write(b"0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1446,19 +1475,19 @@ fn write_usize(mut value: usize) {
|
|||||||
value /= 10;
|
value /= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
console::write(&buffer[index..]);
|
tty_service::write(&buffer[index..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_alloc(name: &[u8], addr: usize, len: usize) {
|
fn trace_alloc(name: &[u8], addr: usize, len: usize) {
|
||||||
if !TRACE_ALLOC {
|
if !TRACE_ALLOC {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console::write(name);
|
tty_service::write(name);
|
||||||
console::write(b" ");
|
tty_service::write(b" ");
|
||||||
write_hex_usize(addr);
|
write_hex_usize(addr);
|
||||||
console::write(b" ");
|
tty_service::write(b" ");
|
||||||
write_hex_usize(len);
|
write_hex_usize(len);
|
||||||
console::write(b"\n");
|
tty_service::write(b"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_ioctl(request: usize, arg: usize, frame: *mut TrapFrame) {
|
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;
|
IOCTL_TRACE_COUNT += 1;
|
||||||
}
|
}
|
||||||
console::write(b"ioctl req=");
|
tty_service::write(b"ioctl req=");
|
||||||
write_hex_usize(request);
|
write_hex_usize(request);
|
||||||
console::write(b" arg=");
|
tty_service::write(b" arg=");
|
||||||
write_hex_usize(arg);
|
write_hex_usize(arg);
|
||||||
if !frame.is_null() {
|
if !frame.is_null() {
|
||||||
let frame = unsafe { &*frame };
|
let frame = unsafe { &*frame };
|
||||||
console::write(b" ret=");
|
tty_service::write(b" ret=");
|
||||||
write_hex_usize(frame.rcx);
|
write_hex_usize(frame.rcx);
|
||||||
console::write(b" rsp=");
|
tty_service::write(b" rsp=");
|
||||||
write_hex_usize(frame.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 {
|
fn trace_fs_result(name: &[u8], arg0: usize, arg1: usize, result: isize) -> isize {
|
||||||
if !TRACE_FS_FDS {
|
if !TRACE_FS_FDS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
console::write(name);
|
tty_service::write(name);
|
||||||
console::write(b" a0=");
|
tty_service::write(b" a0=");
|
||||||
write_hex_usize(arg0);
|
write_hex_usize(arg0);
|
||||||
console::write(b" a1=");
|
tty_service::write(b" a1=");
|
||||||
write_hex_usize(arg1);
|
write_hex_usize(arg1);
|
||||||
console::write(b" -> ");
|
tty_service::write(b" -> ");
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
console::write(b"-");
|
tty_service::write(b"-");
|
||||||
write_usize((-result) as usize);
|
write_usize((-result) as usize);
|
||||||
} else {
|
} else {
|
||||||
write_usize(result as usize);
|
write_usize(result as usize);
|
||||||
}
|
}
|
||||||
console::write(b"\n");
|
tty_service::write(b"\n");
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_hex_usize(value: usize) {
|
fn write_hex_usize(value: usize) {
|
||||||
console::write(b"0x");
|
tty_service::write(b"0x");
|
||||||
let mut shift = usize::BITS as usize;
|
let mut shift = usize::BITS as usize;
|
||||||
let mut started = false;
|
let mut started = false;
|
||||||
while shift > 0 {
|
while shift > 0 {
|
||||||
@@ -1519,7 +1548,7 @@ fn write_hex_usize(value: usize) {
|
|||||||
} else {
|
} else {
|
||||||
b'a' + digit - 10
|
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