merge upstream

This commit is contained in:
val213 2024-10-16 12:32:37 +08:00
commit b9f04fc3a4
54 changed files with 1262 additions and 347 deletions

View File

@ -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
View File

@ -0,0 +1,109 @@
# 内核启动命令行参数
:::{note}
本文作者:
- 龙进 <longjin@DragonOS.org>
:::
## 概述
&emsp;&emsp;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重构后)
- 支持设置回调函数,调用回调函数来设置参数值

View File

@ -1,10 +1,9 @@
引导加载
====================================
DragonOS采用GRUB2作为其引导加载程序支持Multiboot2协议引导。目前仅支持GRUB2.06版本。
.. toctree::
:maxdepth: 1
:caption: 目录
bootloader
cmdline

View File

@ -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"

View File

@ -0,0 +1,6 @@
[package]
name = "kcmdline_macros"
version = "0.1.0"
edition = "2021"
[dependencies]

View 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)
};
};
}

View File

@ -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) {}
}

View File

@ -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.

View File

@ -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
}
}

View File

@ -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),
}
}

View File

@ -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);
}

View File

@ -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> {

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}
}
/// 初始化帧缓冲区子系统

View File

@ -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,

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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() {

View File

@ -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();

View File

@ -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
View 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()
})
}
}

View File

@ -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();
}

View File

@ -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(())
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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());
}

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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(())
}

View File

@ -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);

View File

@ -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)

View File

@ -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()),
}
}
}

View File

@ -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> {

View File

@ -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 {

View File

@ -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(),

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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));

View File

@ -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)
}

View File

@ -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 };
}

View File

@ -1 +1 @@
v1.3
v1.4

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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];

View File

@ -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(())
// }
// }

View File

@ -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(())
}
}

View File

@ -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(())
}

View File

@ -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"),
}
}
}