From 64aea4b3494bee7375e1c1ee5739c9fab0db0cb7 Mon Sep 17 00:00:00 2001 From: Gou Ngai Date: Tue, 28 Mar 2023 20:44:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0x87FPU=E6=94=AF=E6=8C=81=20(#?= =?UTF-8?q?212)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove `ret_from_syscall` *修复ps2键盘驱动程序inode在进程fork的时候导致死锁的问题. *更新: VFS每次拷贝文件描述符的时候,都会去调用inode的open函数 --------- Co-authored-by: longjin --- DragonOS | 1 + kernel/src/arch/x86_64/context.rs | 4 + kernel/src/arch/x86_64/fpu.rs | 147 +++++++++++++++++++++ kernel/src/arch/x86_64/mod.rs | 1 + kernel/src/driver/keyboard/ps2_keyboard.rs | 44 +++--- kernel/src/exception/entry.S | 11 +- kernel/src/exception/irq.c | 116 ++++++++++------ kernel/src/exception/trap.c | 4 +- kernel/src/filesystem/vfs/file.rs | 41 +++++- kernel/src/ipc/signal.rs | 23 +++- kernel/src/ipc/signal_types.rs | 2 + kernel/src/mm/mmio_buddy.rs | 1 + kernel/src/process/fork.c | 18 +-- kernel/src/process/proc-types.h | 1 + kernel/src/process/process.c | 10 +- kernel/src/process/process.rs | 40 +++++- kernel/src/sched/core.rs | 2 +- kernel/src/sched/rt.rs | 1 + kernel/src/syscall/syscall.c | 19 +-- kernel/src/syscall/syscall.h | 2 - tools/run-qemu.sh | 1 - user/apps/about/about.c | 3 +- user/apps/shell/cmd.c | 7 +- user/apps/test_signal/main.c | 3 +- 24 files changed, 388 insertions(+), 114 deletions(-) create mode 160000 DragonOS create mode 100644 kernel/src/arch/x86_64/fpu.rs diff --git a/DragonOS b/DragonOS new file mode 160000 index 00000000..45b83711 --- /dev/null +++ b/DragonOS @@ -0,0 +1 @@ +Subproject commit 45b8371173b070028457f7ee64be33f68b4f9ada diff --git a/kernel/src/arch/x86_64/context.rs b/kernel/src/arch/x86_64/context.rs index 60444a28..91750348 100644 --- a/kernel/src/arch/x86_64/context.rs +++ b/kernel/src/arch/x86_64/context.rs @@ -2,6 +2,8 @@ use crate::include::bindings::bindings::{process_control_block, switch_proc}; use core::sync::atomic::compiler_fence; +use super::fpu::{fp_state_save, fp_state_restore}; + /// @brief 切换进程的上下文(没有切换页表的动作) /// /// @param next 下一个进程的pcb @@ -11,6 +13,8 @@ pub fn switch_process( prev: &'static mut process_control_block, next: &'static mut process_control_block, ) { + fp_state_save(prev); + fp_state_restore(next); compiler_fence(core::sync::atomic::Ordering::SeqCst); unsafe { switch_proc(prev, next); diff --git a/kernel/src/arch/x86_64/fpu.rs b/kernel/src/arch/x86_64/fpu.rs new file mode 100644 index 00000000..654cf391 --- /dev/null +++ b/kernel/src/arch/x86_64/fpu.rs @@ -0,0 +1,147 @@ +use core::{ + arch::{ + asm, + x86_64::{_fxrstor64, _fxsave64}, + }, + ffi::c_void, + ptr::null_mut, +}; + +use alloc::boxed::Box; + +use crate::include::bindings::bindings::process_control_block; + +use super::asm::irqflags::{local_irq_restore, local_irq_save}; +/// https://www.felixcloutier.com/x86/fxsave#tbl-3-47 +#[repr(C, align(16))] +#[derive(Debug, Copy, Clone)] +pub struct FpState { + //0 + fcw: u16, + fsw: u16, + ftw: u16, + fop: u16, + word2: u64, + //16 + word3: u64, + mxcsr: u32, + mxcsr_mask: u32, + //32 + mm: [u64; 16], + //160 + xmm: [u64; 32], + //416 + rest: [u64; 12], +} + +impl Default for FpState { + fn default() -> Self { + Self { + fcw: 0x037f, + fsw: Default::default(), + ftw: Default::default(), + fop: Default::default(), + word2: Default::default(), + word3: Default::default(), + mxcsr: 0x1f80, + mxcsr_mask: Default::default(), + mm: Default::default(), + xmm: Default::default(), + rest: Default::default(), + } + } +} +impl FpState { + #[allow(dead_code)] + pub fn new() -> Self { + assert!(core::mem::size_of::() == 512); + return Self::default(); + } + #[allow(dead_code)] + pub fn save(&mut self) { + unsafe { + _fxsave64(self as *mut FpState as *mut u8); + } + } + #[allow(dead_code)] + pub fn restore(&self) { + unsafe { + _fxrstor64(self as *const FpState as *const u8); + } + } + + /// @brief 清空fp_state + pub fn clear(&mut self) { + *self = Self::default(); + } +} + +/// @brief 从用户态进入内核时,保存浮点寄存器,并关闭浮点功能 +pub fn fp_state_save(pcb: &mut process_control_block) { + // 该过程中不允许中断 + let mut rflags: u64 = 0; + local_irq_save(&mut rflags); + + let fp: &mut FpState = if pcb.fp_state == null_mut() { + let f = Box::leak(Box::new(FpState::default())); + pcb.fp_state = f as *mut FpState as usize as *mut c_void; + f + } else { + unsafe { (pcb.fp_state as usize as *mut FpState).as_mut().unwrap() } + }; + + // 保存浮点寄存器 + fp.save(); + + // 关闭浮点功能 + unsafe { + asm!( + "mov rax, cr4", + "and ax,~(3<<9)", //[9][10]->0 + "mov cr4,rax", + "mov rax, cr0", + "and ax,~(02h)", //[1]->0 + "or ax, ~(0FFFBh)", //[2]->1 + "mov cr0, rax" /* + "mov rax, cr0", + "and ax, 0xFFFB", + "or ax,0x2", + "mov cr0,rax", + "mov rax, cr4", + "or ax,3<<9", + "mov cr4, rax" */ + ) + } + local_irq_restore(&rflags); +} + +/// @brief 从内核态返回用户态时,恢复浮点寄存器,并开启浮点功能 +pub fn fp_state_restore(pcb: &mut process_control_block) { + // 该过程中不允许中断 + let mut rflags: u64 = 0; + local_irq_save(&mut rflags); + + if pcb.fp_state == null_mut() { + panic!("fp_state_restore: fp_state is null. pid={}", pcb.pid); + } + + unsafe { + asm! { + "mov rax, cr0", + "and ax, 0FFFBh",//[2]->0 + "or ax,02h",//[1]->1 + "mov cr0,rax", + "mov rax, cr4", + "or ax,3<<9", + "mov cr4, rax", + "clts", + "fninit" + } + } + + let fp = unsafe { (pcb.fp_state as usize as *mut FpState).as_mut().unwrap() }; + fp.restore(); + fp.clear(); + + local_irq_restore(&rflags); +} diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 0df59e68..83450a21 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -5,3 +5,4 @@ pub mod cpu; pub mod interrupt; pub mod mm; pub mod sched; +pub mod fpu; diff --git a/kernel/src/driver/keyboard/ps2_keyboard.rs b/kernel/src/driver/keyboard/ps2_keyboard.rs index 9b0d2ea0..e72c74c5 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.rs +++ b/kernel/src/driver/keyboard/ps2_keyboard.rs @@ -1,3 +1,5 @@ +use core::sync::atomic::AtomicI32; + use alloc::sync::{Arc, Weak}; use crate::{ @@ -6,13 +8,12 @@ use crate::{ vfs::{core::generate_inode_id, file::FileMode, FileType, IndexNode, Metadata, PollStatus}, }, include::bindings::bindings::{vfs_file_operations_t, vfs_file_t, vfs_index_node_t, ENOTSUP}, - kdebug, - libs::spinlock::SpinLock, + libs::rwlock::RwLock, time::TimeSpec, }; #[derive(Debug)] -pub struct LockedPS2KeyBoardInode(SpinLock); +pub struct LockedPS2KeyBoardInode(RwLock, AtomicI32); // self.1 用来记录有多少个文件打开了这个inode #[derive(Debug)] pub struct PS2KeyBoardInode { @@ -53,8 +54,11 @@ impl LockedPS2KeyBoardInode { }, }; - let result = Arc::new(LockedPS2KeyBoardInode(SpinLock::new(inode))); - result.0.lock().self_ref = Arc::downgrade(&result); + let result = Arc::new(LockedPS2KeyBoardInode( + RwLock::new(inode), + AtomicI32::new(0), + )); + result.0.write().self_ref = Arc::downgrade(&result); return result; } @@ -62,7 +66,7 @@ impl LockedPS2KeyBoardInode { impl DeviceINode for LockedPS2KeyBoardInode { fn set_fs(&self, fs: Weak) { - self.0.lock().fs = fs; + self.0.write().fs = fs; } } @@ -80,7 +84,7 @@ impl IndexNode for LockedPS2KeyBoardInode { buf: &mut [u8], _data: &mut crate::filesystem::vfs::FilePrivateData, ) -> Result { - let guard = self.0.lock(); + let guard = self.0.read(); let func = guard.f_ops.read.unwrap(); let r = unsafe { func( @@ -108,16 +112,24 @@ impl IndexNode for LockedPS2KeyBoardInode { _data: &mut crate::filesystem::vfs::FilePrivateData, _mode: &FileMode, ) -> Result<(), i32> { - let guard = self.0.lock(); - let func = guard.f_ops.open.unwrap(); - let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) }; + let prev_ref_count = self.1.fetch_add(1, core::sync::atomic::Ordering::SeqCst); + if prev_ref_count == 0 { + // 第一次打开,需要初始化 + let guard = self.0.write(); + let func = guard.f_ops.open.unwrap(); + let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) }; + } return Ok(()); } fn close(&self, _data: &mut crate::filesystem::vfs::FilePrivateData) -> Result<(), i32> { - let guard = self.0.lock(); - let func = guard.f_ops.close.unwrap(); - let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) }; + let prev_ref_count = self.1.fetch_sub(1, core::sync::atomic::Ordering::SeqCst); + if prev_ref_count == 1 { + // 最后一次关闭,需要释放 + let guard = self.0.write(); + let func = guard.f_ops.close.unwrap(); + let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) }; + } return Ok(()); } @@ -128,11 +140,11 @@ impl IndexNode for LockedPS2KeyBoardInode { } fn metadata(&self) -> Result { - return Ok(self.0.lock().metadata.clone()); + return Ok(self.0.read().metadata.clone()); } fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { - let mut inode = self.0.lock(); + let mut inode = self.0.write(); inode.metadata.atime = metadata.atime; inode.metadata.mtime = metadata.mtime; inode.metadata.ctime = metadata.ctime; @@ -144,7 +156,7 @@ impl IndexNode for LockedPS2KeyBoardInode { } fn fs(&self) -> alloc::sync::Arc { - return self.0.lock().fs.upgrade().unwrap(); + return self.0.read().fs.upgrade().unwrap(); } fn as_any_ref(&self) -> &dyn core::any::Any { diff --git a/kernel/src/exception/entry.S b/kernel/src/exception/entry.S index ee1c7e4f..6cb76762 100644 --- a/kernel/src/exception/entry.S +++ b/kernel/src/exception/entry.S @@ -64,17 +64,18 @@ ENTRY(ret_from_intr) // 进入信号处理流程 cli + // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数 movq %rsp, %rdi callq do_signal - + // 恢复寄存器 jmp Restore_all Err_Code: - // ===== 有错误码的情况下,保存寄存器并跳转服务程序 + // ===== 有错误码的情况下,保存寄存器并跳转服务程序 pushq %rax movq %es, %rax pushq %rax @@ -108,16 +109,10 @@ Err_Code: movq %rsp, %rdi // 把栈指针装入rdi,作为函数的第一个的参数 - callq *%rdx //调用服务程序 带*号表示调用的是绝对地址 jmp ret_from_exception -// 从系统调用中返回 -ENTRY(ret_from_system_call) - jmp Restore_all - - // 0 #DE 除法错误 ENTRY(divide_error) diff --git a/kernel/src/exception/irq.c b/kernel/src/exception/irq.c index b886f317..80d454c4 100644 --- a/kernel/src/exception/irq.c +++ b/kernel/src/exception/irq.c @@ -18,31 +18,31 @@ extern void ignore_int(); #pragma GCC push_options #pragma GCC optimize("O0") // 保存函数调用现场的寄存器 -#define SAVE_ALL_REGS \ - "cld; \n\t" \ - "pushq %rax; \n\t" \ - "pushq %rax; \n\t" \ - "movq %es, %rax; \n\t" \ - "pushq %rax; \n\t" \ - "movq %ds, %rax; \n\t" \ - "pushq %rax; \n\t" \ - "xorq %rax, %rax;\n\t" \ - "pushq %rbp; \n\t" \ - "pushq %rdi; \n\t" \ - "pushq %rsi; \n\t" \ - "pushq %rdx; \n\t" \ - "pushq %rcx; \n\t" \ - "pushq %rbx; \n\t" \ - "pushq %r8 ; \n\t" \ - "pushq %r9 ; \n\t" \ - "pushq %r10; \n\t" \ - "pushq %r11; \n\t" \ - "pushq %r12; \n\t" \ - "pushq %r13; \n\t" \ - "pushq %r14; \n\t" \ - "pushq %r15; \n\t" \ - "movq $0x10, %rdx;\n\t" \ - "movq %rdx, %ds; \n\t" \ +#define SAVE_ALL_REGS \ + "cld; \n\t" \ + "pushq %rax; \n\t" \ + "pushq %rax; \n\t" \ + "movq %es, %rax; \n\t" \ + "pushq %rax; \n\t" \ + "movq %ds, %rax; \n\t" \ + "pushq %rax; \n\t" \ + "xorq %rax, %rax;\n\t" \ + "pushq %rbp; \n\t" \ + "pushq %rdi; \n\t" \ + "pushq %rsi; \n\t" \ + "pushq %rdx; \n\t" \ + "pushq %rcx; \n\t" \ + "pushq %rbx; \n\t" \ + "pushq %r8 ; \n\t" \ + "pushq %r9 ; \n\t" \ + "pushq %r10; \n\t" \ + "pushq %r11; \n\t" \ + "pushq %r12; \n\t" \ + "pushq %r13; \n\t" \ + "pushq %r14; \n\t" \ + "pushq %r15; \n\t" \ + "movq $0x10, %rdx;\n\t" \ + "movq %rdx, %ds; \n\t" \ "movq %rdx, %es; \n\t" // 定义IRQ处理函数的名字格式:IRQ+中断号+interrupt @@ -52,13 +52,13 @@ extern void ignore_int(); // 构造中断entry // 为了复用返回函数的代码,需要压入一个错误码0 // todo: 将这里改为volatile,也许能解决编译选项为O1时,系统崩溃的问题 -#define Build_IRQ(number) \ - void IRQ_NAME(number); \ - __asm__(SYMBOL_NAME_STR(IRQ) #number "interrupt: \n\t" \ - "pushq $0x00 \n\t" SAVE_ALL_REGS "movq %rsp, %rdi \n\t" \ - "leaq ret_from_intr(%rip), %rax \n\t" \ - "pushq %rax \n\t" \ - "movq $" #number ", %rsi \n\t" \ +#define Build_IRQ(number) \ + void IRQ_NAME(number); \ + __asm__(SYMBOL_NAME_STR(IRQ) #number "interrupt: \n\t" \ + "pushq $0x00 \n\t" SAVE_ALL_REGS "movq %rsp, %rdi \n\t" \ + "leaq ret_from_intr(%rip), %rax \n\t" \ + "pushq %rax \n\t" \ + "movq $" #number ", %rsi \n\t" \ "jmp do_IRQ \n\t"); // 构造中断入口 @@ -89,10 +89,30 @@ Build_IRQ(0x37); // 初始化中断数组 void (*interrupt_table[24])(void) = { - IRQ0x20interrupt, IRQ0x21interrupt, IRQ0x22interrupt, IRQ0x23interrupt, IRQ0x24interrupt, IRQ0x25interrupt, - IRQ0x26interrupt, IRQ0x27interrupt, IRQ0x28interrupt, IRQ0x29interrupt, IRQ0x2ainterrupt, IRQ0x2binterrupt, - IRQ0x2cinterrupt, IRQ0x2dinterrupt, IRQ0x2einterrupt, IRQ0x2finterrupt, IRQ0x30interrupt, IRQ0x31interrupt, - IRQ0x32interrupt, IRQ0x33interrupt, IRQ0x34interrupt, IRQ0x35interrupt, IRQ0x36interrupt, IRQ0x37interrupt, + IRQ0x20interrupt, + IRQ0x21interrupt, + IRQ0x22interrupt, + IRQ0x23interrupt, + IRQ0x24interrupt, + IRQ0x25interrupt, + IRQ0x26interrupt, + IRQ0x27interrupt, + IRQ0x28interrupt, + IRQ0x29interrupt, + IRQ0x2ainterrupt, + IRQ0x2binterrupt, + IRQ0x2cinterrupt, + IRQ0x2dinterrupt, + IRQ0x2einterrupt, + IRQ0x2finterrupt, + IRQ0x30interrupt, + IRQ0x31interrupt, + IRQ0x32interrupt, + IRQ0x33interrupt, + IRQ0x34interrupt, + IRQ0x35interrupt, + IRQ0x36interrupt, + IRQ0x37interrupt, }; /** @@ -118,8 +138,16 @@ void (*syscall_intr_table[1])(void) = {IRQ0x80interrupt}; // 初始化IPI中断服务程序数组 void (*SMP_interrupt_table[SMP_IRQ_NUM])(void) = { - IRQ0xc8interrupt, IRQ0xc9interrupt, IRQ0xcainterrupt, IRQ0xcbinterrupt, IRQ0xccinterrupt, - IRQ0xcdinterrupt, IRQ0xceinterrupt, IRQ0xcfinterrupt, IRQ0xd0interrupt, IRQ0xd1interrupt, + IRQ0xc8interrupt, + IRQ0xc9interrupt, + IRQ0xcainterrupt, + IRQ0xcbinterrupt, + IRQ0xccinterrupt, + IRQ0xcdinterrupt, + IRQ0xceinterrupt, + IRQ0xcfinterrupt, + IRQ0xd0interrupt, + IRQ0xd1interrupt, }; // 初始化local apic中断服务程序数组 @@ -134,8 +162,16 @@ Build_IRQ(0x9d); Build_IRQ(0x9e); Build_IRQ(0x9f); void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void) = { - IRQ0x96interrupt, IRQ0x97interrupt, IRQ0x98interrupt, IRQ0x99interrupt, IRQ0x9ainterrupt, - IRQ0x9binterrupt, IRQ0x9cinterrupt, IRQ0x9dinterrupt, IRQ0x9einterrupt, IRQ0x9finterrupt, + IRQ0x96interrupt, + IRQ0x97interrupt, + IRQ0x98interrupt, + IRQ0x99interrupt, + IRQ0x9ainterrupt, + IRQ0x9binterrupt, + IRQ0x9cinterrupt, + IRQ0x9dinterrupt, + IRQ0x9einterrupt, + IRQ0x9finterrupt, }; /** diff --git a/kernel/src/exception/trap.c b/kernel/src/exception/trap.c index 08e86daa..68acd3cb 100644 --- a/kernel/src/exception/trap.c +++ b/kernel/src/exception/trap.c @@ -96,8 +96,8 @@ void do_undefined_opcode(struct pt_regs *regs, unsigned long error_code) void do_dev_not_avaliable(struct pt_regs *regs, unsigned long error_code) { - kerror("do_dev_not_avaliable(7),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\t CPU:%d\n", error_code, regs->rsp, - regs->rip, proc_current_cpu_id); + kerror("do_dev_not_avaliable(7),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\t CPU:%d, pid=%d\n", error_code, regs->rsp, + regs->rip, proc_current_cpu_id, current_pcb->pid); current_pcb->state = PROC_STOPPED; sched(); diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index ab84e2bd..326a283e 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -4,12 +4,13 @@ use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec}; use crate::{ arch::asm::current::current_pcb, + driver::tty::TtyFilePrivateData, filesystem::procfs::ProcfsFilePrivateData, include::bindings::bindings::{ process_control_block, EINVAL, ENOBUFS, EOVERFLOW, EPERM, ESPIPE, }, io::SeekFrom, - kerror, driver::tty::TtyFilePrivateData, + kerror, }; use super::{Dirent, FileType, IndexNode, Metadata}; @@ -79,7 +80,7 @@ bitflags! { } /// @brief 抽象文件结构体 -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct File { inode: Arc, /// 对于文件,表示字节偏移量;对于文件夹,表示当前操作的子目录项偏移量 @@ -262,9 +263,30 @@ impl File { return Ok((name_bytes.len() + ::core::mem::size_of::() - ::core::mem::size_of_val(&dirent.d_name)) as u64); } + pub fn inode(&self) -> Arc { return self.inode.clone(); } + + /// @brief 尝试克隆一个文件 + /// + /// @return Option> 克隆后的文件结构体。如果克隆失败,返回None + pub fn try_clone(&self) -> Option> { + let mut res: Box = Box::new(Self { + inode: self.inode.clone(), + offset: self.offset.clone(), + mode: self.mode.clone(), + file_type: self.file_type.clone(), + readdir_subdirs_name: self.readdir_subdirs_name.clone(), + private_data: self.private_data.clone(), + }); + // 调用inode的open方法,让inode知道有新的文件打开了这个inode + if self.inode.open(&mut res.private_data, &res.mode).is_err() { + return None; + } + + return Some(res); + } } impl Drop for File { @@ -283,7 +305,7 @@ impl Drop for File { } /// @brief pcb里面的文件描述符数组 -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FileDescriptorVec { /// 当前进程打开的文件描述符 pub fds: [Option>; FileDescriptorVec::PROCESS_MAX_FD], @@ -310,6 +332,19 @@ impl FileDescriptorVec { return Box::new(FileDescriptorVec { fds: data }); } + /// @brief 克隆一个文件描述符数组 + /// + /// @return Box 克隆后的文件描述符数组 + pub fn clone(&self) -> Box { + let mut res: Box = FileDescriptorVec::new(); + for i in 0..FileDescriptorVec::PROCESS_MAX_FD { + if let Some(file) = &self.fds[i] { + res.fds[i] = file.try_clone(); + } + } + return res; + } + /// @brief 从pcb的fds字段,获取文件描述符数组的可变引用 #[inline] pub fn from_pcb(pcb: &'static process_control_block) -> Option<&'static mut FileDescriptorVec> { diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 4f91e149..65bc670a 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -1,8 +1,14 @@ -use core::{ffi::c_void, intrinsics::size_of, ptr::read_volatile, sync::atomic::compiler_fence}; +use core::{ + ffi::c_void, + intrinsics::size_of, + ptr::{null_mut, read_volatile}, + sync::atomic::compiler_fence, +}; use crate::{ arch::{ asm::{bitops::ffz, current::current_pcb, ptrace::user_mode}, + fpu::FpState, interrupt::sti, }, include::bindings::bindings::{ @@ -658,6 +664,17 @@ fn setup_frame( (*frame).handler = ka._u._sa_handler as usize as *mut c_void; } + // 将当前进程的fp_state拷贝到用户栈 + if current_pcb().fp_state != null_mut() { + unsafe { + let fp_state: &mut FpState = (current_pcb().fp_state as usize as *mut FpState) + .as_mut() + .unwrap(); + (*frame).context.sc_stack.fpstate = *fp_state; + // 保存完毕后,清空fp_state,以免下次save的时候,出现SIMD exception + fp_state.clear(); + } + } // 将siginfo拷贝到用户栈 err |= copy_siginfo_to_user(unsafe { &mut (*frame).info }, info).unwrap_or(1); @@ -768,7 +785,11 @@ fn restore_sigcontext(context: *const sigcontext, regs: &mut pt_regs) -> bool { (*current_thread).trap_num = (*context).trap_num; (*current_thread).cr2 = (*context).cr2; (*current_thread).err_code = (*context).err_code; + + // 如果当前进程有fpstate,则将其恢复到pcb的fp_state中 + *(current_pcb().fp_state as usize as *mut FpState) = (*context).sc_stack.fpstate; } + return true; } diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 6f29980e..3fee759b 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -6,6 +6,7 @@ use core::fmt::Debug; use alloc::vec::Vec; +use crate::arch::fpu::FpState; use crate::include::bindings::bindings::NULL; // todo: 将这里更换为手动编写的ffi绑定 use crate::include::bindings::bindings::atomic_t; @@ -664,4 +665,5 @@ pub struct signal_stack { pub sp: *mut c_void, pub flags: u32, pub size: u32, + pub fpstate:FpState, } diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index c25cb732..7c3b8d28 100644 --- a/kernel/src/mm/mmio_buddy.rs +++ b/kernel/src/mm/mmio_buddy.rs @@ -635,6 +635,7 @@ pub struct MmioFreeRegionList { num_free: i64, } impl MmioFreeRegionList { + #[allow(dead_code)] fn new() -> Self { return MmioFreeRegionList { ..Default::default() diff --git a/kernel/src/process/fork.c b/kernel/src/process/fork.c index 93ccf3a1..01147d37 100644 --- a/kernel/src/process/fork.c +++ b/kernel/src/process/fork.c @@ -9,6 +9,7 @@ extern long process_global_pid; extern void kernel_thread_func(void); extern uint64_t rs_procfs_register_pid(uint64_t); extern uint64_t rs_procfs_unregister_pid(uint64_t); +extern void *rs_dup_fpstate(); extern 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); @@ -134,12 +135,12 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned tsk->flags &= ~PF_KFORK; - // 唤醒进程 - process_wakeup(tsk); - // 创建对应procfs文件 rs_procfs_register_pid(tsk->pid); + // 唤醒进程 + process_wakeup(tsk); + return retval; copy_thread_failed:; @@ -175,7 +176,6 @@ int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb) return 0; } - /** * @brief 拷贝当前进程的内存空间分布结构体信息 * @@ -334,6 +334,7 @@ int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, 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); @@ -349,8 +350,7 @@ int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, // 设置子进程的返回值为0 child_regs->rax = 0; if (pcb->flags & PF_KFORK) - thd->rbp = - (uint64_t)(child_regs + 1); // 设置新的内核线程开始执行时的rbp(也就是进入ret_from_system_call时的rbp) + thd->rbp = (uint64_t)(child_regs + 1); // 设置新的内核线程开始执行时的rbp(也就是进入ret_from_intr时的rbp) else thd->rbp = (uint64_t)pcb + STACK_SIZE; @@ -361,11 +361,13 @@ int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, // 根据是否为内核线程、是否在内核态fork,设置进程的开始执行的地址 if (pcb->flags & PF_KFORK) - thd->rip = (uint64_t)ret_from_system_call; + thd->rip = (uint64_t)ret_from_intr; 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; + thd->rip = (uint64_t)ret_from_intr; + + pcb->fp_state = rs_dup_fpstate(); return 0; } \ No newline at end of file diff --git a/kernel/src/process/proc-types.h b/kernel/src/process/proc-types.h index c2dda17c..712806ca 100644 --- a/kernel/src/process/proc-types.h +++ b/kernel/src/process/proc-types.h @@ -136,6 +136,7 @@ struct process_control_block // 如果当前进程等待被迁移到另一个cpu核心上(也就是flags中的PF_NEED_MIGRATE被置位), // 该字段存储要被迁移到的目标处理器核心号 uint32_t migrate_to; + void* fp_state;//Fpstate 用于用户态切换到内核态时保存浮点寄存器里面的值 }; // 将进程的pcb和内核栈融合到一起,8字节对齐 diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index ad3715a0..acb864cd 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include extern int __rust_demo_func(); // #pragma GCC push_options // #pragma GCC optimize("O0") @@ -46,6 +46,7 @@ extern struct sighand_struct INITIAL_SIGHAND; extern void process_exit_sighand(struct process_control_block *pcb); extern void process_exit_signal(struct process_control_block *pcb); extern void initial_proc_init_signal(struct process_control_block *pcb); +extern void rs_process_exit_fpstate(struct process_control_block *pcb); extern int process_init_files(); // 设置初始进程的PCB @@ -410,8 +411,6 @@ load_elf_failed:; ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[]) { - // kdebug("do_execve is running..."); - // 当前进程正在与父进程共享地址空间,需要创建 // 独立的地址空间才能使新程序正常运行 if (current_pcb->flags & PF_VFORK) @@ -584,7 +583,7 @@ ul initial_kernel_thread(ul arg) // 若在后面这段代码中触发中断,return时会导致段选择子错误,从而触发#GP,因此这里需要cli cli(); - current_pcb->thread->rip = (ul)ret_from_system_call; + current_pcb->thread->rip = (ul)ret_from_intr; current_pcb->thread->rsp = (ul)current_pcb + STACK_SIZE - sizeof(struct pt_regs); current_pcb->thread->fs = USER_DS | 0x3; barrier(); @@ -616,9 +615,9 @@ ul initial_kernel_thread(ul arg) */ void process_exit_notify() { - wait_queue_wakeup(¤t_pcb->parent_pcb->wait_child_proc_exit, PROC_INTERRUPTIBLE); } + /** * @brief 进程退出时执行的函数 * @@ -882,6 +881,7 @@ int process_release_pcb(struct process_control_block *pcb) pcb->next_pcb->prev_pcb = pcb->prev_pcb; process_exit_sighand(pcb); process_exit_signal(pcb); + rs_process_exit_fpstate(pcb); rs_procfs_unregister_pid(pcb->pid); // 释放当前pcb kfree(pcb); diff --git a/kernel/src/process/process.rs b/kernel/src/process/process.rs index e4ed92c9..1cca6215 100644 --- a/kernel/src/process/process.rs +++ b/kernel/src/process/process.rs @@ -6,7 +6,7 @@ use core::{ use alloc::boxed::Box; use crate::{ - arch::asm::current::current_pcb, + arch::{asm::current::current_pcb, fpu::FpState}, filesystem::vfs::file::{File, FileDescriptorVec}, include::bindings::bindings::{ process_control_block, CLONE_FS, EBADF, EFAULT, ENFILE, EPERM, PROC_INTERRUPTIBLE, @@ -151,7 +151,7 @@ impl process_control_block { }; // 拷贝文件描述符数组 - let new_fd_vec: &mut FileDescriptorVec = Box::leak(Box::new(old_fds.clone())); + let new_fd_vec: &mut FileDescriptorVec = Box::leak(old_fds.clone()); self.fds = new_fd_vec as *mut FileDescriptorVec as usize as *mut c_void; @@ -259,7 +259,8 @@ impl process_control_block { /// 当我们要把一个进程,交给其他机制管理时,那么就应该调用本函数。 /// /// 由于本函数可能造成进程不再被调度,因此标记为unsafe - pub unsafe fn mark_sleep_interruptible(&mut self){ + #[allow(dead_code)] + pub unsafe fn mark_sleep_interruptible(&mut self) { self.state = PROC_INTERRUPTIBLE as u64; } @@ -267,7 +268,8 @@ impl process_control_block { /// 当我们要把一个进程,交给其他机制管理时,那么就应该调用本函数 /// /// 由于本函数可能造成进程不再被调度,因此标记为unsafe - pub unsafe fn mark_sleep_uninterruptible(&mut self){ + #[allow(dead_code)] + pub unsafe fn mark_sleep_uninterruptible(&mut self) { self.state = PROC_UNINTERRUPTIBLE as u64; } } @@ -318,4 +320,34 @@ pub extern "C" fn process_exit_files(pcb: &'static mut process_control_block) -> } } +/// @brief 复制当前进程的浮点状态 +#[allow(dead_code)] +#[no_mangle] +pub extern "C" fn rs_dup_fpstate() -> *mut c_void { + // 如果当前进程没有浮点状态,那么就返回一个默认的浮点状态 + if current_pcb().fp_state == null_mut() { + return Box::leak(Box::new(FpState::default())) as *mut FpState as usize as *mut c_void; + } else { + // 如果当前进程有浮点状态,那么就复制一个新的浮点状态 + let state = current_pcb().fp_state as usize as *mut FpState; + unsafe { + let s = state.as_ref().unwrap(); + let state: &mut FpState = Box::leak(Box::new(s.clone())); + + return state as *mut FpState as usize as *mut c_void; + } + } +} + +/// @brief 释放进程的浮点状态所占用的内存 +#[no_mangle] +pub extern "C" fn rs_process_exit_fpstate(pcb: &'static mut process_control_block) { + if pcb.fp_state != null_mut() { + let state = pcb.fp_state as usize as *mut FpState; + unsafe { + drop(Box::from_raw(state)); + } + } +} + // =========== 以上为导出到C的函数,在将来,进程管理模块被完全重构之后,需要删掉他们 END ============ diff --git a/kernel/src/sched/core.rs b/kernel/src/sched/core.rs index 649c78b7..b1f5e4f9 100644 --- a/kernel/src/sched/core.rs +++ b/kernel/src/sched/core.rs @@ -11,7 +11,7 @@ use crate::{ process_control_block, pt_regs, EINVAL, EPERM, MAX_CPU_NUM, PF_NEED_MIGRATE, PROC_RUNNING, SCHED_FIFO, SCHED_NORMAL, SCHED_RR, }, - process::process::process_cpu + process::process::process_cpu, }; use super::cfs::{sched_cfs_init, SchedulerCFS, __get_cfs_scheduler}; diff --git a/kernel/src/sched/rt.rs b/kernel/src/sched/rt.rs index 86aaaff3..348a11f2 100644 --- a/kernel/src/sched/rt.rs +++ b/kernel/src/sched/rt.rs @@ -154,6 +154,7 @@ impl SchedulerRT { return sum as usize; } + #[allow(dead_code)] #[inline] pub fn load_list_len(&mut self, cpu_id: u32) -> usize { return self.load_list[cpu_id as usize].len(); diff --git a/kernel/src/syscall/syscall.c b/kernel/src/syscall/syscall.c index 922171d4..31be416a 100644 --- a/kernel/src/syscall/syscall.c +++ b/kernel/src/syscall/syscall.c @@ -89,17 +89,6 @@ ul system_call_not_exists(struct pt_regs *regs) */ #define SYSCALL_COMMON(syscall_num, symbol) [syscall_num] = symbol, -/** - * @brief sysenter的系统调用函数,从entry.S中跳转到这里 - * - * @param regs 3特权级下的寄存器值,rax存储系统调用号 - * @return ul 对应的系统调用函数的地址 - */ -ul system_call_function(struct pt_regs *regs) -{ - return system_call_table[regs->rax](regs); -} - /** * @brief 初始化系统调用模块 * @@ -298,13 +287,12 @@ extern uint64_t sys_getdents(struct pt_regs *regs); */ uint64_t sys_execve(struct pt_regs *regs) { - // kdebug("sys_execve"); + char *user_path = (char *)regs->r8; char **argv = (char **)regs->r9; int path_len = strnlen_user(user_path, PAGE_4K_SIZE); - // kdebug("path_len=%d", path_len); if (path_len >= PAGE_4K_SIZE) return -ENAMETOOLONG; else if (path_len <= 0) @@ -316,12 +304,10 @@ uint64_t sys_execve(struct pt_regs *regs) memset(path, 0, path_len + 1); - // kdebug("before copy file path from user"); // 拷贝文件路径 strncpy_from_user(path, user_path, path_len); path[path_len] = '\0'; - // kdebug("before do_execve, path = %s", path); // 执行新的程序 uint64_t retval = do_execve(regs, path, argv, NULL); @@ -362,6 +348,8 @@ uint64_t sys_wait4(struct pt_regs *regs) return -EINVAL; // 如果子进程没有退出,则等待其退出 + // BUG: 这里存在问题,由于未对进程管理模块加锁,因此可能会出现子进程退出后,父进程还在等待的情况 + // (子进程退出后,process_exit_notify消息丢失) while (child_proc->state != PROC_ZOMBIE) wait_queue_sleep_on_interriptible(¤t_pcb->wait_child_proc_exit); @@ -402,7 +390,6 @@ ul sys_ahci_end_req(struct pt_regs *regs) // 系统调用的内核入口程序 void do_syscall_int(struct pt_regs *regs, unsigned long error_code) { - ul ret = system_call_table[regs->rax](regs); regs->rax = ret; // 返回码 } diff --git a/kernel/src/syscall/syscall.h b/kernel/src/syscall/syscall.h index 49124793..47d5d1c0 100644 --- a/kernel/src/syscall/syscall.h +++ b/kernel/src/syscall/syscall.h @@ -12,8 +12,6 @@ typedef unsigned long (*system_call_t)(struct pt_regs *regs); -extern void ret_from_system_call(void); // 导出从系统调用返回的函数(定义在entry.S) - extern system_call_t system_call_table[MAX_SYSTEM_CALL_NUM]; // 判断系统调用是否来自用户态 diff --git a/tools/run-qemu.sh b/tools/run-qemu.sh index e7c1afd6..e4b571d9 100644 --- a/tools/run-qemu.sh +++ b/tools/run-qemu.sh @@ -35,7 +35,6 @@ QEMU_ARGUMENT="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot or QEMU_ARGUMENT+="-s -S -cpu ${QEMU_CPU_FEATURES} -rtc ${QEMU_RTC_CLOCK} -serial ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES}" - if [ $flag_can_run -eq 1 ]; then case "$1" in --bios) diff --git a/user/apps/about/about.c b/user/apps/about/about.c index 2762550a..a61145be 100644 --- a/user/apps/about/about.c +++ b/user/apps/about/about.c @@ -36,9 +36,8 @@ void print_copyright() } int main() -{ +{ print_ascii_logo(); - print_copyright(); return 0; diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c index de43b143..5e218131 100644 --- a/user/apps/shell/cmd.c +++ b/user/apps/shell/cmd.c @@ -486,6 +486,7 @@ int shell_cmd_exec(int argc, char **argv) char *file_path = get_target_filepath(argv[1], &path_len); // printf("before execv, path=%s, argc=%d\n", file_path, argc); execv(file_path, argv); + // printf("after execv, path=%s, argc=%d\n", file_path, argc); free(argv); free(file_path); @@ -497,10 +498,8 @@ int shell_cmd_exec(int argc, char **argv) if (strcmp(argv[argc - 1], "&") != 0) waitpid(pid, &retval, 0); else - { - // 输出子进程的pid - printf("[1] %d\n", pid); - } + printf("[1] %d\n", pid); // 输出子进程的pid + free(argv); } } diff --git a/user/apps/test_signal/main.c b/user/apps/test_signal/main.c index 23707488..0d35b182 100644 --- a/user/apps/test_signal/main.c +++ b/user/apps/test_signal/main.c @@ -18,11 +18,11 @@ */ #include +#include #include #include #include #include -#include bool handle_ok = false; @@ -39,6 +39,7 @@ int main() printf("registered.\n"); clock_t last = clock(); + while (1) { if ((clock() - last) / CLOCKS_PER_SEC >= 1)