mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
merge upstream
This commit is contained in:
commit
b9f04fc3a4
16
.github/workflows/makefile.yml
vendored
16
.github/workflows/makefile.yml
vendored
@ -12,14 +12,14 @@ jobs:
|
||||
name: Format check ${{ matrix.arch }}
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container: dragonos/dragonos-dev:v1.3
|
||||
container: dragonos/dragonos-dev:v1.4
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, riscv64]
|
||||
|
||||
steps:
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.3"
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.4"
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Format check
|
||||
@ -35,14 +35,14 @@ jobs:
|
||||
name: Kernel static test ${{ matrix.arch }}
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container: dragonos/dragonos-dev:v1.3
|
||||
container: dragonos/dragonos-dev:v1.4
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, riscv64]
|
||||
|
||||
steps:
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.3"
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.4"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@ -56,10 +56,10 @@ jobs:
|
||||
build-x86_64:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container: dragonos/dragonos-dev:v1.3
|
||||
container: dragonos/dragonos-dev:v1.4
|
||||
|
||||
steps:
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.3"
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.4"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- name: build the DragonOS
|
||||
@ -78,10 +78,10 @@ jobs:
|
||||
build-riscv64:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container: dragonos/dragonos-dev:v1.3
|
||||
container: dragonos/dragonos-dev:v1.4
|
||||
|
||||
steps:
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.3"
|
||||
- run: echo "Running in dragonos/dragonos-dev:v1.4"
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
|
109
docs/kernel/boot/cmdline.md
Normal file
109
docs/kernel/boot/cmdline.md
Normal file
@ -0,0 +1,109 @@
|
||||
# 内核启动命令行参数
|
||||
|
||||
:::{note}
|
||||
本文作者:
|
||||
- 龙进 <longjin@DragonOS.org>
|
||||
:::
|
||||
|
||||
## 概述
|
||||
|
||||
  DragonOS内核启动命令行参数解析模块旨在提供类似Linux的内核启动命令行参数解析支持,以便更灵活地让内核执行不同的行为。该模块允许内核在启动时接收并解析命令行参数,根据参数的不同类型执行相应的回调函数或设置环境变量。
