mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
feat(syscall): 添加syscall table的实现 (#1164)
* feat(syscall): 添加syscall table的实现 - 实现syscall table - 为syscall table适配write/writev、read和readv系统调用 --------- Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
parent
545bc2c346
commit
b322121dd9
@ -17,7 +17,7 @@ import os
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'DragonOS'
|
||||
copyright = '2022-2024, DragonOS Community'
|
||||
copyright = '2022-2025, DragonOS Community'
|
||||
author = 'longjin'
|
||||
github_org = 'DragonOS-Community'
|
||||
github_repo = 'DragonOS'
|
||||
@ -31,7 +31,12 @@ release = 'dev'
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['myst_parser', 'sphinx_multiversion']
|
||||
extensions = [
|
||||
'myst_parser',
|
||||
'sphinx_multiversion',
|
||||
'sphinxcontrib.mermaid',
|
||||
'sphinx.ext.extlinks',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
@ -33,6 +33,7 @@
|
||||
kernel/container/index
|
||||
kernel/libs/index
|
||||
kernel/trace/index
|
||||
kernel/syscall/index
|
||||
|
||||
|
||||
|
||||
@ -42,11 +43,6 @@
|
||||
|
||||
userland/appdev/index
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: 系统调用api文档
|
||||
|
||||
syscall_api/index
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
@ -67,7 +67,7 @@ Syscall: │ sys_open, sys_read, sys_write, sys_close, │
|
||||
- `sys_fchmod`:修改文件权限(未实现)
|
||||
- 其他系统调用接口(未实现)
|
||||
|
||||
  关于接口的具体含义,可以参考 [DragonOS系统调用接口](../../syscall_api/index.rst)。
|
||||
  关于接口的具体含义,可以参考Linux的相关文档。
|
||||
|
||||
## 虚拟文件系统(VFS)
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
.. _syscall_api:
|
||||
.. _syscall:
|
||||
|
||||
系统调用API
|
||||
系统调用
|
||||
====================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: 目录
|
||||
|
||||
intro
|
||||
syscall_table
|
120
docs/kernel/syscall/syscall_table.rst
Normal file
120
docs/kernel/syscall/syscall_table.rst
Normal file
@ -0,0 +1,120 @@
|
||||
系统调用表实现方案
|
||||
====================
|
||||
|
||||
.. note::
|
||||
Author: longjin <longjin@dragonos.org>
|
||||
|
||||
Date: 2025/05/13
|
||||
|
||||
概述
|
||||
----
|
||||
|
||||
.. mermaid::
|
||||
:align: center
|
||||
:caption: 系统调用表架构
|
||||
|
||||
classDiagram
|
||||
class Syscall {
|
||||
<<trait>>
|
||||
+num_args() usize
|
||||
+handle(args, from_user) Result<usize, SystemError>
|
||||
+entry_format(args) Vec<FormattedSyscallParam>
|
||||
}
|
||||
|
||||
class SyscallHandle {
|
||||
+nr: usize
|
||||
+inner_handle: &dyn Syscall
|
||||
}
|
||||
|
||||
class SyscallTable {
|
||||
-entries: [Option<&SyscallHandle>; 512]
|
||||
+get(nr) Option<&dyn Syscall>
|
||||
}
|
||||
|
||||
Syscall <|.. SysXXXXXXHandle
|
||||
SyscallHandle "1" *-- "1" Syscall
|
||||
SyscallTable "1" *-- "512" SyscallHandle
|
||||
|
||||
相比于将原本集中在一个大match中的系统调用分发,本方案采用基于trait和系统调用表的实现。主要优势包括:
|
||||
|
||||
- 降低栈内存使用:避免单个大函数占用过多栈空间
|
||||
- 支持参数打印:通过统一的参数格式化接口
|
||||
- 更好的扩展性:新增系统调用无需修改分发逻辑
|
||||
|
||||
核心设计
|
||||
--------
|
||||
|
||||
Syscall Trait
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
所有系统调用处理函数都需要实现 `Syscall` trait:
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub trait Syscall: Send + Sync + 'static {
|
||||
fn num_args(&self) -> usize;
|
||||
fn handle(&self, args: &[usize], from_user: bool) -> Result<usize, SystemError>;
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam>;
|
||||
}
|
||||
|
||||
- `num_args()`: 返回该系统调用需要的参数数量
|
||||
- `handle()`: 实际执行系统调用处理
|
||||
- `entry_format()`: 格式化参数用于调试打印
|
||||
|
||||
SyscallHandle
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
`SyscallHandle` 结构体将系统调用号与处理函数关联:
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub struct SyscallHandle {
|
||||
pub nr: usize, // 系统调用号
|
||||
pub inner_handle: &'static dyn Syscall, // 处理函数
|
||||
pub name: &'static str,
|
||||
}
|
||||
|
||||
SyscallTable
|
||||
~~~~~~~~~~~~
|
||||
|
||||
`SyscallTable` 管理所有系统调用:
|
||||
|
||||
- 固定大小512项
|
||||
- 编译时初始化
|
||||
- 通过系统调用号快速查找处理函数
|
||||
|
||||
使用方式
|
||||
--------
|
||||
|
||||
实现系统调用
|
||||
~~~~~~~~~~~~
|
||||
|
||||
1. 定义实现``Syscall`` trait的结构体
|
||||
2. 实现``handle()``和``entry_format()``方法
|
||||
3. 使用``declare_syscall!``宏注册
|
||||
|
||||
参考实现:`sys_write.rs <sys_write_>`_
|
||||
|
||||
.. _sys_write:
|
||||
https://github.com/DragonOS-Community/DragonOS/blob/master/kernel/src/filesystem/vfs/syscall/sys_write.rs
|
||||
|
||||
注册系统调用
|
||||
~~~~~~~~~~~~
|
||||
|
||||
使用``declare_syscall!``宏注册系统调用:
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
syscall_table_macros::declare_syscall!(SYS_WRITE, SysWriteHandle);
|
||||
|
||||
参数说明:
|
||||
|
||||
1. 系统调用名称(用于生成符号)
|
||||
2. 实现``Syscall`` trait的结构体
|
||||
|
||||
初始化流程
|
||||
----------
|
||||
|
||||
1. 内核启动时调用``syscall_table_init()``
|
||||
2. 从链接器符号``_syscall_table``加载所有注册的系统调用
|
||||
3. 填充系统调用表
|
@ -1,4 +1,5 @@
|
||||
sphinx==5.0.2
|
||||
myst-parser==0.18.0
|
||||
sphinx-rtd-theme
|
||||
sphinxcontrib-mermaid==1.0.0
|
||||
git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/sphinx-multiversion.git@5858b75#egg=sphinx-multiversion
|
||||
|
@ -1 +0,0 @@
|
||||
# 简介
|
5
kernel/Cargo.lock
generated
5
kernel/Cargo.lock
generated
@ -531,6 +531,7 @@ dependencies = [
|
||||
"slabmalloc",
|
||||
"smoltcp",
|
||||
"static-keys",
|
||||
"syscall_table_macros",
|
||||
"system_error",
|
||||
"uefi",
|
||||
"uefi-raw",
|
||||
@ -1665,6 +1666,10 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syscall_table_macros"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "system_error"
|
||||
version = "0.1.0"
|
||||
|
@ -60,6 +60,7 @@ smoltcp = { version = "=0.11.0", default-features = false, features = [
|
||||
"proto-ipv4",
|
||||
"proto-ipv6",
|
||||
] }
|
||||
syscall_table_macros = { path = "crates/syscall_table_macros" }
|
||||
system_error = { path = "crates/system_error" }
|
||||
uefi = { version = "=0.26.0", features = ["alloc"] }
|
||||
uefi-raw = "=0.5.0"
|
||||
|
7
kernel/crates/syscall_table_macros/Cargo.toml
Normal file
7
kernel/crates/syscall_table_macros/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "syscall_table_macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
19
kernel/crates/syscall_table_macros/src/lib.rs
Normal file
19
kernel/crates/syscall_table_macros/src/lib.rs
Normal file
@ -0,0 +1,19 @@
|
||||
#![no_std]
|
||||
#![deny(clippy::all)]
|
||||
|
||||
#[macro_export]
|
||||
#[allow(clippy::crate_in_macro_def)]
|
||||
macro_rules! declare_syscall {
|
||||
($nr:ident, $inner_handle:ident) => {
|
||||
paste::paste! {
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[link_section = ".syscall_table"]
|
||||
#[used]
|
||||
pub static [<HANDLE_ $nr>]: crate::syscall::table::SyscallHandle = crate::syscall::table::SyscallHandle {
|
||||
nr: $nr,
|
||||
inner_handle: &$inner_handle,
|
||||
name: stringify!($nr),
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
@ -74,8 +74,18 @@ SECTIONS
|
||||
*(.tracepoint.*)
|
||||
_etracepoint = .;
|
||||
}
|
||||
. = ALIGN(32768);
|
||||
|
||||
. = ALIGN(4096);
|
||||
syscall_table_start_pa = .;
|
||||
.syscall_table (syscall_table_start_pa):
|
||||
{
|
||||
_syscall_table = .;
|
||||
*(.syscall_table)
|
||||
*(.syscall_table.*)
|
||||
_esyscall_table = .;
|
||||
}
|
||||
|
||||
. = ALIGN(32768);
|
||||
init_proc_union_start_pa = .;
|
||||
.data.init_proc_union (init_proc_union_start_pa):
|
||||
{ *(.data.init_proc_union) }
|
||||
|
@ -76,8 +76,19 @@ SECTIONS
|
||||
*(.tracepoint.*)
|
||||
_etracepoint = .;
|
||||
}
|
||||
. = ALIGN(32768);
|
||||
|
||||
. = ALIGN(4096);
|
||||
|
||||
syscall_table_start_pa = .;
|
||||
.syscall_table (syscall_table_start_pa): AT(syscall_table_start_pa - KERNEL_VMA)
|
||||
{
|
||||
_syscall_table = .;
|
||||
*(.syscall_table)
|
||||
*(.syscall_table.*)
|
||||
_esyscall_table = .;
|
||||
}
|
||||
|
||||
. = ALIGN(32768);
|
||||
init_proc_union_start_pa = .;
|
||||
.data.init_proc_union (init_proc_union_start_pa): AT(init_proc_union_start_pa - KERNEL_VMA)
|
||||
{ *(.data.init_proc_union) }
|
||||
|
@ -40,7 +40,7 @@ SECTIONS
|
||||
_etext = .;
|
||||
__etext = .;
|
||||
}
|
||||
. = ALIGN(32768);
|
||||
. = ALIGN(4096);
|
||||
data_start_pa = .;
|
||||
.data (data_start_pa): AT(data_start_pa - KERNEL_VMA)
|
||||
{
|
||||
@ -51,7 +51,7 @@ SECTIONS
|
||||
_edata = .;
|
||||
}
|
||||
|
||||
. = ALIGN(32768);
|
||||
. = ALIGN(4096);
|
||||
|
||||
rodata_start_pa = .;
|
||||
.rodata (rodata_start_pa): AT(rodata_start_pa - KERNEL_VMA)
|
||||
@ -65,7 +65,7 @@ SECTIONS
|
||||
_erodata = .;
|
||||
}
|
||||
|
||||
. = ALIGN(32768);
|
||||
. = ALIGN(4096);
|
||||
|
||||
trace_point_start_pa = .;
|
||||
.tracepoint (trace_point_start_pa): AT(trace_point_start_pa - KERNEL_VMA)
|
||||
@ -75,8 +75,18 @@ SECTIONS
|
||||
*(.tracepoint.*)
|
||||
_etracepoint = .;
|
||||
}
|
||||
. = ALIGN(32768);
|
||||
. = ALIGN(4096);
|
||||
|
||||
syscall_table_start_pa = .;
|
||||
.syscall_table (syscall_table_start_pa): AT(syscall_table_start_pa - KERNEL_VMA)
|
||||
{
|
||||
_syscall_table = .;
|
||||
*(.syscall_table)
|
||||
*(.syscall_table.*)
|
||||
_esyscall_table = .;
|
||||
}
|
||||
|
||||
. = ALIGN(32768);
|
||||
init_proc_union_start_pa = .;
|
||||
.data.init_proc_union (init_proc_union_start_pa): AT(init_proc_union_start_pa - KERNEL_VMA)
|
||||
{ *(.data.init_proc_union) }
|
||||
|
@ -4,7 +4,6 @@ use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use log::debug;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
@ -106,7 +105,7 @@ impl MbrDiskPartionTable {
|
||||
table.dpte[i].starting_lba = cursor.read_u32()?;
|
||||
table.dpte[i].total_sectors = cursor.read_u32()?;
|
||||
|
||||
debug!("dpte[{i}] = {:?}", table.dpte[i]);
|
||||
// debug!("dpte[{i}] = {:?}", table.dpte[i]);
|
||||
}
|
||||
table.bs_trailsig = cursor.read_u16()?;
|
||||
// debug!("bs_trailsig = {}", unsafe {
|
||||
|
149
kernel/src/filesystem/vfs/iov.rs
Normal file
149
kernel/src/filesystem/vfs/iov.rs
Normal file
@ -0,0 +1,149 @@
|
||||
use alloc::vec::Vec;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::syscall::user_access::{UserBufferReader, UserBufferWriter};
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct IoVec {
|
||||
/// 缓冲区的起始地址
|
||||
pub iov_base: *mut u8,
|
||||
/// 缓冲区的长度
|
||||
pub iov_len: usize,
|
||||
}
|
||||
|
||||
/// 用于存储多个来自用户空间的IoVec
|
||||
///
|
||||
/// 由于目前内核中的文件系统还不支持分散读写,所以暂时只支持将用户空间的IoVec聚合成一个缓冲区,然后进行操作。
|
||||
/// TODO:支持分散读写
|
||||
#[derive(Debug)]
|
||||
pub struct IoVecs(Vec<IoVec>);
|
||||
|
||||
impl IoVecs {
|
||||
/// 获取IoVecs中所有缓冲区的总长度
|
||||
#[inline(never)]
|
||||
pub fn total_len(&self) -> usize {
|
||||
self.0.iter().map(|x| x.iov_len).sum()
|
||||
}
|
||||
|
||||
/// Constructs `IoVecs` from an array of `IoVec` in userspace.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `iov` - Pointer to the array of `IoVec` in userspace
|
||||
/// * `iovcnt` - Number of `IoVec` elements in the array
|
||||
/// * `readv` - Whether this is for the `readv` syscall (currently unused)
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns `Ok(IoVecs)` on success, or `Err(SystemError)` if any error occurs.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because it operates on raw pointers from userspace.
|
||||
/// The caller must ensure:
|
||||
/// - The pointer `iov` is valid and points to at least `iovcnt` valid `IoVec` structures
|
||||
/// - The userspace memory is not modified during this operation
|
||||
#[inline(never)]
|
||||
pub unsafe fn from_user(
|
||||
iov: *const IoVec,
|
||||
iovcnt: usize,
|
||||
_readv: bool,
|
||||
) -> Result<Self, SystemError> {
|
||||
let iovs_reader = UserBufferReader::new(iov, iovcnt * core::mem::size_of::<IoVec>(), true)?;
|
||||
|
||||
// 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放)
|
||||
let iovs = iovs_reader.buffer::<IoVec>(0)?;
|
||||
|
||||
let mut slices: Vec<IoVec> = Vec::with_capacity(iovs.len());
|
||||
|
||||
for iov in iovs.iter() {
|
||||
if iov.iov_len == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let _ = UserBufferWriter::new(iov.iov_base, iov.iov_len, true)?;
|
||||
slices.push(*iov);
|
||||
}
|
||||
|
||||
return Ok(Self(slices));
|
||||
}
|
||||
|
||||
/// Aggregates data from all IoVecs into a single buffer.
|
||||
///
|
||||
/// This function reads data from each IoVec in sequence and combines them into
|
||||
/// a single contiguous buffer.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a [`Vec<u8>`] containing all the data from the IoVecs.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// let iovecs = IoVecs::from_user(/* ... */)?;
|
||||
/// let buffer = iovecs.gather();
|
||||
/// ```
|
||||
pub fn gather(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
for slice in self.0.iter() {
|
||||
let buf_reader = UserBufferReader::new(slice.iov_base, slice.iov_len, true).unwrap();
|
||||
let slice = buf_reader.buffer::<u8>(0).unwrap();
|
||||
buf.extend_from_slice(slice);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// Scatters the given data into the IoVecs.
|
||||
///
|
||||
/// This function writes data sequentially to each IoVec, splitting the input data
|
||||
/// across multiple buffers as needed. If the input data is smaller than the total
|
||||
/// capacity of the IoVecs, only the required amount of data will be written.
|
||||
/// If the input data is larger than the total capacity, the excess data will be ignored.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `data` - The data to be scattered across the IoVecs
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// let iovecs = IoVecs::from_user(/* ... */)?;
|
||||
/// iovecs.scatter(&[1, 2, 3, 4, 5]);
|
||||
/// ```
|
||||
pub fn scatter(&self, data: &[u8]) {
|
||||
let mut data: &[u8] = data;
|
||||
for slice in self.0.iter() {
|
||||
let len = core::cmp::min(slice.iov_len, data.len());
|
||||
if len == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut buf_writer =
|
||||
UserBufferWriter::new(slice.iov_base, slice.iov_len, true).unwrap();
|
||||
let slice = buf_writer.buffer::<u8>(0).unwrap();
|
||||
|
||||
slice[..len].copy_from_slice(&data[..len]);
|
||||
data = &data[len..];
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a buffer with capacity equal to the total length of all IoVecs.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `set_len` - If true, sets the length of the returned Vec to the total length of all IoVecs.
|
||||
/// If false, the returned Vec will have length 0 but capacity equal to the total length.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new [`Vec<u8>`] with capacity (and potentially length) equal to the total length of all IoVecs.
|
||||
pub fn new_buf(&self, set_len: bool) -> Vec<u8> {
|
||||
let total_len = self.total_len();
|
||||
let mut buf: Vec<u8> = Vec::with_capacity(total_len);
|
||||
|
||||
if set_len {
|
||||
buf.resize(total_len, 0);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
pub mod fcntl;
|
||||
pub mod file;
|
||||
pub mod iov;
|
||||
pub mod mount;
|
||||
pub mod open;
|
||||
pub mod stat;
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
driver::base::{block::SeekFrom, device::device_number::DeviceNumber},
|
||||
filesystem::vfs::{file::FileDescriptorVec, vcore as Vcore},
|
||||
libs::rwlock::RwLockWriteGuard,
|
||||
mm::{verify_area, VirtAddr},
|
||||
mm::VirtAddr,
|
||||
process::ProcessManager,
|
||||
syscall::{
|
||||
user_access::{self, check_and_clone_cstr, UserBufferWriter},
|
||||
@ -35,6 +35,11 @@ use super::{
|
||||
VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||
};
|
||||
|
||||
mod sys_read;
|
||||
mod sys_readv;
|
||||
mod sys_write;
|
||||
mod sys_writev;
|
||||
|
||||
pub const SEEK_SET: u32 = 0;
|
||||
pub const SEEK_CUR: u32 = 1;
|
||||
pub const SEEK_END: u32 = 2;
|
||||
@ -497,48 +502,6 @@ impl Syscall {
|
||||
return r;
|
||||
}
|
||||
|
||||
/// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。
|
||||
///
|
||||
/// @param fd 文件描述符编号
|
||||
/// @param buf 输出缓冲区
|
||||
///
|
||||
/// @return Ok(usize) 成功读取的数据的字节数
|
||||
/// @return Err(SystemError) 读取失败,返回posix错误码
|
||||
pub fn read(fd: i32, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.read();
|
||||
|
||||
let file = fd_table_guard.get_file_by_fd(fd);
|
||||
if file.is_none() {
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
// drop guard 以避免无法调度的问题
|
||||
drop(fd_table_guard);
|
||||
let file = file.unwrap();
|
||||
|
||||
return file.read(buf.len(), buf);
|
||||
}
|
||||
|
||||
/// @brief 根据文件描述符,向文件写入数据。尝试写入的数据长度与buf的长度相同。
|
||||
///
|
||||
/// @param fd 文件描述符编号
|
||||
/// @param buf 输入缓冲区
|
||||
///
|
||||
/// @return Ok(usize) 成功写入的数据的字节数
|
||||
/// @return Err(SystemError) 写入失败,返回posix错误码
|
||||
pub fn write(fd: i32, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.read();
|
||||
|
||||
let file = fd_table_guard
|
||||
.get_file_by_fd(fd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
|
||||
// drop guard 以避免无法调度的问题
|
||||
drop(fd_table_guard);
|
||||
return file.write(buf.len(), buf);
|
||||
}
|
||||
|
||||
/// @brief 调整文件操作指针的位置
|
||||
///
|
||||
/// @param fd 文件描述符编号
|
||||
@ -1421,28 +1384,6 @@ impl Syscall {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn writev(fd: i32, iov: usize, count: usize) -> Result<usize, SystemError> {
|
||||
// IoVecs会进行用户态检验
|
||||
let iovecs = unsafe { IoVecs::from_user(iov as *const IoVec, count, false) }?;
|
||||
|
||||
let data = iovecs.gather();
|
||||
|
||||
Self::write(fd, &data)
|
||||
}
|
||||
|
||||
pub fn readv(fd: i32, iov: usize, count: usize) -> Result<usize, SystemError> {
|
||||
// IoVecs会进行用户态检验
|
||||
let mut iovecs = unsafe { IoVecs::from_user(iov as *const IoVec, count, true) }?;
|
||||
|
||||
let mut data = vec![0; iovecs.0.iter().map(|x| x.len()).sum()];
|
||||
|
||||
let len = Self::read(fd, &mut data)?;
|
||||
|
||||
iovecs.scatter(&data[..len]);
|
||||
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
pub fn readlink_at(
|
||||
dirfd: i32,
|
||||
path: *const u8,
|
||||
@ -1675,104 +1616,3 @@ impl Syscall {
|
||||
do_utimes(&pathname, times)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct IoVec {
|
||||
/// 缓冲区的起始地址
|
||||
pub iov_base: *mut u8,
|
||||
/// 缓冲区的长度
|
||||
pub iov_len: usize,
|
||||
}
|
||||
|
||||
/// 用于存储多个来自用户空间的IoVec
|
||||
///
|
||||
/// 由于目前内核中的文件系统还不支持分散读写,所以暂时只支持将用户空间的IoVec聚合成一个缓冲区,然后进行操作。
|
||||
/// TODO:支持分散读写
|
||||
#[derive(Debug)]
|
||||
pub struct IoVecs(Vec<&'static mut [u8]>);
|
||||
|
||||
impl IoVecs {
|
||||
/// 从用户空间的IoVec中构造IoVecs
|
||||
///
|
||||
/// @param iov 用户空间的IoVec
|
||||
/// @param iovcnt 用户空间的IoVec的数量
|
||||
/// @param readv 是否为readv系统调用
|
||||
///
|
||||
/// @return 构造成功返回IoVecs,否则返回错误码
|
||||
pub unsafe fn from_user(
|
||||
iov: *const IoVec,
|
||||
iovcnt: usize,
|
||||
_readv: bool,
|
||||
) -> Result<Self, SystemError> {
|
||||
// 检查iov指针所在空间是否合法
|
||||
verify_area(
|
||||
VirtAddr::new(iov as usize),
|
||||
iovcnt * core::mem::size_of::<IoVec>(),
|
||||
)
|
||||
.map_err(|_| SystemError::EFAULT)?;
|
||||
|
||||
// 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放)
|
||||
let iovs: &[IoVec] = core::slice::from_raw_parts(iov, iovcnt);
|
||||
|
||||
let mut slices: Vec<&mut [u8]> = Vec::with_capacity(iovs.len());
|
||||
|
||||
for iov in iovs.iter() {
|
||||
if iov.iov_len == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
verify_area(
|
||||
VirtAddr::new(iov.iov_base as usize),
|
||||
iovcnt * core::mem::size_of::<IoVec>(),
|
||||
)
|
||||
.map_err(|_| SystemError::EFAULT)?;
|
||||
|
||||
slices.push(core::slice::from_raw_parts_mut(iov.iov_base, iov.iov_len));
|
||||
}
|
||||
|
||||
return Ok(Self(slices));
|
||||
}
|
||||
|
||||
/// @brief 将IoVecs中的数据聚合到一个缓冲区中
|
||||
///
|
||||
/// @return 返回聚合后的缓冲区
|
||||
pub fn gather(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
for slice in self.0.iter() {
|
||||
buf.extend_from_slice(slice);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// @brief 将给定的数据分散写入到IoVecs中
|
||||
pub fn scatter(&mut self, data: &[u8]) {
|
||||
let mut data: &[u8] = data;
|
||||
for slice in self.0.iter_mut() {
|
||||
let len = core::cmp::min(slice.len(), data.len());
|
||||
if len == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
slice[..len].copy_from_slice(&data[..len]);
|
||||
data = &data[len..];
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 创建与IoVecs等长的缓冲区
|
||||
///
|
||||
/// @param set_len 是否设置返回的Vec的len。
|
||||
/// 如果为true,则返回的Vec的len为所有IoVec的长度之和;
|
||||
/// 否则返回的Vec的len为0,capacity为所有IoVec的长度之和.
|
||||
///
|
||||
/// @return 返回创建的缓冲区
|
||||
pub fn new_buf(&self, set_len: bool) -> Vec<u8> {
|
||||
let total_len: usize = self.0.iter().map(|slice| slice.len()).sum();
|
||||
let mut buf: Vec<u8> = Vec::with_capacity(total_len);
|
||||
|
||||
if set_len {
|
||||
buf.resize(total_len, 0);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
105
kernel/src/filesystem/vfs/syscall/sys_read.rs
Normal file
105
kernel/src/filesystem/vfs/syscall/sys_read.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::syscall::nr::SYS_READ;
|
||||
use crate::process::ProcessManager;
|
||||
use crate::syscall::table::FormattedSyscallParam;
|
||||
use crate::syscall::table::Syscall;
|
||||
use crate::syscall::user_access::UserBufferWriter;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// System call handler for the `read` syscall
|
||||
///
|
||||
/// This handler implements the `Syscall` trait to provide functionality for reading data from a file descriptor.
|
||||
pub struct SysReadHandle;
|
||||
|
||||
impl Syscall for SysReadHandle {
|
||||
/// Returns the number of arguments expected by the `read` syscall
|
||||
fn num_args(&self) -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
/// Handles the `read` system call
|
||||
///
|
||||
/// Reads data from the specified file descriptor into a user buffer.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - Array containing:
|
||||
/// - args[0]: File descriptor (i32)
|
||||
/// - args[1]: Pointer to user buffer (*mut u8)
|
||||
/// - args[2]: Length of data to read (usize)
|
||||
/// * `from_user` - Indicates if the call originates from user space
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(usize)` - Number of bytes successfully read
|
||||
/// * `Err(SystemError)` - Error code if operation fails
|
||||
fn handle(&self, args: &[usize], from_user: bool) -> Result<usize, SystemError> {
|
||||
let fd = Self::fd(args);
|
||||
let buf_vaddr = Self::buf(args);
|
||||
let len = Self::len(args);
|
||||
|
||||
let mut user_buffer_writer = UserBufferWriter::new(buf_vaddr, len, from_user)?;
|
||||
|
||||
let user_buf = user_buffer_writer.buffer(0)?;
|
||||
do_read(fd, user_buf)
|
||||
}
|
||||
|
||||
/// Formats the syscall parameters for display/debug purposes
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - The raw syscall arguments
|
||||
///
|
||||
/// # Returns
|
||||
/// Vector of formatted parameters with descriptive names
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("fd", Self::fd(args).to_string()),
|
||||
FormattedSyscallParam::new("buf", format!("{:#x}", Self::buf(args) as usize)),
|
||||
FormattedSyscallParam::new("len", Self::len(args).to_string()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl SysReadHandle {
|
||||
/// Extracts the file descriptor from syscall arguments
|
||||
fn fd(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
|
||||
/// Extracts the buffer pointer from syscall arguments
|
||||
fn buf(args: &[usize]) -> *mut u8 {
|
||||
args[1] as *mut u8
|
||||
}
|
||||
|
||||
/// Extracts the buffer length from syscall arguments
|
||||
fn len(args: &[usize]) -> usize {
|
||||
args[2]
|
||||
}
|
||||
}
|
||||
|
||||
syscall_table_macros::declare_syscall!(SYS_READ, SysReadHandle);
|
||||
|
||||
/// Internal implementation of the read operation
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `fd` - File descriptor to read from
|
||||
/// * `buf` - Buffer to store read data
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(usize)` - Number of bytes successfully read
|
||||
/// * `Err(SystemError)` - Error code if operation fails
|
||||
pub(super) fn do_read(fd: i32, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.read();
|
||||
|
||||
let file = fd_table_guard.get_file_by_fd(fd);
|
||||
if file.is_none() {
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
// drop guard 以避免无法调度的问题
|
||||
drop(fd_table_guard);
|
||||
let file = file.unwrap();
|
||||
|
||||
return file.read(buf.len(), buf);
|
||||
}
|
65
kernel/src/filesystem/vfs/syscall/sys_readv.rs
Normal file
65
kernel/src/filesystem/vfs/syscall/sys_readv.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::syscall::nr::SYS_READV;
|
||||
use crate::filesystem::vfs::iov::IoVec;
|
||||
use crate::filesystem::vfs::iov::IoVecs;
|
||||
use crate::syscall::table::FormattedSyscallParam;
|
||||
use crate::syscall::table::Syscall;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use super::sys_read::do_read;
|
||||
|
||||
/// System call handler for `readv` operation
|
||||
///
|
||||
/// The `readv` system call reads data into multiple buffers from a file descriptor.
|
||||
/// It is equivalent to multiple `read` calls but is more efficient.
|
||||
pub struct SysReadVHandle;
|
||||
|
||||
impl Syscall for SysReadVHandle {
|
||||
fn num_args(&self) -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
fn handle(&self, args: &[usize], _from_user: bool) -> Result<usize, SystemError> {
|
||||
let fd = Self::fd(args);
|
||||
let iov = Self::iov(args);
|
||||
let count = Self::count(args);
|
||||
|
||||
// IoVecs会进行用户态检验
|
||||
let iovecs = unsafe { IoVecs::from_user(iov, count, true) }?;
|
||||
|
||||
let mut data = vec![0; iovecs.total_len()];
|
||||
|
||||
let len = do_read(fd, &mut data)?;
|
||||
|
||||
iovecs.scatter(&data[..len]);
|
||||
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("fd", Self::fd(args).to_string()),
|
||||
FormattedSyscallParam::new("iov", format!("{:#x}", Self::iov(args) as usize)),
|
||||
FormattedSyscallParam::new("count", Self::count(args).to_string()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl SysReadVHandle {
|
||||
fn fd(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
|
||||
fn iov(args: &[usize]) -> *const IoVec {
|
||||
args[1] as *const IoVec
|
||||
}
|
||||
|
||||
fn count(args: &[usize]) -> usize {
|
||||
args[2]
|
||||
}
|
||||
}
|
||||
|
||||
syscall_table_macros::declare_syscall!(SYS_READV, SysReadVHandle);
|
104
kernel/src/filesystem/vfs/syscall/sys_write.rs
Normal file
104
kernel/src/filesystem/vfs/syscall/sys_write.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::syscall::nr::SYS_WRITE;
|
||||
use crate::process::ProcessManager;
|
||||
use crate::syscall::table::FormattedSyscallParam;
|
||||
use crate::syscall::table::Syscall;
|
||||
use crate::syscall::user_access::UserBufferReader;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// System call handler for the `write` syscall
|
||||
///
|
||||
/// This handler implements the `Syscall` trait to provide functionality for writing data to a file descriptor.
|
||||
pub struct SysWriteHandle;
|
||||
|
||||
impl Syscall for SysWriteHandle {
|
||||
/// Returns the number of arguments expected by the `write` syscall
|
||||
fn num_args(&self) -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
/// Handles the `write` system call
|
||||
///
|
||||
/// Writes data from a user buffer to the specified file descriptor.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - Array containing:
|
||||
/// - args[0]: File descriptor (i32)
|
||||
/// - args[1]: Pointer to user buffer (*const u8)
|
||||
/// - args[2]: Length of data to write (usize)
|
||||
/// * `from_user` - Indicates if the call originates from user space
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(usize)` - Number of bytes successfully written
|
||||
/// * `Err(SystemError)` - Error code if operation fails
|
||||
fn handle(&self, args: &[usize], from_user: bool) -> Result<usize, SystemError> {
|
||||
let fd = Self::fd(args);
|
||||
let buf_vaddr = Self::buf(args);
|
||||
let len = Self::len(args);
|
||||
|
||||
let user_buffer_reader = UserBufferReader::new(buf_vaddr, len, from_user)?;
|
||||
|
||||
let user_buf = user_buffer_reader.read_from_user(0)?;
|
||||
|
||||
do_write(fd, user_buf)
|
||||
}
|
||||
|
||||
/// Formats the syscall parameters for display/debug purposes
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - The raw syscall arguments
|
||||
///
|
||||
/// # Returns
|
||||
/// Vector of formatted parameters with descriptive names
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("fd", Self::fd(args).to_string()),
|
||||
FormattedSyscallParam::new("buf", format!("{:#x}", Self::buf(args) as usize)),
|
||||
FormattedSyscallParam::new("len", Self::len(args).to_string()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl SysWriteHandle {
|
||||
/// Extracts the file descriptor from syscall arguments
|
||||
fn fd(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
|
||||
/// Extracts the buffer pointer from syscall arguments
|
||||
fn buf(args: &[usize]) -> *const u8 {
|
||||
args[1] as *const u8
|
||||
}
|
||||
|
||||
/// Extracts the buffer length from syscall arguments
|
||||
fn len(args: &[usize]) -> usize {
|
||||
args[2]
|
||||
}
|
||||
}
|
||||
|
||||
syscall_table_macros::declare_syscall!(SYS_WRITE, SysWriteHandle);
|
||||
|
||||
/// Internal implementation of the write operation
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `fd` - File descriptor to write to
|
||||
/// * `buf` - Buffer containing data to write
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(usize)` - Number of bytes successfully written
|
||||
/// * `Err(SystemError)` - Error code if operation fails
|
||||
pub(super) fn do_write(fd: i32, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.read();
|
||||
|
||||
let file = fd_table_guard
|
||||
.get_file_by_fd(fd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
|
||||
// drop guard 以避免无法调度的问题
|
||||
drop(fd_table_guard);
|
||||
return file.write(buf.len(), buf);
|
||||
}
|
85
kernel/src/filesystem/vfs/syscall/sys_writev.rs
Normal file
85
kernel/src/filesystem/vfs/syscall/sys_writev.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::syscall::nr::SYS_WRITEV;
|
||||
use crate::filesystem::vfs::iov::IoVec;
|
||||
use crate::filesystem::vfs::iov::IoVecs;
|
||||
use crate::syscall::table::FormattedSyscallParam;
|
||||
use crate::syscall::table::Syscall;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use super::sys_write::do_write;
|
||||
|
||||
/// System call handler for `writev` operation
|
||||
///
|
||||
/// The `writev` system call writes data from multiple buffers to a file descriptor.
|
||||
/// It is equivalent to multiple `write` calls but is more efficient.
|
||||
pub struct SysWriteVHandle;
|
||||
|
||||
impl Syscall for SysWriteVHandle {
|
||||
/// Returns the number of arguments required by the `writev` system call
|
||||
fn num_args(&self) -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
/// Handles the `writev` system call
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - System call arguments containing:
|
||||
/// * `fd`: File descriptor to write to
|
||||
/// * `iov`: Pointer to array of I/O vectors
|
||||
/// * `count`: Number of elements in the I/O vector array
|
||||
/// * `_from_user` - Flag indicating if the call originated from user space
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(usize)` - Number of bytes written
|
||||
/// * `Err(SystemError)` - Error that occurred during operation
|
||||
///
|
||||
/// # Safety
|
||||
/// The caller must ensure the `iov` pointer is valid and points to properly initialized memory.
|
||||
fn handle(&self, args: &[usize], _from_user: bool) -> Result<usize, SystemError> {
|
||||
let fd = Self::fd(args);
|
||||
let iov = Self::iov(args);
|
||||
let count = Self::count(args);
|
||||
|
||||
// IoVecs会进行用户态检验
|
||||
let iovecs = unsafe { IoVecs::from_user(iov, count, false) }?;
|
||||
let data = iovecs.gather();
|
||||
do_write(fd, &data)
|
||||
}
|
||||
|
||||
/// Formats the system call parameters for display/debug purposes
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - System call arguments to format
|
||||
///
|
||||
/// # Returns
|
||||
/// Vector of formatted parameters with their names and values
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("fd", Self::fd(args).to_string()),
|
||||
FormattedSyscallParam::new("iov", format!("{:#x}", Self::iov(args) as usize)),
|
||||
FormattedSyscallParam::new("count", Self::count(args).to_string()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl SysWriteVHandle {
|
||||
/// Extracts the file descriptor from system call arguments
|
||||
fn fd(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
|
||||
/// Extracts the I/O vector pointer from system call arguments
|
||||
fn iov(args: &[usize]) -> *const IoVec {
|
||||
args[1] as *const IoVec
|
||||
}
|
||||
|
||||
/// Extracts the I/O vector count from system call arguments
|
||||
fn count(args: &[usize]) -> usize {
|
||||
args[2]
|
||||
}
|
||||
}
|
||||
|
||||
syscall_table_macros::declare_syscall!(SYS_WRITEV, SysWriteVHandle);
|
@ -23,7 +23,7 @@ use crate::{
|
||||
process::{kthread::kthread_init, process_init, ProcessManager},
|
||||
sched::SchedArch,
|
||||
smp::{early_smp_init, SMPArch},
|
||||
syscall::Syscall,
|
||||
syscall::{syscall_init, Syscall},
|
||||
time::{
|
||||
clocksource::clocksource_boot_finish, timekeeping::timekeeping_init, timer::timer_init,
|
||||
},
|
||||
@ -69,6 +69,8 @@ fn do_start_kernel() {
|
||||
|
||||
init_intertrait();
|
||||
|
||||
syscall_init().expect("syscall init failed");
|
||||
|
||||
vfs_init().expect("vfs init failed");
|
||||
driver_init().expect("driver init failed");
|
||||
|
||||
|
@ -8,7 +8,7 @@ use system_error::SystemError;
|
||||
use crate::{
|
||||
filesystem::vfs::{
|
||||
file::{File, FileMode},
|
||||
syscall::{IoVec, IoVecs},
|
||||
iov::{IoVec, IoVecs},
|
||||
FileType,
|
||||
},
|
||||
libs::spinlock::SpinLockGuard,
|
||||
@ -295,7 +295,7 @@ impl Syscall {
|
||||
/// @return 成功返回接收的字节数,失败返回错误码
|
||||
pub fn recvmsg(fd: usize, msg: &mut MsgHdr, _flags: u32) -> Result<usize, SystemError> {
|
||||
// 检查每个缓冲区地址是否合法,生成iovecs
|
||||
let mut iovs = unsafe { IoVecs::from_user(msg.msg_iov, msg.msg_iovlen, true)? };
|
||||
let iovs = unsafe { IoVecs::from_user(msg.msg_iov, msg.msg_iovlen, true)? };
|
||||
|
||||
let socket: Arc<SocketInode> = ProcessManager::current_pcb()
|
||||
.get_socket(fd as i32)
|
||||
|
@ -23,6 +23,7 @@ use crate::{
|
||||
use log::{info, warn};
|
||||
use num_traits::FromPrimitive;
|
||||
use system_error::SystemError;
|
||||
use table::{syscall_table, syscall_table_init};
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::TrapFrame, MMArch},
|
||||
@ -49,6 +50,7 @@ use self::{
|
||||
};
|
||||
|
||||
pub mod misc;
|
||||
pub mod table;
|
||||
pub mod user_access;
|
||||
|
||||
// 与linux不一致的调用,在linux基础上累加
|
||||
@ -99,6 +101,18 @@ impl Syscall {
|
||||
args: &[usize],
|
||||
frame: &mut TrapFrame,
|
||||
) -> Result<usize, SystemError> {
|
||||
// 首先尝试从syscall_table获取处理函数
|
||||
if let Some(handler) = syscall_table().get(syscall_num) {
|
||||
// 使用以下代码可以打印系统调用号和参数,方便调试
|
||||
// log::debug!(
|
||||
// "Syscall {} called with args {}",
|
||||
// handler.name,
|
||||
// handler.args_string(args)
|
||||
// );
|
||||
return handler.inner_handle.handle(args, frame.is_from_user());
|
||||
}
|
||||
|
||||
// 如果找不到,fallback到原有逻辑
|
||||
let r = match syscall_num {
|
||||
SYS_PUT_STRING => {
|
||||
Self::put_string(args[0] as *const u8, args[1] as u32, args[2] as u32)
|
||||
@ -155,28 +169,6 @@ impl Syscall {
|
||||
let fd = args[0];
|
||||
Self::close(fd)
|
||||
}
|
||||
SYS_READ => {
|
||||
let fd = args[0] as i32;
|
||||
let buf_vaddr = args[1];
|
||||
let len = args[2];
|
||||
let from_user = frame.is_from_user();
|
||||
let mut user_buffer_writer =
|
||||
UserBufferWriter::new(buf_vaddr as *mut u8, len, from_user)?;
|
||||
|
||||
let user_buf = user_buffer_writer.buffer(0)?;
|
||||
Self::read(fd, user_buf)
|
||||
}
|
||||
SYS_WRITE => {
|
||||
let fd = args[0] as i32;
|
||||
let buf_vaddr = args[1];
|
||||
let len = args[2];
|
||||
let from_user = frame.is_from_user();
|
||||
let user_buffer_reader =
|
||||
UserBufferReader::new(buf_vaddr as *const u8, len, from_user)?;
|
||||
|
||||
let user_buf = user_buffer_reader.read_from_user(0)?;
|
||||
Self::write(fd, user_buf)
|
||||
}
|
||||
|
||||
SYS_LSEEK => {
|
||||
let fd = args[0] as i32;
|
||||
@ -781,9 +773,6 @@ impl Syscall {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SYS_READV => Self::readv(args[0] as i32, args[1], args[2]),
|
||||
SYS_WRITEV => Self::writev(args[0] as i32, args[1], args[2]),
|
||||
|
||||
SYS_SET_TID_ADDRESS => Self::set_tid_address(args[0]),
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@ -1267,3 +1256,9 @@ impl Syscall {
|
||||
return Ok(s.len());
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn syscall_init() -> Result<(), SystemError> {
|
||||
syscall_table_init()?;
|
||||
Ok(())
|
||||
}
|
||||
|
129
kernel/src/syscall/table.rs
Normal file
129
kernel/src/syscall/table.rs
Normal file
@ -0,0 +1,129 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::string::ToString;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::OnceCell;
|
||||
use core::fmt::Display;
|
||||
|
||||
use crate::libs::once::Once;
|
||||
use crate::syscall::SystemError;
|
||||
|
||||
/// 定义Syscall trait
|
||||
pub trait Syscall: Send + Sync + 'static {
|
||||
/// 系统调用参数数量
|
||||
fn num_args(&self) -> usize;
|
||||
fn handle(&self, args: &[usize], from_user: bool) -> Result<usize, SystemError>;
|
||||
|
||||
/// Formats the system call parameters for display/debug purposes
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - System call arguments to format
|
||||
///
|
||||
/// # Returns
|
||||
/// Vector of formatted parameters with their names and values
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam>;
|
||||
}
|
||||
|
||||
pub struct FormattedSyscallParam {
|
||||
pub name: &'static str,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl FormattedSyscallParam {
|
||||
pub fn new(name: &'static str, value: String) -> Self {
|
||||
Self { name, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FormattedSyscallParam {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{}: {}", self.name, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
/// 系统调用处理句柄
|
||||
#[repr(C)]
|
||||
pub struct SyscallHandle {
|
||||
pub nr: usize,
|
||||
pub inner_handle: &'static dyn Syscall,
|
||||
pub name: &'static str,
|
||||
}
|
||||
|
||||
impl SyscallHandle {
|
||||
#[inline(never)]
|
||||
pub fn args_string(&self, args: &[usize]) -> String {
|
||||
let args_slice = self.inner_handle.entry_format(args);
|
||||
args_slice
|
||||
.iter()
|
||||
.map(|p| format!("{}", p))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
}
|
||||
}
|
||||
|
||||
/// 系统调用表类型
|
||||
#[repr(C)]
|
||||
pub struct SyscallTable {
|
||||
entries: [Option<&'static SyscallHandle>; Self::ENTRIES],
|
||||
}
|
||||
|
||||
impl SyscallTable {
|
||||
pub const ENTRIES: usize = 512;
|
||||
/// 获取系统调用处理函数
|
||||
pub fn get(&self, nr: usize) -> Option<&'static SyscallHandle> {
|
||||
*self.entries.get(nr)?
|
||||
}
|
||||
}
|
||||
|
||||
// 声明外部链接的syscall_table符号
|
||||
extern "C" {
|
||||
fn _syscall_table();
|
||||
fn _esyscall_table();
|
||||
}
|
||||
|
||||
/// 全局系统调用表实例
|
||||
#[used]
|
||||
#[link_section = ".data"]
|
||||
static mut SYS_CALL_TABLE: SyscallTable = SyscallTable {
|
||||
entries: [None; SyscallTable::ENTRIES],
|
||||
};
|
||||
|
||||
#[inline]
|
||||
pub(super) fn syscall_table() -> &'static SyscallTable {
|
||||
unsafe { &SYS_CALL_TABLE }
|
||||
}
|
||||
|
||||
/// 初始化系统调用表
|
||||
#[inline(never)]
|
||||
pub(super) fn syscall_table_init() -> Result<(), SystemError> {
|
||||
static INIT: Once = Once::new();
|
||||
INIT.call_once(|| {
|
||||
log::debug!("Initializing syscall table...");
|
||||
|
||||
// 初始化系统调用表
|
||||
unsafe {
|
||||
let start = _syscall_table as usize;
|
||||
let end = _esyscall_table as usize;
|
||||
let size = end - start;
|
||||
let count = size / core::mem::size_of::<SyscallHandle>();
|
||||
|
||||
if size % core::mem::size_of::<SyscallHandle>() != 0 {
|
||||
panic!("Invalid syscall table size: {}", size);
|
||||
}
|
||||
|
||||
let handles =
|
||||
core::slice::from_raw_parts(_syscall_table as *const SyscallHandle, count);
|
||||
for handle in handles {
|
||||
if handle.nr < SyscallTable::ENTRIES {
|
||||
SYS_CALL_TABLE.entries[handle.nr] = Some(handle);
|
||||
} else {
|
||||
panic!("Invalid syscall number: {}", handle.nr);
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!("Syscall table (count: {count}) initialized successfully.")
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
@ -8,14 +8,12 @@ CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
|
||||
.PHONY: all
|
||||
all: main.c
|
||||
# $(CC) -static -o init main.c
|
||||
all: $(riscv_rust_init)
|
||||
$(MAKE) -C riscv_rust_init ARCH=$(ARCH) install
|
||||
|
||||
.PHONY: install clean
|
||||
install: all
|
||||
$(MAKE) -C riscv_rust_init ARCH=$(ARCH) install
|
||||
# mv init $(DADK_CURRENT_BUILD_DIR)/init
|
||||
|
||||
|
||||
clean:
|
||||
|
@ -1,9 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
while(1){
|
||||
printf("\033[43;37mHello, World!\033[0m\n");
|
||||
sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -29,7 +29,7 @@ build-command = "make install"
|
||||
# 安装相关信息
|
||||
[install]
|
||||
# (可选)安装到DragonOS的路径
|
||||
in-dragonos-path = "/bin"
|
||||
in-dragonos-path = "/"
|
||||
# 清除相关信息
|
||||
[clean]
|
||||
# (可选)清除命令
|
||||
|
Loading…
x
Reference in New Issue
Block a user