diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs new file mode 100644 index 00000000..dc611b22 --- /dev/null +++ b/kernel/src/arch/mod.rs @@ -0,0 +1,3 @@ +#[cfg(target_arch="x86_64")] +#[macro_use] +pub mod x86_64; \ No newline at end of file diff --git a/kernel/src/arch/x86_64/asm/current.rs b/kernel/src/arch/x86_64/asm/current.rs new file mode 100644 index 00000000..3713be82 --- /dev/null +++ b/kernel/src/arch/x86_64/asm/current.rs @@ -0,0 +1,18 @@ +use crate::include::bindings::bindings::process_control_block; + +use core::{arch::asm, sync::atomic::compiler_fence}; + +/// @brief 获取指向当前进程的pcb的可变引用 +#[inline] +pub fn current_pcb() -> &'static mut process_control_block { + let ret: Option<&mut process_control_block>; + unsafe { + let mut tmp: u64 = !(32767u64); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + asm!("and {0}, rsp", inout(reg)(tmp),); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + ret = (tmp as *mut process_control_block).as_mut(); + } + + ret.unwrap() +} diff --git a/kernel/src/arch/x86_64/asm/irqflags.rs b/kernel/src/arch/x86_64/asm/irqflags.rs new file mode 100644 index 00000000..2d17b995 --- /dev/null +++ b/kernel/src/arch/x86_64/asm/irqflags.rs @@ -0,0 +1,24 @@ +use core::arch::asm; + +#[inline] +pub fn local_irq_save(flags: &mut u64) { + unsafe { + asm!( + "pushfq", + "pop rax", + "mov rax, {0}", + "cli", + out(reg)(*flags), + ); + } +} + +#[inline] +pub fn local_irq_restore(flags: &u64) { + let x = *flags; + + unsafe { + asm!("push r15", + "popfq", in("r15")(x)); + } +} diff --git a/kernel/src/arch/x86_64/asm/mod.rs b/kernel/src/arch/x86_64/asm/mod.rs new file mode 100644 index 00000000..941c53c9 --- /dev/null +++ b/kernel/src/arch/x86_64/asm/mod.rs @@ -0,0 +1,3 @@ +pub mod irqflags; +#[macro_use] +pub mod current; \ No newline at end of file diff --git a/kernel/src/arch/x86_64/cpu.rs b/kernel/src/arch/x86_64/cpu.rs new file mode 100644 index 00000000..bc4b5c5d --- /dev/null +++ b/kernel/src/arch/x86_64/cpu.rs @@ -0,0 +1,16 @@ +use core::arch::asm; + +/// @brief 获取当前cpu的apic id +#[inline] +pub fn arch_current_apic_id() -> u8 { + let cpuid_res: u32; + unsafe { + asm!( + "mov eax, 1", + "cpuid", + "mov r15, ebx", + lateout("r15") cpuid_res + ); + } + return (cpuid_res >> 24) as u8; +} diff --git a/kernel/src/arch/x86_64/asm/asm.h b/kernel/src/arch/x86_64/include/asm/asm.h similarity index 100% rename from kernel/src/arch/x86_64/asm/asm.h rename to kernel/src/arch/x86_64/include/asm/asm.h diff --git a/kernel/src/arch/x86_64/asm/cmpxchg.h b/kernel/src/arch/x86_64/include/asm/cmpxchg.h similarity index 99% rename from kernel/src/arch/x86_64/asm/cmpxchg.h rename to kernel/src/arch/x86_64/include/asm/cmpxchg.h index 520b4a97..d27f83f6 100644 --- a/kernel/src/arch/x86_64/asm/cmpxchg.h +++ b/kernel/src/arch/x86_64/include/asm/cmpxchg.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include /** * @brief 通过extern不存在的函数,来让编译器报错。以防止不符合要求的代码的产生。 diff --git a/kernel/src/arch/x86_64/include/asm/irqflags.h b/kernel/src/arch/x86_64/include/asm/irqflags.h index 6d84c171..3886ba96 100644 --- a/kernel/src/arch/x86_64/include/asm/irqflags.h +++ b/kernel/src/arch/x86_64/include/asm/irqflags.h @@ -1,5 +1,5 @@ #pragma once - +#include // 保存当前rflags的值到变量x内并关闭中断 #define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \ : "=g"(x)::"memory") diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs new file mode 100644 index 00000000..42da5087 --- /dev/null +++ b/kernel/src/arch/x86_64/mod.rs @@ -0,0 +1,3 @@ +#[macro_use] +pub mod asm; +pub mod cpu; \ No newline at end of file diff --git a/kernel/src/common/glib.h b/kernel/src/common/glib.h index 82b344f0..8bed13d6 100644 --- a/kernel/src/common/glib.h +++ b/kernel/src/common/glib.h @@ -13,11 +13,8 @@ #include #include -#if ARCH(I386) || ARCH(X86_64) -#include -#else -#error Arch not supported. -#endif + +#include /** * @brief 根据结构体变量内某个成员变量member的基地址,计算出该结构体变量的基地址 diff --git a/kernel/src/common/list.h b/kernel/src/common/list.h index 86469f44..aad36543 100644 --- a/kernel/src/common/list.h +++ b/kernel/src/common/list.h @@ -1,11 +1,7 @@ #pragma once #include -#if ARCH(I386) || ARCH(X86_64) -#include -#else -#error Arch not supported. -#endif +#include //链表数据结构 struct List diff --git a/kernel/src/include/DragonOS/refcount.h b/kernel/src/include/DragonOS/refcount.h index 44fca9e3..6ebb44e5 100644 --- a/kernel/src/include/DragonOS/refcount.h +++ b/kernel/src/include/DragonOS/refcount.h @@ -1,6 +1,7 @@ #pragma once #include +// 该结构体需要与libs/refcount.rs的保持一致,且以rust版本为准 typedef struct refcount_struct { atomic_t refs; } refcount_t; \ No newline at end of file diff --git a/kernel/src/include/DragonOS/signal.h b/kernel/src/include/DragonOS/signal.h index c58cc252..b4b3c1d1 100644 --- a/kernel/src/include/DragonOS/signal.h +++ b/kernel/src/include/DragonOS/signal.h @@ -14,6 +14,46 @@ typedef __signalfn_t *__sighandler_t; typedef uint64_t sigset_t; +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO + +#define SIGPWR 30 +#define SIGSYS 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX MAX_SIG_NUM + +// 注意,该结构体最大16字节 union __sifields { /* kill() */ struct @@ -27,8 +67,9 @@ union __sifields { struct \ { \ int32_t si_signo; /* signal number */ \ - int32_t code; \ + int32_t si_code; \ int32_t si_errno; \ + uint32_t reserved; /* 保留备用 */ \ union __sifields _sifields; \ } @@ -80,7 +121,6 @@ struct sighand_struct /** * @brief 正在等待的信号的标志位 - * */ struct sigpending { diff --git a/kernel/src/include/DragonOS/signal.rs b/kernel/src/include/DragonOS/signal.rs index 4e296339..2eab511a 100644 --- a/kernel/src/include/DragonOS/signal.rs +++ b/kernel/src/include/DragonOS/signal.rs @@ -3,14 +3,21 @@ // todo: 将这里更换为手动编写的ffi绑定 use crate::include::bindings::bindings::atomic_t; -use crate::include::bindings::bindings::refcount_t; use crate::include::bindings::bindings::spinlock_t; use crate::include::bindings::bindings::wait_queue_head_t; +use crate::libs::ffi_convert::FFIBind2Rust; +use crate::libs::ffi_convert::__convert_mut; +use crate::libs::ffi_convert::__convert_ref; +use crate::libs::refcount::RefCount; +/// 请注意,sigset_t这个bitmap, 第0位表示sig=1的信号。也就是说,SignalNumber-1才是sigset_t中对应的位 pub type sigset_t = u64; pub type __signalfn_t = ::core::option::Option; pub type __sighandler_t = __signalfn_t; +// 最大的信号数量(改动这个值的时候请同步到signal.h) +pub const MAX_SIG_NUM: i32 = 64; + /// 由于signal_struct总是和sighand_struct一起使用,并且信号处理的过程中必定会对sighand加锁 /// 因此signal_struct不用加锁 /// **请将该结构体与`include/DragonOS/signal.h`中的保持同步** @@ -37,11 +44,17 @@ pub union sigaction__union_u { >, } +impl core::fmt::Debug for sigaction__union_u{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("sigaction__union_u") + } +} + /** * @brief 信号处理结构体 */ #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct sigaction { pub _u: sigaction__union_u, pub sa_flags: u64, @@ -49,6 +62,7 @@ pub struct sigaction { pub sa_restorer: ::core::option::Option, // 暂时未实现该函数 } + /** * 信号消息的结构体,作为参数传入sigaction结构体中指向的处理函数 */ @@ -68,13 +82,15 @@ pub union __siginfo_union { #[derive(Copy, Clone)] pub struct __siginfo_union_data { pub si_signo: i32, - pub code: i32, + pub si_code: i32, pub si_errno: i32, + pub reserved: u32, pub _sifields: __sifields, } /** - * siginfo中,根据signal的来源不同,该union中对应了不同的数据 + * siginfo中,根据signal的来源不同,该union中对应了不同的数据./= + * 请注意,该union最大占用16字节 */ #[repr(C)] #[derive(Copy, Clone)] @@ -95,12 +111,12 @@ pub struct __sifields__kill { * @brief 信号处理结构体,位于pcb之中 */ #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct sighand_struct { pub siglock: spinlock_t, - pub count: refcount_t, + pub count: RefCount, pub signal_fd_wqh: wait_queue_head_t, - pub action: [sigaction; 64usize], + pub action: [sigaction; MAX_SIG_NUM as usize], } /** @@ -111,3 +127,196 @@ pub struct sighand_struct { pub struct sigpending { pub signal: sigset_t, } + +#[allow(dead_code)] +#[repr(i32)] +pub enum si_code_val { + /// sent by kill, sigsend, raise + SI_USER = 0, + /// sent by kernel from somewhere + SI_KERNEL = 0x80, + /// 通过sigqueue发送 + SI_QUEUE = -1, + /// 定时器过期时发送 + SI_TIMER = -2, + /// 当实时消息队列的状态发生改变时发送 + SI_MESGQ = -3, + /// 当异步IO完成时发送 + SI_ASYNCIO = -4, + /// sent by queued SIGIO + SI_SIGIO = -5, +} + +impl si_code_val { + /// 为si_code_val这个枚举类型实现从i32转换到枚举类型的转换函数 + #[allow(dead_code)] + pub fn from_i32(x: i32) -> si_code_val { + match x { + 0 => Self::SI_USER, + 0x80 => Self::SI_KERNEL, + -1 => Self::SI_QUEUE, + -2 => Self::SI_TIMER, + -3 => Self::SI_MESGQ, + -4 => Self::SI_ASYNCIO, + -5 => Self::SI_SIGIO, + _ => panic!("si code not valid"), + } + } +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +#[repr(i32)] +pub enum SignalNumber { + SIGHUP = 1, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + /// SIGABRT和SIGIOT共用这个号码 + SIGABRT_OR_IOT, + SIGBUS, + SIGFPE, + SIGKILL, + SIGUSR1, + + SIGSEGV = 11, + SIGUSR2, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGSTKFLT, + SIGCHLD, + SIGCONT, + SIGSTOP, + SIGTSTP, + + SIGTTIN = 21, + SIGTTOU, + SIGURG, + SIGXCPU, + SIGXFSZ, + SIGVTALRM, + SIGPROF, + SIGWINCH, + /// SIGIO和SIGPOLL共用这个号码 + SIGIO_OR_POLL, + SIGPWR, + + SIGSYS = 31, +} + +/// 为SignalNumber实现判断相等的trait +impl PartialEq for SignalNumber { + fn eq(&self, other: &SignalNumber) -> bool { + *self as i32 == *other as i32 + } +} + +impl SignalNumber { + /// @brief 从i32转换为SignalNumber枚举类型,如果传入的x不符合要求,则返回None + #[allow(dead_code)] + pub fn from_i32(x: i32) -> Option { + if Self::valid_signal_number(x) { + let ret: SignalNumber = unsafe { core::mem::transmute(x) }; + return Some(ret); + } + + return None; + } + + /// 判断一个数字是否为可用的信号 + fn valid_signal_number(x: i32) -> bool { + if x > 0 && x < MAX_SIG_NUM { + return true; + } else { + return false; + } + } +} + +#[allow(dead_code)] +pub const SIGRTMIN: i32 = 32; +#[allow(dead_code)] +pub const SIGRTMAX: i32 = MAX_SIG_NUM; + +/// @brief 将给定的signal_struct解析为Rust的signal.rs中定义的signal_struct的引用 +/// +/// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 +impl FFIBind2Rust for signal_struct { + fn convert_mut<'a>( + src: *mut crate::include::bindings::bindings::signal_struct, + ) -> Option<&'a mut Self> { + return __convert_mut(src); + } + fn convert_ref<'a>( + src: *const crate::include::bindings::bindings::signal_struct, + ) -> Option<&'a Self> { + return __convert_ref(src); + } +} + +/// @brief 将给定的siginfo解析为Rust的signal.rs中定义的siginfo的引用 +/// +/// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 +impl FFIBind2Rust for siginfo { + fn convert_mut<'a>( + src: *mut crate::include::bindings::bindings::siginfo, + ) -> Option<&'a mut Self> { + return __convert_mut(src); + } + fn convert_ref<'a>( + src: *const crate::include::bindings::bindings::siginfo, + ) -> Option<&'a Self> { + return __convert_ref(src) + } +} + + +/// @brief 将给定的sigset_t解析为Rust的signal.rs中定义的sigset_t的引用 +/// +/// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 +impl FFIBind2Rust for sigset_t { + fn convert_mut<'a>( + src: *mut crate::include::bindings::bindings::sigset_t, + ) -> Option<&'a mut Self> { + return __convert_mut(src); + } + fn convert_ref<'a>( + src: *const crate::include::bindings::bindings::sigset_t, + ) -> Option<&'a Self> { + return __convert_ref(src) + } +} + +/// @brief 将给定的sigpending解析为Rust的signal.rs中定义的sigpending的引用 +/// +/// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 +impl FFIBind2Rust for sigpending { + fn convert_mut<'a>( + src: *mut crate::include::bindings::bindings::sigpending, + ) -> Option<&'a mut Self> { + return __convert_mut(src); + } + fn convert_ref<'a>( + src: *const crate::include::bindings::bindings::sigpending, + ) -> Option<&'a Self> { + return __convert_ref(src) + } +} + +/// @brief 将给定的来自bindgen的sighand_struct解析为Rust的signal.rs中定义的sighand_struct的引用 +/// +/// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的,会导致无法自定义功能的问题。 +impl FFIBind2Rust for sighand_struct{ + fn convert_mut<'a>( + src: *mut crate::include::bindings::bindings::sighand_struct, + ) -> Option<&'a mut Self> { + return __convert_mut(src); + } + fn convert_ref<'a>( + src: *const crate::include::bindings::bindings::sighand_struct, + ) -> Option<&'a Self> { + return __convert_ref(src) + } +} \ No newline at end of file diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h index 2b6c7372..dea4d6e1 100644 --- a/kernel/src/include/bindings/wrapper.h +++ b/kernel/src/include/bindings/wrapper.h @@ -27,5 +27,6 @@ #include #include #include +#include #include #include \ No newline at end of file diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index e69de29b..0501fa34 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -0,0 +1,402 @@ +use core::ptr::read_volatile; + +use crate::{ + include::{ + bindings::bindings::{ + pid_t, process_control_block, process_find_pcb_by_pid, pt_regs, spinlock_t, EINVAL, + ENOTSUP, ESRCH, PF_EXITING, PF_KTHREAD, PF_WAKEKILL, PROC_INTERRUPTIBLE, + }, + DragonOS::signal::{ + si_code_val, sighand_struct, siginfo, signal_struct, sigpending, sigset_t, + SignalNumber, MAX_SIG_NUM, sigaction, sigaction__union_u, + }, + }, + kBUG, kdebug, kwarn, + libs::{ + ffi_convert::FFIBind2Rust, + spinlock::{spin_is_locked, spin_lock_irqsave, spin_unlock_irqrestore}, + }, + println, + process::{ + pid::PidType, + process::{process_is_stopped, process_kick, process_wake_up_state}, + }, +}; + +use crate::include::DragonOS::signal::{__siginfo_union, __siginfo_union_data}; + +/// 默认信号处理程序占位符(用于在sighand结构体中的action数组中占位) +pub static DEFAULT_SIGACTION: sigaction = sigaction{ + _u: sigaction__union_u{ + _sa_handler: None, + }, + sa_flags:0, + sa_mask:0, + sa_restorer:None +}; + +/// @brief kill系统调用,向指定的进程发送信号 +/// @param regs->r8 pid 要接收信号的进程id +/// @param regs->r9 sig 信号 +#[no_mangle] +pub extern "C" fn sys_kill(regs: &pt_regs) -> u64 { + println!( + "sys kill, target pid={}, file={}, line={}", + regs.r8, + file!(), + line!() + ); + + let pid: pid_t = regs.r8 as pid_t; + let sig: Option = SignalNumber::from_i32(regs.r9 as i32); + if sig.is_none() { + // 传入的signal数值不合法 + kwarn!("Not a valid signal number"); + return (-(EINVAL as i64)) as u64; + } + + // 初始化signal info + let mut info = siginfo { + _sinfo: __siginfo_union { + data: __siginfo_union_data { + si_signo: sig.unwrap() as i32, + si_code: si_code_val::SI_USER as i32, + si_errno: 0, + reserved: 0, + _sifields: crate::include::DragonOS::signal::__sifields { + _kill: crate::include::DragonOS::signal::__sifields__kill { _pid: pid }, + }, + }, + }, + }; + + return signal_kill_something_info(sig.unwrap(), Some(&mut info), pid) as u64; +} + +/// 通过kill的方式向目标进程发送信号 +/// @param sig 要发送的信号 +/// @param info 要发送的信息 +/// @param pid 进程id(目前只支持pid>0) +fn signal_kill_something_info(sig: SignalNumber, info: Option<&mut siginfo>, pid: pid_t) -> i32 { + // 暂时不支持特殊的kill操作 + if pid <= 0 { + kwarn!("Kill operation not support: pid={}", pid); + return -(ENOTSUP as i32); + } + + // kill单个进程 + return signal_kill_proc_info(sig, info, pid); +} + +fn signal_kill_proc_info(sig: SignalNumber, info: Option<&mut siginfo>, pid: pid_t) -> i32 { + let mut retval: i32 = -(ESRCH as i32); + + // step1: 当进程管理模块拥有pcblist_lock之后,对其加锁 + + // step2: 根据pid找到pcb + let pcb = unsafe { process_find_pcb_by_pid(pid).as_mut() }; + + if pcb.is_none() { + kwarn!("No such process."); + return retval; + } + + println!("Target pcb = {:?}", pcb.as_ref().unwrap()); + + // step3: 调用signal_send_sig_info函数,发送信息 + retval = signal_send_sig_info(sig, info, pcb.unwrap()); + // step4: 解锁 + return retval; +} + +/// @brief 验证信号的值是否在范围内 +#[inline] +fn verify_signal(sig: SignalNumber) -> bool { + return if (sig as i32) <= MAX_SIG_NUM { + true + } else { + false + }; +} + +/// @brief 在发送信号给指定的进程前,做一些权限检查. 检查是否有权限发送 +/// @param sig 要发送的信号 +/// @param info 要发送的信息 +/// @param target_pcb 信号的接收者 +fn signal_send_sig_info( + sig: SignalNumber, + info: Option<&mut siginfo>, + target_pcb: &mut process_control_block, +) -> i32 { + kdebug!("signal_send_sig_info"); + // 检查sig是否符合要求,如果不符合要求,则退出。 + if !verify_signal(sig) { + return -(EINVAL as i32); + } + + // 信号符合要求,可以发送 + + let mut retval = -(ESRCH as i32); + let mut flags: u64 = 0; + // 如果上锁成功,则发送信号 + if !lock_process_sighand(target_pcb, &mut flags).is_none() { + // 发送信号 + retval = send_signal_locked(sig, info, target_pcb, PidType::PID); + + kdebug!("flags=0x{:016x}", flags); + // 对sighand放锁 + unlock_process_sighand(target_pcb, &flags); + } + return retval; +} + +/// @brief 对pcb的sighand结构体中的siglock进行加锁,并关闭中断 +/// @param pcb 目标pcb +/// @param flags 用来保存rflags的变量 +/// @return 指向sighand_struct的可变引用 +fn lock_process_sighand<'a>( + pcb: &'a mut process_control_block, + flags: &mut u64, +) -> Option<&'a mut sighand_struct> { + kdebug!("lock_process_sighand"); + let x = unsafe { &mut *pcb.sighand }; + + let sighand_ptr = sighand_struct::convert_mut(unsafe { &mut *pcb.sighand }); + // kdebug!("sighand_ptr={:?}", &sighand_ptr); + if !sighand_ptr.is_some() { + kBUG!("Sighand ptr of process {pid} is NULL!", pid = pcb.pid); + return None; + }else{ + + kdebug!("7777"); + } + let lock = {&mut sighand_ptr.unwrap().siglock}; + kdebug!("123"); + kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)}); + spin_lock_irqsave(lock, flags); + kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)}); + kdebug!("locked"); + let ret = unsafe { ((*pcb).sighand as *mut sighand_struct).as_mut() }; + + return ret; +} + +/// @brief 对pcb的sighand结构体中的siglock进行放锁,并恢复之前存储的rflags +/// @param pcb 目标pcb +/// @param flags 用来保存rflags的变量,将这个值恢复到rflags寄存器中 +fn unlock_process_sighand(pcb: &mut process_control_block, flags: &u64) { + kdebug!("unlock_process_sighand"); + let lock = unsafe{&mut (*pcb.sighand).siglock}; + kdebug!("lock={:?}", lock); + spin_unlock_irqrestore(lock, flags); + kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)}); + kdebug!("123443"); +} + +/// @brief 判断是否需要强制发送信号,然后发送信号 +/// 注意,进入该函数前,我们应当对pcb.sighand.siglock加锁。 +/// +/// @return i32 错误码 +fn send_signal_locked( + sig: SignalNumber, + info: Option<&mut siginfo>, + pcb: &mut process_control_block, + pt: PidType, +) -> i32 { + kdebug!("send_signal_locked"); + // 是否强制发送信号 + let mut force_send = false; + // signal的信息为空 + if info.is_none() { + // todo: 判断signal是否来自于一个祖先进程的namespace,如果是,则强制发送信号 + } else { + force_send = unsafe { info.as_ref().unwrap()._sinfo.data }.si_code + == (si_code_val::SI_KERNEL as i32); + } + + kdebug!("force send={}", force_send); + + return __send_signal_locked(sig, info, pcb, pt, force_send); +} + +/// @brief 发送信号 +/// 注意,进入该函数前,我们应当对pcb.sighand.siglock加锁。 +/// +/// @param sig 信号 +/// @param _info 信号携带的信息 +/// @param pcb 目标进程的pcb +/// @param pt siginfo结构体中,pid字段代表的含义 +/// @return i32 错误码 +fn __send_signal_locked( + sig: SignalNumber, + _info: Option<&mut siginfo>, + pcb: &mut process_control_block, + pt: PidType, + _force_send: bool, +) -> i32 { + kdebug!("__send_signal_locked"); + let mut retval = 0; + + // 判断该进入该函数时,是否已经持有了锁 + println!("locked={}",spin_is_locked(unsafe { &(*pcb.sighand).siglock })); + kdebug!("1234"); + let _pending: Option<&mut sigpending> = sigpending::convert_mut(&mut pcb.sig_pending); + kdebug!("567"); + + // 如果是kill或者目标pcb是内核线程,则无需获取sigqueue,直接发送信号即可 + if sig == SignalNumber::SIGKILL || (pcb.flags & (PF_KTHREAD as u64)) != 0 { + complete_signal(sig, pcb, pt); + } else { + // todo: 如果是其他信号,则加入到sigqueue内,然后complete_signal + retval = -(ENOTSUP as i32); + } + kdebug!("12342"); + return retval; +} + +/// @brief 将信号添加到目标进程的sig_pending。在引入进程组后,本函数还将负责把信号传递给整个进程组。 +/// +/// @param sig 信号 +/// @param pcb 目标pcb +/// @param pt siginfo结构体中,pid字段代表的含义 +fn complete_signal(sig: SignalNumber, pcb: &mut process_control_block, pt: PidType) { + // todo: 将信号产生的消息通知到正在监听这个信号的进程(引入signalfd之后,在这里调用signalfd_notify) + kdebug!("complete_signal"); + // 将这个信号加到目标进程的sig_pending中 + sigset_add( + sigset_t::convert_mut(&mut pcb.sig_pending.signal).unwrap(), + sig, + ); + + // ===== 寻找需要wakeup的目标进程 ===== + // 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。 + // todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。 + + let _signal: Option<&mut signal_struct> = signal_struct::convert_mut(pcb.signal); + + let mut _target: Option<&mut process_control_block> = None; + + // 判断目标进程是否想接收这个信号 + if wants_signal(sig, pcb) { + _target = Some(pcb); + } else if pt == PidType::PID { + /* + * There is just one thread and it does not need to be woken. + * It will dequeue unblocked signals before it runs again. + */ + return; + } else { + /* + * Otherwise try to find a suitable thread. + * 由于目前每个进程只有1个线程,因此当前情况可以返回。信号队列的dequeue操作不需要考虑同步阻塞的问题。 + */ + return; + } + + // todo:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。 + // todo!(); + + // todo: 到这里,信号已经被放置在共享的pending队列中,我们在这里把目标进程唤醒。 + if _target.is_some() { + signal_wake_up(pcb, sig == SignalNumber::SIGKILL); + } +} + +/// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。 +/// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。 +/// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。 +#[inline] +fn wants_signal(sig: SignalNumber, pcb: &process_control_block) -> bool { + // 如果改进程屏蔽了这个signal,则不能接收 + if sig_is_member(sigset_t::convert_ref(&pcb.sig_blocked).unwrap(), sig) { + return false; + } + + // 如果进程正在退出,则不能接收信号 + if (pcb.flags & (PF_EXITING as u64)) > 0 { + return false; + } + + if sig == SignalNumber::SIGKILL { + return true; + } + + if process_is_stopped(pcb) { + return false; + } + + // todo: 检查目标进程是否正在一个cpu上执行,如果是,则返回true,否则继续检查下一项 + + // 检查目标进程是否有信号正在等待处理,如果是,则返回false,否则返回true + return !has_sig_pending(pcb); +} + +/// @brief 判断指定的信号在sigset中的对应位是否被置位 +/// @return true: 给定的信号在sigset中被置位 +/// @return false: 给定的信号在sigset中没有被置位 +#[inline] +fn sig_is_member(set: &sigset_t, _sig: SignalNumber) -> bool { + return if 1 & (set >> ((_sig as u32) - 1)) != 0 { + true + } else { + false + }; +} + +/// @brief 将指定的信号在sigset中的对应bit进行置位 +#[inline] +fn sigset_add(set: &mut sigset_t, _sig: SignalNumber) { + *set |= 1 << ((_sig as u32) - 1); +} + +/// @brief 判断signal的处理是否可能使得整个进程组退出 +/// @return true 可能会导致退出(不一定) +#[allow(dead_code)] +#[inline] +fn sig_fatal(pcb: &process_control_block, sig: SignalNumber) -> bool { + let handler = unsafe { + sighand_struct::convert_ref(pcb.sighand).unwrap().action[(sig as usize) - 1] + ._u + ._sa_handler + }; + + // 如果handler是空,采用默认函数,signal处理可能会导致进程退出。 + if handler.is_none() { + return true; + } else { + return false; + } + + // todo: 参照linux的sig_fatal实现完整功能 +} + +/// @brief 判断某个进程是否有信号正在等待处理 +#[inline] +fn has_sig_pending(pcb: &process_control_block) -> bool { + let ptr = &sigpending::convert_ref(&(*pcb).sig_pending).unwrap().signal; + if unsafe { read_volatile(ptr) } != 0 { + return true; + } else { + return false; + } +} + +#[inline] +fn signal_wake_up(pcb: &mut process_control_block, fatal: bool) { + let mut state: u64 = 0; + if fatal { + state = PF_WAKEKILL as u64; + } + signal_wake_up_state(pcb, state); +} + +fn signal_wake_up_state(pcb: &mut process_control_block, state: u64) { + assert!(spin_is_locked(&unsafe { *pcb.sighand }.siglock)); + // todo: 设置线程结构体的标志位为TIF_SIGPENDING + + // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核 + if !process_wake_up_state(pcb, state | (PROC_INTERRUPTIBLE as u64)) { + process_kick(pcb); + } +} + diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 10671bd7..14ad3097 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -2,27 +2,32 @@ #![no_main] // <1> #![feature(core_intrinsics)] // <2> #![feature(alloc_error_handler)] +#![feature(panic_info_message)] #[allow(non_upper_case_globals)] #[allow(non_camel_case_types)] #[allow(non_snake_case)] - -use core::intrinsics; // <2> use core::panic::PanicInfo; +#[macro_use] +mod arch; +#[macro_use] +mod include; +mod ipc; #[macro_use] -mod mm; -mod include; mod libs; -mod ipc; +mod mm; +mod process; +mod sched; +mod smp; extern crate alloc; use mm::allocator::KernelAllocator; // <3> -use crate::include::bindings::bindings::{BLACK, GREEN}; +use crate::{include::bindings::bindings::{process_do_exit, BLACK, GREEN}, arch::x86_64::asm::current::current_pcb}; // 声明全局的slab分配器 #[cfg_attr(not(test), global_allocator)] @@ -31,14 +36,44 @@ pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator {}; /// 全局的panic处理函数 #[panic_handler] #[no_mangle] -pub fn panic(_info: &PanicInfo) -> ! { - intrinsics::abort(); // <4> +pub fn panic(info: &PanicInfo) -> ! { + kerror!("Kernel Panic Occurred."); + + match info.location() { + Some(loc) => { + println!( + "Location:\n\tFile: {}\n\tLine: {}, Column: {}", + loc.file(), + loc.line(), + loc.column() + ); + } + None => { + println!("No location info"); + } + } + + match info.message() { + Some(msg) => { + println!("Message:\n\t{}", msg); + } + None => { + println!("No panic message."); + } + } + + println!("Current PCB:\n\t{:?}", current_pcb()); + unsafe { + process_do_exit(u64::MAX); + }; + loop { + + } } /// 该函数用作测试,在process.c的initial_kernel_thread()中调用了此函数 #[no_mangle] pub extern "C" fn __rust_demo_func() -> i32 { - printk_color!(GREEN, BLACK, "__rust_demo_func()\n"); return 0; diff --git a/kernel/src/libs/atomic.rs b/kernel/src/libs/atomic.rs new file mode 100644 index 00000000..010dca1b --- /dev/null +++ b/kernel/src/libs/atomic.rs @@ -0,0 +1,11 @@ +use core::ptr::read_volatile; + +use crate::include::bindings::bindings::atomic_t; + +/// @brief 原子的读取指定的原子变量的值 +#[inline] +pub fn atomic_read(ato:*const atomic_t)-> i64{ + unsafe{ + return read_volatile(&(*ato).value); + } +} \ No newline at end of file diff --git a/kernel/src/libs/ffi_convert.rs b/kernel/src/libs/ffi_convert.rs new file mode 100644 index 00000000..77e50e45 --- /dev/null +++ b/kernel/src/libs/ffi_convert.rs @@ -0,0 +1,29 @@ +/// @brief 由bindgen生成的结构体转换成rust原生定义的结构体的特性 +pub trait FFIBind2Rust { + /// 转换为不可变引用 + fn convert_ref<'a>(src: *const T) -> Option<&'a Self>; + /// 转换为可变引用 + fn convert_mut<'a>(src: *mut T) -> Option<&'a mut Self>; +} + + + +pub fn __convert_mut<'a, S, D>(src:*mut S) ->Option<&'a mut D>{ + return unsafe { + core::mem::transmute::< + *mut S, + *mut D, + >(src) + .as_mut() + }; +} + +pub fn __convert_ref<'a, S, D>(src:*const S) ->Option<&'a D>{ + return unsafe { + core::mem::transmute::< + *const S, + *const D, + >(src) + .as_ref() + }; +} diff --git a/kernel/src/libs/lockref.c b/kernel/src/libs/lockref.c index 67c375ba..6491d7a0 100644 --- a/kernel/src/libs/lockref.c +++ b/kernel/src/libs/lockref.c @@ -2,7 +2,7 @@ #include #ifdef __LOCKREF_ENABLE_CMPXCHG__ -#include +#include #define CMPXCHG_LOOP(__lock_ref, CODE, SUCCESS) \ { \ diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index dee1127d..0070fb09 100644 --- a/kernel/src/libs/mod.rs +++ b/kernel/src/libs/mod.rs @@ -1 +1,6 @@ -pub mod printk; \ No newline at end of file +pub mod printk; +pub mod spinlock; +pub mod ffi_convert; +#[macro_use] +pub mod refcount; +pub mod atomic; \ No newline at end of file diff --git a/kernel/src/libs/refcount.rs b/kernel/src/libs/refcount.rs new file mode 100644 index 00000000..a3c7e14a --- /dev/null +++ b/kernel/src/libs/refcount.rs @@ -0,0 +1,54 @@ +use crate::{include::bindings::bindings::{atomic_inc, atomic_t, atomic_dec}, kwarn}; + +use super::{ffi_convert::{FFIBind2Rust, __convert_mut, __convert_ref}, atomic::atomic_read}; + +#[derive(Debug, Copy, Clone)] +pub struct RefCount { + pub refs: atomic_t, +} + +/// @brief 将给定的来自bindgen的refcount_t解析为Rust的RefCount的引用 +impl FFIBind2Rust for RefCount{ + fn convert_mut<'a>( + src: *mut crate::include::bindings::bindings::refcount_struct, + ) -> Option<&'a mut Self> { + return __convert_mut(src); + } + fn convert_ref<'a>( + src: *const crate::include::bindings::bindings::refcount_struct, + ) -> Option<&'a Self> { + return __convert_ref(src) + } +} + +macro_rules! REFCOUNT_INIT { + ($x:expr) => { + $crate::libs::refcount::RefCount { + refs: atomic_t { value: 0 }, + } + }; +} + +/// @brief 引用计数自增1 +#[allow(dead_code)] +#[inline] +pub fn refcount_inc(r: &mut RefCount) { + if atomic_read(&r.refs) == 0{ + kwarn!("Refcount increased from 0, may be use-after free"); + } + + unsafe { + atomic_inc(&mut r.refs); + } +} + +/// @brief 引用计数自减1 +#[allow(dead_code)] +#[inline] +pub fn refcount_dec(r: &mut RefCount){ + unsafe{ + atomic_dec(&mut r.refs); + } +} + + diff --git a/kernel/src/libs/spinlock.rs b/kernel/src/libs/spinlock.rs new file mode 100644 index 00000000..c6fc8235 --- /dev/null +++ b/kernel/src/libs/spinlock.rs @@ -0,0 +1,30 @@ +#![allow(dead_code)] +use core::ptr::read_volatile; + +use crate::arch::x86_64::asm::irqflags::{local_irq_restore, local_irq_save}; +use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t}; + +/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁 +pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) { + local_irq_save(flags); + unsafe { + spin_lock(lock); + } +} + +/// @brief 恢复rflags以及中断状态并解锁自旋锁 +#[no_mangle] +pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) { + unsafe { + spin_unlock(lock); + } + // kdebug!("123"); + local_irq_restore(flags); +} + +/// 判断一个自旋锁是否已经被加锁 +pub fn spin_is_locked(lock: &spinlock_t) -> bool { + let val = unsafe { read_volatile(&lock.lock as *const i8) }; + + return if val == 0 { true } else { false }; +} diff --git a/kernel/src/process/fork.c b/kernel/src/process/fork.c new file mode 100644 index 00000000..52b3ba45 --- /dev/null +++ b/kernel/src/process/fork.c @@ -0,0 +1,391 @@ +#include "process.h" +#include +#include +#include + +extern spinlock_t process_global_pid_write_lock; +extern long process_global_pid; + +extern void kernel_thread_func(void); + +int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb); +int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb); +int process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb); +int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, + uint64_t stack_size, struct pt_regs *current_regs); + +extern int process_copy_sighand(uint64_t clone_flags, struct process_control_block * pcb); +extern int process_copy_signal(uint64_t clone_flags, struct process_control_block * pcb); + + +/** + * @brief fork当前进程 + * + * @param regs 新的寄存器值 + * @param clone_flags 克隆标志 + * @param stack_start 堆栈开始地址 + * @param stack_size 堆栈大小 + * @return unsigned long + */ +unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start, + unsigned long stack_size) +{ + int retval = 0; + struct process_control_block *tsk = NULL; + + // 为新的进程分配栈空间,并将pcb放置在底部 + tsk = (struct process_control_block *)kzalloc(STACK_SIZE, 0); + barrier(); + + if (tsk == NULL) + { + retval = -ENOMEM; + return retval; + } + + barrier(); + memset(tsk, 0, sizeof(struct process_control_block)); + io_mfence(); + // 将当前进程的pcb复制到新的pcb内 + memcpy(tsk, current_pcb, sizeof(struct process_control_block)); + tsk->worker_private = NULL; + io_mfence(); + + // 初始化进程的循环链表结点 + list_init(&tsk->list); + + io_mfence(); + // 判断是否为内核态调用fork + if ((current_pcb->flags & PF_KTHREAD) && stack_start != 0) + tsk->flags |= PF_KFORK; + + if (tsk->flags & PF_KTHREAD) + { + // 对于内核线程,设置其worker私有信息 + retval = kthread_set_worker_private(tsk); + if (IS_ERR_VALUE(retval)) + goto copy_flags_failed; + tsk->virtual_runtime = 0; + } + tsk->priority = 2; + tsk->preempt_count = 0; + + // 增加全局的pid并赋值给新进程的pid + spin_lock(&process_global_pid_write_lock); + tsk->pid = process_global_pid++; + barrier(); + // 加入到进程链表中 + // todo: 对pcb_list_lock加锁 + tsk->prev_pcb = &initial_proc_union.pcb; + barrier(); + tsk->next_pcb = initial_proc_union.pcb.next_pcb; + barrier(); + initial_proc_union.pcb.next_pcb = tsk; + barrier(); + tsk->parent_pcb = current_pcb; + barrier(); + + spin_unlock(&process_global_pid_write_lock); + + tsk->cpu_id = proc_current_cpu_id; + tsk->state = PROC_UNINTERRUPTIBLE; + + tsk->parent_pcb = current_pcb; + wait_queue_init(&tsk->wait_child_proc_exit, NULL); + barrier(); + list_init(&tsk->list); + + retval = -ENOMEM; + + // 拷贝标志位 + retval = process_copy_flags(clone_flags, tsk); + if (retval) + goto copy_flags_failed; + + // 拷贝内存空间分布结构体 + retval = process_copy_mm(clone_flags, tsk); + if (retval) + goto copy_mm_failed; + + // 拷贝文件 + retval = process_copy_files(clone_flags, tsk); + if (retval) + goto copy_files_failed; + + // 拷贝信号处理函数 + retval = process_copy_sighand(clone_flags, tsk); + if(retval) + goto copy_sighand_failed; + + retval = process_copy_signal(clone_flags, tsk); + if(retval) + goto copy_signal_failed; + + // 拷贝线程结构体 + retval = process_copy_thread(clone_flags, tsk, stack_start, stack_size, regs); + if (retval) + goto copy_thread_failed; + + // 拷贝成功 + retval = tsk->pid; + + tsk->flags &= ~PF_KFORK; + + // 唤醒进程 + process_wakeup(tsk); + + return retval; + +copy_thread_failed:; + // 回收线程 + process_exit_thread(tsk); +copy_files_failed:; + // 回收文件 + process_exit_files(tsk); +copy_sighand_failed:; + process_exit_sighand(tsk); +copy_signal_failed:; + process_exit_signal(tsk); +copy_mm_failed:; + // 回收内存空间分布结构体 + process_exit_mm(tsk); +copy_flags_failed:; + kfree(tsk); + return retval; +} + +/** + * @brief 拷贝当前进程的标志位 + * + * @param clone_flags 克隆标志位 + * @param pcb 新的进程的pcb + * @return uint64_t + */ +int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb) +{ + if (clone_flags & CLONE_VM) + pcb->flags |= PF_VFORK; + return 0; +} + +/** + * @brief 拷贝当前进程的文件描述符等信息 + * + * @param clone_flags 克隆标志位 + * @param pcb 新的进程的pcb + * @return uint64_t + */ +int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb) +{ + int retval = 0; + // 如果CLONE_FS被置位,那么子进程与父进程共享文件描述符 + // 文件描述符已经在复制pcb时被拷贝 + if (clone_flags & CLONE_FS) + return retval; + + // 为新进程拷贝新的文件描述符 + for (int i = 0; i < PROC_MAX_FD_NUM; ++i) + { + if (current_pcb->fds[i] == NULL) + continue; + + pcb->fds[i] = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0); + memcpy(pcb->fds[i], current_pcb->fds[i], sizeof(struct vfs_file_t)); + } + + return retval; +} + +/** + * @brief 拷贝当前进程的内存空间分布结构体信息 + * + * @param clone_flags 克隆标志位 + * @param pcb 新的进程的pcb + * @return uint64_t + */ +int process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb) +{ + int retval = 0; + // 与父进程共享内存空间 + if (clone_flags & CLONE_VM) + { + pcb->mm = current_pcb->mm; + + return retval; + } + + // 分配新的内存空间分布结构体 + struct mm_struct *new_mms = (struct mm_struct *)kmalloc(sizeof(struct mm_struct), 0); + memset(new_mms, 0, sizeof(struct mm_struct)); + + memcpy(new_mms, current_pcb->mm, sizeof(struct mm_struct)); + new_mms->vmas = NULL; + pcb->mm = new_mms; + + // 分配顶层页表, 并设置顶层页表的物理地址 + new_mms->pgd = (pml4t_t *)virt_2_phys(kmalloc(PAGE_4K_SIZE, 0)); + // 由于高2K部分为内核空间,在接下来需要覆盖其数据,因此不用清零 + memset(phys_2_virt(new_mms->pgd), 0, PAGE_4K_SIZE / 2); + + // 拷贝内核空间的页表指针 + memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]->mm->pgd) + 256, + PAGE_4K_SIZE / 2); + + uint64_t *current_pgd = (uint64_t *)phys_2_virt(current_pcb->mm->pgd); + + uint64_t *new_pml4t = (uint64_t *)phys_2_virt(new_mms->pgd); + + // 拷贝用户空间的vma + struct vm_area_struct *vma = current_pcb->mm->vmas; + while (vma != NULL) + { + if (vma->vm_end > USER_MAX_LINEAR_ADDR || vma->vm_flags & VM_DONTCOPY) + { + vma = vma->vm_next; + continue; + } + + int64_t vma_size = vma->vm_end - vma->vm_start; + // kdebug("vma_size=%ld, vm_start=%#018lx", vma_size, vma->vm_start); + if (vma_size > PAGE_2M_SIZE / 2) + { + int page_to_alloc = (PAGE_2M_ALIGN(vma_size)) >> PAGE_2M_SHIFT; + for (int i = 0; i < page_to_alloc; ++i) + { + uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys; + + struct vm_area_struct *new_vma = NULL; + int ret = mm_create_vma(new_mms, vma->vm_start + i * PAGE_2M_SIZE, PAGE_2M_SIZE, vma->vm_flags, + vma->vm_ops, &new_vma); + // 防止内存泄露 + if (unlikely(ret == -EEXIST)) + free_pages(Phy_to_2M_Page(pa), 1); + else + mm_map_vma(new_vma, pa, 0, PAGE_2M_SIZE); + + memcpy((void *)phys_2_virt(pa), (void *)(vma->vm_start + i * PAGE_2M_SIZE), + (vma_size >= PAGE_2M_SIZE) ? PAGE_2M_SIZE : vma_size); + vma_size -= PAGE_2M_SIZE; + } + } + else + { + uint64_t map_size = PAGE_4K_ALIGN(vma_size); + uint64_t va = (uint64_t)kmalloc(map_size, 0); + + struct vm_area_struct *new_vma = NULL; + int ret = mm_create_vma(new_mms, vma->vm_start, map_size, vma->vm_flags, vma->vm_ops, &new_vma); + // 防止内存泄露 + if (unlikely(ret == -EEXIST)) + kfree((void *)va); + else + mm_map_vma(new_vma, virt_2_phys(va), 0, map_size); + + memcpy((void *)va, (void *)vma->vm_start, vma_size); + } + vma = vma->vm_next; + } + + return retval; +} + +/** + * @brief 重写内核栈中的rbp地址 + * + * @param new_regs 子进程的reg + * @param new_pcb 子进程的pcb + * @return int + */ +static int process_rewrite_rbp(struct pt_regs *new_regs, struct process_control_block *new_pcb) +{ + + uint64_t new_top = ((uint64_t)new_pcb) + STACK_SIZE; + uint64_t old_top = (uint64_t)(current_pcb) + STACK_SIZE; + + uint64_t *rbp = &new_regs->rbp; + uint64_t *tmp = rbp; + + // 超出内核栈范围 + if ((uint64_t)*rbp >= old_top || (uint64_t)*rbp < (old_top - STACK_SIZE)) + return 0; + + while (1) + { + // 计算delta + uint64_t delta = old_top - *rbp; + // 计算新的rbp值 + uint64_t newVal = new_top - delta; + + // 新的值不合法 + if (unlikely((uint64_t)newVal >= new_top || (uint64_t)newVal < (new_top - STACK_SIZE))) + break; + // 将新的值写入对应位置 + *rbp = newVal; + // 跳转栈帧 + rbp = (uint64_t *)*rbp; + } + + // 设置内核态fork返回到enter_syscall_int()函数内的时候,rsp寄存器的值 + new_regs->rsp = new_top - (old_top - new_regs->rsp); + return 0; +} + +/** + * @brief 拷贝当前进程的线程结构体 + * + * @param clone_flags 克隆标志位 + * @param pcb 新的进程的pcb + * @return uint64_t + */ +int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, + uint64_t stack_size, struct pt_regs *current_regs) +{ + // 将线程结构体放置在pcb后方 + struct thread_struct *thd = (struct thread_struct *)(pcb + 1); + memset(thd, 0, sizeof(struct thread_struct)); + pcb->thread = thd; + + struct pt_regs *child_regs = NULL; + // 拷贝栈空间 + if (pcb->flags & PF_KFORK) // 内核态下的fork + { + // 内核态下则拷贝整个内核栈 + uint32_t size = ((uint64_t)current_pcb) + STACK_SIZE - (uint64_t)(current_regs); + + child_regs = (struct pt_regs *)(((uint64_t)pcb) + STACK_SIZE - size); + memcpy(child_regs, (void *)current_regs, size); + barrier(); + // 然后重写新的栈中,每个栈帧的rbp值 + process_rewrite_rbp(child_regs, pcb); + } + else + { + child_regs = (struct pt_regs *)((uint64_t)pcb + STACK_SIZE - sizeof(struct pt_regs)); + memcpy(child_regs, current_regs, sizeof(struct pt_regs)); + barrier(); + child_regs->rsp = stack_start; + } + + // 设置子进程的返回值为0 + child_regs->rax = 0; + if (pcb->flags & PF_KFORK) + thd->rbp = + (uint64_t)(child_regs + 1); // 设置新的内核线程开始执行时的rbp(也就是进入ret_from_system_call时的rbp) + else + thd->rbp = (uint64_t)pcb + STACK_SIZE; + + // 设置新的内核线程开始执行的时候的rsp + thd->rsp = (uint64_t)child_regs; + thd->fs = current_pcb->thread->fs; + thd->gs = current_pcb->thread->gs; + + // 根据是否为内核线程、是否在内核态fork,设置进程的开始执行的地址 + if (pcb->flags & PF_KFORK) + thd->rip = (uint64_t)ret_from_system_call; + else if (pcb->flags & PF_KTHREAD && (!(pcb->flags & PF_KFORK))) + thd->rip = (uint64_t)kernel_thread_func; + else + thd->rip = (uint64_t)ret_from_system_call; + + return 0; +} \ No newline at end of file diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs new file mode 100644 index 00000000..34538934 --- /dev/null +++ b/kernel/src/process/fork.rs @@ -0,0 +1,27 @@ +use crate::{include::bindings::bindings::{process_control_block, CLONE_SIGHAND}, kdebug, libs::{refcount::{refcount_inc, RefCount}, ffi_convert::FFIBind2Rust}, arch::x86_64::asm::current::current_pcb}; + +#[no_mangle] +pub extern "C" fn process_copy_sighand(clone_flags: u64, pcb: *mut process_control_block) -> i32 { + kdebug!("process_copy_sighand"); + if(clone_flags & (CLONE_SIGHAND as u64)) != 0{ + let r = RefCount::convert_mut(unsafe{&mut (*((current_pcb().sighand))).count}).unwrap(); + refcount_inc(r); + } + 0 +} + +#[no_mangle] +pub extern "C" fn process_copy_signal(clone_flags: u64, pcb: *mut process_control_block) -> i32 { + kdebug!("process_copy_signal"); + 0 +} + +#[no_mangle] +pub extern "C" fn process_exit_signal(pcb: *mut process_control_block){ + // todo: 回收进程的信号结构体 +} + +#[no_mangle] +pub extern "C" fn process_exit_sighand(pcb: *mut process_control_block){ + // todo: 回收进程的sighand结构体 +} diff --git a/kernel/src/process/initial_proc.rs b/kernel/src/process/initial_proc.rs new file mode 100644 index 00000000..7b3fc3bb --- /dev/null +++ b/kernel/src/process/initial_proc.rs @@ -0,0 +1,26 @@ +use crate::{ + include::{ + bindings::bindings::{atomic_t, spinlock_t, wait_queue_head_t, List}, + DragonOS::signal::{sighand_struct, signal_struct, MAX_SIG_NUM}, + }, + ipc::signal::DEFAULT_SIGACTION, +}; + +#[no_mangle] +pub static INITIAL_SIGNALS: signal_struct = signal_struct { + sig_cnt: atomic_t { value: 0 }, +}; + +#[no_mangle] +pub static mut INITIAL_SIGHAND: sighand_struct = sighand_struct { + count: REFCOUNT_INIT!(1), + siglock: spinlock_t { lock: 1 }, + signal_fd_wqh: wait_queue_head_t { + lock: spinlock_t { lock: 1 }, + wait_list: List { + prev: unsafe { &INITIAL_SIGHAND.signal_fd_wqh.wait_list as *const List } as *mut List, + next: unsafe { &INITIAL_SIGHAND.signal_fd_wqh.wait_list as *const List } as *mut List, + }, + }, + action: [DEFAULT_SIGACTION; MAX_SIG_NUM as usize], +}; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs new file mode 100644 index 00000000..1b7c5b40 --- /dev/null +++ b/kernel/src/process/mod.rs @@ -0,0 +1,5 @@ +pub mod pid; +pub mod process; +pub mod preempt; +pub mod initial_proc; +pub mod fork; \ No newline at end of file diff --git a/kernel/src/process/pid.rs b/kernel/src/process/pid.rs new file mode 100644 index 00000000..db8e20e6 --- /dev/null +++ b/kernel/src/process/pid.rs @@ -0,0 +1,18 @@ +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum PidType { + /// pid类型是进程id + PID = 1, + TGID = 2, + PGID = 3, + SID = 4, + MAX = 5, +} + +/// 为PidType实现判断相等的trait +impl PartialEq for PidType { + fn eq(&self, other: &PidType) -> bool { + *self as u8 == *other as u8 + } +} \ No newline at end of file diff --git a/kernel/src/process/preempt.rs b/kernel/src/process/preempt.rs new file mode 100644 index 00000000..59987cfa --- /dev/null +++ b/kernel/src/process/preempt.rs @@ -0,0 +1,13 @@ +use crate::arch::x86_64::asm::current::current_pcb; + +/// @brief 增加进程的锁持有计数 +#[inline] +pub fn preempt_disable() { + current_pcb().preempt_count += 1; +} + +/// @brief 减少进程的锁持有计数 +#[inline] +pub fn preempt_enable() { + current_pcb().preempt_count -= 1; +} diff --git a/kernel/src/process/proc-types.h b/kernel/src/process/proc-types.h index a7ce7c2b..5ec91ef5 100644 --- a/kernel/src/process/proc-types.h +++ b/kernel/src/process/proc-types.h @@ -1,7 +1,8 @@ #pragma once -#include +#include #include +#include // 进程最大可拥有的文件描述符数量 #define PROC_MAX_FD_NUM 16 @@ -12,9 +13,9 @@ // 进程的运行状态 // 正在运行 #define PROC_RUNNING (1 << 0) -// 可被中断 +// 可被信号打断 #define PROC_INTERRUPTIBLE (1 << 1) -// 不可被中断 +// 不可被信号打断 #define PROC_UNINTERRUPTIBLE (1 << 2) // 挂起 #define PROC_ZOMBIE (1 << 3) @@ -32,8 +33,9 @@ // 进程初始化时的数据拷贝标志位 #define CLONE_FS (1UL << 0) // 在进程间共享打开的文件 -#define CLONE_SIGNAL (1UL << 1) +#define CLONE_SIGNAL (1UL << 1) // 克隆时,与父进程共享信号结构体 #define CLONE_VM (1UL << 2) // 在进程间共享虚拟内存空间 +#define CLONE_SIGHAND (1UL << 3) // 克隆时,与父进程共享信号处理结构体 #define PCB_NAME_LEN 16 @@ -60,9 +62,10 @@ struct thread_struct #define PF_KTHREAD (1UL << 0) // 内核线程 #define PF_NEED_SCHED (1UL << 1) // 进程需要被调度 #define PF_VFORK (1UL << 2) // 标志进程是否由于vfork而存在资源共享 -#define PF_KFORK (1UL << 3) // 标志在内核态下调用fork(临时标记,do_fork()结束后会将其复位) -#define PF_NOFREEZE (1UL << 4) // 当前进程不能被冻结 - +#define PF_KFORK (1UL << 3) // 标志在内核态下调用fork(临时标记,do_fork()结束后会将其复位) +#define PF_NOFREEZE (1UL << 4) // 当前进程不能被冻结 +#define PF_EXITING (1UL << 5) // 进程正在退出 +#define PF_WAKEKILL (1UL << 6) // 进程由于接收到终止信号唤醒 /** * @brief 进程控制块 * @@ -70,12 +73,12 @@ struct thread_struct struct process_control_block { // 进程的状态 - volatile long state; + volatile uint64_t state; // 进程标志:进程、线程、内核线程 - unsigned long flags; - int64_t preempt_count; // 持有的自旋锁的数量 - - long cpu_id; // 当前进程在哪个CPU核心上运行 + uint64_t flags; + int32_t preempt_count; // 持有的自旋锁的数量 + + uint32_t cpu_id; // 当前进程在哪个CPU核心上运行 char name[PCB_NAME_LEN]; // 内存空间分布结构体, 记录内存页表和程序段信息 @@ -87,9 +90,9 @@ struct process_control_block // pcb加入调度队列时,所使用的链表节点 struct List list; - //todo:给pcb中加一个spinlock_t成员 + // todo:给pcb中加一个spinlock_t成员 //进程自旋锁 - // spinlock_t alloc_lock; + // spinlock_t alloc_lock; // 地址空间范围 // 用户空间: 0x0000 0000 0000 0000 ~ 0x0000 7fff ffff ffff @@ -119,16 +122,14 @@ struct process_control_block // ==== 信号处理相关 ===== struct signal_struct *signal; struct sighand_struct *sighand; - // 一个bitmap,表示被阻塞的信号 - sigset_t blocked; + // 一个bitmap,表示当前进程被禁用的信号 + sigset_t sig_blocked; // 正在等待的信号的标志位,表示某个信号正在等待处理 struct sigpending sig_pending; - }; // 将进程的pcb和内核栈融合到一起,8字节对齐 -union proc_union -{ +union proc_union { struct process_control_block pcb; ul stack[STACK_SIZE / sizeof(ul)]; } __attribute__((aligned(8))); diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index dbd4b5a9..5b808bcd 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -1,5 +1,6 @@ #include "process.h" +#include #include #include #include @@ -21,13 +22,12 @@ #include #include #include +#include #include #include #include #include -#include - #include #include @@ -43,6 +43,19 @@ extern void kernel_thread_func(void); ul _stack_start; // initial proc的栈基地址(虚拟地址) extern struct mm_struct initial_mm; +extern struct signal_struct INITIAL_SIGNALS; +extern struct sighand_struct INITIAL_SIGHAND; + +// 设置初始进程的PCB +#define INITIAL_PROC(proc) \ + { \ + .state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0, \ + .mm = &initial_mm, .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2, \ + .virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0, \ + .wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL, .sig_blocked = 0, \ + .signal = &INITIAL_SIGNALS, .sighand = &INITIAL_SIGHAND, \ + } + struct thread_struct initial_thread = { .rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), .rsp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), @@ -62,24 +75,6 @@ struct process_control_block *initial_proc[MAX_CPU_NUM] = {&initial_proc_union.p // 为每个核心初始化初始进程的tss struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_TSS}; -/** - * @brief 拷贝当前进程的标志位 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb); - -/** - * @brief 拷贝当前进程的文件描述符等信息 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block *pcb); - /** * @brief 回收进程的所有文件描述符 * @@ -88,15 +83,6 @@ uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block * */ uint64_t process_exit_files(struct process_control_block *pcb); -/** - * @brief 拷贝当前进程的内存空间分布结构体信息 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb); - /** * @brief 释放进程的页表 * @@ -105,17 +91,7 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb */ uint64_t process_exit_mm(struct process_control_block *pcb); -/** - * @brief 拷贝当前进程的线程结构体 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, - uint64_t stack_size, struct pt_regs *current_regs); -void process_exit_thread(struct process_control_block *pcb); /** * @brief 切换进程 @@ -644,6 +620,7 @@ void process_init() // 初始化进程的循环链表 list_init(&initial_proc_union.pcb.list); + wait_queue_init(&initial_proc_union.pcb.wait_child_proc_exit, NULL); // 临时设置IDLE进程的的虚拟运行时间为0,防止下面的这些内核线程的虚拟运行时间出错 current_pcb->virtual_runtime = 0; @@ -660,130 +637,9 @@ void process_init() current_pcb->virtual_runtime = (1UL << 60); } -/** - * @brief fork当前进程 - * - * @param regs 新的寄存器值 - * @param clone_flags 克隆标志 - * @param stack_start 堆栈开始地址 - * @param stack_size 堆栈大小 - * @return unsigned long - */ -unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start, - unsigned long stack_size) -{ - int retval = 0; - struct process_control_block *tsk = NULL; - - // 为新的进程分配栈空间,并将pcb放置在底部 - tsk = (struct process_control_block *)kzalloc(STACK_SIZE, 0); - barrier(); - - if (tsk == NULL) - { - retval = -ENOMEM; - return retval; - } - - barrier(); - memset(tsk, 0, sizeof(struct process_control_block)); - io_mfence(); - // 将当前进程的pcb复制到新的pcb内 - memcpy(tsk, current_pcb, sizeof(struct process_control_block)); - tsk->worker_private = NULL; - io_mfence(); - - // 初始化进程的循环链表结点 - list_init(&tsk->list); - - io_mfence(); - // 判断是否为内核态调用fork - if ((current_pcb->flags & PF_KTHREAD) && stack_start != 0) - tsk->flags |= PF_KFORK; - - if (tsk->flags & PF_KTHREAD) - { - // 对于内核线程,设置其worker私有信息 - retval = kthread_set_worker_private(tsk); - if (IS_ERR_VALUE(retval)) - goto copy_flags_failed; - tsk->virtual_runtime = 0; - } - tsk->priority = 2; - tsk->preempt_count = 0; - - // 增加全局的pid并赋值给新进程的pid - spin_lock(&process_global_pid_write_lock); - tsk->pid = process_global_pid++; - barrier(); - // 加入到进程链表中 - // todo: 对pcb_list_lock加锁 - tsk->prev_pcb = &initial_proc_union.pcb; - barrier(); - tsk->next_pcb = initial_proc_union.pcb.next_pcb; - barrier(); - initial_proc_union.pcb.next_pcb = tsk; - barrier(); - tsk->parent_pcb = current_pcb; - barrier(); - - spin_unlock(&process_global_pid_write_lock); - - tsk->cpu_id = proc_current_cpu_id; - tsk->state = PROC_UNINTERRUPTIBLE; - - tsk->parent_pcb = current_pcb; - wait_queue_init(&tsk->wait_child_proc_exit, NULL); - barrier(); - list_init(&tsk->list); - - retval = -ENOMEM; - - // 拷贝标志位 - if (process_copy_flags(clone_flags, tsk)) - goto copy_flags_failed; - - // 拷贝内存空间分布结构体 - if (process_copy_mm(clone_flags, tsk)) - goto copy_mm_failed; - - // 拷贝文件 - if (process_copy_files(clone_flags, tsk)) - goto copy_files_failed; - - // 拷贝线程结构体 - if (process_copy_thread(clone_flags, tsk, stack_start, stack_size, regs)) - goto copy_thread_failed; - - // 拷贝成功 - retval = tsk->pid; - - tsk->flags &= ~PF_KFORK; - - // 唤醒进程 - process_wakeup(tsk); - - return retval; - -copy_thread_failed:; - // 回收线程 - process_exit_thread(tsk); -copy_files_failed:; - // 回收文件 - process_exit_files(tsk); -copy_mm_failed:; - // 回收内存空间分布结构体 - process_exit_mm(tsk); -copy_flags_failed:; - kfree(tsk); - return retval; - - return 0; -} - /** * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL - * + * 当进程管理模块拥有pcblist_lock之后,调用本函数之前,应当对其加锁 * @param pid * @return struct process_control_block* */ @@ -803,16 +659,19 @@ struct process_control_block *process_find_pcb_by_pid(pid_t pid) } /** - * @brief 将进程加入到调度器的就绪队列中 + * @brief 将进程加入到调度器的就绪队列中. * * @param pcb 进程的pcb + * + * @return true 成功加入调度队列 + * @return false 进程已经在运行 */ int process_wakeup(struct process_control_block *pcb) { // kdebug("pcb pid = %#018lx", pcb->pid); BUG_ON(pcb == NULL); - if (pcb == current_pcb || pcb == NULL) + if (pcb == NULL) return -EINVAL; // 如果pcb正在调度队列中,则不重复加入调度队列 if (pcb->state & PROC_RUNNING) @@ -820,7 +679,7 @@ int process_wakeup(struct process_control_block *pcb) pcb->state |= PROC_RUNNING; sched_enqueue(pcb); - return 0; + return 1; } /** @@ -838,47 +697,6 @@ int process_wakeup_immediately(struct process_control_block *pcb) // 将当前进程标志为需要调度,缩短新进程被wakeup的时间 current_pcb->flags |= PF_NEED_SCHED; } -/** - * @brief 拷贝当前进程的标志位 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb) -{ - if (clone_flags & CLONE_VM) - pcb->flags |= PF_VFORK; - return 0; -} - -/** - * @brief 拷贝当前进程的文件描述符等信息 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block *pcb) -{ - int retval = 0; - // 如果CLONE_FS被置位,那么子进程与父进程共享文件描述符 - // 文件描述符已经在复制pcb时被拷贝 - if (clone_flags & CLONE_FS) - return retval; - - // 为新进程拷贝新的文件描述符 - for (int i = 0; i < PROC_MAX_FD_NUM; ++i) - { - if (current_pcb->fds[i] == NULL) - continue; - - pcb->fds[i] = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0); - memcpy(pcb->fds[i], current_pcb->fds[i], sizeof(struct vfs_file_t)); - } - - return retval; -} /** * @brief 回收进程的所有文件描述符 @@ -903,99 +721,6 @@ uint64_t process_exit_files(struct process_control_block *pcb) memset(pcb->fds, 0, sizeof(struct vfs_file_t *) * PROC_MAX_FD_NUM); } -/** - * @brief 拷贝当前进程的内存空间分布结构体信息 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb) -{ - int retval = 0; - // 与父进程共享内存空间 - if (clone_flags & CLONE_VM) - { - pcb->mm = current_pcb->mm; - - return retval; - } - - // 分配新的内存空间分布结构体 - struct mm_struct *new_mms = (struct mm_struct *)kmalloc(sizeof(struct mm_struct), 0); - memset(new_mms, 0, sizeof(struct mm_struct)); - - memcpy(new_mms, current_pcb->mm, sizeof(struct mm_struct)); - new_mms->vmas = NULL; - pcb->mm = new_mms; - - // 分配顶层页表, 并设置顶层页表的物理地址 - new_mms->pgd = (pml4t_t *)virt_2_phys(kmalloc(PAGE_4K_SIZE, 0)); - // 由于高2K部分为内核空间,在接下来需要覆盖其数据,因此不用清零 - memset(phys_2_virt(new_mms->pgd), 0, PAGE_4K_SIZE / 2); - - // 拷贝内核空间的页表指针 - memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]->mm->pgd) + 256, - PAGE_4K_SIZE / 2); - - uint64_t *current_pgd = (uint64_t *)phys_2_virt(current_pcb->mm->pgd); - - uint64_t *new_pml4t = (uint64_t *)phys_2_virt(new_mms->pgd); - - // 拷贝用户空间的vma - struct vm_area_struct *vma = current_pcb->mm->vmas; - while (vma != NULL) - { - if (vma->vm_end > USER_MAX_LINEAR_ADDR || vma->vm_flags & VM_DONTCOPY) - { - vma = vma->vm_next; - continue; - } - - int64_t vma_size = vma->vm_end - vma->vm_start; - // kdebug("vma_size=%ld, vm_start=%#018lx", vma_size, vma->vm_start); - if (vma_size > PAGE_2M_SIZE / 2) - { - int page_to_alloc = (PAGE_2M_ALIGN(vma_size)) >> PAGE_2M_SHIFT; - for (int i = 0; i < page_to_alloc; ++i) - { - uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys; - - struct vm_area_struct *new_vma = NULL; - int ret = mm_create_vma(new_mms, vma->vm_start + i * PAGE_2M_SIZE, PAGE_2M_SIZE, vma->vm_flags, - vma->vm_ops, &new_vma); - // 防止内存泄露 - if (unlikely(ret == -EEXIST)) - free_pages(Phy_to_2M_Page(pa), 1); - else - mm_map_vma(new_vma, pa, 0, PAGE_2M_SIZE); - - memcpy((void *)phys_2_virt(pa), (void *)(vma->vm_start + i * PAGE_2M_SIZE), - (vma_size >= PAGE_2M_SIZE) ? PAGE_2M_SIZE : vma_size); - vma_size -= PAGE_2M_SIZE; - } - } - else - { - uint64_t map_size = PAGE_4K_ALIGN(vma_size); - uint64_t va = (uint64_t)kmalloc(map_size, 0); - - struct vm_area_struct *new_vma = NULL; - int ret = mm_create_vma(new_mms, vma->vm_start, map_size, vma->vm_flags, vma->vm_ops, &new_vma); - // 防止内存泄露 - if (unlikely(ret == -EEXIST)) - kfree((void *)va); - else - mm_map_vma(new_vma, virt_2_phys(va), 0, map_size); - - memcpy((void *)va, (void *)vma->vm_start, vma_size); - } - vma = vma->vm_next; - } - - return retval; -} - /** * @brief 释放进程的页表 * @@ -1059,106 +784,6 @@ uint64_t process_exit_mm(struct process_control_block *pcb) return 0; } -/** - * @brief 重写内核栈中的rbp地址 - * - * @param new_regs 子进程的reg - * @param new_pcb 子进程的pcb - * @return int - */ -static int process_rewrite_rbp(struct pt_regs *new_regs, struct process_control_block *new_pcb) -{ - - uint64_t new_top = ((uint64_t)new_pcb) + STACK_SIZE; - uint64_t old_top = (uint64_t)(current_pcb) + STACK_SIZE; - - uint64_t *rbp = &new_regs->rbp; - uint64_t *tmp = rbp; - - // 超出内核栈范围 - if ((uint64_t)*rbp >= old_top || (uint64_t)*rbp < (old_top - STACK_SIZE)) - return 0; - - while (1) - { - // 计算delta - uint64_t delta = old_top - *rbp; - // 计算新的rbp值 - uint64_t newVal = new_top - delta; - - // 新的值不合法 - if (unlikely((uint64_t)newVal >= new_top || (uint64_t)newVal < (new_top - STACK_SIZE))) - break; - // 将新的值写入对应位置 - *rbp = newVal; - // 跳转栈帧 - rbp = (uint64_t *)*rbp; - } - - // 设置内核态fork返回到enter_syscall_int()函数内的时候,rsp寄存器的值 - new_regs->rsp = new_top - (old_top - new_regs->rsp); - return 0; -} - -/** - * @brief 拷贝当前进程的线程结构体 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, - uint64_t stack_size, struct pt_regs *current_regs) -{ - // 将线程结构体放置在pcb后方 - struct thread_struct *thd = (struct thread_struct *)(pcb + 1); - memset(thd, 0, sizeof(struct thread_struct)); - pcb->thread = thd; - - struct pt_regs *child_regs = NULL; - // 拷贝栈空间 - if (pcb->flags & PF_KFORK) // 内核态下的fork - { - // 内核态下则拷贝整个内核栈 - uint32_t size = ((uint64_t)current_pcb) + STACK_SIZE - (uint64_t)(current_regs); - - child_regs = (struct pt_regs *)(((uint64_t)pcb) + STACK_SIZE - size); - memcpy(child_regs, (void *)current_regs, size); - barrier(); - // 然后重写新的栈中,每个栈帧的rbp值 - process_rewrite_rbp(child_regs, pcb); - } - else - { - child_regs = (struct pt_regs *)((uint64_t)pcb + STACK_SIZE - sizeof(struct pt_regs)); - memcpy(child_regs, current_regs, sizeof(struct pt_regs)); - barrier(); - child_regs->rsp = stack_start; - } - - // 设置子进程的返回值为0 - child_regs->rax = 0; - if (pcb->flags & PF_KFORK) - thd->rbp = - (uint64_t)(child_regs + 1); // 设置新的内核线程开始执行时的rbp(也就是进入ret_from_system_call时的rbp) - else - thd->rbp = (uint64_t)pcb + STACK_SIZE; - - // 设置新的内核线程开始执行的时候的rsp - thd->rsp = (uint64_t)child_regs; - thd->fs = current_pcb->thread->fs; - thd->gs = current_pcb->thread->gs; - - // 根据是否为内核线程、是否在内核态fork,设置进程的开始执行的地址 - if (pcb->flags & PF_KFORK) - thd->rip = (uint64_t)ret_from_system_call; - else if (pcb->flags & PF_KTHREAD && (!(pcb->flags & PF_KFORK))) - thd->rip = (uint64_t)kernel_thread_func; - else - thd->rip = (uint64_t)ret_from_system_call; - - return 0; -} /** * @brief todo: 回收线程结构体 @@ -1181,12 +806,12 @@ int process_release_pcb(struct process_control_block *pcb) process_exit_mm(pcb); if ((pcb->flags & PF_KTHREAD)) // 释放内核线程的worker private结构体 free_kthread_struct(pcb); - + // 将pcb从pcb链表中移除 // todo: 对相关的pcb加锁 pcb->prev_pcb->next_pcb = pcb->next_pcb; pcb->next_pcb->prev_pcb = pcb->prev_pcb; - + // 释放当前pcb kfree(pcb); return 0; diff --git a/kernel/src/process/process.h b/kernel/src/process/process.h index b3a2aaf5..bcf12a36 100644 --- a/kernel/src/process/process.h +++ b/kernel/src/process/process.h @@ -22,14 +22,8 @@ #include "proc-types.h" -// 设置初始进程的PCB -#define INITIAL_PROC(proc) \ - { \ - .state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0, \ - .mm = &initial_mm, .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2, \ - .virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0, \ - .wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL \ - } +extern void process_exit_thread(struct process_control_block *pcb); +extern uint64_t process_exit_files(struct process_control_block *pcb); /** * @brief 任务状态段结构体 @@ -96,7 +90,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned /** * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL - * + * 当进程管理模块拥有pcblist_lock之后,调用本函数之前,应当对其加锁 * @param pid * @return struct process_control_block* */ @@ -106,6 +100,8 @@ struct process_control_block *process_find_pcb_by_pid(pid_t pid); * @brief 将进程加入到调度器的就绪队列中 * * @param pcb 进程的pcb + * + * @return 如果进程被成功唤醒,则返回1,如果进程正在运行,则返回0.如果pcb为NULL,则返回-EINVAL */ int process_wakeup(struct process_control_block *pcb); @@ -197,3 +193,30 @@ extern struct process_control_block *initial_proc[MAX_CPU_NUM]; * @param pcb_name 保存名字的char数组 */ void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_name); + +/** + * @brief 判断进程是否已经停止 + * + * hint: 本函数在rust中实现,请参考rust版本的注释 + * + * @param pcb 目标pcb + * @return true + * @return false + */ +extern bool process_is_stopped(struct process_control_block *pcb); + +/** + * @brief 尝试唤醒指定的进程。 + * 本函数的行为:If (@_state & @pcb->state) @pcb->state = TASK_RUNNING. + * + * hint: 本函数在rust中实现,请参考rust版本的注释 + */ +extern int process_try_to_wake_up(struct process_control_block *_pcb, uint64_t _state, int32_t _wake_flags); + +/** @brief 当进程,满足 (@state & @pcb->state)时,唤醒进程,并设置: @pcb->state = TASK_RUNNING. + * + * hint: 本函数在rust中实现,请参考rust版本的注释 + * @return true 唤醒成功 + * @return false 唤醒失败 + */ +extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state); \ No newline at end of file diff --git a/kernel/src/process/process.rs b/kernel/src/process/process.rs new file mode 100644 index 00000000..6eaffb81 --- /dev/null +++ b/kernel/src/process/process.rs @@ -0,0 +1,103 @@ +use core::ptr::{read_volatile, write_volatile}; + +use crate::{ + arch::x86_64::asm::current::current_pcb, + include::bindings::bindings::{ + process_control_block, sched_enqueue, PROC_RUNNING, PROC_STOPPED, + }, + sched::core::cpu_executing, + smp::core::{smp_get_processor_id, smp_send_reschedule}, +}; + +use super::preempt::{preempt_disable, preempt_enable}; + +/// 判断进程是否已经停止 +#[no_mangle] +pub extern "C" fn process_is_stopped(pcb: *const process_control_block) -> bool { + let state: u64 = unsafe { read_volatile(&(*pcb).state) } as u64; + if (state & (PROC_STOPPED as u64)) != 0 { + return true; + } else { + return false; + } +} + +/// @brief 尝试唤醒指定的进程。 +/// 本函数的行为:If (@_state & @pcb->state) @pcb->state = TASK_RUNNING. +/// +/// @param _pcb 要被唤醒的进程的pcb +/// @param _state 如果pcb的state与_state匹配,则唤醒这个进程 +/// @param _wake_flags 保留,暂未使用,请置为0 +/// @return true: 成功唤醒 +/// false: 不符合唤醒条件,无法唤醒 +#[no_mangle] +pub extern "C" fn process_try_to_wake_up( + _pcb: *mut process_control_block, + _state: u64, + _wake_flags: i32, +) -> bool { + preempt_disable(); + + let mut retval = false; + // 获取对pcb的可变引用 + let pcb = unsafe { _pcb.as_mut() }.unwrap(); + + // 如果要唤醒的就是当前的进程 + if current_pcb() as *mut process_control_block as usize == _pcb as usize { + unsafe { + write_volatile(&mut pcb.state, PROC_RUNNING as u64); + } + preempt_enable(); + retval = true; + return retval; + } + // todo: 将来调度器引入ttwu队列之后,需要修改这里的判断条件 + + // todo: 为pcb引入pi_lock,然后在这里加锁 + if unsafe { read_volatile(&pcb.state) } & _state != 0 { + // 可以wakeup + unsafe { + write_volatile(&mut pcb.state, PROC_RUNNING as u64); + sched_enqueue(pcb); + } + retval = true; + } + // todo: 对pcb的pi_lock放锁 + preempt_enable(); + return retval; +} + +/// @brief 当进程,满足 (@state & @pcb->state)时,唤醒进程,并设置: @pcb->state = TASK_RUNNING. +/// +/// @return true 唤醒成功 +/// @return false 唤醒失败 +#[no_mangle] +pub extern "C" fn process_wake_up_state(pcb: *mut process_control_block, state: u64) -> bool { + return process_try_to_wake_up(pcb, state, 0); +} + + +/// @brief 让一个正在cpu上运行的进程陷入内核 +pub fn process_kick(pcb: *mut process_control_block) { + preempt_disable(); + let cpu = process_cpu(pcb); + // 如果给定的进程正在别的核心上执行,则立即发送请求,让它陷入内核态,以及时响应信号。 + if cpu != smp_get_processor_id() && process_is_executing(pcb) { + smp_send_reschedule(cpu); + } + preempt_enable(); +} + +/// @brief 获取给定的进程在哪个cpu核心上运行(使用volatile避免编译器优化) +#[inline] +pub fn process_cpu(pcb: *const process_control_block) -> u32 { + unsafe { read_volatile(&(*pcb).cpu_id) } +} + +/// @brief 判断给定的进程是否正在处理器上执行 +/// +/// @param pcb 进程的pcb +#[inline] +pub fn process_is_executing(pcb: *const process_control_block) -> bool { + return cpu_executing(process_cpu(pcb)) == pcb; +} diff --git a/kernel/src/sched/core.rs b/kernel/src/sched/core.rs new file mode 100644 index 00000000..195917e7 --- /dev/null +++ b/kernel/src/sched/core.rs @@ -0,0 +1,13 @@ +use crate::{include::bindings::bindings::process_control_block, process::process::process_cpu, arch::x86_64::asm::current::current_pcb}; + +/// @brief 获取指定的cpu上正在执行的进程的pcb +#[inline] +pub fn cpu_executing(cpu_id:u32) -> *const process_control_block{ + // todo: 引入per_cpu之后,该函数真正执行“返回指定的cpu上正在执行的pcb”的功能 + + if cpu_id == process_cpu(current_pcb()){ + return current_pcb(); + }else { + todo!() + } +} \ No newline at end of file diff --git a/kernel/src/sched/mod.rs b/kernel/src/sched/mod.rs new file mode 100644 index 00000000..689cad34 --- /dev/null +++ b/kernel/src/sched/mod.rs @@ -0,0 +1 @@ +pub mod core; \ No newline at end of file diff --git a/kernel/src/sched/sched.c b/kernel/src/sched/sched.c index 1f4f551c..adaa4087 100644 --- a/kernel/src/sched/sched.c +++ b/kernel/src/sched/sched.c @@ -4,6 +4,7 @@ #include #include #include + /** * @brief * diff --git a/kernel/src/smp/core.rs b/kernel/src/smp/core.rs new file mode 100644 index 00000000..886dfe11 --- /dev/null +++ b/kernel/src/smp/core.rs @@ -0,0 +1,14 @@ +/// @brief 获取当前的cpu id +#[inline] +pub fn smp_get_processor_id() -> u32 { + if cfg!(x86_64) { + return crate::arch::x86_64::cpu::arch_current_apic_id() as u32; + } else { + 255 + } +} + +#[inline] +pub fn smp_send_reschedule(_cpu: u32) { + // todo: +} diff --git a/kernel/src/smp/mod.rs b/kernel/src/smp/mod.rs new file mode 100644 index 00000000..689cad34 --- /dev/null +++ b/kernel/src/smp/mod.rs @@ -0,0 +1 @@ +pub mod core; \ No newline at end of file diff --git a/kernel/src/syscall/syscall.c b/kernel/src/syscall/syscall.c index 0e20b627..5ba420db 100644 --- a/kernel/src/syscall/syscall.c +++ b/kernel/src/syscall/syscall.c @@ -1,6 +1,7 @@ #include "syscall.h" #include #include +#include #include #include #include @@ -10,7 +11,6 @@ #include #include #include