|
||||
|
||||
:::{note}
|
||||
暂时不支持设置回调函数
|
||||
:::
|
||||
|
||||
## 设计方案
|
||||
|
||||
|
||||
### 参数类型
|
||||
|
||||
内核启动命令行参数分为三种类型:
|
||||
|
||||
- Arg类型
|
||||
- KV类型
|
||||
- EarlyKV类型
|
||||
|
||||
#### Arg类型
|
||||
|
||||
Arg类型的参数在命令行中只有名称,没有值。分为以下两种类型:
|
||||
|
||||
- ArgNormal:默认值为`false`,如果命令行中包含这个参数,则会设置为`true`。
|
||||
- ArgInv:默认值为`true`,如果命令行中包含这个参数,则会设置为`false`。
|
||||
|
||||
#### KV类型
|
||||
|
||||
KV类型的参数在命令行中表现为`name=value`,`value`按照逗号分隔。内核模块可提供参数的默认值。
|
||||
|
||||
#### EarlyKV类型
|
||||
|
||||
EarlyKV类型的参数与KV类型类似,但它们在内存管理初始化之前被解析。
|
||||
|
||||
### Module标志
|
||||
|
||||
Module标志类似于`usbprobe.xxxx`。
|
||||
|
||||
### 参数声明
|
||||
提供宏来声明内核命令行参数。
|
||||
### procfs支持
|
||||
|
||||
:::{note}
|
||||
TODO: 在`/proc/cmdline`下显示当前内核的启动命令行参数。
|
||||
:::
|
||||
|
||||
## 声明内核启动命令行参数的宏
|
||||
|
||||
### Arg类型参数声明
|
||||
```rust
|
||||
kernel_cmdline_param_arg!(varname, name, default_bool, inv);
|
||||
```
|
||||
- `varname`:参数的变量名
|
||||
- `name`:参数的名称
|
||||
- `default_bool`:默认值
|
||||
- `inv`:是否反转
|
||||
|
||||
### KV类型参数声明
|
||||
|
||||
```rust
|
||||
kernel_cmdline_param_kv!(varname, name, default_str);
|
||||
```
|
||||
|
||||
- `varname`:参数的变量名
|
||||
- `name`:参数的名称
|
||||
- `default_str`:默认值
|
||||
|
||||
### 内存管理初始化之前的KV类型参数声明
|
||||
|
||||
```rust
|
||||
kernel_cmdline_param_early_kv!(varname, name, default_str);
|
||||
```
|
||||
|
||||
- `varname`:参数的变量名
|
||||
- `name`:参数的名称
|
||||
- `default_str`:默认值
|
||||
|
||||
## 示例
|
||||
|
||||
以下示例展示了如何声明和使用KV类型参数:
|
||||
```rust
|
||||
kernel_cmdline_param_kv!(ROOTFS_PATH_PARAM, root, "");
|
||||
if let Some(rootfs_dev_path) = ROOTFS_PATH_PARAM.value_str() {
|
||||
.......
|
||||
} else {
|
||||
.......
|
||||
};
|
||||
```
|
||||
|
||||
### 使用方式
|
||||
|
||||
1. 在内核代码中,使用`kernel_cmdline_param_kv!`宏声明所需的KV类型参数。
|
||||
2. 在内核初始化过程中,通过参数的`value_str()`或者`value_bool()`方法获取参数值。
|
||||
3. 根据参数值执行相应的操作。
|
||||
|
||||
通过以上步骤,开发者可以灵活地使用内核启动命令行参数来控制内核行为。
|
||||
|
||||
|
||||
## TODO
|
||||
|
||||
- 支持在`/proc/cmdline`下显示当前内核的启动命令行参数。(需要在procfs重构后)
|
||||
- 支持设置回调函数,调用回调函数来设置参数值
|
@ -1,10 +1,9 @@
|
||||
引导加载
|
||||
====================================
|
||||
|
||||
DragonOS采用GRUB2作为其引导加载程序,支持Multiboot2协议引导。目前仅支持GRUB2.06版本。
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: 目录
|
||||
|
||||
bootloader
|
||||
cmdline
|
||||
|
@ -41,6 +41,7 @@ fdt = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt", rev
|
||||
hashbrown = "=0.13.2"
|
||||
ida = { path = "crates/ida" }
|
||||
intertrait = { path = "crates/intertrait" }
|
||||
kcmdline_macros = { path = "crates/kcmdline_macros" }
|
||||
kdepends = { path = "crates/kdepends" }
|
||||
klog_types = { path = "crates/klog_types" }
|
||||
linkme = "=0.3.27"
|
||||
|
6
kernel/crates/kcmdline_macros/Cargo.toml
Normal file
6
kernel/crates/kcmdline_macros/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "kcmdline_macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
74
kernel/crates/kcmdline_macros/src/lib.rs
Normal file
74
kernel/crates/kcmdline_macros/src/lib.rs
Normal file
@ -0,0 +1,74 @@
|
||||
#![no_std]
|
||||
#![deny(clippy::all)]
|
||||
#![allow(clippy::crate_in_macro_def)]
|
||||
|
||||
/// 定义一个bool类型的参数
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// - `$varname`: 参数的变量名
|
||||
/// - `$name`: 参数的名称
|
||||
/// - `$default_bool`: 默认值
|
||||
/// - `$inv`: 是否反转
|
||||
#[macro_export]
|
||||
macro_rules! kernel_cmdline_param_arg {
|
||||
($varname:ident, $name:ident, $default_bool:expr, $inv:expr) => {
|
||||
#[::linkme::distributed_slice(crate::init::cmdline::KCMDLINE_PARAM_ARG)]
|
||||
static $varname: crate::init::cmdline::KernelCmdlineParameter =
|
||||
crate::init::cmdline::KernelCmdlineParamBuilder::new(
|
||||
stringify!($name),
|
||||
crate::init::cmdline::KCmdlineParamType::Arg,
|
||||
)
|
||||
.default_bool($default_bool)
|
||||
.inv($inv)
|
||||
.build()
|
||||
.unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
/// 定义一个key-value类型的参数
|
||||
///
|
||||
/// # 参数
|
||||
/// - `$varname`: 参数的变量名
|
||||
/// - `$name`: 参数的名称
|
||||
/// - `$default_str`: 默认值
|
||||
#[macro_export]
|
||||
macro_rules! kernel_cmdline_param_kv {
|
||||
($varname:ident, $name:ident, $default_str:expr) => {
|
||||
#[::linkme::distributed_slice(crate::init::cmdline::KCMDLINE_PARAM_KV)]
|
||||
static $varname: crate::init::cmdline::KernelCmdlineParameter =
|
||||
crate::init::cmdline::KernelCmdlineParamBuilder::new(
|
||||
stringify!($name),
|
||||
crate::init::cmdline::KCmdlineParamType::KV,
|
||||
)
|
||||
.default_str($default_str)
|
||||
.build()
|
||||
.unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
/// 定义一个内存管理初始化之前就要设置的key-value类型的参数
|
||||
///
|
||||
/// # 参数
|
||||
/// - `$varname`: 参数的变量名
|
||||
/// - `$name`: 参数的名称
|
||||
/// - `$default_str`: 默认值
|
||||
#[macro_export]
|
||||
macro_rules! kernel_cmdline_param_early_kv {
|
||||
($varname:ident, $name:ident, $default_str:expr) => {
|
||||
#[::linkme::distributed_slice(crate::init::cmdline::KCMDLINE_PARAM_EARLY_KV)]
|
||||
static $varname: crate::init::cmdline::KernelCmdlineParameter = {
|
||||
static ___KV: crate::init::cmdline::KernelCmdlineEarlyKV = {
|
||||
const { assert!($default_str.len() < KernelCmdlineEarlyKV::VALUE_MAX_LEN) };
|
||||
crate::init::cmdline::KernelCmdlineParamBuilder::new(
|
||||
stringify!($name),
|
||||
crate::init::cmdline::KCmdlineParamType::EarlyKV,
|
||||
)
|
||||
.default_str($default_str)
|
||||
.build_early_kv()
|
||||
.unwrap()
|
||||
};
|
||||
crate::init::cmdline::KernelCmdlineParameter::EarlyKV(&___KV)
|
||||
};
|
||||
};
|
||||
}
|
@ -65,7 +65,12 @@ pub enum AllocationError {
|
||||
/// Needs to adhere to safety requirements of a rust allocator (see GlobalAlloc et. al.).
|
||||
pub unsafe trait Allocator<'a> {
|
||||
fn allocate(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocationError>;
|
||||
fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) -> Result<(), AllocationError>;
|
||||
unsafe fn deallocate(
|
||||
&mut self,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
slab_callback: &'static dyn CallBack,
|
||||
) -> Result<(), AllocationError>;
|
||||
|
||||
/// Refill the allocator with a [`ObjectPage`].
|
||||
///
|
||||
@ -77,3 +82,8 @@ pub unsafe trait Allocator<'a> {
|
||||
new_page: &'a mut ObjectPage<'a>,
|
||||
) -> Result<(), AllocationError>;
|
||||
}
|
||||
|
||||
/// 将slab_page归还Buddy的回调函数
|
||||
pub trait CallBack: Send + Sync {
|
||||
unsafe fn free_slab_page(&self, _: *mut u8, _: usize) {}
|
||||
}
|
||||
|
@ -255,6 +255,20 @@ pub trait AllocablePage {
|
||||
self.bitfield().clear_bit(idx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 统计page中还可以分配多少个object
|
||||
fn free_obj_count(&self) -> usize {
|
||||
// 统计page中还可以分配多少个object
|
||||
let mut free_obj_count = 0;
|
||||
|
||||
// 遍历page中的bitfield(用来统计内存分配情况的u64数组)
|
||||
for b in self.bitfield().iter() {
|
||||
let bitval = b.load(Ordering::Relaxed);
|
||||
free_obj_count += bitval.count_zeros() as usize;
|
||||
}
|
||||
|
||||
free_obj_count
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds allocated data within a 4 KiB page.
|
||||
|
@ -59,21 +59,29 @@ pub struct SCAllocator<'a, P: AllocablePage> {
|
||||
pub(crate) slabs: PageList<'a, P>,
|
||||
/// List of full ObjectPages (everything allocated in these don't need to search them).
|
||||
pub(crate) full_slabs: PageList<'a, P>,
|
||||
/// Free objects count
|
||||
pub(crate) free_obj_count: usize,
|
||||
/// Maximum free objects num for this `SCAllocator`.
|
||||
pub(crate) free_limit: usize,
|
||||
}
|
||||
|
||||
/// Creates an instance of a scallocator, we do this in a macro because we
|
||||
/// re-use the code in const and non-const functions
|
||||
macro_rules! new_sc_allocator {
|
||||
($size:expr) => {
|
||||
($size:expr) => {{
|
||||
let obj_per_page = cmin((P::SIZE - OBJECT_PAGE_METADATA_OVERHEAD) / $size, 8 * 64);
|
||||
SCAllocator {
|
||||
size: $size,
|
||||
allocation_count: 0,
|
||||
obj_per_page: cmin((P::SIZE - OBJECT_PAGE_METADATA_OVERHEAD) / $size, 8 * 64),
|
||||
obj_per_page,
|
||||
empty_slabs: PageList::new(),
|
||||
slabs: PageList::new(),
|
||||
full_slabs: PageList::new(),
|
||||
// TODO: 优化free_limit的计算: https://bbs.dragonos.org.cn/t/topic/358
|
||||
free_limit: 2 * obj_per_page,
|
||||
free_obj_count: 0,
|
||||
}
|
||||
};
|
||||
}};
|
||||
}
|
||||
|
||||
impl<'a, P: AllocablePage> SCAllocator<'a, P> {
|
||||
@ -241,6 +249,7 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> {
|
||||
*page.next() = Rawlink::none();
|
||||
trace!("adding page to SCAllocator {:p}", page);
|
||||
self.insert_empty(page);
|
||||
self.free_obj_count += self.obj_per_page;
|
||||
}
|
||||
|
||||
/// Allocates a block of memory descriped by `layout`.
|
||||
@ -294,6 +303,7 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> {
|
||||
self.size,
|
||||
ptr as usize
|
||||
);
|
||||
self.free_obj_count -= 1;
|
||||
}
|
||||
|
||||
res
|
||||
@ -304,7 +314,12 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> {
|
||||
/// May return an error in case an invalid `layout` is provided.
|
||||
/// The function may also move internal slab pages between lists partial -> empty
|
||||
/// or full -> partial lists.
|
||||
pub fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) -> Result<(), AllocationError> {
|
||||
pub unsafe fn deallocate(
|
||||
&mut self,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
slab_callback: &'static dyn CallBack,
|
||||
) -> Result<(), AllocationError> {
|
||||
assert!(layout.size() <= self.size);
|
||||
assert!(self.size <= (P::SIZE - OBJECT_PAGE_METADATA_OVERHEAD));
|
||||
trace!(
|
||||
@ -324,6 +339,17 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> {
|
||||
|
||||
let ret = slab_page.deallocate(ptr, new_layout);
|
||||
debug_assert!(ret.is_ok(), "Slab page deallocate won't fail at the moment");
|
||||
self.free_obj_count += 1;
|
||||
let is_empty_after_dealloc = slab_page.is_empty(self.obj_per_page);
|
||||
|
||||
// 如果slab_page是空白的,且空闲块数大于free_limit,将slab_page归还buddy
|
||||
if self.free_obj_count >= self.free_limit && is_empty_after_dealloc {
|
||||
self.slabs.remove_from_list(slab_page);
|
||||
// 将slab_page归还buddy
|
||||
slab_callback.free_slab_page(slab_page as *const P as *mut u8, P::SIZE);
|
||||
}
|
||||
self.check_page_assignments();
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
//! The ZoneAllocator achieves this by having many `SCAllocator`
|
||||
|
||||
use crate::*;
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
/// Creates an instance of a zone, we do this in a macro because we
|
||||
/// re-use the code in const and non-const functions
|
||||
@ -139,16 +138,8 @@ impl<'a> ZoneAllocator<'a> {
|
||||
|
||||
// 遍历scallocator中的部分分配的page(partial_page)
|
||||
for slab_page in scallocator.slabs.iter_mut() {
|
||||
// 统计page中还可以分配多少个object
|
||||
let mut free_obj_count = 0;
|
||||
// 遍历page中的bitfield(用来统计内存分配情况的u64数组)
|
||||
for b in slab_page.bitfield().iter() {
|
||||
let bitval = b.load(Ordering::Relaxed);
|
||||
let free_count = bitval.count_zeros() as usize;
|
||||
free_obj_count += free_count;
|
||||
}
|
||||
// 剩余可分配object数乘上page中规定的每个object的大小,即空闲空间
|
||||
free += free_obj_count * scallocator.size();
|
||||
free += slab_page.free_obj_count() * scallocator.size();
|
||||
}
|
||||
// 遍历scallocator中的empty_page,把空页空间也加上去
|
||||
free +=
|
||||
@ -178,9 +169,15 @@ unsafe impl<'a> crate::Allocator<'a> for ZoneAllocator<'a> {
|
||||
/// # Arguments
|
||||
/// * `ptr` - Address of the memory location to free.
|
||||
/// * `layout` - Memory layout of the block pointed to by `ptr`.
|
||||
fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) -> Result<(), AllocationError> {
|
||||
/// * `slab_callback` - The callback function to free slab_page in buddy.
|
||||
unsafe fn deallocate(
|
||||
&mut self,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
slab_callback: &'static dyn CallBack,
|
||||
) -> Result<(), AllocationError> {
|
||||
match ZoneAllocator::get_slab(layout.size()) {
|
||||
Slab::Base(idx) => self.small_slabs[idx].deallocate(ptr, layout),
|
||||
Slab::Base(idx) => self.small_slabs[idx].deallocate(ptr, layout, slab_callback),
|
||||
Slab::Unsupported => Err(AllocationError::InvalidLayout),
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) {
|
||||
show &= false;
|
||||
}
|
||||
}
|
||||
show = false;
|
||||
show &= false;
|
||||
if show {
|
||||
debug!("[SYS] [Pid: {:?}] [Call: {:?}]", pid, to_print);
|
||||
}
|
||||
|
@ -241,24 +241,27 @@ impl IfaceCommon {
|
||||
self.poll_at_ms.store(0, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
if has_events {
|
||||
// log::debug!("IfaceCommon::poll: has_events");
|
||||
// We never try to hold the write lock in the IRQ context, and we disable IRQ when
|
||||
// holding the write lock. So we don't need to disable IRQ when holding the read lock.
|
||||
self.bounds.read().iter().for_each(|bound_socket| {
|
||||
bound_socket.on_iface_events();
|
||||
// if has_events {
|
||||
|
||||
// log::debug!("IfaceCommon::poll: has_events");
|
||||
// We never try to hold the write lock in the IRQ context, and we disable IRQ when
|
||||
// holding the write lock. So we don't need to disable IRQ when holding the read lock.
|
||||
self.bounds.read().iter().for_each(|bound_socket| {
|
||||
bound_socket.on_iface_events();
|
||||
if has_events {
|
||||
bound_socket
|
||||
.wait_queue()
|
||||
.wakeup(Some(ProcessState::Blocked(true)));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// let closed_sockets = self
|
||||
// .closing_sockets
|
||||
// .lock_irq_disabled()
|
||||
// .extract_if(|closing_socket| closing_socket.is_closed())
|
||||
// .collect::<Vec<_>>();
|
||||
// drop(closed_sockets);
|
||||
}
|
||||
// let closed_sockets = self
|
||||
// .closing_sockets
|
||||
// .lock_irq_disabled()
|
||||
// .extract_if(|closing_socket| closing_socket.is_closed())
|
||||
// .collect::<Vec<_>>();
|
||||
// drop(closed_sockets);
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn update_ip_addrs(&self, ip_addrs: &[smoltcp::wire::IpCidr]) -> Result<(), SystemError> {
|
||||
|
@ -257,7 +257,7 @@ impl Device for VirtIONetDevice {
|
||||
|
||||
impl VirtIODevice for VirtIONetDevice {
|
||||
fn handle_irq(&self, _irq: IrqNumber) -> Result<IrqReturn, SystemError> {
|
||||
log::warn!("VirtioInterface: poll_ifaces_try_lock_onetime -> poll_ifaces");
|
||||
// log::warn!("VirtioInterface: poll_ifaces_try_lock_onetime -> poll_ifaces");
|
||||
poll_ifaces();
|
||||
return Ok(IrqReturn::Handled);
|
||||
}
|
||||
|
@ -19,12 +19,14 @@ use crate::{
|
||||
},
|
||||
serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort},
|
||||
tty::{
|
||||
console::ConsoleSwitch,
|
||||
kthread::send_to_tty_refresh_thread,
|
||||
termios::WindowSize,
|
||||
tty_core::{TtyCore, TtyCoreData},
|
||||
tty_driver::{TtyDriver, TtyDriverManager, TtyOperation},
|
||||
virtual_terminal::{vc_manager, VirtConsole},
|
||||
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, VirtConsole},
|
||||
},
|
||||
video::console::dummycon::dummy_console,
|
||||
},
|
||||
exception::{
|
||||
irqdata::IrqHandlerData,
|
||||
@ -32,7 +34,7 @@ use crate::{
|
||||
manage::irq_manager,
|
||||
IrqNumber,
|
||||
},
|
||||
libs::rwlock::RwLock,
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
@ -265,9 +267,20 @@ impl UartPort for Serial8250PIOPort {
|
||||
}
|
||||
|
||||
fn handle_irq(&self) -> Result<(), SystemError> {
|
||||
if let Some(c) = self.read_one_byte() {
|
||||
send_to_tty_refresh_thread(&[c]);
|
||||
let mut buf = [0; 8];
|
||||
let mut index = 0;
|
||||
|
||||
// Read up to the size of the buffer
|
||||
while index < buf.len() {
|
||||
if let Some(c) = self.read_one_byte() {
|
||||
buf[index] = c;
|
||||
index += 1;
|
||||
} else {
|
||||
break; // No more bytes to read
|
||||
}
|
||||
}
|
||||
|
||||
send_to_tty_refresh_thread(&buf[0..index]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -385,7 +398,18 @@ impl TtyOperation for Serial8250PIOTtyDriverInner {
|
||||
if tty.core().index() >= unsafe { PIO_PORTS.len() } {
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
let vc = VirtConsole::new(None);
|
||||
|
||||
*tty.core().window_size_write() = WindowSize::DEFAULT;
|
||||
let vc_data = Arc::new(SpinLock::new(VirtualConsoleData::new(usize::MAX)));
|
||||
let mut vc_data_guard = vc_data.lock_irqsave();
|
||||
vc_data_guard.set_driver_funcs(Arc::downgrade(&dummy_console()) as Weak<dyn ConsoleSwitch>);
|
||||
vc_data_guard.init(
|
||||
Some(tty.core().window_size().row.into()),
|
||||
Some(tty.core().window_size().col.into()),
|
||||
true,
|
||||
);
|
||||
drop(vc_data_guard);
|
||||
let vc = VirtConsole::new(Some(vc_data));
|
||||
let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
|
||||
self.do_install(driver, tty, vc.clone()).inspect_err(|_| {
|
||||
vc_manager().free(vc_index);
|
||||
|
@ -12,7 +12,6 @@ use crate::{
|
||||
kobject::KObject,
|
||||
subsys::SubSysPrivate,
|
||||
},
|
||||
filesystem::sysfs::AttributeGroup,
|
||||
init::initcall::INITCALL_SUBSYS,
|
||||
};
|
||||
|
||||
@ -62,7 +61,6 @@ impl Class for TtyClass {
|
||||
fn subsystem(&self) -> &SubSysPrivate {
|
||||
return &self.subsystem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// 初始化帧缓冲区子系统
|
||||
|
@ -2,7 +2,7 @@ use super::tty_ldisc::LineDisciplineType;
|
||||
|
||||
/// ## 窗口大小
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||
pub struct WindowSize {
|
||||
/// 行
|
||||
pub row: u16,
|
||||
@ -26,12 +26,6 @@ impl WindowSize {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WindowSize {
|
||||
fn default() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Termios {
|
||||
pub input_mode: InputMode,
|
||||
|
@ -31,7 +31,7 @@ use super::{
|
||||
TtyLineDiscipline,
|
||||
},
|
||||
tty_port::TtyPort,
|
||||
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData},
|
||||
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, DrawRegion},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -103,7 +103,7 @@ impl TtyCore {
|
||||
self.line_discipline.clone()
|
||||
}
|
||||
|
||||
pub fn write_without_serial(&self, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
|
||||
pub fn write_to_core(&self, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
|
||||
self.core
|
||||
.driver()
|
||||
.driver_funcs()
|
||||
@ -489,6 +489,61 @@ impl TtyCoreData {
|
||||
pub fn add_epitem(&self, epitem: Arc<EPollItem>) {
|
||||
self.epitems.lock().push_back(epitem)
|
||||
}
|
||||
|
||||
pub fn eptiems(&self) -> &SpinLock<LinkedList<Arc<EPollItem>>> {
|
||||
&self.epitems
|
||||
}
|
||||
|
||||
pub fn do_write(&self, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
|
||||
// 关闭中断
|
||||
if let Some(vc_data) = self.vc_data() {
|
||||
let mut vc_data_guard = vc_data.lock_irqsave();
|
||||
let mut offset = 0;
|
||||
|
||||
// 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着
|
||||
let mut rescan = false;
|
||||
let mut ch: u32 = 0;
|
||||
|
||||
let mut draw = DrawRegion::default();
|
||||
|
||||
// 首先隐藏光标再写
|
||||
vc_data_guard.hide_cursor();
|
||||
|
||||
while nr != 0 {
|
||||
if !rescan {
|
||||
ch = buf[offset] as u32;
|
||||
offset += 1;
|
||||
nr -= 1;
|
||||
}
|
||||
|
||||
let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
|
||||
if tc.is_none() {
|
||||
// 表示未转换完成
|
||||
continue;
|
||||
}
|
||||
|
||||
let tc = tc.unwrap();
|
||||
rescan = rescan_last;
|
||||
|
||||
if vc_data_guard.is_control(tc, ch) {
|
||||
vc_data_guard.flush(&mut draw);
|
||||
vc_data_guard.do_control(ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
vc_data_guard.flush(&mut draw);
|
||||
|
||||
// TODO: notify update
|
||||
return Ok(offset);
|
||||
} else {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TtyOperation for TtyCore {
|
||||
|
@ -4,7 +4,10 @@ use alloc::sync::{Arc, Weak};
|
||||
use kdepends::thingbuf::mpsc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
||||
use crate::{
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
net::event_poll::EventPoll,
|
||||
};
|
||||
|
||||
use super::tty_core::TtyCore;
|
||||
|
||||
@ -85,6 +88,8 @@ pub trait TtyPort: Sync + Send + Debug {
|
||||
return ld.receive_buf(tty, buf, None, count);
|
||||
}
|
||||
|
||||
EventPoll::wakeup_epoll(tty.core().eptiems(), None)?;
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
@ -300,55 +300,6 @@ impl TtyConsoleDriverInner {
|
||||
Ok(Self { console })
|
||||
}
|
||||
|
||||
fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
|
||||
// 关闭中断
|
||||
let vc_data = tty.vc_data().unwrap();
|
||||
let mut vc_data_guard = vc_data.lock_irqsave();
|
||||
|
||||
let mut offset = 0;
|
||||
|
||||
// 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着
|
||||
let mut rescan = false;
|
||||
let mut ch: u32 = 0;
|
||||
|
||||
let mut draw = DrawRegion::default();
|
||||
|
||||
// 首先隐藏光标再写
|
||||
vc_data_guard.hide_cursor();
|
||||
|
||||
while nr != 0 {
|
||||
if !rescan {
|
||||
ch = buf[offset] as u32;
|
||||
offset += 1;
|
||||
nr -= 1;
|
||||
}
|
||||
|
||||
let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
|
||||
if tc.is_none() {
|
||||
// 表示未转换完成
|
||||
continue;
|
||||
}
|
||||
|
||||
let tc = tc.unwrap();
|
||||
rescan = rescan_last;
|
||||
|
||||
if vc_data_guard.is_control(tc, ch) {
|
||||
vc_data_guard.flush(&mut draw);
|
||||
vc_data_guard.do_control(ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
vc_data_guard.flush(&mut draw);
|
||||
|
||||
// TODO: notify update
|
||||
return Ok(offset);
|
||||
}
|
||||
|
||||
fn do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError> {
|
||||
let tty_core = tty.core();
|
||||
|
||||
@ -426,7 +377,7 @@ impl TtyOperation for TtyConsoleDriverInner {
|
||||
// loop {}
|
||||
// }
|
||||
send_to_default_serial8250_port(buf);
|
||||
let ret = self.do_write(tty, buf, nr);
|
||||
let ret = tty.do_write(buf, nr);
|
||||
self.flush_chars(tty);
|
||||
ret
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ impl VirtualConsoleData {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
|
||||
pub fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
|
||||
if let Some(rows) = rows {
|
||||
self.rows = rows;
|
||||
}
|
||||
@ -242,7 +242,7 @@ impl VirtualConsoleData {
|
||||
self.driver_funcs.as_ref().unwrap().upgrade().unwrap()
|
||||
}
|
||||
|
||||
pub(super) fn set_driver_funcs(&mut self, func: Weak<dyn ConsoleSwitch>) {
|
||||
pub fn set_driver_funcs(&mut self, func: Weak<dyn ConsoleSwitch>) {
|
||||
self.driver_funcs = Some(func);
|
||||
}
|
||||
|
||||
@ -312,7 +312,7 @@ impl VirtualConsoleData {
|
||||
///
|
||||
/// ### 返回值
|
||||
/// ### (转换后的字符:i32,是否需要更多的数据才能进行转换:bool)
|
||||
pub(super) fn translate(&mut self, c: &mut u32) -> (Option<u32>, bool) {
|
||||
pub fn translate(&mut self, c: &mut u32) -> (Option<u32>, bool) {
|
||||
if self.vc_state != VirtualConsoleState::ESnormal {
|
||||
// 在控制字符状态下不需要翻译
|
||||
return (Some(*c), false);
|
||||
@ -440,7 +440,7 @@ impl VirtualConsoleData {
|
||||
const CTRL_ALWAYS: u32 = 0x0800f501;
|
||||
|
||||
/// ## 用于判断tc(终端字符)在当前VC下是不是需要显示的控制字符
|
||||
pub(super) fn is_control(&self, tc: u32, c: u32) -> bool {
|
||||
pub fn is_control(&self, tc: u32, c: u32) -> bool {
|
||||
// 当前vc状态机不在正常状态,即在接收特殊字符的状态,则是控制字符
|
||||
if self.vc_state != VirtualConsoleState::ESnormal {
|
||||
return true;
|
||||
@ -1257,7 +1257,7 @@ impl VirtualConsoleData {
|
||||
|
||||
/// ## 处理终端控制字符
|
||||
#[inline(never)]
|
||||
pub(super) fn do_control(&mut self, ch: u32) {
|
||||
pub fn do_control(&mut self, ch: u32) {
|
||||
// 首先检查是否处于 ANSI 控制字符串状态
|
||||
if self.vc_state.is_ansi_control_string() && (8..=13).contains(&ch) {
|
||||
return;
|
||||
@ -1534,12 +1534,7 @@ impl VirtualConsoleData {
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub(super) fn console_write_normal(
|
||||
&mut self,
|
||||
mut tc: u32,
|
||||
c: u32,
|
||||
draw: &mut DrawRegion,
|
||||
) -> bool {
|
||||
pub fn console_write_normal(&mut self, mut tc: u32, c: u32, draw: &mut DrawRegion) -> bool {
|
||||
let mut attr = self.attr;
|
||||
let himask = self.hi_font_mask;
|
||||
let charmask = if himask == 0 { 0xff } else { 0x1ff };
|
||||
@ -1753,7 +1748,7 @@ impl VirtualConsoleData {
|
||||
return (self.attr & 0x88) | ((self.attr & 0x70) >> 4) | ((self.attr & 0x07) << 4);
|
||||
}
|
||||
|
||||
pub(super) fn flush(&self, draw: &mut DrawRegion) {
|
||||
pub fn flush(&self, draw: &mut DrawRegion) {
|
||||
if draw.x.is_none() {
|
||||
return;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ impl IndexNode for EventFdInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
|
||||
|
||||
return Ok(8);
|
||||
}
|
||||
@ -184,7 +184,7 @@ impl IndexNode for EventFdInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
|
||||
return Ok(8);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use log::{error, info};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::block::manager::block_dev_manager,
|
||||
driver::base::block::{gendisk::GenDisk, manager::block_dev_manager},
|
||||
filesystem::{
|
||||
devfs::devfs_init,
|
||||
fat::fs::FATFileSystem,
|
||||
@ -28,6 +28,7 @@ use super::{
|
||||
|
||||
/// 当没有指定根文件系统时,尝试的根文件系统列表
|
||||
const ROOTFS_TRY_LIST: [&str; 4] = ["/dev/sda1", "/dev/sda", "/dev/vda1", "/dev/vda"];
|
||||
kernel_cmdline_param_kv!(ROOTFS_PATH_PARAM, root, "");
|
||||
|
||||
/// @brief 原子地生成新的Inode号。
|
||||
/// 请注意,所有的inode号都需要通过该函数来生成.全局的inode号,除了以下两个特殊的以外,都是唯一的
|
||||
@ -116,20 +117,26 @@ fn migrate_virtual_filesystem(new_fs: Arc<dyn FileSystem>) -> Result<(), SystemE
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn try_find_gendisk_as_rootfs(path: &str) -> Option<Arc<GenDisk>> {
|
||||
if let Some(gd) = block_dev_manager().lookup_gendisk_by_path(path) {
|
||||
info!("Use {} as rootfs", path);
|
||||
return Some(gd);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn mount_root_fs() -> Result<(), SystemError> {
|
||||
info!("Try to mount root fs...");
|
||||
block_dev_manager().print_gendisks();
|
||||
|
||||
let gendisk = ROOTFS_TRY_LIST
|
||||
.iter()
|
||||
.find_map(|&path| {
|
||||
if let Some(gd) = block_dev_manager().lookup_gendisk_by_path(path) {
|
||||
info!("Use {} as rootfs", path);
|
||||
return Some(gd);
|
||||
}
|
||||
return None;
|
||||
})
|
||||
.ok_or(SystemError::ENODEV)?;
|
||||
let gendisk = if let Some(rootfs_dev_path) = ROOTFS_PATH_PARAM.value_str() {
|
||||
try_find_gendisk_as_rootfs(rootfs_dev_path)
|
||||
.unwrap_or_else(|| panic!("Failed to find rootfs device {}", rootfs_dev_path))
|
||||
} else {
|
||||
ROOTFS_TRY_LIST
|
||||
.iter()
|
||||
.find_map(|&path| try_find_gendisk_as_rootfs(path))
|
||||
.ok_or(SystemError::ENODEV)?
|
||||
};
|
||||
|
||||
let fatfs: Result<Arc<FATFileSystem>, SystemError> = FATFileSystem::new(gendisk);
|
||||
if fatfs.is_err() {
|
||||
|
@ -399,6 +399,15 @@ impl IndexNode for MountFSInode {
|
||||
return self.inner_inode.ioctl(cmd, data, private_data);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn kernel_ioctl(
|
||||
&self,
|
||||
arg: Arc<dyn crate::net::event_poll::KernelIoctlData>,
|
||||
data: &FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
return self.inner_inode.kernel_ioctl(arg, data);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
|
||||
return self.inner_inode.list();
|
||||
|
@ -46,13 +46,20 @@ impl BootParams {
|
||||
|
||||
/// 开机命令行参数字符串
|
||||
pub fn boot_cmdline_str(&self) -> &str {
|
||||
core::str::from_utf8(self.boot_cmdline()).unwrap()
|
||||
core::str::from_utf8(&self.boot_cmdline()[..self.boot_cmdline_len()]).unwrap()
|
||||
}
|
||||
|
||||
pub fn bootloader_name(&self) -> Option<&str> {
|
||||
self.bootloader_name.as_deref()
|
||||
}
|
||||
|
||||
pub fn boot_cmdline_len(&self) -> usize {
|
||||
self.boot_command_line
|
||||
.iter()
|
||||
.position(|&x| x == 0)
|
||||
.unwrap_or(self.boot_command_line.len())
|
||||
}
|
||||
|
||||
/// 追加开机命令行参数
|
||||
///
|
||||
/// 如果开机命令行参数已经满了,则不会追加。
|
||||
@ -149,13 +156,6 @@ pub fn boot_callbacks() -> &'static dyn BootCallbacks {
|
||||
}
|
||||
|
||||
pub(super) fn boot_callback_except_early() {
|
||||
boot_callbacks()
|
||||
.init_kernel_cmdline()
|
||||
.inspect_err(|e| {
|
||||
log::error!("Failed to init kernel cmdline: {:?}", e);
|
||||
})
|
||||
.ok();
|
||||
|
||||
let mut boot_params = boot_params().write();
|
||||
boot_params.bootloader_name = boot_callbacks()
|
||||
.init_bootloader_name()
|
||||
|
476
kernel/src/init/cmdline.rs
Normal file
476
kernel/src/init/cmdline.rs
Normal file
@ -0,0 +1,476 @@
|
||||
use core::{
|
||||
str,
|
||||
sync::atomic::{fence, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{ffi::CString, vec::Vec};
|
||||
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
|
||||
use super::boot_params;
|
||||
|
||||
#[::linkme::distributed_slice]
|
||||
pub static KCMDLINE_PARAM_EARLY_KV: [KernelCmdlineParameter] = [..];
|
||||
|
||||
#[::linkme::distributed_slice]
|
||||
pub static KCMDLINE_PARAM_KV: [KernelCmdlineParameter] = [..];
|
||||
|
||||
#[::linkme::distributed_slice]
|
||||
pub static KCMDLINE_PARAM_ARG: [KernelCmdlineParameter] = [..];
|
||||
|
||||
static KERNEL_CMDLINE_PARAM_MANAGER: KernelCmdlineManager = KernelCmdlineManager::new();
|
||||
|
||||
#[inline(always)]
|
||||
pub fn kenrel_cmdline_param_manager() -> &'static KernelCmdlineManager {
|
||||
&KERNEL_CMDLINE_PARAM_MANAGER
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum KCmdlineParamType {
|
||||
/// bool类型参数
|
||||
Arg,
|
||||
/// key-value类型参数
|
||||
KV,
|
||||
/// 内存管理初始化之前的KV参数
|
||||
EarlyKV,
|
||||
}
|
||||
|
||||
pub struct KernelCmdlineParamBuilder {
|
||||
name: &'static str,
|
||||
ty: KCmdlineParamType,
|
||||
default_str: &'static str,
|
||||
default_bool: bool,
|
||||
inv: bool,
|
||||
}
|
||||
|
||||
impl KernelCmdlineParamBuilder {
|
||||
pub const fn new(name: &'static str, ty: KCmdlineParamType) -> Self {
|
||||
Self {
|
||||
name,
|
||||
ty,
|
||||
default_str: "",
|
||||
default_bool: false,
|
||||
inv: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn default_str(mut self, default_str: &'static str) -> Self {
|
||||
self.default_str = default_str;
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn default_bool(mut self, default_bool: bool) -> Self {
|
||||
self.default_bool = default_bool;
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn inv(mut self, inv: bool) -> Self {
|
||||
self.inv = inv;
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn build_early_kv(self) -> Option<KernelCmdlineEarlyKV> {
|
||||
if matches!(self.ty, KCmdlineParamType::EarlyKV) {
|
||||
Some(KernelCmdlineEarlyKV {
|
||||
name: self.name,
|
||||
value: [0; KernelCmdlineEarlyKV::VALUE_MAX_LEN],
|
||||
index: 0,
|
||||
initialized: false,
|
||||
default: self.default_str,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn build(self) -> Option<KernelCmdlineParameter> {
|
||||
match self.ty {
|
||||
KCmdlineParamType::Arg => Some(KernelCmdlineParameter::Arg(KernelCmdlineArg {
|
||||
name: self.name,
|
||||
value: self.default_bool,
|
||||
initialized: false,
|
||||
inv: self.inv,
|
||||
default: self.default_bool,
|
||||
})),
|
||||
KCmdlineParamType::KV => Some(KernelCmdlineParameter::KV(KernelCmdlineKV {
|
||||
name: self.name,
|
||||
value: None,
|
||||
initialized: false,
|
||||
default: self.default_str,
|
||||
})),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum KernelCmdlineParameter {
|
||||
Arg(KernelCmdlineArg),
|
||||
KV(KernelCmdlineKV),
|
||||
EarlyKV(&'static KernelCmdlineEarlyKV),
|
||||
}
|
||||
|
||||
impl KernelCmdlineParameter {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
KernelCmdlineParameter::Arg(v) => v.name,
|
||||
KernelCmdlineParameter::KV(v) => v.name,
|
||||
KernelCmdlineParameter::EarlyKV(v) => v.name,
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取bool类型参数的值
|
||||
pub fn value_bool(&self) -> Option<bool> {
|
||||
match self {
|
||||
KernelCmdlineParameter::Arg(v) => Some(v.value()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取key-value类型参数的值
|
||||
pub fn value_str(&self) -> Option<&str> {
|
||||
match self {
|
||||
KernelCmdlineParameter::Arg(_) => None,
|
||||
KernelCmdlineParameter::KV(v) => v
|
||||
.value
|
||||
.as_ref()
|
||||
.and_then(|v| str::from_utf8(v.as_bytes()).ok()),
|
||||
KernelCmdlineParameter::EarlyKV(v) => v.value_str(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_arg(&self) -> bool {
|
||||
matches!(self, KernelCmdlineParameter::Arg(_))
|
||||
}
|
||||
|
||||
pub fn is_kv(&self) -> bool {
|
||||
matches!(self, KernelCmdlineParameter::KV(_))
|
||||
}
|
||||
|
||||
pub fn is_early_kv(&self) -> bool {
|
||||
matches!(self, KernelCmdlineParameter::EarlyKV(_))
|
||||
}
|
||||
|
||||
/// 强行获取可变引用
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 只能在内核初始化阶段pid0使用!
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
unsafe fn force_mut(&self) -> &mut Self {
|
||||
let p = self as *const Self as *mut Self;
|
||||
p.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct KernelCmdlineArg {
|
||||
name: &'static str,
|
||||
value: bool,
|
||||
initialized: bool,
|
||||
/// 是否反转
|
||||
inv: bool,
|
||||
default: bool,
|
||||
}
|
||||
|
||||
impl KernelCmdlineArg {
|
||||
pub fn value(&self) -> bool {
|
||||
volatile_read!(self.value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KernelCmdlineKV {
|
||||
name: &'static str,
|
||||
value: Option<CString>,
|
||||
initialized: bool,
|
||||
default: &'static str,
|
||||
}
|
||||
|
||||
/// 在内存管理初始化之前的KV参数
|
||||
pub struct KernelCmdlineEarlyKV {
|
||||
name: &'static str,
|
||||
value: [u8; Self::VALUE_MAX_LEN],
|
||||
index: usize,
|
||||
initialized: bool,
|
||||
default: &'static str,
|
||||
}
|
||||
|
||||
impl KernelCmdlineEarlyKV {
|
||||
pub const VALUE_MAX_LEN: usize = 256;
|
||||
|
||||
pub fn value(&self) -> &[u8] {
|
||||
&self.value[..self.index]
|
||||
}
|
||||
|
||||
pub fn value_str(&self) -> Option<&str> {
|
||||
core::str::from_utf8(&self.value[..self.index]).ok()
|
||||
}
|
||||
|
||||
/// 强行获取可变引用
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 只能在内核初始化阶段pid0使用!
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
unsafe fn force_mut(&self) -> &mut Self {
|
||||
let p = self as *const Self as *mut Self;
|
||||
p.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KernelCmdlineManager {
|
||||
inner: SpinLock<InnerKernelCmdlineManager>,
|
||||
}
|
||||
|
||||
pub(super) struct InnerKernelCmdlineManager {
|
||||
/// init进程的路径
|
||||
init_path: Option<CString>,
|
||||
init_args: Vec<CString>,
|
||||
init_envs: Vec<CString>,
|
||||
}
|
||||
|
||||
impl KernelCmdlineManager {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
inner: SpinLock::new(InnerKernelCmdlineManager {
|
||||
init_path: None,
|
||||
init_args: Vec::new(),
|
||||
init_envs: Vec::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn init_proc_path(&self) -> Option<CString> {
|
||||
self.inner.lock().init_path.clone()
|
||||
}
|
||||
|
||||
pub(super) fn init_proc_args(&self) -> Vec<CString> {
|
||||
self.inner.lock().init_args.clone()
|
||||
}
|
||||
|
||||
pub(super) fn init_proc_envs(&self) -> Vec<CString> {
|
||||
self.inner.lock().init_envs.clone()
|
||||
}
|
||||
|
||||
/// 在内存管理初始化之前设置部分参数
|
||||
pub fn early_init(&self) {
|
||||
let boot_params = boot_params().read();
|
||||
|
||||
for argument in self.split_args(boot_params.boot_cmdline_str()) {
|
||||
let (node, option, value) = match self.split_arg(argument) {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
// 查找参数
|
||||
if let Some(param) = self.find_param(node, option, KCmdlineParamType::EarlyKV) {
|
||||
let param = unsafe { param.force_mut() };
|
||||
match param {
|
||||
KernelCmdlineParameter::EarlyKV(p) => {
|
||||
let p = unsafe { p.force_mut() };
|
||||
if let Some(value) = value {
|
||||
let value = value.as_bytes();
|
||||
let len = value.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN);
|
||||
p.value[..len].copy_from_slice(&value[..len]);
|
||||
p.index = len;
|
||||
}
|
||||
p.initialized = true;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
fence(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化默认值
|
||||
KCMDLINE_PARAM_EARLY_KV.iter().for_each(|x| {
|
||||
let x = unsafe { x.force_mut() };
|
||||
if let KernelCmdlineParameter::EarlyKV(v) = x {
|
||||
if !v.initialized {
|
||||
let v = unsafe { v.force_mut() };
|
||||
let len = v.default.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN);
|
||||
v.value[..len].copy_from_slice(v.default.as_bytes());
|
||||
v.index = len;
|
||||
v.initialized = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// 在内存管理初始化之后设置命令行参数
|
||||
pub fn init(&self) {
|
||||
let mut inner = self.inner.lock();
|
||||
let boot_params = boot_params().read();
|
||||
// `--`以后的参数都是init进程的参数
|
||||
let mut kernel_cmdline_end = false;
|
||||
for argument in self.split_args(boot_params.boot_cmdline_str()) {
|
||||
if kernel_cmdline_end {
|
||||
if inner.init_path.is_none() {
|
||||
panic!("cmdline: init proc path is not set while init proc args are set");
|
||||
}
|
||||
if !argument.is_empty() {
|
||||
inner.init_args.push(CString::new(argument).unwrap());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if argument == "--" {
|
||||
kernel_cmdline_end = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
let (node, option, value) = match self.split_arg(argument) {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
if option == "init" && value.is_some() {
|
||||
if inner.init_path.is_some() {
|
||||
panic!("cmdline: init proc path is set twice");
|
||||
}
|
||||
inner.init_path = Some(CString::new(value.unwrap()).unwrap());
|
||||
continue;
|
||||
}
|
||||
// log::debug!(
|
||||
// "cmdline: node: {:?}, option: {:?}, value: {:?}",
|
||||
// node,
|
||||
// option,
|
||||
// value
|
||||
// );
|
||||
if let Some(param) = self.find_param(node, option, KCmdlineParamType::KV) {
|
||||
let param = unsafe { param.force_mut() };
|
||||
match param {
|
||||
KernelCmdlineParameter::KV(p) => {
|
||||
if p.value.is_some() {
|
||||
log::warn!("cmdline: parameter {} is set twice", p.name);
|
||||
continue;
|
||||
}
|
||||
p.value = Some(CString::new(value.unwrap()).unwrap());
|
||||
p.initialized = true;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
fence(Ordering::SeqCst);
|
||||
} else if let Some(param) = self.find_param(node, option, KCmdlineParamType::Arg) {
|
||||
let param = unsafe { param.force_mut() };
|
||||
match param {
|
||||
KernelCmdlineParameter::Arg(p) => {
|
||||
if p.initialized {
|
||||
log::warn!("cmdline: parameter {} is set twice", p.name);
|
||||
continue;
|
||||
}
|
||||
p.value = !p.inv;
|
||||
p.initialized = true;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
fence(Ordering::SeqCst);
|
||||
} else if node.is_none() {
|
||||
if let Some(val) = value {
|
||||
inner
|
||||
.init_envs
|
||||
.push(CString::new(format!("{}={}", option, val)).unwrap());
|
||||
} else if !option.is_empty() {
|
||||
inner.init_args.push(CString::new(option).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
fence(Ordering::SeqCst);
|
||||
// 初始化默认值
|
||||
self.default_initialize();
|
||||
fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn default_initialize(&self) {
|
||||
KCMDLINE_PARAM_ARG.iter().for_each(|x| {
|
||||
let x = unsafe { x.force_mut() };
|
||||
if let KernelCmdlineParameter::Arg(v) = x {
|
||||
if !v.initialized {
|
||||
v.value = v.default;
|
||||
v.initialized = true;
|
||||
}
|
||||
}
|
||||
fence(Ordering::SeqCst);
|
||||
});
|
||||
|
||||
KCMDLINE_PARAM_KV.iter().for_each(|x| {
|
||||
let x = unsafe { x.force_mut() };
|
||||
if let KernelCmdlineParameter::KV(v) = x {
|
||||
if !v.initialized {
|
||||
v.value = Some(CString::new(v.default).unwrap());
|
||||
v.initialized = true;
|
||||
}
|
||||
}
|
||||
fence(Ordering::SeqCst);
|
||||
});
|
||||
}
|
||||
|
||||
fn find_param(
|
||||
&self,
|
||||
node: Option<&str>,
|
||||
option: &str,
|
||||
param_typ: KCmdlineParamType,
|
||||
) -> Option<&KernelCmdlineParameter> {
|
||||
let list = match param_typ {
|
||||
KCmdlineParamType::Arg => &KCMDLINE_PARAM_ARG,
|
||||
KCmdlineParamType::KV => &KCMDLINE_PARAM_KV,
|
||||
KCmdlineParamType::EarlyKV => &KCMDLINE_PARAM_EARLY_KV,
|
||||
};
|
||||
|
||||
list.iter().find(|x| {
|
||||
let name = x.name();
|
||||
if let Some(node) = node {
|
||||
// 加1是因为有一个点号
|
||||
name.len() == (node.len() + option.len() + 1)
|
||||
&& name.starts_with(node)
|
||||
&& name[node.len() + 1..].starts_with(option)
|
||||
} else {
|
||||
name == option
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn split_arg<'a>(&self, arg: &'a str) -> Option<(Option<&'a str>, &'a str, Option<&'a str>)> {
|
||||
let mut iter = arg.splitn(2, '=');
|
||||
let key = iter.next().unwrap();
|
||||
let value = iter.next();
|
||||
let value = value.map(|v| v.trim());
|
||||
if value.is_some() && iter.next().is_some() {
|
||||
log::warn!("cmdline: invalid argument: {}", arg);
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut iter = key.splitn(2, '.');
|
||||
let v1 = iter.next().map(|v| v.trim());
|
||||
let v2 = iter.next().map(|v| v.trim());
|
||||
let v3 = iter.next().map(|v| v.trim());
|
||||
let v = [v1, v2, v3];
|
||||
|
||||
let mut key_split_len = 0;
|
||||
v.iter().for_each(|x| {
|
||||
if x.is_some() {
|
||||
key_split_len += 1
|
||||
}
|
||||
});
|
||||
|
||||
let (node, option) = match key_split_len {
|
||||
1 => (None, v[0].unwrap()),
|
||||
2 => (Some(v[0].unwrap()), v[1].unwrap()),
|
||||
_ => {
|
||||
log::warn!("cmdline: invalid argument: {}", arg);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some((node, option, value))
|
||||
}
|
||||
|
||||
fn split_args<'a>(&self, cmdline: &'a str) -> impl Iterator<Item = &'a str> {
|
||||
// 是否在引号内
|
||||
let mut in_quote = false;
|
||||
cmdline.split(move |c: char| {
|
||||
if c == '"' {
|
||||
in_quote = !in_quote;
|
||||
}
|
||||
!in_quote && c.is_whitespace()
|
||||
})
|
||||
}
|
||||
}
|
@ -31,7 +31,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::boot::boot_callback_except_early;
|
||||
use super::{
|
||||
boot::{boot_callback_except_early, boot_callbacks},
|
||||
cmdline::kenrel_cmdline_param_manager,
|
||||
};
|
||||
|
||||
/// The entry point for the kernel
|
||||
///
|
||||
@ -52,9 +55,7 @@ pub fn start_kernel() -> ! {
|
||||
#[inline(never)]
|
||||
fn do_start_kernel() {
|
||||
init_before_mem_init();
|
||||
early_init_logging();
|
||||
|
||||
early_setup_arch().expect("setup_arch failed");
|
||||
unsafe { mm_init() };
|
||||
|
||||
if scm_reinit().is_ok() {
|
||||
@ -62,8 +63,10 @@ fn do_start_kernel() {
|
||||
warn!("Failed to init textui: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化内核命令行参数
|
||||
kenrel_cmdline_param_manager().init();
|
||||
boot_callback_except_early();
|
||||
|
||||
init_intertrait();
|
||||
|
||||
vfs_init().expect("vfs init failed");
|
||||
@ -99,4 +102,16 @@ fn init_before_mem_init() {
|
||||
serial_early_init().expect("serial early init failed");
|
||||
let video_ok = unsafe { VideoRefreshManager::video_init().is_ok() };
|
||||
scm_init(video_ok);
|
||||
|
||||
early_init_logging();
|
||||
|
||||
early_setup_arch().expect("setup_arch failed");
|
||||
|
||||
boot_callbacks()
|
||||
.init_kernel_cmdline()
|
||||
.inspect_err(|e| {
|
||||
log::error!("Failed to init kernel cmdline: {:?}", e);
|
||||
})
|
||||
.ok();
|
||||
kenrel_cmdline_param_manager().early_init();
|
||||
}
|
||||
|
@ -14,12 +14,17 @@ use crate::{
|
||||
},
|
||||
filesystem::vfs::core::mount_root_fs,
|
||||
net::net_core::net_init,
|
||||
process::{kthread::KernelThreadMechanism, stdio::stdio_init, ProcessFlags, ProcessManager},
|
||||
process::{
|
||||
exec::ProcInitInfo, kthread::KernelThreadMechanism, stdio::stdio_init, ProcessFlags,
|
||||
ProcessManager,
|
||||
},
|
||||
smp::smp_init,
|
||||
syscall::Syscall,
|
||||
};
|
||||
|
||||
use super::initcall::do_initcalls;
|
||||
use super::{cmdline::kenrel_cmdline_param_manager, initcall::do_initcalls};
|
||||
|
||||
const INIT_PROC_TRYLIST: [&str; 3] = ["/bin/dragonreach", "/bin/init", "/bin/sh"];
|
||||
|
||||
pub fn initial_kernel_thread() -> i32 {
|
||||
kernel_init().unwrap_or_else(|err| {
|
||||
@ -73,39 +78,79 @@ fn switch_to_user() -> ! {
|
||||
*current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS;
|
||||
drop(current_pcb);
|
||||
|
||||
let mut trap_frame = TrapFrame::new();
|
||||
// 逐个尝试运行init进程
|
||||
if try_to_run_init_process("/bin/dragonreach", &mut trap_frame).is_err()
|
||||
&& try_to_run_init_process("/bin/init", &mut trap_frame).is_err()
|
||||
&& try_to_run_init_process("/bin/sh", &mut trap_frame).is_err()
|
||||
{
|
||||
panic!("Failed to run init process: No working init found.");
|
||||
}
|
||||
let mut proc_init_info = ProcInitInfo::new("");
|
||||
proc_init_info.envs.push(CString::new("PATH=/").unwrap());
|
||||
proc_init_info.args = kenrel_cmdline_param_manager().init_proc_args();
|
||||
proc_init_info.envs = kenrel_cmdline_param_manager().init_proc_envs();
|
||||
|
||||
let mut trap_frame = TrapFrame::new();
|
||||
|
||||
if let Some(path) = kenrel_cmdline_param_manager().init_proc_path() {
|
||||
log::info!("Boot with specified init process: {:?}", path);
|
||||
|
||||
try_to_run_init_process(
|
||||
path.as_c_str().to_str().unwrap(),
|
||||
&mut proc_init_info,
|
||||
&mut trap_frame,
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"Failed to run specified init process: {:?}, err: {:?}",
|
||||
path, e
|
||||
)
|
||||
});
|
||||
} else {
|
||||
let mut ok = false;
|
||||
for path in INIT_PROC_TRYLIST.iter() {
|
||||
if try_to_run_init_process(path, &mut proc_init_info, &mut trap_frame).is_ok() {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
panic!("Failed to run init process: No working init found.");
|
||||
}
|
||||
}
|
||||
drop(proc_init_info);
|
||||
// 需要确保执行到这里之后,上面所有的资源都已经释放(比如arc之类的)
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
unsafe { arch_switch_to_user(trap_frame) };
|
||||
}
|
||||
|
||||
fn try_to_run_init_process(path: &str, trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
|
||||
if let Err(e) = run_init_process(path, trap_frame) {
|
||||
fn try_to_run_init_process(
|
||||
path: &str,
|
||||
proc_init_info: &mut ProcInitInfo,
|
||||
trap_frame: &mut TrapFrame,
|
||||
) -> Result<(), SystemError> {
|
||||
proc_init_info.proc_name = CString::new(path).unwrap();
|
||||
proc_init_info.args.insert(0, CString::new(path).unwrap());
|
||||
if let Err(e) = run_init_process(proc_init_info, trap_frame) {
|
||||
if e != SystemError::ENOENT {
|
||||
error!(
|
||||
"Failed to run init process: {path} exists but couldn't execute it (error {:?})",
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
proc_init_info.args.remove(0);
|
||||
return Err(e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_init_process(path: &str, trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
|
||||
let argv = vec![CString::new(path).unwrap()];
|
||||
let envp = vec![CString::new("PATH=/").unwrap()];
|
||||
|
||||
fn run_init_process(
|
||||
proc_init_info: &ProcInitInfo,
|
||||
trap_frame: &mut TrapFrame,
|
||||
) -> Result<(), SystemError> {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
Syscall::do_execve(path.to_string(), argv, envp, trap_frame)?;
|
||||
let path = proc_init_info.proc_name.to_str().unwrap();
|
||||
|
||||
Syscall::do_execve(
|
||||
path.to_string(),
|
||||
proc_init_info.args.clone(),
|
||||
proc_init_info.envs.clone(),
|
||||
trap_frame,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use crate::libs::rwlock::RwLock;
|
||||
|
||||
use self::boot::BootParams;
|
||||
pub mod boot;
|
||||
pub mod cmdline;
|
||||
#[allow(clippy::module_inception)]
|
||||
pub mod init;
|
||||
pub mod initcall;
|
||||
|
@ -267,7 +267,7 @@ impl IndexNode for LockedPipeInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&inode.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
|
||||
|
||||
//返回读取的字节数
|
||||
return Ok(num);
|
||||
@ -413,7 +413,7 @@ impl IndexNode for LockedPipeInode {
|
||||
|
||||
let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
|
||||
// 唤醒epoll中等待的进程
|
||||
EventPoll::wakeup_epoll(&inode.epitems, pollflag)?;
|
||||
EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
|
||||
|
||||
// 返回写入的字节数
|
||||
return Ok(len);
|
||||
|
@ -81,7 +81,8 @@ extern crate smoltcp;
|
||||
extern crate intertrait;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
extern crate x86;
|
||||
|
||||
#[macro_use]
|
||||
extern crate kcmdline_macros;
|
||||
extern crate klog_types;
|
||||
extern crate uefi;
|
||||
extern crate uefi_raw;
|
||||
|
@ -1045,9 +1045,8 @@ pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32)
|
||||
let port = current_vc.port();
|
||||
let tty = port.port_data().internal_tty();
|
||||
if let Some(tty) = tty {
|
||||
send_to_default_serial8250_port(&[character]);
|
||||
return tty
|
||||
.write_without_serial(buf.as_bytes(), buf.len())
|
||||
.write_to_core(buf.as_bytes(), buf.len())
|
||||
.map(|_| 0)
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl KernelAllocator {
|
||||
return Ok(NonNull::from(slice));
|
||||
}
|
||||
|
||||
unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) {
|
||||
pub(super) unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) {
|
||||
// 由于buddy分配的页数量是2的幂,因此释放的时候也需要按照2的幂向上取整。
|
||||
let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
|
||||
let page_frame_count = PageFrameCount::new(count);
|
||||
|
@ -4,12 +4,16 @@ use alloc::boxed::Box;
|
||||
use log::debug;
|
||||
use slabmalloc::*;
|
||||
|
||||
use crate::{arch::MMArch, mm::MemoryManagementArch, KERNEL_ALLOCATOR};
|
||||
|
||||
// 全局slab分配器
|
||||
pub(crate) static mut SLABALLOCATOR: Option<SlabAllocator> = None;
|
||||
|
||||
// slab初始化状态
|
||||
pub(crate) static mut SLABINITSTATE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
static SLAB_CALLBACK: SlabCallback = SlabCallback;
|
||||
|
||||
/// slab分配器,实际为一堆小的allocator,可以在里面装4K的page
|
||||
/// 利用这些allocator可以为对象分配不同大小的空间
|
||||
pub(crate) struct SlabAllocator {
|
||||
@ -52,7 +56,7 @@ impl SlabAllocator {
|
||||
) -> Result<(), AllocationError> {
|
||||
if let Some(nptr) = NonNull::new(ptr) {
|
||||
self.zone
|
||||
.deallocate(nptr, layout)
|
||||
.deallocate(nptr, layout, &SLAB_CALLBACK)
|
||||
.expect("Couldn't deallocate");
|
||||
return Ok(());
|
||||
} else {
|
||||
@ -80,3 +84,13 @@ pub unsafe fn slab_usage() -> SlabUsage {
|
||||
SlabUsage::new(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// 归还slab_page给buddy的回调
|
||||
pub struct SlabCallback;
|
||||
impl CallBack for SlabCallback {
|
||||
unsafe fn free_slab_page(&self, base_addr: *mut u8, size: usize) {
|
||||
assert_eq!(base_addr as usize & (MMArch::PAGE_SIZE - 1), 0); // 确认地址4k对齐
|
||||
assert_eq!(size, MMArch::PAGE_SIZE); // 确认释放的slab_page大小
|
||||
KERNEL_ALLOCATOR.free_in_buddy(base_addr, Layout::from_size_align_unchecked(size, 1));
|
||||
}
|
||||
}
|
||||
|
@ -716,41 +716,50 @@ impl EventPoll {
|
||||
/// ### epoll的回调,支持epoll的文件有事件到来时直接调用该方法即可
|
||||
pub fn wakeup_epoll(
|
||||
epitems: &SpinLock<LinkedList<Arc<EPollItem>>>,
|
||||
pollflags: EPollEventType,
|
||||
pollflags: Option<EPollEventType>,
|
||||
) -> Result<(), SystemError> {
|
||||
let mut epitems_guard = epitems.try_lock_irqsave()?;
|
||||
// 一次只取一个,因为一次也只有一个进程能拿到对应文件的🔓
|
||||
if let Some(epitem) = epitems_guard.pop_front() {
|
||||
let epoll = epitem.epoll().upgrade().unwrap();
|
||||
let mut epoll_guard = epoll.try_lock()?;
|
||||
let binding = epitem.clone();
|
||||
let event_guard = binding.event().read();
|
||||
let ep_events = EPollEventType::from_bits_truncate(event_guard.events());
|
||||
let pollflags = pollflags.unwrap_or({
|
||||
if let Some(file) = epitem.file.upgrade() {
|
||||
EPollEventType::from_bits_truncate(file.poll()? as u32)
|
||||
} else {
|
||||
EPollEventType::empty()
|
||||
}
|
||||
});
|
||||
|
||||
// 检查事件合理性以及是否有感兴趣的事件
|
||||
if !(ep_events
|
||||
.difference(EPollEventType::EP_PRIVATE_BITS)
|
||||
.is_empty()
|
||||
|| pollflags.difference(ep_events).is_empty())
|
||||
{
|
||||
// TODO: 未处理pm相关
|
||||
if let Some(epoll) = epitem.epoll().upgrade() {
|
||||
let mut epoll_guard = epoll.try_lock()?;
|
||||
let binding = epitem.clone();
|
||||
let event_guard = binding.event().read();
|
||||
let ep_events = EPollEventType::from_bits_truncate(event_guard.events());
|
||||
|
||||
// 首先将就绪的epitem加入等待队列
|
||||
epoll_guard.ep_add_ready(epitem.clone());
|
||||
// 检查事件合理性以及是否有感兴趣的事件
|
||||
if !(ep_events
|
||||
.difference(EPollEventType::EP_PRIVATE_BITS)
|
||||
.is_empty()
|
||||
|| pollflags.difference(ep_events).is_empty())
|
||||
{
|
||||
// TODO: 未处理pm相关
|
||||
|
||||
if epoll_guard.ep_has_waiter() {
|
||||
if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE)
|
||||
&& !pollflags.contains(EPollEventType::POLLFREE)
|
||||
{
|
||||
// 避免惊群
|
||||
epoll_guard.ep_wake_one();
|
||||
} else {
|
||||
epoll_guard.ep_wake_all();
|
||||
// 首先将就绪的epitem加入等待队列
|
||||
epoll_guard.ep_add_ready(epitem.clone());
|
||||
|
||||
if epoll_guard.ep_has_waiter() {
|
||||
if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE)
|
||||
&& !pollflags.contains(EPollEventType::POLLFREE)
|
||||
{
|
||||
// 避免惊群
|
||||
epoll_guard.ep_wake_one();
|
||||
} else {
|
||||
epoll_guard.ep_wake_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
epitems_guard.push_back(epitem);
|
||||
epitems_guard.push_back(epitem);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use log::debug;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
@ -43,14 +42,14 @@ impl Buffer {
|
||||
let len = core::cmp::min(buf.len(), read_buffer.len());
|
||||
buf[..len].copy_from_slice(&read_buffer[..len]);
|
||||
let _ = read_buffer.split_off(len);
|
||||
log::debug!("recv buf {}", String::from_utf8_lossy(buf));
|
||||
// log::debug!("recv buf {}", String::from_utf8_lossy(buf));
|
||||
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
pub fn write_read_buffer(&self, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
let mut buffer = self.read_buffer.lock_irqsave();
|
||||
log::debug!("send buf {}", String::from_utf8_lossy(buf));
|
||||
// log::debug!("send buf {}", String::from_utf8_lossy(buf));
|
||||
let len = buf.len();
|
||||
if self.metadata.buf_size - buffer.len() < len {
|
||||
return Err(SystemError::ENOBUFS);
|
||||
|
@ -45,7 +45,7 @@ impl BoundInner {
|
||||
// iface
|
||||
// }
|
||||
// 强绑VirtualIO
|
||||
log::debug!("Not bind to any iface, bind to virtIO");
|
||||
// log::debug!("Not bind to any iface, bind to virtIO");
|
||||
let iface = NET_DEVICES
|
||||
.read_irqsave()
|
||||
.get(&0)
|
||||
|
@ -3,6 +3,7 @@ use core::sync::atomic::{AtomicU32, AtomicUsize};
|
||||
use crate::libs::rwlock::RwLock;
|
||||
use crate::net::socket::EPollEventType;
|
||||
use crate::net::socket::{self, inet::Types};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use smoltcp;
|
||||
use system_error::SystemError::{self, *};
|
||||
@ -30,13 +31,13 @@ where
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Init {
|
||||
Unbound(smoltcp::socket::tcp::Socket<'static>),
|
||||
Unbound(Box<smoltcp::socket::tcp::Socket<'static>>),
|
||||
Bound((socket::inet::BoundInner, smoltcp::wire::IpEndpoint)),
|
||||
}
|
||||
|
||||
impl Init {
|
||||
pub(super) fn new() -> Self {
|
||||
Init::Unbound(new_smoltcp_socket())
|
||||
Init::Unbound(Box::new(new_smoltcp_socket()))
|
||||
}
|
||||
|
||||
/// 传入一个已经绑定的socket
|
||||
@ -55,7 +56,7 @@ impl Init {
|
||||
) -> Result<Self, SystemError> {
|
||||
match self {
|
||||
Init::Unbound(socket) => {
|
||||
let bound = socket::inet::BoundInner::bind(socket, &local_endpoint.addr)?;
|
||||
let bound = socket::inet::BoundInner::bind(*socket, &local_endpoint.addr)?;
|
||||
bound
|
||||
.port_manager()
|
||||
.bind_port(Types::Tcp, local_endpoint.port)?;
|
||||
@ -73,7 +74,7 @@ impl Init {
|
||||
match self {
|
||||
Init::Unbound(socket) => {
|
||||
let (bound, address) =
|
||||
socket::inet::BoundInner::bind_ephemeral(socket, remote_endpoint.addr)
|
||||
socket::inet::BoundInner::bind_ephemeral(*socket, remote_endpoint.addr)
|
||||
.map_err(|err| (Self::new(), err))?;
|
||||
let bound_port = bound
|
||||
.port_manager()
|
||||
@ -125,7 +126,7 @@ impl Init {
|
||||
} else {
|
||||
smoltcp::wire::IpListenEndpoint::from(local)
|
||||
};
|
||||
log::debug!("listen at {:?}", listen_addr);
|
||||
// log::debug!("listen at {:?}", listen_addr);
|
||||
let mut inners = Vec::new();
|
||||
if let Err(err) = || -> Result<(), SystemError> {
|
||||
for _ in 0..(backlog - 1) {
|
||||
@ -440,4 +441,13 @@ impl Inner {
|
||||
Inner::Established(est) => est.with_mut(|socket| socket.recv_capacity()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iface(&self) -> Option<&alloc::sync::Arc<dyn crate::driver::net::Iface>> {
|
||||
match self {
|
||||
Inner::Init(_) => None,
|
||||
Inner::Connecting(conn) => Some(conn.inner.iface()),
|
||||
Inner::Listening(listen) => Some(listen.inners[0].iface()),
|
||||
Inner::Established(est) => Some(est.inner.iface()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,11 +185,19 @@ impl TcpSocket {
|
||||
}
|
||||
|
||||
pub fn try_recv(&self, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
poll_ifaces();
|
||||
match self.inner.read().as_ref().expect("Tcp Inner is None") {
|
||||
Inner::Established(inner) => inner.recv_slice(buf),
|
||||
_ => Err(EINVAL),
|
||||
}
|
||||
self.inner
|
||||
.read()
|
||||
.as_ref()
|
||||
.map(|inner| {
|
||||
inner.iface().unwrap().poll();
|
||||
let result = match inner {
|
||||
Inner::Established(inner) => inner.recv_slice(buf),
|
||||
_ => Err(EINVAL),
|
||||
};
|
||||
inner.iface().unwrap().poll();
|
||||
result
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn try_send(&self, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
@ -221,6 +229,7 @@ impl TcpSocket {
|
||||
// should only call on accept
|
||||
fn is_acceptable(&self) -> bool {
|
||||
// (self.poll() & EP::EPOLLIN.bits() as usize) != 0
|
||||
self.inner.read().as_ref().unwrap().iface().unwrap().poll();
|
||||
EP::from_bits_truncate(self.poll() as u32).contains(EP::EPOLLIN)
|
||||
}
|
||||
}
|
||||
@ -233,7 +242,7 @@ impl Socket for TcpSocket {
|
||||
fn get_name(&self) -> Result<Endpoint, SystemError> {
|
||||
match self.inner.read().as_ref().expect("Tcp Inner is None") {
|
||||
Inner::Init(Init::Unbound(_)) => Ok(Endpoint::Ip(UNSPECIFIED_LOCAL_ENDPOINT)),
|
||||
Inner::Init(Init::Bound((_, local))) => Ok(Endpoint::Ip(local.clone())),
|
||||
Inner::Init(Init::Bound((_, local))) => Ok(Endpoint::Ip(*local)),
|
||||
Inner::Connecting(connecting) => Ok(Endpoint::Ip(connecting.get_name())),
|
||||
Inner::Established(established) => Ok(Endpoint::Ip(established.local_endpoint())),
|
||||
Inner::Listening(listening) => Ok(Endpoint::Ip(listening.get_name())),
|
||||
@ -255,7 +264,7 @@ impl Socket for TcpSocket {
|
||||
}
|
||||
|
||||
fn poll(&self) -> usize {
|
||||
self.pollee.load(core::sync::atomic::Ordering::Relaxed)
|
||||
self.pollee.load(core::sync::atomic::Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn listen(&self, backlog: usize) -> Result<(), SystemError> {
|
||||
|
@ -11,7 +11,7 @@ fn create_inet_socket(
|
||||
socket_type: Type,
|
||||
protocol: smoltcp::wire::IpProtocol,
|
||||
) -> Result<Arc<dyn Socket>, SystemError> {
|
||||
log::debug!("type: {:?}, protocol: {:?}", socket_type, protocol);
|
||||
// log::debug!("type: {:?}, protocol: {:?}", socket_type, protocol);
|
||||
use smoltcp::wire::IpProtocol::*;
|
||||
use Type::*;
|
||||
match socket_type {
|
||||
|
@ -27,7 +27,7 @@ impl family::Family for Unix {
|
||||
|
||||
impl Unix {
|
||||
pub fn new_pairs(socket_type: Type) -> Result<(Arc<Inode>, Arc<Inode>), SystemError> {
|
||||
log::debug!("socket_type {:?}", socket_type);
|
||||
// log::debug!("socket_type {:?}", socket_type);
|
||||
match socket_type {
|
||||
Type::SeqPacket => seqpacket::SeqpacketSocket::new_pairs(),
|
||||
Type::Stream | Type::Datagram => stream::StreamSocket::new_pairs(),
|
||||
|
@ -62,11 +62,7 @@ pub(super) struct Listener {
|
||||
impl Listener {
|
||||
pub(super) fn new(inode: Endpoint, backlog: usize) -> Self {
|
||||
log::debug!("backlog {}", backlog);
|
||||
let back = if backlog > 1024 {
|
||||
1024 as usize
|
||||
} else {
|
||||
backlog
|
||||
};
|
||||
let back = if backlog > 1024 { 1024_usize } else { backlog };
|
||||
return Self {
|
||||
inode,
|
||||
backlog: AtomicUsize::new(back),
|
||||
@ -82,7 +78,7 @@ impl Listener {
|
||||
log::debug!(" incom len {}", incoming_conns.len());
|
||||
let conn = incoming_conns
|
||||
.pop_front()
|
||||
.ok_or_else(|| SystemError::EAGAIN_OR_EWOULDBLOCK)?;
|
||||
.ok_or(SystemError::EAGAIN_OR_EWOULDBLOCK)?;
|
||||
let socket =
|
||||
Arc::downcast::<SeqpacketSocket>(conn.inner()).map_err(|_| SystemError::EINVAL)?;
|
||||
let peer = match &*socket.inner.read() {
|
||||
@ -190,7 +186,7 @@ impl Connected {
|
||||
if self.can_send()? {
|
||||
return self.send_slice(buf);
|
||||
} else {
|
||||
log::debug!("can not send {:?}", String::from_utf8_lossy(&buf[..]));
|
||||
log::debug!("can not send {:?}", String::from_utf8_lossy(buf));
|
||||
return Err(SystemError::ENOBUFS);
|
||||
}
|
||||
}
|
||||
|
@ -230,11 +230,7 @@ impl Socket for SeqpacketSocket {
|
||||
if !self.is_nonblocking() {
|
||||
loop {
|
||||
wq_wait_event_interruptible!(self.wait_queue, self.is_acceptable(), {})?;
|
||||
match self
|
||||
.try_accept()
|
||||
.map(|(seqpacket_socket, remote_endpoint)| {
|
||||
(seqpacket_socket, Endpoint::from(remote_endpoint))
|
||||
}) {
|
||||
match self.try_accept() {
|
||||
Ok((socket, epoint)) => return Ok((socket, epoint)),
|
||||
Err(_) => continue,
|
||||
}
|
||||
@ -260,7 +256,7 @@ impl Socket for SeqpacketSocket {
|
||||
}
|
||||
|
||||
fn close(&self) -> Result<(), SystemError> {
|
||||
log::debug!("seqpacket close");
|
||||
// log::debug!("seqpacket close");
|
||||
self.shutdown.recv_shutdown();
|
||||
self.shutdown.send_shutdown();
|
||||
Ok(())
|
||||
@ -274,7 +270,7 @@ impl Socket for SeqpacketSocket {
|
||||
};
|
||||
|
||||
if let Some(endpoint) = endpoint {
|
||||
return Ok(Endpoint::from(endpoint));
|
||||
return Ok(endpoint);
|
||||
} else {
|
||||
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||||
}
|
||||
@ -289,7 +285,7 @@ impl Socket for SeqpacketSocket {
|
||||
};
|
||||
|
||||
if let Some(endpoint) = endpoint {
|
||||
return Ok(Endpoint::from(endpoint));
|
||||
return Ok(endpoint);
|
||||
} else {
|
||||
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||||
}
|
||||
@ -402,7 +398,7 @@ impl Socket for SeqpacketSocket {
|
||||
flags: MessageFlag,
|
||||
_address: Option<Endpoint>,
|
||||
) -> Result<(usize, Endpoint), SystemError> {
|
||||
log::debug!("recvfrom flags {:?}", flags);
|
||||
// log::debug!("recvfrom flags {:?}", flags);
|
||||
if flags.contains(MessageFlag::OOB) {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
@ -417,7 +413,7 @@ impl Socket for SeqpacketSocket {
|
||||
match &*self.inner.write() {
|
||||
Inner::Connected(connected) => match connected.recv_slice(buffer) {
|
||||
Ok(usize) => {
|
||||
log::debug!("recvs from successfully");
|
||||
// log::debug!("recvs from successfully");
|
||||
return Ok((usize, connected.peer_endpoint().unwrap().clone()));
|
||||
}
|
||||
Err(_) => continue,
|
||||
|
@ -231,10 +231,7 @@ impl Socket for StreamSocket {
|
||||
//目前只实现了阻塞式实现
|
||||
loop {
|
||||
wq_wait_event_interruptible!(self.wait_queue, self.is_acceptable(), {})?;
|
||||
match self
|
||||
.try_accept()
|
||||
.map(|(stream_socket, remote_endpoint)| (stream_socket, remote_endpoint))
|
||||
{
|
||||
match self.try_accept() {
|
||||
Ok((socket, endpoint)) => {
|
||||
debug!("server accept!:{:?}", endpoint);
|
||||
return Ok((socket, endpoint));
|
||||
|
@ -41,18 +41,18 @@ impl Syscall {
|
||||
protocol: usize,
|
||||
) -> Result<usize, SystemError> {
|
||||
// 打印收到的参数
|
||||
log::debug!(
|
||||
"socket: address_family={:?}, socket_type={:?}, protocol={:?}",
|
||||
address_family,
|
||||
socket_type,
|
||||
protocol
|
||||
);
|
||||
// log::debug!(
|
||||
// "socket: address_family={:?}, socket_type={:?}, protocol={:?}",
|
||||
// address_family,
|
||||
// socket_type,
|
||||
// protocol
|
||||
// );
|
||||
let address_family = socket::AddressFamily::try_from(address_family as u16)?;
|
||||
let type_arg = SysArgSocketType::from_bits_truncate(socket_type as u32);
|
||||
let is_nonblock = type_arg.is_nonblock();
|
||||
let is_close_on_exec = type_arg.is_cloexec();
|
||||
let stype = socket::Type::try_from(type_arg)?;
|
||||
log::debug!("type_arg {:?} stype {:?}", type_arg, stype);
|
||||
// log::debug!("type_arg {:?} stype {:?}", type_arg, stype);
|
||||
|
||||
let inode = socket::create_socket(
|
||||
address_family,
|
||||
@ -256,7 +256,7 @@ impl Syscall {
|
||||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||||
.get_socket(fd as i32)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
log::debug!("bind: socket={:?}", socket);
|
||||
// log::debug!("bind: socket={:?}", socket);
|
||||
socket.bind(endpoint)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ impl From<Endpoint> for SockAddr {
|
||||
}
|
||||
let addr_un = SockAddrUn {
|
||||
sun_family: AddressFamily::Unix as u16,
|
||||
sun_path: sun_path,
|
||||
sun_path,
|
||||
};
|
||||
return SockAddr { addr_un };
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
v1.3
|
||||
v1.4
|
@ -232,6 +232,7 @@ rustInstall() {
|
||||
|
||||
echo "正在安装DragonOS所需的rust组件...首次安装需要一些时间来更新索引,请耐心等待..."
|
||||
cargo install cargo-binutils
|
||||
cargo install bpf-linker
|
||||
rustup toolchain install nightly-2023-08-15-x86_64-unknown-linux-gnu
|
||||
rustup toolchain install $RUST_VERSION-x86_64-unknown-linux-gnu
|
||||
rustup component add rust-src --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu
|
||||
|
@ -126,9 +126,8 @@ cfg_content='set timeout=15
|
||||
set default=0
|
||||
insmod efi_gop
|
||||
menuentry "DragonOS" {
|
||||
multiboot2 /boot/kernel.elf "KERNEL_ELF"
|
||||
multiboot2 /boot/kernel.elf init=/bin/dragonreach
|
||||
}'
|
||||
|
||||
# 增加insmod efi_gop防止32位uefi启动报错
|
||||
echo "echo '${cfg_content}' > ${boot_folder}/grub/grub.cfg" | sh
|
||||
fi
|
||||
|
@ -101,7 +101,7 @@ impl Ping {
|
||||
|
||||
for i in 0..this.config.count {
|
||||
let _this = this.clone();
|
||||
let handle = thread::spawn(move||{
|
||||
let handle = thread::spawn(move || {
|
||||
_this.ping(i).unwrap();
|
||||
});
|
||||
_send.fetch_add(1, Ordering::SeqCst);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use libc::{sockaddr, recvfrom, bind, sendto, socket, AF_NETLINK, SOCK_DGRAM, getpid, c_void};
|
||||
use nix::libc;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::{ mem, io};
|
||||
use std::{io, mem};
|
||||
|
||||
#[repr(C)]
|
||||
struct Nlmsghdr {
|
||||
@ -33,7 +33,11 @@ fn bind_netlink_socket(sock: RawFd) -> io::Result<()> {
|
||||
addr.nl_groups = 1;
|
||||
|
||||
let ret = unsafe {
|
||||
bind(sock, &addr as *const _ as *const sockaddr, mem::size_of::<libc::sockaddr_nl>() as u32)
|
||||
bind(
|
||||
sock,
|
||||
&addr as *const _ as *const sockaddr,
|
||||
mem::size_of::<libc::sockaddr_nl>() as u32,
|
||||
)
|
||||
};
|
||||
|
||||
if ret < 0 {
|
||||
@ -90,7 +94,10 @@ fn receive_uevent(sock: RawFd) -> io::Result<String> {
|
||||
// 检查套接字文件描述符是否有效
|
||||
if sock < 0 {
|
||||
println!("Invalid socket file descriptor: {}", sock);
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid socket file descriptor"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid socket file descriptor",
|
||||
));
|
||||
}
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
@ -100,7 +107,10 @@ fn receive_uevent(sock: RawFd) -> io::Result<String> {
|
||||
// 检查缓冲区指针和长度是否有效
|
||||
if buf.is_empty() {
|
||||
println!("Buffer is empty");
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "Buffer is empty"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Buffer is empty",
|
||||
));
|
||||
}
|
||||
let len = unsafe {
|
||||
recvfrom(
|
||||
@ -122,13 +132,19 @@ fn receive_uevent(sock: RawFd) -> io::Result<String> {
|
||||
let nlmsghdr_size = mem::size_of::<Nlmsghdr>();
|
||||
if (len as usize) < nlmsghdr_size {
|
||||
println!("Received message is too short");
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "Received message is too short"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"Received message is too short",
|
||||
));
|
||||
}
|
||||
|
||||
let nlmsghdr = unsafe { &*(buf.as_ptr() as *const Nlmsghdr) };
|
||||
if nlmsghdr.nlmsg_len as isize > len {
|
||||
println!("Received message is incomplete");
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "Received message is incomplete"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"Received message is incomplete",
|
||||
));
|
||||
}
|
||||
|
||||
let message_data = &buf[nlmsghdr_size..nlmsghdr.nlmsg_len as usize];
|
||||
|
@ -1,8 +1,8 @@
|
||||
mod seq_socket;
|
||||
mod seq_pair;
|
||||
mod seq_socket;
|
||||
|
||||
use seq_socket::test_seq_socket;
|
||||
use seq_pair::test_seq_pair;
|
||||
use seq_socket::test_seq_socket;
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
if let Err(e) = test_seq_socket() {
|
||||
@ -187,4 +187,4 @@ fn main() -> Result<(), std::io::Error> {
|
||||
// let len = socket1.read(&mut buf)?;
|
||||
// println!("sock1 receive: {:?}", String::from_utf8_lossy(&buf[..len]));
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
@ -1,16 +1,17 @@
|
||||
use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write,Error};
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::os::fd::FromRawFd;
|
||||
|
||||
pub fn test_seq_pair()->Result<(),Error>{
|
||||
pub fn test_seq_pair() -> Result<(), Error> {
|
||||
// 创建 socket pair
|
||||
let (sock1, sock2) = socketpair(
|
||||
AddressFamily::Unix,
|
||||
SockType::SeqPacket, // 使用 SeqPacket 类型
|
||||
None, // 协议默认
|
||||
SockFlag::empty(),
|
||||
).expect("Failed to create socket pair");
|
||||
)
|
||||
.expect("Failed to create socket pair");
|
||||
|
||||
let mut socket1 = unsafe { File::from_raw_fd(sock1) };
|
||||
let mut socket2 = unsafe { File::from_raw_fd(sock2) };
|
||||
@ -36,4 +37,4 @@ pub fn test_seq_pair()->Result<(),Error>{
|
||||
let len = socket1.read(&mut buf)?;
|
||||
println!("sock1 receive: {:?}", String::from_utf8_lossy(&buf[..len]));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,14 @@
|
||||
|
||||
use libc::*;
|
||||
use std::{fs, str};
|
||||
use std::ffi::CString;
|
||||
use std::io::Error;
|
||||
use std::mem;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::{fs, str};
|
||||
|
||||
const SOCKET_PATH: &str = "/test.seqpacket";
|
||||
const MSG1: &str = "Hello, Unix SEQPACKET socket from Client!";
|
||||
const MSG2: &str = "Hello, Unix SEQPACKET socket from Server!";
|
||||
|
||||
|
||||
fn create_seqpacket_socket() -> Result<RawFd, Error> {
|
||||
unsafe {
|
||||
let fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
@ -33,7 +31,12 @@ fn bind_socket(fd: RawFd) -> Result<(), Error> {
|
||||
addr.sun_path[i] = byte as i8;
|
||||
}
|
||||
|
||||
if bind(fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
|
||||
if bind(
|
||||
fd,
|
||||
&addr as *const _ as *const sockaddr,
|
||||
mem::size_of_val(&addr) as socklen_t,
|
||||
) == -1
|
||||
{
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
}
|
||||
@ -68,7 +71,13 @@ fn accept_connection(fd: RawFd) -> Result<RawFd, Error> {
|
||||
fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let msg_bytes = msg.as_bytes();
|
||||
if send(fd, msg_bytes.as_ptr() as *const libc::c_void, msg_bytes.len(), 0) == -1 {
|
||||
if send(
|
||||
fd,
|
||||
msg_bytes.as_ptr() as *const libc::c_void,
|
||||
msg_bytes.len(),
|
||||
0,
|
||||
) == -1
|
||||
{
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
}
|
||||
@ -78,7 +87,12 @@ fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> {
|
||||
fn receive_message(fd: RawFd) -> Result<String, Error> {
|
||||
let mut buffer = [0; 1024];
|
||||
unsafe {
|
||||
let len = recv(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(), 0);
|
||||
let len = recv(
|
||||
fd,
|
||||
buffer.as_mut_ptr() as *mut libc::c_void,
|
||||
buffer.len(),
|
||||
0,
|
||||
);
|
||||
if len == -1 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
@ -86,70 +100,82 @@ fn receive_message(fd: RawFd) -> Result<String, Error> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_seq_socket() ->Result<(), Error>{
|
||||
// Create and bind the server socket
|
||||
fs::remove_file(&SOCKET_PATH).ok();
|
||||
pub fn test_seq_socket() -> Result<(), Error> {
|
||||
// Create and bind the server socket
|
||||
fs::remove_file(&SOCKET_PATH).ok();
|
||||
|
||||
let server_fd = create_seqpacket_socket()?;
|
||||
bind_socket(server_fd)?;
|
||||
listen_socket(server_fd)?;
|
||||
let server_fd = create_seqpacket_socket()?;
|
||||
bind_socket(server_fd)?;
|
||||
listen_socket(server_fd)?;
|
||||
|
||||
// Accept connection in a separate thread
|
||||
let server_thread = std::thread::spawn(move || {
|
||||
let client_fd = accept_connection(server_fd).expect("Failed to accept connection");
|
||||
|
||||
// Receive and print message
|
||||
let received_msg = receive_message(client_fd).expect("Failed to receive message");
|
||||
println!("Server: Received message: {}", received_msg);
|
||||
|
||||
send_message(client_fd, MSG2).expect("Failed to send message");
|
||||
|
||||
// Close client connection
|
||||
unsafe { close(client_fd) };
|
||||
});
|
||||
|
||||
// Create and connect the client socket
|
||||
let client_fd = create_seqpacket_socket()?;
|
||||
unsafe {
|
||||
let mut addr = sockaddr_un {
|
||||
sun_family: AF_UNIX as u16,
|
||||
sun_path: [0; 108],
|
||||
};
|
||||
let path_cstr = CString::new(SOCKET_PATH).unwrap();
|
||||
let path_bytes = path_cstr.as_bytes();
|
||||
// Convert u8 to i8
|
||||
for (i, &byte) in path_bytes.iter().enumerate() {
|
||||
addr.sun_path[i] = byte as i8;
|
||||
}
|
||||
if connect(client_fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
}
|
||||
send_message(client_fd, MSG1)?;
|
||||
// Accept connection in a separate thread
|
||||
let server_thread = std::thread::spawn(move || {
|
||||
let client_fd = accept_connection(server_fd).expect("Failed to accept connection");
|
||||
|
||||
// Receive and print message
|
||||
let received_msg = receive_message(client_fd).expect("Failed to receive message");
|
||||
println!("Client: Received message: {}", received_msg);
|
||||
// get peer_name
|
||||
unsafe {
|
||||
let mut addrss = sockaddr_un {
|
||||
sun_family: AF_UNIX as u16,
|
||||
sun_path: [0; 108],
|
||||
};
|
||||
let mut len = mem::size_of_val(&addrss) as socklen_t;
|
||||
let res = getpeername(client_fd, &mut addrss as *mut _ as *mut sockaddr, &mut len);
|
||||
if res == -1 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
let sun_path = addrss.sun_path.clone();
|
||||
let peer_path:[u8;108] = sun_path.iter().map(|&x| x as u8).collect::<Vec<u8>>().try_into().unwrap();
|
||||
println!("Client: Connected to server at path: {}", String::from_utf8_lossy(&peer_path));
|
||||
println!("Server: Received message: {}", received_msg);
|
||||
|
||||
send_message(client_fd, MSG2).expect("Failed to send message");
|
||||
|
||||
}
|
||||
|
||||
server_thread.join().expect("Server thread panicked");
|
||||
let received_msg = receive_message(client_fd).expect("Failed to receive message");
|
||||
println!("Client: Received message: {}", received_msg);
|
||||
// Close client connection
|
||||
unsafe { close(client_fd) };
|
||||
fs::remove_file(&SOCKET_PATH).ok();
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
|
||||
// Create and connect the client socket
|
||||
let client_fd = create_seqpacket_socket()?;
|
||||
unsafe {
|
||||
let mut addr = sockaddr_un {
|
||||
sun_family: AF_UNIX as u16,
|
||||
sun_path: [0; 108],
|
||||
};
|
||||
let path_cstr = CString::new(SOCKET_PATH).unwrap();
|
||||
let path_bytes = path_cstr.as_bytes();
|
||||
// Convert u8 to i8
|
||||
for (i, &byte) in path_bytes.iter().enumerate() {
|
||||
addr.sun_path[i] = byte as i8;
|
||||
}
|
||||
if connect(
|
||||
client_fd,
|
||||
&addr as *const _ as *const sockaddr,
|
||||
mem::size_of_val(&addr) as socklen_t,
|
||||
) == -1
|
||||
{
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
}
|
||||
send_message(client_fd, MSG1)?;
|
||||
let received_msg = receive_message(client_fd).expect("Failed to receive message");
|
||||
println!("Client: Received message: {}", received_msg);
|
||||
// get peer_name
|
||||
unsafe {
|
||||
let mut addrss = sockaddr_un {
|
||||
sun_family: AF_UNIX as u16,
|
||||
sun_path: [0; 108],
|
||||
};
|
||||
let mut len = mem::size_of_val(&addrss) as socklen_t;
|
||||
let res = getpeername(client_fd, &mut addrss as *mut _ as *mut sockaddr, &mut len);
|
||||
if res == -1 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
let sun_path = addrss.sun_path.clone();
|
||||
let peer_path: [u8; 108] = sun_path
|
||||
.iter()
|
||||
.map(|&x| x as u8)
|
||||
.collect::<Vec<u8>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
println!(
|
||||
"Client: Connected to server at path: {}",
|
||||
String::from_utf8_lossy(&peer_path)
|
||||
);
|
||||
}
|
||||
|
||||
server_thread.join().expect("Server thread panicked");
|
||||
let received_msg = receive_message(client_fd).expect("Failed to receive message");
|
||||
println!("Client: Received message: {}", received_msg);
|
||||
// Close client connection
|
||||
unsafe { close(client_fd) };
|
||||
fs::remove_file(&SOCKET_PATH).ok();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
use std::io::Error;
|
||||
use std::os::fd::RawFd;
|
||||
use std::fs;
|
||||
use libc::*;
|
||||
use std::ffi::CString;
|
||||
use std::fs;
|
||||
use std::io::Error;
|
||||
use std::mem;
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
const SOCKET_PATH: &str = "/test.stream";
|
||||
const MSG1: &str = "Hello, unix stream socket from Client!";
|
||||
const MSG2: &str = "Hello, unix stream socket from Server!";
|
||||
|
||||
fn create_stream_socket() -> Result<RawFd, Error>{
|
||||
fn create_stream_socket() -> Result<RawFd, Error> {
|
||||
unsafe {
|
||||
let fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if fd == -1 {
|
||||
return Err(Error::last_os_error())
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
Ok(fd)
|
||||
}
|
||||
@ -31,7 +31,12 @@ fn bind_socket(fd: RawFd) -> Result<(), Error> {
|
||||
addr.sun_path[i] = byte as i8;
|
||||
}
|
||||
|
||||
if bind(fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
|
||||
if bind(
|
||||
fd,
|
||||
&addr as *const _ as *const sockaddr,
|
||||
mem::size_of_val(&addr) as socklen_t,
|
||||
) == -1
|
||||
{
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
}
|
||||
@ -61,7 +66,13 @@ fn accept_conn(fd: RawFd) -> Result<RawFd, Error> {
|
||||
fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let msg_bytes = msg.as_bytes();
|
||||
if send(fd, msg_bytes.as_ptr() as *const libc::c_void, msg_bytes.len(), 0)== -1 {
|
||||
if send(
|
||||
fd,
|
||||
msg_bytes.as_ptr() as *const libc::c_void,
|
||||
msg_bytes.len(),
|
||||
0,
|
||||
) == -1
|
||||
{
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
}
|
||||
@ -71,7 +82,12 @@ fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> {
|
||||
fn recv_message(fd: RawFd) -> Result<String, Error> {
|
||||
let mut buffer = [0; 1024];
|
||||
unsafe {
|
||||
let len = recv(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(),0);
|
||||
let len = recv(
|
||||
fd,
|
||||
buffer.as_mut_ptr() as *mut libc::c_void,
|
||||
buffer.len(),
|
||||
0,
|
||||
);
|
||||
if len == -1 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
@ -82,7 +98,7 @@ fn recv_message(fd: RawFd) -> Result<String, Error> {
|
||||
fn test_stream() -> Result<(), Error> {
|
||||
fs::remove_file(&SOCKET_PATH).ok();
|
||||
|
||||
let server_fd = create_stream_socket()?;
|
||||
let server_fd = create_stream_socket()?;
|
||||
bind_socket(server_fd)?;
|
||||
listen_socket(server_fd)?;
|
||||
|
||||
@ -95,7 +111,7 @@ fn test_stream() -> Result<(), Error> {
|
||||
send_message(client_fd, MSG2).expect("Failed to send message");
|
||||
println!("Server send finish");
|
||||
|
||||
unsafe {close(client_fd)};
|
||||
unsafe { close(client_fd) };
|
||||
});
|
||||
|
||||
let client_fd = create_stream_socket()?;
|
||||
@ -111,9 +127,14 @@ fn test_stream() -> Result<(), Error> {
|
||||
addr.sun_path[i] = byte as i8;
|
||||
}
|
||||
|
||||
if connect(client_fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
|
||||
if connect(
|
||||
client_fd,
|
||||
&addr as *const _ as *const sockaddr,
|
||||
mem::size_of_val(&addr) as socklen_t,
|
||||
) == -1
|
||||
{
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_message(client_fd, MSG1)?;
|
||||
@ -129,9 +150,16 @@ fn test_stream() -> Result<(), Error> {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
let sun_path = addrss.sun_path.clone();
|
||||
let peer_path:[u8;108] = sun_path.iter().map(|&x| x as u8).collect::<Vec<u8>>().try_into().unwrap();
|
||||
println!("Client: Connected to server at path: {}", String::from_utf8_lossy(&peer_path));
|
||||
|
||||
let peer_path: [u8; 108] = sun_path
|
||||
.iter()
|
||||
.map(|&x| x as u8)
|
||||
.collect::<Vec<u8>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
println!(
|
||||
"Client: Connected to server at path: {}",
|
||||
String::from_utf8_lossy(&peer_path)
|
||||
);
|
||||
}
|
||||
|
||||
server_thread.join().expect("Server thread panicked");
|
||||
@ -139,7 +167,7 @@ fn test_stream() -> Result<(), Error> {
|
||||
let recv_msg = recv_message(client_fd).expect("Failed to receive message from server");
|
||||
println!("Client Received message: {}", recv_msg);
|
||||
|
||||
unsafe {close(client_fd)};
|
||||
unsafe { close(client_fd) };
|
||||
fs::remove_file(&SOCKET_PATH).ok();
|
||||
|
||||
Ok(())
|
||||
@ -148,6 +176,6 @@ fn test_stream() -> Result<(), Error> {
|
||||
fn main() {
|
||||
match test_stream() {
|
||||
Ok(_) => println!("test for unix stream success"),
|
||||
Err(_) => println!("test for unix stream failed")
|
||||
Err(_) => println!("test for unix stream failed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user