diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile index 528611cf..685fb617 100644 --- a/libmaxsi/Makefile +++ b/libmaxsi/Makefile @@ -46,6 +46,7 @@ kernelinfo.o \ init.o \ signal.o \ $(CPU)/signal.o \ +$(CPU)/fork.o \ start.o \ time.o \ random.o \ diff --git a/libmaxsi/include/unistd.h b/libmaxsi/include/unistd.h index f28dd0fe..41362ad4 100644 --- a/libmaxsi/include/unistd.h +++ b/libmaxsi/include/unistd.h @@ -29,6 +29,10 @@ #define _UNISTD_H 1 #include +#if defined(_SORTIX_SOURCE) +#include +#include +#endif #include #include @@ -187,6 +191,7 @@ size_t pwriteleast(int fd, const void* buf, size_t least, size_t max, off_t off) size_t readall(int fd, void* buf, size_t count); size_t readleast(int fd, void* buf, size_t least, size_t max); pid_t sfork(int flags); +pid_t sforkr(int flags, sforkregs_t* regs); int uptime(uintmax_t* usecssinceboot); size_t writeall(int fd, const void* buf, size_t count); size_t writeleast(int fd, const void* buf, size_t least, size_t max); diff --git a/libmaxsi/process.cpp b/libmaxsi/process.cpp index cde922e6..6e8fe123 100644 --- a/libmaxsi/process.cpp +++ b/libmaxsi/process.cpp @@ -36,8 +36,7 @@ namespace Maxsi { DEFN_SYSCALL1_VOID(SysExit, SYSCALL_EXIT, int); DEFN_SYSCALL3(int, SysExecVE, SYSCALL_EXEC, const char*, char* const*, char* const*); - DEFN_SYSCALL0(pid_t, SysFork, SYSCALL_FORK); - DEFN_SYSCALL1(pid_t, SysSFork, SYSCALL_SFORK, int); + DEFN_SYSCALL2(pid_t, SysSForkR, SYSCALL_SFORKR, int, sforkregs_t*); DEFN_SYSCALL0(pid_t, SysGetPID, SYSCALL_GETPID); DEFN_SYSCALL0(pid_t, SysGetParentPID, SYSCALL_GETPPID); DEFN_SYSCALL3(pid_t, SysWait, SYSCALL_WAIT, pid_t, int*, int); @@ -73,14 +72,21 @@ namespace Maxsi _exit(status); } - DUAL_FUNCTION(pid_t, fork, Fork, ()) + extern "C" pid_t sforkr(int flags, sforkregs_t* regs) { - return SysFork(); + return SysSForkR(flags, regs); } + extern "C" pid_t __call_sforkr_with_regs(int flags); + extern "C" pid_t sfork(int flags) { - return SysSFork(flags); + return __call_sforkr_with_regs(flags); + } + + DUAL_FUNCTION(pid_t, fork, Fork, ()) + { + return sfork(SFFORK); } DUAL_FUNCTION(pid_t, getpid, GetPID, ()) diff --git a/libmaxsi/x64/fork.s b/libmaxsi/x64/fork.s new file mode 100644 index 00000000..96e1ea21 --- /dev/null +++ b/libmaxsi/x64/fork.s @@ -0,0 +1,67 @@ +/******************************************************************************* + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012. + + This file is part of LibMaxsi. + + LibMaxsi is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with LibMaxsi. If not, see . + + x64/fork.s + Assembly functions related to forking x64 processes. + +*******************************************************************************/ + +.section .text + +.globl __call_sforkr_with_regs +.type __call_sforkr_with_regs, @function +__call_sforkr_with_regs: + pushq %rbp + movq %rsp, %rbp + + # The actual system call expects a struct sforkregs_x64 containing the state + # of each register in the child. Since we create an identical copy, we + # simply set each member of the structure to our own state. Note that since + # the stack goes downwards, we create it in the reverse order. + pushfq + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rbp + pushq %rsp + pushq %rsi + pushq %rdi + pushq %rdx + pushq %rcx + pushq %rbx + pushq $0 # rax, result of sfork is 0 for the child. + pushq $after_fork # rip, child will start execution from here. + + # Call sforkr with a nice pointer to our structure. Note that %rdi contains + # the flag parameter that this function accepted. + movq %rsp, %rsi + call sforkr + +after_fork: + # The value in %rax determines whether we are child or parent. There is no + # need to clean up the stack from the above pushes, leaveq sets %rsp to %rbp + # which does that for us. + leaveq + retq + diff --git a/libmaxsi/x86/fork.s b/libmaxsi/x86/fork.s new file mode 100644 index 00000000..e40b0851 --- /dev/null +++ b/libmaxsi/x86/fork.s @@ -0,0 +1,62 @@ +/******************************************************************************* + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012. + + This file is part of LibMaxsi. + + LibMaxsi is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with LibMaxsi. If not, see . + + x86/fork.s + Assembly functions related to forking x86 processes. + +*******************************************************************************/ + +.section .text + +.globl __call_sforkr_with_regs +.type __call_sforkr_with_regs, @function +__call_sforkr_with_regs: + pushl %ebp + movl %esp, %ebp + + movl 8(%ebp), %edx # flags parameter, edx need not be preserved. + + # The actual system call expects a struct sforkregs_x86 containing the state + # of each register in the child. Since we create an identical copy, we + # simply set each member of the structure to our own state. Note that since + # the stack goes downwards, we create it in the reverse order. + pushfl + pushl %ebp + pushl %esp + pushl %esi + pushl %edi + pushl %edx + pushl %ecx + pushl %ebx + pushl $0 # rax, result of sfork is 0 for the child. + pushl $after_fork # rip, child will start execution from here. + + # Call sforkr with a nice pointer to our structure. Note that %edi contains + # the flag parameter that this function accepted. + pushl %esp + pushl %edx + call sforkr + +after_fork: + # The value in %eax determines whether we are child or parent. There is no + # need to clean up the stack from the above pushes, leavel sets %esp to %ebp + # which does that for us. + leavel + retl + diff --git a/sortix/include/sortix/fork.h b/sortix/include/sortix/fork.h new file mode 100644 index 00000000..bd26217b --- /dev/null +++ b/sortix/include/sortix/fork.h @@ -0,0 +1,89 @@ +/******************************************************************************* + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + sortix/fork.h + Declarations related to the fork family of system calls on Sortix. + +*******************************************************************************/ + +#ifndef SORTIX_FORK_H +#define SORTIX_FORK_H + +#include +#include +#include + +__BEGIN_DECLS + +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +#define X_OK 1 /* Test for execute permission. */ +#define F_OK 0 /* Test for existence. */ + +/* The sfork system call is much like the rfork system call found in Plan 9 and + BSD systems, however it works slightly differently and was renamed to avoid + conflicts with existing programs. In particular, it never forks an item + unless its bit is set, whereas rfork sometimes forks an item by default. If + you wish to fork certain items simply set the proper flags. Note that since + flags may be added from time to time, you should use various compound flags + defined below such as SFFORK and SFALL. It can be useful do combine these + compount flags with bitoperations, for instance "I want traditional fork, + except share the working dir pointer" is sfork(SFFORK & ~SFCWD). */ +#define SFPROC (1<<0) /* Creates child, otherwise affect current process. */ +#define SFPID (1<<1) /* Allocates new PID. */ +#define SFFD (1<<2) /* Fork file descriptor table. */ +#define SFMEM (1<<3) /* Forks address space. */ +#define SFCWD (1<<4) /* Forks current directory pointer. */ +#define SFROOT (1<<5) /* Forks root directory pointer. */ +#define SFNAME (1<<6) /* Forks namespace. */ +#define SFSIG (1<<7) /* Forks signal table. */ +#define SFCSIG (1<<8) /* Child will have no pending signals, like fork(2). */ + +/* Creates a new thread in this process. Beware that it will share the stack of + the parent thread and that various threading featues may not have been set up + properly. You should use the standard threading API unless you know what you + are doing; remember that you can always sfork more stuff after the standard + threading API returns control to you. */ +#define SFTHREAD (SFPROC | SFCSIG) + +/* Provides traditional fork(2) behavior; use this instead of the above values + if you want "as fork(2), but also fork foo", or "as fork(2), except bar". In + those cases it is better to sfork(SFFORK & ~SFFOO); or sfork(SFFORK | SFBAR); + as that would allow to add new flags to SFFORK if a new kernel feature is + added to the system that applications don't know about yet. */ +#define SFFORK (SFPROC | SFPID | SFFD | SFMEM | SFCWD | SFROOT | SFCSIG) + +/* This allows creating a process that is completely forked from the original + process, unlike SFFORK which does share a few things (such as the process + namespace). Note that there is a few unset high bits in this value, these + are reserved and must not be set. */ +#define SFALL ((1<<20)-1) + +#ifdef PLATFORM_X86 +typedef struct sforkregs_x86 sforkregs_t; +#elif defined(PLATFORM_X64) +typedef struct sforkregs_x64 sforkregs_t; +#else +#warning No sforkresgs_cpu structure declared +#endif + +__END_DECLS + +#endif + diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h index 66bb4169..b1779f9e 100644 --- a/sortix/include/sortix/syscallnum.h +++ b/sortix/include/sortix/syscallnum.h @@ -35,7 +35,6 @@ #define SYSCALL_SET_FREQUENCY 9 #define SYSCALL_EXEC 10 #define SYSCALL_PRINT_PATH_FILES 11 -#define SYSCALL_FORK 12 #define SYSCALL_GETPID 13 #define SYSCALL_GETPPID 14 #define SYSCALL_GET_FILEINFO 15 @@ -74,7 +73,7 @@ #define SYSCALL_KERNELINFO 48 #define SYSCALL_PREAD 49 #define SYSCALL_PWRITE 50 -#define SYSCALL_SFORK 51 +#define SYSCALL_SFORKR 51 #define SYSCALL_MAX_NUM 52 /* index of highest constant + 1 */ #endif diff --git a/sortix/include/sortix/unistd.h b/sortix/include/sortix/unistd.h index 2f4028f7..074ebe49 100644 --- a/sortix/include/sortix/unistd.h +++ b/sortix/include/sortix/unistd.h @@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License along with Sortix. If not, see . - unistd.h - Standard symbolic constants and types. + sortix/unistd.h + Standard symbolic constants and types for Sortix. *******************************************************************************/ @@ -34,38 +34,6 @@ __BEGIN_DECLS #define X_OK 1 /* Test for execute permission. */ #define F_OK 0 /* Test for existence. */ -/* The sfork system call is much like the rfork system call found in Plan 9 and - BSD systems, however it works slightly differently and was renamed to avoid - conflicts with existing programs. In particular, it never forks an item - unless its bit is set, whereas rfork sometimes forks an item by default. If - you wish to fork certain items simply set the proper flags. Note that since - flags may be added from time to time, you should use various compound flags - defined below such as SFFORK and SFALL. It can be useful do combine these - compount flags with bitoperations, for instance "I want traditional fork, - except share the working dir pointer" is sfork(SFFORK & ~SFCWD). */ -#define SFPROC (1<<0) /* Creates child, otherwise affect current process. */ -#define SFPID (1<<1) /* Allocates new PID. */ -#define SFFD (1<<2) /* Fork file descriptor table. */ -#define SFMEM (1<<3) /* Forks address space. */ -#define SFCWD (1<<4) /* Forks current directory pointer. */ -#define SFROOT (1<<5) /* Forks root directory pointer. */ -#define SFNAME (1<<6) /* Forks namespace. */ -#define SFSIG (1<<7) /* Forks signal table. */ -#define SFCSIG (1<<8) /* Child will have no pending signals, like fork(2). */ - -/* Provides traditional fork(2) behavior; use this instead of the above values - if you want "as fork(2), but also fork foo", or "as fork(2), except bar". In - those cases it is better to sfork(SFFORK & ~SFFOO); or sfork(SFFORK | SFBAR); - as that would allow to add new flags to SFFORK if a new kernel feature is - added to the system that applications don't know about yet. */ -#define SFFORK (SFPROC | SFPID | SFFD | SFMEM | SFCWD | SFROOT | SFCSIG) - -/* This allows creating a process that is completely forked from the original - process, unlike SFFORK which does share a few things (such as the process - namespace). Note that there is a few unset high bits in this value, these - are reserved and must not be set. */ -#define SFALL ((1<<20)-1) - __END_DECLS #endif diff --git a/sortix/include/sortix/x64/fork.h b/sortix/include/sortix/x64/fork.h new file mode 100644 index 00000000..0fc267cd --- /dev/null +++ b/sortix/include/sortix/x64/fork.h @@ -0,0 +1,57 @@ +/******************************************************************************* + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + sortix/x64/fork.h + Declarations related to the fork family of system calls on x64 Sortix. + +*******************************************************************************/ + +#ifndef SORTIX_X64_FORK_H +#define SORTIX_X64_FORK_H + +#include + +__BEGIN_DECLS + +struct sforkregs_x64 +{ + uint64_t rip; + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rdi; + uint64_t rsi; + uint64_t rsp; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rflags; +}; + +__END_DECLS + +#endif + diff --git a/sortix/include/sortix/x86/fork.h b/sortix/include/sortix/x86/fork.h new file mode 100644 index 00000000..4e60faf3 --- /dev/null +++ b/sortix/include/sortix/x86/fork.h @@ -0,0 +1,49 @@ +/******************************************************************************* + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + sortix/x86/fork.h + Declarations related to the fork family of system calls on x86 Sortix. + +*******************************************************************************/ + +#ifndef SORTIX_X86_FORK_H +#define SORTIX_X86_FORK_H + +#include + +__BEGIN_DECLS + +struct sforkregs_x86 +{ + uint32_t eip; + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t edi; + uint32_t esi; + uint32_t esp; + uint32_t ebp; + uint32_t eflags; +}; + +__END_DECLS + +#endif + diff --git a/sortix/process.cpp b/sortix/process.cpp index 52721027..ac1d20c0 100644 --- a/sortix/process.cpp +++ b/sortix/process.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -479,14 +480,56 @@ namespace Sortix return SysExevVEStage2(state); } - pid_t SysSFork(int flags) + pid_t SysSForkR(int flags, sforkregs_t* regs) { - // TODO: Properly support sfork(2). + // TODO: Properly support sforkr(2). if ( flags != SFFORK ) { Error::Set(ENOSYS); return -1; } - // Prepare the state of the clone. - Syscall::SyscallRegs()->result = 0; - CurrentThread()->SaveRegisters(Syscall::InterruptRegs()); + CPU::InterruptRegisters cpuregs; + Maxsi::Memory::Set(&cpuregs, 0, sizeof(cpuregs)); +#if defined(PLATFORM_X64) + cpuregs.rip = regs->rip; + cpuregs.userrsp = regs->rsp; + cpuregs.rax = regs->rax; + cpuregs.rbx = regs->rbx; + cpuregs.rcx = regs->rcx; + cpuregs.rdx = regs->rdx; + cpuregs.rdi = regs->rdi; + cpuregs.rsi = regs->rsi; + cpuregs.rbp = regs->rbp; + cpuregs.r8 = regs->r8; + cpuregs.r9 = regs->r9; + cpuregs.r10 = regs->r10; + cpuregs.r11 = regs->r11; + cpuregs.r12 = regs->r12; + cpuregs.r13 = regs->r13; + cpuregs.r14 = regs->r14; + cpuregs.r15 = regs->r15; + cpuregs.cs = 0x18 | 0x3; + cpuregs.ds = 0x20 | 0x3; + cpuregs.ss = 0x20 | 0x3; + //cpuregs.rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + cpuregs.rflags = (1<<1) | (1<<9) | (1<<21); +#elif defined(PLATFORM_X86) + cpuregs.eip = regs->eip; + cpuregs.useresp = regs->esp; + cpuregs.eax = regs->eax; + cpuregs.ebx = regs->ebx; + cpuregs.ecx = regs->ecx; + cpuregs.edx = regs->edx; + cpuregs.edi = regs->edi; + cpuregs.esi = regs->esi; + cpuregs.ebp = regs->ebp; + cpuregs.cs = 0x18 | 0x3; + cpuregs.ds = 0x20 | 0x3; + cpuregs.ss = 0x20 | 0x3; + //cpuregs.eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + cpuregs.eflags = (1<<1) | (1<<9) | (1<<21); +#else + #error SysSForkR needs to know about your platform +#endif + + CurrentThread()->SaveRegisters(&cpuregs); Process* clone = CurrentProcess()->Fork(); if ( !clone ) { return -1; } @@ -494,11 +537,6 @@ namespace Sortix return clone->pid; } - pid_t SysFork() - { - return SysSFork(SFFORK); - } - pid_t SysGetPID() { return CurrentProcess()->pid; @@ -801,8 +839,7 @@ namespace Sortix void Process::Init() { Syscall::Register(SYSCALL_EXEC, (void*) SysExecVE); - Syscall::Register(SYSCALL_FORK, (void*) SysFork); - Syscall::Register(SYSCALL_SFORK, (void*) SysSFork); + Syscall::Register(SYSCALL_SFORKR, (void*) SysSForkR); Syscall::Register(SYSCALL_GETPID, (void*) SysGetPID); Syscall::Register(SYSCALL_GETPPID, (void*) SysGetParentPID); Syscall::Register(SYSCALL_EXIT, (void*) SysExit);