diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index 5ff5d87..007d63f 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -136,6 +136,14 @@ impl MemoryAttr { self } /* + ** @brief unset the memory attribute's readonly bit + ** @retval MemoryAttr the memory attribute itself + */ + pub fn writable(mut self) -> Self { + self.readonly = false; + self + } + /* ** @brief set the memory attribute's execute bit ** @retval MemoryAttr the memory attribute itself */ diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/x86_64/gdt.rs index d87d17d..a445e9b 100644 --- a/kernel/src/arch/x86_64/gdt.rs +++ b/kernel/src/arch/x86_64/gdt.rs @@ -40,7 +40,7 @@ impl Cpu { } unsafe fn init(&'static mut self) { - use x86_64::instructions::segmentation::set_cs; + use x86_64::instructions::segmentation::{set_cs, load_fs}; use x86_64::instructions::tables::load_tss; // Set the stack when DoubleFault occurs diff --git a/kernel/src/arch/x86_64/interrupt/trapframe.rs b/kernel/src/arch/x86_64/interrupt/trapframe.rs index 5322a62..8fd5b2f 100644 --- a/kernel/src/arch/x86_64/interrupt/trapframe.rs +++ b/kernel/src/arch/x86_64/interrupt/trapframe.rs @@ -48,7 +48,7 @@ impl TrapFrame { tf.rflags = 0x282; tf } - fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self { + fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool, tls: usize) -> Self { use crate::arch::gdt; let mut tf = TrapFrame::default(); tf.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize; @@ -56,6 +56,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.fsbase = tls; tf } pub fn is_user(&self) -> bool { @@ -166,11 +167,11 @@ impl Context { tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), }.push_at(kstack_top) } - pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize) -> Self { + pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize, tls: usize) -> Self { InitStack { context: ContextData::new(cr3), trapret: trap_ret as usize, - tf: TrapFrame::new_user_thread(entry_addr, ustack_top, is32), + tf: TrapFrame::new_user_thread(entry_addr, ustack_top, is32, tls), }.push_at(kstack_top) } pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 508bc76..9c5140d 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -5,12 +5,14 @@ use rcore_fs::vfs::INode; use spin::Mutex; use xmas_elf::{ElfFile, header, program::{Flags, Type}}; use smoltcp::socket::{SocketSet, SocketHandle}; +use smoltcp::wire::IpEndpoint; 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}; @@ -24,7 +26,7 @@ pub struct Thread { #[derive(Clone)] pub enum SocketType { Raw, - Tcp, + Tcp(Option), // save local endpoint for bind() Udp, Icmp } @@ -106,7 +108,7 @@ impl Thread { } // Make page table - let (mut memory_set, entry_addr) = memory_set_from(&elf); + let (mut memory_set, entry_addr, tls) = memory_set_from(&elf); // User stack use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET}; @@ -152,7 +154,7 @@ impl Thread { Box::new(Thread { context: unsafe { Context::new_user_thread( - entry_addr, ustack_top, kstack.top(), is32, memory_set.token()) + entry_addr, ustack_top, kstack.top(), is32, memory_set.token(), tls) }, kstack, proc: Arc::new(Mutex::new(Process { @@ -203,11 +205,12 @@ impl Process { /// Generate a MemorySet according to the ELF file. -/// Also return the real entry point address. -fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) { +/// Also return the real entry point address and tls top addr. +fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize, usize) { debug!("come in to memory_set_from"); let mut ms = MemorySet::new(); let mut entry = elf.header.pt2.entry_point() as usize; + let mut tls = 0; // [NoMMU] Get total memory size and alloc space let va_begin = elf.program_iter() @@ -225,14 +228,19 @@ fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) { { entry += 0x40000000; } for ph in elf.program_iter() { - if ph.get_type() != Ok(Type::Load) { + if ph.get_type() != Ok(Type::Load) && ph.get_type() != Ok(Type::Tls) { continue; } - let virt_addr = ph.virtual_addr() as usize; + + let mut virt_addr = ph.virtual_addr() as usize; let offset = ph.offset() as usize; let file_size = ph.file_size() as usize; let mem_size = ph.mem_size() as usize; + if ph.get_type() == Ok(Type::Tls) { + virt_addr = USER_TLS_OFFSET; + } + #[cfg(target_arch = "aarch64")] assert_eq!((virt_addr >> 48), 0xffff, "Segment Fault"); @@ -255,8 +263,35 @@ fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) { target[file_size..].iter_mut().for_each(|x| *x = 0); }); } + + if ph.get_type() == Ok(Type::Tls) { + virt_addr = USER_TMP_TLS_OFFSET; + tls = virt_addr + ph.mem_size() as usize; + debug!("tls addr {:X}", tls); + + // TODO: put this in a function + // Get target slice + #[cfg(feature = "no_mmu")] + let target = &mut target[virt_addr - va_begin..virt_addr - va_begin + mem_size]; + #[cfg(feature = "no_mmu")] + info!("area @ {:?}, size = {:#x}", target.as_ptr(), mem_size); + #[cfg(not(feature = "no_mmu"))] + let target = { + ms.push(virt_addr, virt_addr + mem_size, ByFrame::new(memory_attr_from(ph.flags()).writable(), GlobalFrameAlloc), ""); + unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) } + }; + // Copy data + unsafe { + ms.with(|| { + if file_size != 0 { + target[..file_size].copy_from_slice(&elf.input[offset..offset + file_size]); + } + target[file_size..].iter_mut().for_each(|x| *x = 0); + }); + } + } } - (ms, entry) + (ms, entry, tls) } fn memory_attr_from(elf_flags: Flags) -> MemoryAttr { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 4ebff9b..54cd20e 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -59,8 +59,8 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { // 046 => sys_sendmsg(), // 047 => sys_recvmsg(), // 048 => sys_shutdown(), -// 049 => sys_bind(), -// 050 => sys_listen(), + 049 => sys_bind(args[0], args[1] as *const u8, args[2]), + 050 => sys_listen(args[0], args[1]), 054 => sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4]), // 055 => sys_getsockopt(), // 056 => sys_clone(), diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index f51ada5..cd38682 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -77,7 +77,7 @@ pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResu fd, FileLike::Socket(SocketWrapper { handle: tcp_handle, - socket_type: SocketType::Tcp, + socket_type: SocketType::Tcp(None), }), ); @@ -164,6 +164,14 @@ impl Process { _ => Err(SysError::ENOTSOCK), } } + + fn get_socket_mut(&mut self, fd: usize) -> Result<&mut SocketWrapper, SysError> { + let file = self.files.get_mut(&fd).ok_or(SysError::EBADF)?; + match file { + FileLike::Socket(ref mut wrapper) => Ok(wrapper), + _ => Err(SysError::ENOTSOCK), + } + } } pub fn sys_connect(fd: usize, addr: *const u8, addrlen: usize) -> SysResult { @@ -188,7 +196,7 @@ pub fn sys_connect(fd: usize, addr: *const u8, addrlen: usize) -> SysResult { } let wrapper = proc.get_socket(fd)?; - if let SocketType::Tcp = wrapper.socket_type { + if let SocketType::Tcp(_) = wrapper.socket_type { let mut sockets = iface.sockets(); let mut socket = sockets.get::(wrapper.handle); @@ -229,7 +237,7 @@ pub fn sys_connect(fd: usize, addr: *const u8, addrlen: usize) -> SysResult { pub fn sys_write_socket(proc: &mut Process, fd: usize, base: *const u8, len: usize) -> SysResult { let iface = &mut *(NET_DRIVERS.lock()[0]); let wrapper = proc.get_socket(fd)?; - if let SocketType::Tcp = wrapper.socket_type { + if let SocketType::Tcp(_) = wrapper.socket_type { let mut sockets = iface.sockets(); let mut socket = sockets.get::(wrapper.handle); @@ -261,7 +269,7 @@ pub fn sys_write_socket(proc: &mut Process, fd: usize, base: *const u8, len: usi pub fn sys_read_socket(proc: &mut Process, fd: usize, base: *mut u8, len: usize) -> SysResult { let iface = &mut *(NET_DRIVERS.lock()[0]); let wrapper = proc.get_socket(fd)?; - if let SocketType::Tcp = wrapper.socket_type { + if let SocketType::Tcp(_) = wrapper.socket_type { loop { let mut sockets = iface.sockets(); let mut socket = sockets.get::(wrapper.handle); @@ -517,3 +525,69 @@ pub fn sys_close_socket(proc: &mut Process, fd: usize, handle: SocketHandle) -> Ok(0) } + +pub fn sys_bind(fd: usize, addr: *const u8, len: usize) -> SysResult { + let mut proc = process(); + proc.memory_set.check_array(addr, len)?; + + if len < size_of::() { + return Err(SysError::EINVAL); + } + + let mut host = None; + let mut port = 0; + + let sockaddr_in = unsafe { &*(addr as *const SockaddrIn) }; + parse_addr(&sockaddr_in, &mut host, &mut port); + + if host == None { + return Err(SysError::EINVAL); + } + + let iface = &mut *(NET_DRIVERS.lock()[0]); + let wrapper = proc.get_socket_mut(fd)?; + if let SocketType::Tcp(_) = wrapper.socket_type { + wrapper.socket_type = SocketType::Tcp(Some(IpEndpoint::new(host.unwrap(), port))); + Ok(0) + } else { + Err(SysError::EINVAL) + } +} + +pub fn sys_listen(fd: usize, backlog: usize) -> SysResult { + // smoltcp tcp sockets do not support backlog + // open multiple sockets for each connection + let mut proc = process(); + + let iface = &mut *(NET_DRIVERS.lock()[0]); + let wrapper = proc.get_socket_mut(fd)?; + if let SocketType::Tcp(Some(endpoint)) = wrapper.socket_type { + let mut sockets = iface.sockets(); + let mut socket = sockets.get::(wrapper.handle); + + if let Err(_) = socket.listen(endpoint) { + return Err(SysError::EINVAL); + } + + // avoid deadlock + drop(socket); + drop(sockets); + + loop { + let mut sockets = iface.sockets(); + let mut socket = sockets.get::(wrapper.handle); + + if socket.is_active() { + // use the same one for now, but we should create a new one instead + return Ok(fd as isize); + } + + // avoid deadlock + drop(socket); + drop(sockets); + SOCKET_ACTIVITY._wait() + } + } else { + Err(SysError::EINVAL) + } +} \ No newline at end of file diff --git a/user b/user index 64dac11..fb9a1d5 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 64dac11ac304eece980ba4cffb2eac2040aa08b3 +Subproject commit fb9a1d5f7014b3be4f4a234bcaecd069335a216c