diff --git a/kernel/src/arch/x86_64/cpu.rs b/kernel/src/arch/x86_64/cpu.rs index 3229554..2a1eea9 100644 --- a/kernel/src/arch/x86_64/cpu.rs +++ b/kernel/src/arch/x86_64/cpu.rs @@ -1,5 +1,6 @@ use apic::{LocalApic, XApic}; use raw_cpuid::CpuId; +use x86_64::registers::control::{Cr0, Cr0Flags}; /// Exit qemu /// See: https://wiki.osdev.org/Shutdown @@ -24,6 +25,19 @@ pub fn send_ipi(cpu_id: usize) { pub fn init() { let mut lapic = unsafe { XApic::new(0xffffff00_fee00000) }; lapic.cpu_init(); + + // enable FPU, the manual Volume 3 Chapter 13 + let mut value: u64; + unsafe { + asm!("mov %cr4, $0" : "=r" (value)); + // OSFXSR | OSXMMEXCPT + value |= 1 << 9 | 1 << 10 ; + asm!("mov $0, %cr4" :: "r" (value) : "memory"); + Cr0::update(|cr0| { + cr0.remove(Cr0Flags::EMULATE_COPROCESSOR); + cr0.insert(Cr0Flags::MONITOR_COPROCESSOR); + }); + } } pub fn halt() { diff --git a/kernel/src/arch/x86_64/interrupt/trap.asm b/kernel/src/arch/x86_64/interrupt/trap.asm index 98eeaf1..2dcca39 100644 --- a/kernel/src/arch/x86_64/interrupt/trap.asm +++ b/kernel/src/arch/x86_64/interrupt/trap.asm @@ -28,6 +28,21 @@ __alltraps: or rdx, rax push rdx + # save fp registers + # align to 16 byte boundary + sub rsp, 512 + mov rax, rsp + and rax, 0xFFFFFFFFFFFFFFF0 + # fxsave (rax) + .byte 0x0f + .byte 0xae + .byte 0x00 + mov rbx, rsp + sub rbx, rax + # push fp state offset + sub rsp, 16 + push rbx + mov rdi, rsp call rust_trap @@ -37,6 +52,20 @@ trap_ret: mov rdi, rsp call set_return_rsp + # pop fp state offset + pop rbx + cmp rbx, 16 # only 0-15 are valid + jge skip_fxrstor + mov rax, rsp + add rax, 16 + sub rax, rbx + # fxrstor (rax) + .byte 0x0f + .byte 0xae + .byte 0x08 +skip_fxrstor: + add rsp, 16+512 + # pop fs.base pop rax mov rdx, rax diff --git a/kernel/src/arch/x86_64/interrupt/trapframe.rs b/kernel/src/arch/x86_64/interrupt/trapframe.rs index 926085f..81662bb 100644 --- a/kernel/src/arch/x86_64/interrupt/trapframe.rs +++ b/kernel/src/arch/x86_64/interrupt/trapframe.rs @@ -1,6 +1,31 @@ +use core::fmt; +use core::default::Default; + +#[derive(Clone)] +#[repr(C)] +pub struct FpState([u8; 16+512]); + +impl fmt::Debug for FpState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "fpstate") + } +} + +impl Default for FpState { + fn default() -> Self { + FpState([0u8; 16+512]) + } +} + + #[derive(Debug, Clone, Default)] #[repr(C)] pub struct TrapFrame { + // fpstate needs to be 16-byte aligned + // so we reserve some space here and save the offset + // the read fpstate begin from fpstate[offset] + pub fpstate_offset: usize, + pub fpstate: FpState, // Pushed by __alltraps at 'trap.asm' pub fsbase: usize, @@ -46,6 +71,7 @@ impl TrapFrame { tf.ss = gdt::KDATA_SELECTOR.0 as usize; tf.rsp = rsp; tf.rflags = 0x282; + tf.fpstate_offset = 16; // skip restoring for first time tf } fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self { @@ -56,6 +82,7 @@ impl TrapFrame { tf.ss = if is32 { gdt::UDATA32_SELECTOR.0 } else { gdt::UDATA_SELECTOR.0 } as usize; tf.rsp = rsp; tf.rflags = 0x282; + tf.fpstate_offset = 16; // skip restoring for first time tf } pub fn is_user(&self) -> bool { @@ -191,4 +218,4 @@ impl Context { pub unsafe fn get_init_tf(&self) -> TrapFrame { (*(self.0 as *const InitStack)).tf.clone() } -} \ No newline at end of file +} diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs index 0f806b6..bf4221d 100644 --- a/kernel/src/arch/x86_64/paging.rs +++ b/kernel/src/arch/x86_64/paging.rs @@ -41,15 +41,18 @@ impl PageTable for ActivePageTable { fn map(&mut self, addr: usize, target: usize) -> &mut Entry { let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE; unsafe { - self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, &mut FrameAllocatorForX86) - .unwrap().flush(); + if let Ok(flush) = self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, &mut FrameAllocatorForX86) { + flush.flush(); + } } unsafe { &mut *(get_entry_ptr(addr, 1)) } } fn unmap(&mut self, addr: usize) { - let (_, flush) = self.0.unmap(Page::of_addr(addr)).unwrap(); - flush.flush(); + // unmap and flush if it is mapped + if let Ok((_, flush)) = self.0.unmap(Page::of_addr(addr)) { + flush.flush(); + } } fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> { diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs index b599911..6eea754 100644 --- a/kernel/src/fs/file.rs +++ b/kernel/src/fs/file.rs @@ -44,6 +44,14 @@ impl FileHandle { Ok(len) } + pub fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result { + if !self.options.read { + return Err(FsError::InvalidParam); // FIXME: => EBADF + } + let len = self.inode.read_at(offset, buf)?; + Ok(len) + } + pub fn write(&mut self, buf: &[u8]) -> Result { if !self.options.write { return Err(FsError::InvalidParam); // FIXME: => EBADF diff --git a/kernel/src/process/abi.rs b/kernel/src/process/abi.rs index 47bd868..4cbe1d2 100644 --- a/kernel/src/process/abi.rs +++ b/kernel/src/process/abi.rs @@ -65,3 +65,4 @@ impl StackWriter { pub const AT_PHDR: u8 = 3; pub const AT_PHENT: u8 = 4; pub const AT_PHNUM: u8 = 5; +pub const AT_PAGESZ: u8 = 6; diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 2e40d1d..d57cc2d 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -7,13 +7,13 @@ use spin::Mutex; use xmas_elf::{ElfFile, header, program::{Flags, Type}}; use smoltcp::socket::{SocketSet, SocketHandle}; use smoltcp::wire::IpEndpoint; +use rcore_memory::PAGE_SIZE; use crate::arch::interrupt::{Context, TrapFrame}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; use crate::fs::{FileHandle, OpenOptions}; use crate::sync::Condvar; use crate::drivers::NET_DRIVERS; -use crate::consts::{USER_TLS_OFFSET, USER_TMP_TLS_OFFSET}; use super::abi::{self, ProcInitInfo}; @@ -151,6 +151,7 @@ impl Thread { } map.insert(abi::AT_PHENT, elf.header.pt2.ph_entry_size() as usize); map.insert(abi::AT_PHNUM, elf.header.pt2.ph_count() as usize); + map.insert(abi::AT_PAGESZ, PAGE_SIZE); map }, }; diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index d413c03..f5e61cc 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -36,6 +36,16 @@ pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { } } +pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResult { + info!("pread: fd: {}, base: {:?}, len: {}, offset: {}", fd, base, len, offset); + let mut proc = process(); + proc.memory_set.check_mut_array(base, len)?; + + let slice = unsafe { slice::from_raw_parts_mut(base, len) }; + let len = proc.get_file(fd)?.read_at(offset, slice)?; + Ok(len as isize) +} + pub fn sys_read_file(proc: &mut Process, fd: usize, base: *mut u8, len: usize) -> SysResult { let slice = unsafe { slice::from_raw_parts_mut(base, len) }; let len = proc.get_file(fd)?.read(slice)?; diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index 8ca9c9c..8088239 100644 --- a/kernel/src/syscall/mem.rs +++ b/kernel/src/syscall/mem.rs @@ -8,7 +8,7 @@ use crate::memory::GlobalFrameAlloc; use super::*; -pub fn sys_mmap(mut addr: usize, len: usize, prot: usize, flags: usize, fd: i32, offset: usize) -> SysResult { +pub fn sys_mmap(mut addr: usize, mut len: usize, prot: usize, flags: usize, fd: i32, offset: usize) -> SysResult { let prot = MmapProt::from_bits_truncate(prot); let flags = MmapFlags::from_bits_truncate(flags); info!("mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}", addr, len, prot, flags, fd, offset); @@ -20,7 +20,13 @@ pub fn sys_mmap(mut addr: usize, len: usize, prot: usize, flags: usize, fd: i32, // so just skip it addr = PAGE_SIZE; } - addr = proc.memory_set.find_free_area(addr, len); + + if flags.contains(MmapFlags::FIXED) { + // we have to map it to addr, so remove the old mapping first + proc.memory_set.pop(addr, addr + len); + } else { + addr = proc.memory_set.find_free_area(addr, len); + } if flags.contains(MmapFlags::ANONYMOUS) { if flags.contains(MmapFlags::SHARED) { @@ -79,6 +85,8 @@ bitflags! { const SHARED = 1 << 0; /// Changes are private. const PRIVATE = 1 << 1; + /// Place the mapping at the exact address + const FIXED = 1 << 4; /// The mapping is not backed by any file. (non-POSIX) const ANONYMOUS = 1 << 5; } diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs new file mode 100644 index 0000000..19413b9 --- /dev/null +++ b/kernel/src/syscall/misc.rs @@ -0,0 +1,36 @@ +use super::*; +use core::mem::size_of; + +pub fn sys_uname(buf: *mut u8) -> SysResult { + info!("sched_uname: buf: {:?}", buf); + + let offset = 65; + let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"]; + let proc = process(); + proc.memory_set + .check_mut_array(buf, strings.len() * offset)?; + + for i in 0..strings.len() { + unsafe { + util::write_cstr(buf.add(i * offset), &strings[i]); + } + } + Ok(0) +} + +pub fn sys_sched_getaffinity(pid: usize, size: usize, mask: *mut u32) -> SysResult { + info!( + "sched_getaffinity: pid: {}, size: {}, mask: {:?}", + pid, size, mask + ); + let proc = process(); + proc.memory_set + .check_mut_array(mask, size / size_of::())?; + + // we only have 4 cpu at most. + // so just set it. + unsafe { + *mask = 0b1111; + } + Ok(0) +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 0eb4e3a..ab902d0 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -21,6 +21,7 @@ use self::proc::*; use self::time::*; use self::ctrl::*; use self::net::*; +use self::misc::*; mod fs; mod mem; @@ -28,6 +29,7 @@ mod proc; mod time; mod ctrl; mod net; +mod misc; /// System call dispatcher pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { @@ -48,6 +50,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { 009 => sys_mmap(args[0], args[1], args[2], args[3], args[4] as i32, args[5]), 010 => sys_mprotect(args[0], args[1], args[2]), 011 => sys_munmap(args[0], args[1]), + 017 => sys_pread(args[0], args[1] as *mut u8, args[2], args[3]), 019 => sys_readv(args[0], args[1] as *const IoVec, args[2]), 020 => sys_writev(args[0], args[1] as *const IoVec, args[2]), 021 => sys_access(args[0] as *const u8, args[1]), @@ -80,6 +83,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { 060 => sys_exit(args[0] as isize), 061 => sys_wait(args[0], args[1] as *mut i32), // TODO: wait4 062 => sys_kill(args[0]), + 063 => sys_uname(args[0] as *mut u8), // 072 => sys_fcntl(), 074 => sys_fsync(args[0]), 075 => sys_fdatasync(args[0]), @@ -103,6 +107,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { // 169 => sys_reboot(), 186 => sys_gettid(), 201 => sys_time(args[0] as *mut u64), + 204 => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32), 217 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]), // 293 => sys_pipe(), @@ -171,12 +176,16 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { warn!("sys_exit_group is unimplemented"); sys_exit(args[0] as isize); } + 302 => { + warn!("sys_prlimit64 is unimplemented"); + Ok(0) + } _ => { error!("unknown syscall id: {:#x?}, args: {:x?}", id, args); crate::trap::error(tf); } }; - debug!("{}:{} syscall id {} ret with {:?}", pid, tid, id, ret); + debug!("{}:{} syscall id {} ret with {:x?}", pid, tid, id, ret); match ret { Ok(code) => code, Err(err) => -(err as isize), diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index 2c55eb9..a483d14 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -475,7 +475,6 @@ pub fn sys_close_socket(proc: &mut Process, fd: usize, handle: SocketHandle) -> pub fn sys_bind(fd: usize, addr: *const SockaddrIn, len: usize) -> SysResult { info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, len); let mut proc = process(); - proc.memory_set.check_array(addr, len)?; if len < size_of::() { return Err(SysError::EINVAL); @@ -509,6 +508,7 @@ pub fn sys_listen(fd: usize, backlog: usize) -> SysResult { let mut sockets = iface.sockets(); let mut socket = sockets.get::(wrapper.handle); + info!("socket {} listening on {:?}", fd, endpoint); match socket.listen(endpoint) { Ok(()) => Ok(0), Err(err) => { @@ -554,7 +554,7 @@ pub fn sys_accept(fd: usize, addr: *mut SockaddrIn, addr_len: *mut u32) -> SysRe return Err(SysError::EINVAL); } - proc.memory_set.check_mut_array(addr, max_addr_len)?; + proc.memory_set.check_mut_ptr(addr)?; } let wrapper = proc.get_socket_mut(fd)?; diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index af438e7..926b700 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -162,6 +162,7 @@ pub fn sys_exit(exit_code: isize) -> ! { } pub fn sys_sleep(time: usize) -> SysResult { + info!("sleep: time: {}", time); if time >= 1 << 31 { thread::park(); } else {