2018-10-16 09:01:38 +00:00
# include "types.h"
2018-11-01 12:15:46 +00:00
# include "Process.h"
2018-10-16 09:01:38 +00:00
# include "kmalloc.h"
# include "StdLib.h"
# include "i386.h"
# include "system.h"
2019-01-23 04:13:17 +00:00
# include <Kernel/FileDescriptor.h>
# include <Kernel/VirtualFileSystem.h>
2019-02-12 10:25:25 +00:00
# include <Kernel/NullDevice.h>
2018-12-02 19:27:08 +00:00
# include "ELFLoader.h"
2018-10-17 21:13:55 +00:00
# include "MemoryManager.h"
2018-10-25 11:53:49 +00:00
# include "i8253.h"
2018-10-25 15:29:49 +00:00
# include "RTC.h"
2018-12-03 23:27:16 +00:00
# include <AK/StdLibExtras.h>
2018-11-06 14:45:16 +00:00
# include <LibC/signal_numbers.h>
2019-01-22 00:12:53 +00:00
# include <LibC/errno_numbers.h>
2018-11-07 20:19:47 +00:00
# include "Syscall.h"
2018-11-07 21:15:02 +00:00
# include "Scheduler.h"
2018-11-12 00:28:46 +00:00
# include "FIFO.h"
2018-12-24 21:59:10 +00:00
# include "KSyms.h"
2019-02-14 13:17:38 +00:00
# include <Kernel/Socket.h>
2019-01-15 05:30:19 +00:00
# include "MasterPTY.h"
2019-02-06 16:28:14 +00:00
# include "elf.h"
2019-02-16 23:13:47 +00:00
# include <AK/StringBuilder.h>
2018-10-16 09:01:38 +00:00
2018-10-23 08:12:50 +00:00
//#define DEBUG_IO
2018-10-23 22:20:34 +00:00
//#define TASK_DEBUG
2018-11-05 09:23:00 +00:00
//#define FORK_DEBUG
2018-11-07 23:07:56 +00:00
# define SIGNAL_DEBUG
2018-11-07 00:38:51 +00:00
# define MAX_PROCESS_GIDS 32
2019-02-16 23:13:47 +00:00
//#define SHARED_BUFFER_DEBUG
2018-11-05 12:48:07 +00:00
2019-02-03 02:56:08 +00:00
static const dword default_kernel_stack_size = 16384 ;
static const dword default_userspace_stack_size = 65536 ;
2018-10-23 08:12:50 +00:00
2018-10-16 09:01:38 +00:00
static pid_t next_pid ;
2018-11-07 21:15:02 +00:00
InlineLinkedList < Process > * g_processes ;
2018-10-26 07:54:29 +00:00
static String * s_hostname ;
2019-02-07 09:29:26 +00:00
static Lock * s_hostname_lock ;
2018-10-26 12:56:21 +00:00
2018-11-07 21:15:02 +00:00
CoolGlobals * g_cool_globals ;
2018-11-01 13:41:49 +00:00
2018-11-01 12:15:46 +00:00
void Process : : initialize ( )
2018-10-16 09:01:38 +00:00
{
2018-11-05 12:48:07 +00:00
# ifdef COOL_GLOBALS
2018-11-07 21:15:02 +00:00
g_cool_globals = reinterpret_cast < CoolGlobals * > ( 0x1000 ) ;
2018-11-05 12:48:07 +00:00
# endif
2018-10-16 09:01:38 +00:00
next_pid = 0 ;
2018-11-07 21:15:02 +00:00
g_processes = new InlineLinkedList < Process > ;
2018-11-16 23:23:39 +00:00
s_hostname = new String ( " courage " ) ;
2019-02-07 09:29:26 +00:00
s_hostname_lock = new Lock ;
2018-11-07 21:15:02 +00:00
Scheduler : : initialize ( ) ;
2018-11-02 13:06:48 +00:00
}
2019-02-03 11:33:11 +00:00
Vector < pid_t > Process : : all_pids ( )
{
Vector < pid_t > pids ;
2019-02-06 17:45:21 +00:00
pids . ensure_capacity ( system . nprocess ) ;
InterruptDisabler disabler ;
2019-02-03 11:33:11 +00:00
for ( auto * process = g_processes - > head ( ) ; process ; process = process - > next ( ) )
2019-02-06 17:45:21 +00:00
pids . append ( process - > pid ( ) ) ;
2019-02-03 11:33:11 +00:00
return pids ;
}
2019-01-31 16:31:23 +00:00
Vector < Process * > Process : : all_processes ( )
2018-10-23 10:44:46 +00:00
{
2018-11-01 12:15:46 +00:00
Vector < Process * > processes ;
2019-02-06 17:45:21 +00:00
processes . ensure_capacity ( system . nprocess ) ;
InterruptDisabler disabler ;
2018-11-07 21:15:02 +00:00
for ( auto * process = g_processes - > head ( ) ; process ; process = process - > next ( ) )
2019-02-06 17:45:21 +00:00
processes . append ( process ) ;
2018-11-01 12:15:46 +00:00
return processes ;
2018-10-23 10:44:46 +00:00
}
2018-11-19 01:17:20 +00:00
Region * Process : : allocate_region ( LinearAddress laddr , size_t size , String & & name , bool is_readable , bool is_writable , bool commit )
2018-10-18 11:05:00 +00:00
{
2019-01-12 23:27:25 +00:00
size = PAGE_ROUND_UP ( size ) ;
2018-10-18 12:53:00 +00:00
// FIXME: This needs sanity checks. What if this overlaps existing regions?
2018-11-03 10:28:23 +00:00
if ( laddr . is_null ( ) ) {
2019-01-31 16:31:23 +00:00
laddr = m_next_region ;
m_next_region = m_next_region . offset ( size ) . offset ( PAGE_SIZE ) ;
2018-11-03 10:28:23 +00:00
}
laddr . mask ( 0xfffff000 ) ;
2018-11-08 13:35:30 +00:00
m_regions . append ( adopt ( * new Region ( laddr , size , move ( name ) , is_readable , is_writable ) ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * m_regions . last ( ) ) ;
2019-01-22 04:01:00 +00:00
if ( commit )
m_regions . last ( ) - > commit ( ) ;
2018-10-18 12:53:00 +00:00
return m_regions . last ( ) . ptr ( ) ;
2018-10-18 11:05:00 +00:00
}
2019-01-16 11:57:07 +00:00
Region * Process : : allocate_file_backed_region ( LinearAddress laddr , size_t size , RetainPtr < Inode > & & inode , String & & name , bool is_readable , bool is_writable )
2018-11-08 11:59:16 +00:00
{
2019-01-12 23:27:25 +00:00
size = PAGE_ROUND_UP ( size ) ;
2018-11-08 11:59:16 +00:00
// FIXME: This needs sanity checks. What if this overlaps existing regions?
if ( laddr . is_null ( ) ) {
2019-01-31 16:31:23 +00:00
laddr = m_next_region ;
m_next_region = m_next_region . offset ( size ) . offset ( PAGE_SIZE ) ;
2018-11-08 11:59:16 +00:00
}
laddr . mask ( 0xfffff000 ) ;
2019-01-16 11:57:07 +00:00
m_regions . append ( adopt ( * new Region ( laddr , size , move ( inode ) , move ( name ) , is_readable , is_writable ) ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * m_regions . last ( ) ) ;
2018-11-08 11:59:16 +00:00
return m_regions . last ( ) . ptr ( ) ;
}
2018-11-08 20:20:09 +00:00
Region * Process : : allocate_region_with_vmo ( LinearAddress laddr , size_t size , RetainPtr < VMObject > & & vmo , size_t offset_in_vmo , String & & name , bool is_readable , bool is_writable )
{
ASSERT ( vmo ) ;
2019-01-12 23:27:25 +00:00
size = PAGE_ROUND_UP ( size ) ;
2018-11-08 20:20:09 +00:00
// FIXME: This needs sanity checks. What if this overlaps existing regions?
if ( laddr . is_null ( ) ) {
2019-01-31 16:31:23 +00:00
laddr = m_next_region ;
m_next_region = m_next_region . offset ( size ) . offset ( PAGE_SIZE ) ;
2018-11-08 20:20:09 +00:00
}
laddr . mask ( 0xfffff000 ) ;
offset_in_vmo & = PAGE_MASK ;
2019-01-31 16:31:23 +00:00
size = ceil_div ( size , PAGE_SIZE ) * PAGE_SIZE ;
2018-11-08 20:20:09 +00:00
m_regions . append ( adopt ( * new Region ( laddr , size , move ( vmo ) , offset_in_vmo , move ( name ) , is_readable , is_writable ) ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * m_regions . last ( ) ) ;
2018-11-08 20:20:09 +00:00
return m_regions . last ( ) . ptr ( ) ;
}
2018-11-03 10:28:23 +00:00
bool Process : : deallocate_region ( Region & region )
2018-10-24 07:48:24 +00:00
{
2018-10-28 08:36:21 +00:00
InterruptDisabler disabler ;
2018-10-24 07:48:24 +00:00
for ( size_t i = 0 ; i < m_regions . size ( ) ; + + i ) {
if ( m_regions [ i ] . ptr ( ) = = & region ) {
2019-01-22 04:01:00 +00:00
MM . unmap_region ( region ) ;
2018-10-24 07:48:24 +00:00
m_regions . remove ( i ) ;
return true ;
}
}
return false ;
}
2019-01-31 16:31:23 +00:00
Region * Process : : region_from_range ( LinearAddress laddr , size_t size )
2018-10-24 07:48:24 +00:00
{
2019-02-17 07:32:08 +00:00
size = PAGE_ROUND_UP ( size ) ;
2018-10-24 07:48:24 +00:00
for ( auto & region : m_regions ) {
2019-01-24 17:09:46 +00:00
if ( region - > laddr ( ) = = laddr & & region - > size ( ) = = size )
2018-10-24 07:48:24 +00:00
return region . ptr ( ) ;
}
return nullptr ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ set_mmap_name ( void * addr , size_t size , const char * name )
2018-10-28 08:57:22 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( name ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-01-31 16:31:23 +00:00
auto * region = region_from_range ( LinearAddress ( ( dword ) addr ) , size ) ;
2018-10-28 08:57:22 +00:00
if ( ! region )
return - EINVAL ;
2019-01-24 17:09:46 +00:00
region - > set_name ( String ( name ) ) ;
2018-10-28 08:57:22 +00:00
return 0 ;
}
2018-11-08 10:37:01 +00:00
void * Process : : sys $ mmap ( const Syscall : : SC_mmap_params * params )
2018-10-24 07:48:24 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_read ( params , sizeof ( Syscall : : SC_mmap_params ) ) )
return ( void * ) - EFAULT ;
2018-11-08 10:37:01 +00:00
void * addr = ( void * ) params - > addr ;
size_t size = params - > size ;
int prot = params - > prot ;
int flags = params - > flags ;
int fd = params - > fd ;
2019-01-23 05:53:01 +00:00
off_t offset = params - > offset ;
2018-11-08 11:59:16 +00:00
if ( size = = 0 )
return ( void * ) - EINVAL ;
2019-02-09 07:44:46 +00:00
if ( ( dword ) addr & ~ PAGE_MASK )
2018-11-08 11:59:16 +00:00
return ( void * ) - EINVAL ;
if ( flags & MAP_ANONYMOUS ) {
2019-02-16 23:13:47 +00:00
auto * region = allocate_region ( LinearAddress ( ( dword ) addr ) , size , " mmap " , prot & PROT_READ , prot & PROT_WRITE , false ) ;
2018-11-08 11:59:16 +00:00
if ( ! region )
return ( void * ) - ENOMEM ;
2019-02-16 23:13:47 +00:00
if ( flags & MAP_SHARED )
region - > set_shared ( true ) ;
2019-01-24 17:09:46 +00:00
return region - > laddr ( ) . as_ptr ( ) ;
2018-11-08 11:59:16 +00:00
}
if ( offset & ~ PAGE_MASK )
return ( void * ) - EINVAL ;
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return ( void * ) - EBADF ;
2019-01-16 11:57:07 +00:00
if ( ! descriptor - > supports_mmap ( ) )
2018-11-08 11:59:16 +00:00
return ( void * ) - ENODEV ;
2019-02-16 08:57:42 +00:00
auto * region = descriptor - > mmap ( * this , LinearAddress ( ( dword ) addr ) , offset , size , prot ) ;
2018-10-24 07:48:24 +00:00
if ( ! region )
2018-11-08 11:59:16 +00:00
return ( void * ) - ENOMEM ;
2019-02-16 23:13:47 +00:00
if ( flags & MAP_SHARED )
region - > set_shared ( true ) ;
2019-01-24 17:09:46 +00:00
return region - > laddr ( ) . as_ptr ( ) ;
2018-10-24 07:48:24 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ munmap ( void * addr , size_t size )
2018-10-24 07:48:24 +00:00
{
2019-01-31 16:31:23 +00:00
auto * region = region_from_range ( LinearAddress ( ( dword ) addr ) , size ) ;
2018-10-24 07:48:24 +00:00
if ( ! region )
2019-02-16 23:13:47 +00:00
return - EINVAL ;
2018-11-03 10:28:23 +00:00
if ( ! deallocate_region ( * region ) )
2019-02-16 23:13:47 +00:00
return - EINVAL ;
2018-10-24 07:48:24 +00:00
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ gethostname ( char * buffer , size_t size )
2018-10-26 07:54:29 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2019-02-07 09:29:26 +00:00
LOCKER ( * s_hostname_lock ) ;
if ( size < ( s_hostname - > length ( ) + 1 ) )
2018-10-26 07:54:29 +00:00
return - ENAMETOOLONG ;
2019-02-07 09:29:26 +00:00
strcpy ( buffer , s_hostname - > characters ( ) ) ;
2018-10-26 09:16:56 +00:00
return 0 ;
2018-10-26 07:54:29 +00:00
}
2018-11-02 19:41:58 +00:00
Process * Process : : fork ( RegisterDump & regs )
{
2019-01-31 16:31:23 +00:00
auto * child = new Process ( String ( m_name ) , m_uid , m_gid , m_pid , m_ring , m_cwd . copy_ref ( ) , m_executable . copy_ref ( ) , m_tty , this ) ;
2018-11-10 22:29:07 +00:00
if ( ! child )
return nullptr ;
memcpy ( child - > m_signal_action_data , m_signal_action_data , sizeof ( m_signal_action_data ) ) ;
child - > m_signal_mask = m_signal_mask ;
2018-11-02 19:41:58 +00:00
# ifdef FORK_DEBUG
dbgprintf ( " fork: child=%p \n " , child ) ;
# endif
2019-01-21 01:58:19 +00:00
child - > m_initial_arguments = m_initial_arguments ;
child - > m_initial_environment = m_initial_environment ;
2018-11-02 19:41:58 +00:00
for ( auto & region : m_regions ) {
# ifdef FORK_DEBUG
2019-01-24 17:09:46 +00:00
dbgprintf ( " fork: cloning Region{%p} \" %s \" L%x \n " , region . ptr ( ) , region - > name . characters ( ) , region - > laddr ( ) . get ( ) ) ;
2018-11-02 19:41:58 +00:00
# endif
auto cloned_region = region - > clone ( ) ;
child - > m_regions . append ( move ( cloned_region ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * child , * child - > m_regions . last ( ) ) ;
2019-01-21 00:49:30 +00:00
if ( region . ptr ( ) = = m_display_framebuffer_region . ptr ( ) )
2019-01-31 16:31:23 +00:00
child - > m_display_framebuffer_region = child - > m_regions . last ( ) . copy_ref ( ) ;
2018-11-02 19:41:58 +00:00
}
2019-01-21 00:49:30 +00:00
for ( auto gid : m_gids )
child - > m_gids . set ( gid ) ;
2018-11-02 19:41:58 +00:00
child - > m_tss . eax = 0 ; // fork() returns 0 in the child :^)
child - > m_tss . ebx = regs . ebx ;
child - > m_tss . ecx = regs . ecx ;
child - > m_tss . edx = regs . edx ;
child - > m_tss . ebp = regs . ebp ;
child - > m_tss . esp = regs . esp_if_crossRing ;
child - > m_tss . esi = regs . esi ;
child - > m_tss . edi = regs . edi ;
child - > m_tss . eflags = regs . eflags ;
child - > m_tss . eip = regs . eip ;
child - > m_tss . cs = regs . cs ;
child - > m_tss . ds = regs . ds ;
child - > m_tss . es = regs . es ;
child - > m_tss . fs = regs . fs ;
child - > m_tss . gs = regs . gs ;
child - > m_tss . ss = regs . ss_if_crossRing ;
2019-01-25 06:52:44 +00:00
child - > m_fpu_state = m_fpu_state ;
child - > m_has_used_fpu = m_has_used_fpu ;
2018-11-02 19:41:58 +00:00
# ifdef FORK_DEBUG
dbgprintf ( " fork: child will begin executing at %w:%x with stack %w:%x \n " , child - > m_tss . cs , child - > m_tss . eip , child - > m_tss . ss , child - > m_tss . esp ) ;
# endif
2018-11-09 00:25:31 +00:00
{
InterruptDisabler disabler ;
g_processes - > prepend ( child ) ;
system . nprocess + + ;
}
2018-11-02 19:41:58 +00:00
# ifdef TASK_DEBUG
kprintf ( " Process %u (%s) forked from %u @ %p \n " , child - > pid ( ) , child - > name ( ) . characters ( ) , m_pid , child - > m_tss . eip ) ;
# endif
return child ;
}
pid_t Process : : sys $ fork ( RegisterDump & regs )
{
auto * child = fork ( regs ) ;
ASSERT ( child ) ;
return child - > pid ( ) ;
}
2019-02-17 09:18:25 +00:00
int Process : : do_exec ( String path , Vector < String > arguments , Vector < String > environment )
2018-11-03 00:49:40 +00:00
{
2019-02-03 02:56:08 +00:00
ASSERT ( is_ring3 ( ) ) ;
2018-11-03 00:49:40 +00:00
auto parts = path . split ( ' / ' ) ;
2018-12-21 01:10:45 +00:00
if ( parts . is_empty ( ) )
2018-11-03 00:49:40 +00:00
return - ENOENT ;
int error ;
2019-02-01 14:36:45 +00:00
auto descriptor = VFS : : the ( ) . open ( path , error , 0 , 0 , * cwd_inode ( ) ) ;
2018-11-07 10:37:54 +00:00
if ( ! descriptor ) {
2018-11-03 00:49:40 +00:00
ASSERT ( error ! = 0 ) ;
return error ;
}
2019-01-31 16:31:23 +00:00
if ( ! descriptor - > metadata ( ) . may_execute ( m_euid , m_gids ) )
2018-11-03 00:49:40 +00:00
return - EACCES ;
2018-11-08 20:20:09 +00:00
if ( ! descriptor - > metadata ( ) . size ) {
kprintf ( " exec() of 0-length binaries not supported \n " ) ;
return - ENOTIMPL ;
}
2018-11-03 00:49:40 +00:00
dword entry_eip = 0 ;
2018-12-31 13:58:03 +00:00
// FIXME: Is there a race here?
auto old_page_directory = move ( m_page_directory ) ;
2019-01-22 04:01:00 +00:00
m_page_directory = PageDirectory : : create ( ) ;
2018-11-09 00:25:31 +00:00
# ifdef MM_DEBUG
2018-12-31 13:58:03 +00:00
dbgprintf ( " Process %u exec: PD=%x created \n " , pid ( ) , m_page_directory . ptr ( ) ) ;
2018-11-09 00:25:31 +00:00
# endif
ProcessPagingScope paging_scope ( * this ) ;
2018-11-08 20:20:09 +00:00
2019-02-05 05:43:33 +00:00
auto vmo = VMObject : : create_file_backed ( descriptor - > inode ( ) ) ;
2019-01-22 04:01:00 +00:00
vmo - > set_name ( descriptor - > absolute_path ( ) ) ;
2019-02-10 11:42:54 +00:00
RetainPtr < Region > region = allocate_region_with_vmo ( LinearAddress ( ) , descriptor - > metadata ( ) . size , vmo . copy_ref ( ) , 0 , " executable " , true , false ) ;
2019-01-22 04:01:00 +00:00
2018-11-08 21:24:02 +00:00
// FIXME: Should we consider doing on-demand paging here? Is it actually useful?
2019-01-22 04:01:00 +00:00
bool success = region - > page_in ( ) ;
2018-11-08 20:20:09 +00:00
ASSERT ( success ) ;
2018-11-03 00:49:40 +00:00
{
// Okay, here comes the sleight of hand, pay close attention..
auto old_regions = move ( m_regions ) ;
2019-01-24 17:09:46 +00:00
ELFLoader loader ( region - > laddr ( ) . as_ptr ( ) ) ;
2018-11-08 20:20:09 +00:00
loader . map_section_hook = [ & ] ( LinearAddress laddr , size_t size , size_t alignment , size_t offset_in_image , bool is_readable , bool is_writable , const String & name ) {
ASSERT ( size ) ;
2018-11-09 09:03:21 +00:00
ASSERT ( alignment = = PAGE_SIZE ) ;
2018-11-08 20:20:09 +00:00
size = ( ( size / 4096 ) + 1 ) * 4096 ; // FIXME: Use ceil_div?
2019-01-31 16:31:23 +00:00
( void ) allocate_region_with_vmo ( laddr , size , vmo . copy_ref ( ) , offset_in_image , String ( name ) , is_readable , is_writable ) ;
2019-01-24 17:09:46 +00:00
return laddr . as_ptr ( ) ;
2018-11-08 20:20:09 +00:00
} ;
2018-11-04 12:52:53 +00:00
loader . alloc_section_hook = [ & ] ( LinearAddress laddr , size_t size , size_t alignment , bool is_readable , bool is_writable , const String & name ) {
2018-11-03 10:28:23 +00:00
ASSERT ( size ) ;
2018-11-09 09:03:21 +00:00
ASSERT ( alignment = = PAGE_SIZE ) ;
2018-11-03 00:49:40 +00:00
size = ( ( size / 4096 ) + 1 ) * 4096 ; // FIXME: Use ceil_div?
2018-11-04 12:52:53 +00:00
( void ) allocate_region ( laddr , size , String ( name ) , is_readable , is_writable ) ;
2019-01-24 17:09:46 +00:00
return laddr . as_ptr ( ) ;
2018-11-03 00:49:40 +00:00
} ;
2018-11-04 12:52:53 +00:00
bool success = loader . load ( ) ;
2018-11-03 00:49:40 +00:00
if ( ! success ) {
2018-12-31 13:58:03 +00:00
m_page_directory = move ( old_page_directory ) ;
2019-01-01 01:09:43 +00:00
// FIXME: RAII this somehow instead.
ASSERT ( current = = this ) ;
2018-11-03 01:04:36 +00:00
MM . enter_process_paging_scope ( * this ) ;
2018-11-03 00:49:40 +00:00
m_regions = move ( old_regions ) ;
2018-11-03 01:04:36 +00:00
kprintf ( " sys$execve: Failure loading %s \n " , path . characters ( ) ) ;
2018-11-03 00:49:40 +00:00
return - ENOEXEC ;
}
2018-12-29 02:28:55 +00:00
entry_eip = loader . entry ( ) . get ( ) ;
2018-11-03 00:49:40 +00:00
if ( ! entry_eip ) {
2018-12-31 13:58:03 +00:00
m_page_directory = move ( old_page_directory ) ;
2019-01-01 01:09:43 +00:00
// FIXME: RAII this somehow instead.
ASSERT ( current = = this ) ;
2018-11-03 01:04:36 +00:00
MM . enter_process_paging_scope ( * this ) ;
2018-11-03 00:49:40 +00:00
m_regions = move ( old_regions ) ;
return - ENOEXEC ;
}
}
2018-11-28 19:59:10 +00:00
m_signal_stack_kernel_region = nullptr ;
m_signal_stack_user_region = nullptr ;
2019-01-21 02:21:41 +00:00
m_display_framebuffer_region = nullptr ;
2019-02-04 13:06:38 +00:00
set_default_signal_dispositions ( ) ;
2018-11-10 22:29:07 +00:00
m_signal_mask = 0xffffffff ;
2018-11-28 19:59:10 +00:00
m_pending_signals = 0 ;
2018-11-10 22:29:07 +00:00
2018-11-13 00:36:31 +00:00
for ( size_t i = 0 ; i < m_fds . size ( ) ; + + i ) {
auto & daf = m_fds [ i ] ;
if ( daf . descriptor & & daf . flags & FD_CLOEXEC ) {
daf . descriptor - > close ( ) ;
daf = { } ;
}
}
2018-11-16 23:52:29 +00:00
// We cli() manually here because we don't want to get interrupted between do_exec() and Schedule::yield().
// The reason is that the task redirection we've set up above will be clobbered by the timer IRQ.
// If we used an InterruptDisabler that sti()'d on exit, we might timer tick'd too soon in exec().
2019-02-06 16:28:14 +00:00
if ( current = = this )
cli ( ) ;
2018-11-16 23:52:29 +00:00
2018-11-07 22:59:49 +00:00
Scheduler : : prepare_to_modify_tss ( * this ) ;
2018-11-03 00:49:40 +00:00
2019-01-19 21:53:05 +00:00
m_name = parts . take_last ( ) ;
2018-11-03 00:49:40 +00:00
dword old_esp0 = m_tss . esp0 ;
memset ( & m_tss , 0 , sizeof ( m_tss ) ) ;
m_tss . eflags = 0x0202 ;
m_tss . eip = entry_eip ;
m_tss . cs = 0x1b ;
m_tss . ds = 0x23 ;
m_tss . es = 0x23 ;
m_tss . fs = 0x23 ;
2018-11-05 12:48:07 +00:00
m_tss . gs = 0x23 ;
2018-11-03 00:49:40 +00:00
m_tss . ss = 0x23 ;
2018-12-31 13:58:03 +00:00
m_tss . cr3 = page_directory ( ) . cr3 ( ) ;
2019-02-03 02:56:08 +00:00
m_stack_region = allocate_region ( LinearAddress ( ) , default_userspace_stack_size , " stack " ) ;
2018-11-07 20:19:47 +00:00
ASSERT ( m_stack_region ) ;
2019-02-03 02:56:08 +00:00
m_stack_top3 = m_stack_region - > laddr ( ) . offset ( default_userspace_stack_size ) . get ( ) ;
2019-01-31 16:31:23 +00:00
m_tss . esp = m_stack_top3 ;
2018-11-03 00:49:40 +00:00
m_tss . ss0 = 0x10 ;
m_tss . esp0 = old_esp0 ;
m_tss . ss2 = m_pid ;
2019-01-16 11:57:07 +00:00
m_executable = descriptor - > inode ( ) ;
2019-01-21 01:58:19 +00:00
m_initial_arguments = move ( arguments ) ;
m_initial_environment = move ( environment ) ;
2018-11-03 00:49:40 +00:00
# ifdef TASK_DEBUG
2018-11-07 21:15:02 +00:00
kprintf ( " Process %u (%s) exec'd %s @ %p \n " , pid ( ) , name ( ) . characters ( ) , path . characters ( ) , m_tss . eip ) ;
2018-11-03 00:49:40 +00:00
# endif
2018-11-07 22:21:32 +00:00
set_state ( Skip1SchedulerPass ) ;
2018-11-09 16:59:14 +00:00
return 0 ;
}
2019-02-17 09:18:25 +00:00
int Process : : exec ( String path , Vector < String > arguments , Vector < String > environment )
2018-11-09 16:59:14 +00:00
{
// The bulk of exec() is done by do_exec(), which ensures that all locals
// are cleaned up by the time we yield-teleport below.
2019-02-17 09:18:25 +00:00
int rc = do_exec ( move ( path ) , move ( arguments ) , move ( environment ) ) ;
2018-11-09 16:59:14 +00:00
if ( rc < 0 )
return rc ;
2018-11-07 22:13:38 +00:00
if ( current = = this ) {
2018-11-09 00:25:31 +00:00
Scheduler : : yield ( ) ;
2018-11-08 21:24:02 +00:00
ASSERT_NOT_REACHED ( ) ;
2018-11-07 22:13:38 +00:00
}
2018-11-03 00:49:40 +00:00
return 0 ;
}
2018-11-03 09:20:23 +00:00
int Process : : sys $ execve ( const char * filename , const char * * argv , const char * * envp )
{
2019-02-17 09:18:25 +00:00
// NOTE: Be extremely careful with allocating any kernel memory in exec().
// On success, the kernel stack will be lost.
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( filename ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
if ( argv ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( argv ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
for ( size_t i = 0 ; argv [ i ] ; + + i ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( argv [ i ] ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
}
}
if ( envp ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( envp ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
for ( size_t i = 0 ; envp [ i ] ; + + i ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( envp [ i ] ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
}
}
String path ( filename ) ;
Vector < String > arguments ;
2019-02-17 09:18:25 +00:00
Vector < String > environment ;
{
auto parts = path . split ( ' / ' ) ;
if ( argv ) {
for ( size_t i = 0 ; argv [ i ] ; + + i ) {
arguments . append ( argv [ i ] ) ;
}
} else {
arguments . append ( parts . last ( ) ) ;
2018-11-03 09:20:23 +00:00
}
2019-02-17 09:18:25 +00:00
if ( envp ) {
for ( size_t i = 0 ; envp [ i ] ; + + i )
environment . append ( envp [ i ] ) ;
}
2018-11-03 09:20:23 +00:00
}
2019-02-17 09:18:25 +00:00
int rc = exec ( move ( path ) , move ( arguments ) , move ( environment ) ) ;
2018-11-07 22:13:38 +00:00
ASSERT ( rc < 0 ) ; // We should never continue after a successful exec!
2018-11-03 09:49:13 +00:00
return rc ;
2018-11-03 09:20:23 +00:00
}
2018-11-03 09:49:13 +00:00
Process * Process : : create_user_process ( const String & path , uid_t uid , gid_t gid , pid_t parent_pid , int & error , Vector < String > & & arguments , Vector < String > & & environment , TTY * tty )
2018-10-22 13:42:39 +00:00
{
2018-11-03 09:49:13 +00:00
// FIXME: Don't split() the path twice (sys$spawn also does it...)
2018-10-22 13:42:39 +00:00
auto parts = path . split ( ' / ' ) ;
2018-12-21 01:10:45 +00:00
if ( arguments . is_empty ( ) ) {
2018-11-03 09:49:13 +00:00
arguments . append ( parts . last ( ) ) ;
2018-10-25 10:06:00 +00:00
}
2019-01-16 11:57:07 +00:00
RetainPtr < Inode > cwd ;
2018-10-26 12:24:11 +00:00
{
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
if ( auto * parent = Process : : from_pid ( parent_pid ) )
2019-01-31 16:31:23 +00:00
cwd = parent - > m_cwd . copy_ref ( ) ;
2018-10-27 14:43:03 +00:00
}
2019-01-16 11:57:07 +00:00
2018-11-03 09:49:13 +00:00
if ( ! cwd )
2019-01-16 11:57:07 +00:00
cwd = VFS : : the ( ) . root_inode ( ) ;
2018-10-27 14:43:03 +00:00
2019-01-19 21:53:05 +00:00
auto * process = new Process ( parts . take_last ( ) , uid , gid , parent_pid , Ring3 , move ( cwd ) , nullptr , tty ) ;
2018-10-26 09:16:56 +00:00
2018-11-03 09:49:13 +00:00
error = process - > exec ( path , move ( arguments ) , move ( environment ) ) ;
2018-12-26 20:04:27 +00:00
if ( error ! = 0 ) {
delete process ;
2018-10-22 13:42:39 +00:00
return nullptr ;
2018-12-26 20:04:27 +00:00
}
2018-11-01 10:30:48 +00:00
2018-11-09 00:25:31 +00:00
{
InterruptDisabler disabler ;
g_processes - > prepend ( process ) ;
system . nprocess + + ;
}
2018-10-23 22:20:34 +00:00
# ifdef TASK_DEBUG
2018-11-03 09:49:13 +00:00
kprintf ( " Process %u (%s) spawned @ %p \n " , process - > pid ( ) , process - > name ( ) . characters ( ) , process - > m_tss . eip ) ;
2018-10-23 22:20:34 +00:00
# endif
2018-10-25 10:06:00 +00:00
error = 0 ;
2018-11-03 09:49:13 +00:00
return process ;
2018-10-22 13:42:39 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ get_environment ( char * * * environ )
2018-10-31 16:50:43 +00:00
{
2018-11-03 10:28:23 +00:00
auto * region = allocate_region ( LinearAddress ( ) , PAGE_SIZE , " environ " ) ;
2018-10-31 16:50:43 +00:00
if ( ! region )
return - ENOMEM ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * region ) ;
2019-01-24 17:09:46 +00:00
char * envpage = ( char * ) region - > laddr ( ) . get ( ) ;
2018-10-31 16:50:43 +00:00
* environ = ( char * * ) envpage ;
2019-01-21 01:58:19 +00:00
char * bufptr = envpage + ( sizeof ( char * ) * ( m_initial_environment . size ( ) + 1 ) ) ;
for ( size_t i = 0 ; i < m_initial_environment . size ( ) ; + + i ) {
2018-10-31 16:50:43 +00:00
( * environ ) [ i ] = bufptr ;
2019-01-21 01:58:19 +00:00
memcpy ( bufptr , m_initial_environment [ i ] . characters ( ) , m_initial_environment [ i ] . length ( ) ) ;
bufptr + = m_initial_environment [ i ] . length ( ) ;
2018-10-31 16:50:43 +00:00
* ( bufptr + + ) = ' \0 ' ;
}
2019-01-21 01:58:19 +00:00
( * environ ) [ m_initial_environment . size ( ) ] = nullptr ;
2018-10-31 16:50:43 +00:00
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ get_arguments ( int * argc , char * * * argv )
2018-10-26 09:16:56 +00:00
{
2018-11-03 10:28:23 +00:00
auto * region = allocate_region ( LinearAddress ( ) , PAGE_SIZE , " argv " ) ;
2018-10-26 09:16:56 +00:00
if ( ! region )
return - ENOMEM ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * region ) ;
2019-01-24 17:09:46 +00:00
char * argpage = ( char * ) region - > laddr ( ) . get ( ) ;
2019-01-21 01:58:19 +00:00
* argc = m_initial_arguments . size ( ) ;
2018-10-26 09:16:56 +00:00
* argv = ( char * * ) argpage ;
2019-01-23 06:28:38 +00:00
char * bufptr = argpage + ( sizeof ( char * ) * ( m_initial_arguments . size ( ) + 1 ) ) ;
2019-01-21 01:58:19 +00:00
for ( size_t i = 0 ; i < m_initial_arguments . size ( ) ; + + i ) {
2018-10-26 09:16:56 +00:00
( * argv ) [ i ] = bufptr ;
2019-01-21 01:58:19 +00:00
memcpy ( bufptr , m_initial_arguments [ i ] . characters ( ) , m_initial_arguments [ i ] . length ( ) ) ;
bufptr + = m_initial_arguments [ i ] . length ( ) ;
2018-10-26 09:16:56 +00:00
* ( bufptr + + ) = ' \0 ' ;
}
2019-01-23 06:28:38 +00:00
( * argv ) [ m_initial_arguments . size ( ) ] = nullptr ;
2018-10-26 09:16:56 +00:00
return 0 ;
}
2018-12-24 22:10:48 +00:00
Process * Process : : create_kernel_process ( String & & name , void ( * e ) ( ) )
2018-10-25 09:15:17 +00:00
{
2018-11-01 13:41:49 +00:00
auto * process = new Process ( move ( name ) , ( uid_t ) 0 , ( gid_t ) 0 , ( pid_t ) 0 , Ring0 ) ;
2018-11-01 12:15:46 +00:00
process - > m_tss . eip = ( dword ) e ;
2018-10-25 09:15:17 +00:00
2018-11-01 12:15:46 +00:00
if ( process - > pid ( ) ! = 0 ) {
2018-11-09 00:25:31 +00:00
{
InterruptDisabler disabler ;
g_processes - > prepend ( process ) ;
system . nprocess + + ;
}
2018-10-25 09:15:17 +00:00
# ifdef TASK_DEBUG
2018-11-01 12:15:46 +00:00
kprintf ( " Kernel process %u (%s) spawned @ %p \n " , process - > pid ( ) , process - > name ( ) . characters ( ) , process - > m_tss . eip ) ;
2018-10-25 09:15:17 +00:00
# endif
}
2018-11-01 12:15:46 +00:00
return process ;
2018-10-25 09:15:17 +00:00
}
2019-01-16 11:57:07 +00:00
Process : : Process ( String & & name , uid_t uid , gid_t gid , pid_t ppid , RingLevel ring , RetainPtr < Inode > & & cwd , RetainPtr < Inode > & & executable , TTY * tty , Process * fork_parent )
2018-10-22 13:42:39 +00:00
: m_name ( move ( name ) )
2018-11-02 19:41:58 +00:00
, m_pid ( next_pid + + ) // FIXME: RACE: This variable looks racy!
2018-10-22 13:42:39 +00:00
, m_uid ( uid )
, m_gid ( gid )
2018-11-05 14:04:19 +00:00
, m_euid ( uid )
, m_egid ( gid )
2018-10-22 13:42:39 +00:00
, m_state ( Runnable )
2018-10-25 09:15:17 +00:00
, m_ring ( ring )
2018-10-29 23:06:31 +00:00
, m_cwd ( move ( cwd ) )
2018-10-28 13:11:51 +00:00
, m_executable ( move ( executable ) )
2018-10-30 12:59:29 +00:00
, m_tty ( tty )
2018-11-06 12:33:06 +00:00
, m_ppid ( ppid )
2018-10-22 13:42:39 +00:00
{
2019-02-04 13:06:38 +00:00
set_default_signal_dispositions ( ) ;
2019-01-25 06:52:44 +00:00
memset ( & m_fpu_state , 0 , sizeof ( FPUState ) ) ;
2018-11-07 00:38:51 +00:00
m_gids . set ( m_gid ) ;
2018-11-02 19:41:58 +00:00
if ( fork_parent ) {
m_sid = fork_parent - > m_sid ;
m_pgid = fork_parent - > m_pgid ;
} else {
2018-11-02 11:56:51 +00:00
// FIXME: Use a ProcessHandle? Presumably we're executing *IN* the parent right now though..
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
if ( auto * parent = Process : : from_pid ( m_ppid ) ) {
2018-11-02 11:56:51 +00:00
m_sid = parent - > m_sid ;
m_pgid = parent - > m_pgid ;
}
}
2019-01-22 04:01:00 +00:00
m_page_directory = PageDirectory : : create ( ) ;
2018-11-09 00:25:31 +00:00
# ifdef MM_DEBUG
2018-12-31 13:58:03 +00:00
dbgprintf ( " Process %u ctor: PD=%x created \n " , pid ( ) , m_page_directory . ptr ( ) ) ;
2018-11-09 00:25:31 +00:00
# endif
2018-11-01 08:01:51 +00:00
2018-11-02 19:41:58 +00:00
if ( fork_parent ) {
2018-11-13 00:36:31 +00:00
m_fds . resize ( fork_parent - > m_fds . size ( ) ) ;
for ( size_t i = 0 ; i < fork_parent - > m_fds . size ( ) ; + + i ) {
if ( ! fork_parent - > m_fds [ i ] . descriptor )
2018-11-02 19:41:58 +00:00
continue ;
# ifdef FORK_DEBUG
2018-12-29 02:28:55 +00:00
dbgprintf ( " fork: cloning fd %u... (%p) istty? %u \n " , i , fork_parent - > m_fds [ i ] . descriptor . ptr ( ) , fork_parent - > m_fds [ i ] . descriptor - > is_tty ( ) ) ;
2018-11-02 19:41:58 +00:00
# endif
2018-11-13 00:36:31 +00:00
m_fds [ i ] . descriptor = fork_parent - > m_fds [ i ] . descriptor - > clone ( ) ;
m_fds [ i ] . flags = fork_parent - > m_fds [ i ] . flags ;
2018-11-02 19:41:58 +00:00
}
} else {
2018-11-13 00:36:31 +00:00
m_fds . resize ( m_max_open_file_descriptors ) ;
2019-02-12 10:25:25 +00:00
auto & device_to_use_as_tty = tty ? ( CharacterDevice & ) * tty : NullDevice : : the ( ) ;
int error ;
m_fds [ 0 ] . set ( device_to_use_as_tty . open ( error , O_RDONLY ) ) ;
m_fds [ 1 ] . set ( device_to_use_as_tty . open ( error , O_WRONLY ) ) ;
m_fds [ 2 ] . set ( device_to_use_as_tty . open ( error , O_WRONLY ) ) ;
2018-10-16 09:01:38 +00:00
}
2018-11-02 19:41:58 +00:00
if ( fork_parent )
2019-01-31 16:31:23 +00:00
m_next_region = fork_parent - > m_next_region ;
2018-11-02 19:41:58 +00:00
else
2019-01-31 16:31:23 +00:00
m_next_region = LinearAddress ( 0x10000000 ) ;
2018-10-16 09:01:38 +00:00
2018-11-02 19:41:58 +00:00
if ( fork_parent ) {
memcpy ( & m_tss , & fork_parent - > m_tss , sizeof ( m_tss ) ) ;
2018-10-16 09:01:38 +00:00
} else {
2018-11-02 19:41:58 +00:00
memset ( & m_tss , 0 , sizeof ( m_tss ) ) ;
// Only IF is set when a process boots.
m_tss . eflags = 0x0202 ;
word cs , ds , ss ;
2019-01-31 16:31:23 +00:00
if ( is_ring0 ( ) ) {
2018-11-02 19:41:58 +00:00
cs = 0x08 ;
ds = 0x10 ;
ss = 0x10 ;
} else {
cs = 0x1b ;
ds = 0x23 ;
ss = 0x23 ;
}
2018-10-16 09:01:38 +00:00
2018-11-02 19:41:58 +00:00
m_tss . ds = ds ;
m_tss . es = ds ;
m_tss . fs = ds ;
m_tss . gs = ds ;
m_tss . ss = ss ;
m_tss . cs = cs ;
}
2018-10-22 09:15:16 +00:00
2018-12-31 13:58:03 +00:00
m_tss . cr3 = page_directory ( ) . cr3 ( ) ;
2018-10-17 21:13:55 +00:00
2019-01-31 16:31:23 +00:00
if ( is_ring0 ( ) ) {
2018-10-18 12:53:00 +00:00
// FIXME: This memory is leaked.
2018-11-01 12:15:46 +00:00
// But uh, there's also no kernel process termination, so I guess it's not technically leaked...
2019-02-03 02:56:08 +00:00
dword stack_bottom = ( dword ) kmalloc_eternal ( default_kernel_stack_size ) ;
m_stack_top0 = ( stack_bottom + default_kernel_stack_size ) & 0xffffff8 ;
2019-01-31 16:31:23 +00:00
m_tss . esp = m_stack_top0 ;
2018-10-18 12:53:00 +00:00
} else {
2018-11-02 19:41:58 +00:00
if ( fork_parent ) {
2019-01-31 16:31:23 +00:00
m_stack_top3 = fork_parent - > m_stack_top3 ;
2018-11-02 19:41:58 +00:00
} else {
2019-02-03 02:56:08 +00:00
auto * region = allocate_region ( LinearAddress ( ) , default_userspace_stack_size , " stack " ) ;
2018-11-02 19:41:58 +00:00
ASSERT ( region ) ;
2019-02-03 02:56:08 +00:00
m_stack_top3 = region - > laddr ( ) . offset ( default_userspace_stack_size ) . get ( ) ;
2019-01-31 16:31:23 +00:00
m_tss . esp = m_stack_top3 ;
2018-11-02 19:41:58 +00:00
}
2018-10-18 12:53:00 +00:00
}
2018-10-16 09:01:38 +00:00
2019-01-31 16:31:23 +00:00
if ( is_ring3 ( ) ) {
2018-11-01 12:15:46 +00:00
// Ring3 processes need a separate stack for Ring0.
2019-02-03 02:56:08 +00:00
m_kernel_stack = kmalloc ( default_kernel_stack_size ) ;
m_stack_top0 = ( ( dword ) m_kernel_stack + default_kernel_stack_size ) & 0xffffff8 ;
2018-10-16 09:01:38 +00:00
m_tss . ss0 = 0x10 ;
2019-01-31 16:31:23 +00:00
m_tss . esp0 = m_stack_top0 ;
2018-10-16 09:01:38 +00:00
}
// HACK: Ring2 SS in the TSS is the current PID.
m_tss . ss2 = m_pid ;
2019-01-31 16:31:23 +00:00
m_far_ptr . offset = 0x98765432 ;
2018-10-16 09:01:38 +00:00
}
2018-11-01 12:15:46 +00:00
Process : : ~ Process ( )
2018-10-16 09:01:38 +00:00
{
2019-02-07 10:24:09 +00:00
{
InterruptDisabler disabler ;
system . nprocess - - ;
}
2018-11-01 15:23:12 +00:00
2019-01-25 06:52:44 +00:00
if ( g_last_fpu_process = = this )
g_last_fpu_process = nullptr ;
2018-12-26 21:02:24 +00:00
if ( selector ( ) )
gdt_free_entry ( selector ( ) ) ;
2018-10-18 12:53:00 +00:00
2019-01-31 16:31:23 +00:00
if ( m_kernel_stack ) {
kfree ( m_kernel_stack ) ;
m_kernel_stack = nullptr ;
2018-10-18 12:53:00 +00:00
}
}
2019-01-31 16:31:23 +00:00
void Process : : dump_regions ( )
2018-10-18 12:53:00 +00:00
{
2018-11-01 12:15:46 +00:00
kprintf ( " Process %s(%u) regions: \n " , name ( ) . characters ( ) , pid ( ) ) ;
2018-10-18 12:53:00 +00:00
kprintf ( " BEGIN END SIZE NAME \n " ) ;
for ( auto & region : m_regions ) {
kprintf ( " %x -- %x %x %s \n " ,
2019-01-24 17:09:46 +00:00
region - > laddr ( ) . get ( ) ,
region - > laddr ( ) . offset ( region - > size ( ) - 1 ) . get ( ) ,
region - > size ( ) ,
region - > name ( ) . characters ( ) ) ;
2018-10-18 12:53:00 +00:00
}
2018-10-16 09:01:38 +00:00
}
2018-11-01 12:15:46 +00:00
void Process : : sys $ exit ( int status )
2018-10-22 09:43:55 +00:00
{
cli ( ) ;
2018-10-23 22:20:34 +00:00
# ifdef TASK_DEBUG
2018-10-22 09:43:55 +00:00
kprintf ( " sys$exit: %s(%u) exit with status %d \n " , name ( ) . characters ( ) , pid ( ) , status ) ;
2018-10-23 22:20:34 +00:00
# endif
2018-10-22 09:43:55 +00:00
2018-11-07 17:30:59 +00:00
m_termination_status = status ;
m_termination_signal = 0 ;
2019-02-06 17:45:21 +00:00
die ( ) ;
2018-11-07 21:15:02 +00:00
ASSERT_NOT_REACHED ( ) ;
2018-10-22 09:43:55 +00:00
}
2018-11-07 17:30:59 +00:00
void Process : : terminate_due_to_signal ( byte signal )
2018-10-31 00:06:57 +00:00
{
ASSERT_INTERRUPTS_DISABLED ( ) ;
2018-11-07 17:30:59 +00:00
ASSERT ( signal < 32 ) ;
dbgprintf ( " terminate_due_to_signal %s(%u) <- %u \n " , name ( ) . characters ( ) , pid ( ) , signal ) ;
m_termination_status = 0 ;
m_termination_signal = signal ;
2019-01-30 17:26:19 +00:00
die ( ) ;
2018-11-07 17:30:59 +00:00
}
2018-11-06 09:46:40 +00:00
2018-11-07 17:30:59 +00:00
void Process : : send_signal ( byte signal , Process * sender )
{
ASSERT ( signal < 32 ) ;
2018-11-01 00:04:02 +00:00
2018-11-07 17:30:59 +00:00
if ( sender )
dbgprintf ( " signal: %s(%u) sent %d to %s(%u) \n " , sender - > name ( ) . characters ( ) , sender - > pid ( ) , signal , name ( ) . characters ( ) , pid ( ) ) ;
else
dbgprintf ( " signal: kernel sent %d to %s(%u) \n " , signal , name ( ) . characters ( ) , pid ( ) ) ;
2019-02-07 10:24:09 +00:00
2019-02-15 22:45:01 +00:00
InterruptDisabler disabler ;
2019-02-07 10:24:09 +00:00
m_pending_signals | = 1 < < signal ;
2018-11-07 17:30:59 +00:00
}
bool Process : : has_unmasked_pending_signals ( ) const
{
2018-11-10 22:29:07 +00:00
return m_pending_signals & m_signal_mask ;
2018-11-07 17:30:59 +00:00
}
2019-02-04 13:06:38 +00:00
ShouldUnblockProcess Process : : dispatch_one_pending_signal ( )
2018-11-07 17:30:59 +00:00
{
ASSERT_INTERRUPTS_DISABLED ( ) ;
2018-11-10 22:29:07 +00:00
dword signal_candidates = m_pending_signals & m_signal_mask ;
2018-11-07 17:30:59 +00:00
ASSERT ( signal_candidates ) ;
byte signal = 0 ;
for ( ; signal < 32 ; + + signal ) {
if ( signal_candidates & ( 1 < < signal ) ) {
break ;
2018-10-31 00:06:57 +00:00
}
}
2018-11-16 20:14:25 +00:00
return dispatch_signal ( signal ) ;
2018-10-31 00:06:57 +00:00
}
2019-02-04 13:06:38 +00:00
ShouldUnblockProcess Process : : dispatch_signal ( byte signal )
2018-11-06 09:46:40 +00:00
{
ASSERT_INTERRUPTS_DISABLED ( ) ;
ASSERT ( signal < 32 ) ;
2018-11-07 17:30:59 +00:00
dbgprintf ( " dispatch_signal %s(%u) <- %u \n " , name ( ) . characters ( ) , pid ( ) , signal ) ;
2018-11-06 09:46:40 +00:00
auto & action = m_signal_action_data [ signal ] ;
// FIXME: Implement SA_SIGINFO signal handlers.
ASSERT ( ! ( action . flags & SA_SIGINFO ) ) ;
2019-02-04 13:06:38 +00:00
// Mark this signal as handled.
m_pending_signals & = ~ ( 1 < < signal ) ;
2018-11-06 09:46:40 +00:00
auto handler_laddr = action . handler_or_sigaction ;
2018-11-07 17:30:59 +00:00
if ( handler_laddr . is_null ( ) ) {
// FIXME: Is termination really always the appropriate action?
2018-11-16 20:14:25 +00:00
terminate_due_to_signal ( signal ) ;
2019-02-04 13:06:38 +00:00
return ShouldUnblockProcess : : No ;
2018-11-07 17:30:59 +00:00
}
2018-11-06 09:46:40 +00:00
2019-01-24 17:09:46 +00:00
if ( handler_laddr . as_ptr ( ) = = SIG_IGN ) {
2019-02-04 13:06:38 +00:00
dbgprintf ( " %s(%u) ignored signal %u \n " , name ( ) . characters ( ) , pid ( ) , signal ) ;
return ShouldUnblockProcess : : Yes ;
2018-11-16 19:18:58 +00:00
}
2018-11-07 22:59:49 +00:00
Scheduler : : prepare_to_modify_tss ( * this ) ;
2018-11-07 20:19:47 +00:00
2018-11-06 09:46:40 +00:00
word ret_cs = m_tss . cs ;
dword ret_eip = m_tss . eip ;
dword ret_eflags = m_tss . eflags ;
2018-11-07 20:19:47 +00:00
bool interrupting_in_kernel = ( ret_cs & 3 ) = = 0 ;
2018-11-07 22:59:49 +00:00
if ( interrupting_in_kernel ) {
2019-01-31 16:31:23 +00:00
dbgprintf ( " dispatch_signal to %s(%u) in state=%s with return to %w:%x \n " , name ( ) . characters ( ) , pid ( ) , to_string ( state ( ) ) , ret_cs , ret_eip ) ;
2018-11-07 20:19:47 +00:00
ASSERT ( is_blocked ( ) ) ;
2018-11-07 22:59:49 +00:00
m_tss_to_resume_kernel = m_tss ;
# ifdef SIGNAL_DEBUG
dbgprintf ( " resume tss pc: %w:%x \n " , m_tss_to_resume_kernel . cs , m_tss_to_resume_kernel . eip ) ;
# endif
2018-11-06 09:46:40 +00:00
}
2019-01-31 16:31:23 +00:00
ProcessPagingScope paging_scope ( * this ) ;
2018-11-07 20:19:47 +00:00
if ( interrupting_in_kernel ) {
if ( ! m_signal_stack_user_region ) {
2019-02-03 02:56:08 +00:00
m_signal_stack_user_region = allocate_region ( LinearAddress ( ) , default_userspace_stack_size , " signal stack (user) " ) ;
2018-11-07 20:19:47 +00:00
ASSERT ( m_signal_stack_user_region ) ;
2019-02-03 02:56:08 +00:00
m_signal_stack_kernel_region = allocate_region ( LinearAddress ( ) , default_userspace_stack_size , " signal stack (kernel) " ) ;
2018-11-07 20:19:47 +00:00
ASSERT ( m_signal_stack_user_region ) ;
}
m_tss . ss = 0x23 ;
2019-02-03 02:56:08 +00:00
m_tss . esp = m_signal_stack_user_region - > laddr ( ) . offset ( default_userspace_stack_size ) . get ( ) & 0xfffffff8 ;
2018-11-07 20:19:47 +00:00
m_tss . ss0 = 0x10 ;
2019-02-03 02:56:08 +00:00
m_tss . esp0 = m_signal_stack_kernel_region - > laddr ( ) . offset ( default_userspace_stack_size ) . get ( ) & 0xfffffff8 ;
2018-11-07 20:19:47 +00:00
push_value_on_stack ( ret_eflags ) ;
push_value_on_stack ( ret_cs ) ;
push_value_on_stack ( ret_eip ) ;
} else {
push_value_on_stack ( ret_cs ) ;
push_value_on_stack ( ret_eip ) ;
push_value_on_stack ( ret_eflags ) ;
}
// PUSHA
2018-11-06 09:46:40 +00:00
dword old_esp = m_tss . esp ;
push_value_on_stack ( m_tss . eax ) ;
push_value_on_stack ( m_tss . ecx ) ;
push_value_on_stack ( m_tss . edx ) ;
push_value_on_stack ( m_tss . ebx ) ;
push_value_on_stack ( old_esp ) ;
push_value_on_stack ( m_tss . ebp ) ;
push_value_on_stack ( m_tss . esi ) ;
push_value_on_stack ( m_tss . edi ) ;
2018-11-07 20:19:47 +00:00
2018-11-06 09:46:40 +00:00
m_tss . eax = ( dword ) signal ;
m_tss . cs = 0x1b ;
2018-11-07 20:19:47 +00:00
m_tss . ds = 0x23 ;
m_tss . es = 0x23 ;
m_tss . fs = 0x23 ;
m_tss . gs = 0x23 ;
2018-11-06 09:46:40 +00:00
m_tss . eip = handler_laddr . get ( ) ;
2018-11-07 20:19:47 +00:00
if ( m_return_to_ring3_from_signal_trampoline . is_null ( ) ) {
2018-11-07 17:30:59 +00:00
// FIXME: This should be a global trampoline shared by all processes, not one created per process!
// FIXME: Remap as read-only after setup.
auto * region = allocate_region ( LinearAddress ( ) , PAGE_SIZE , " signal_trampoline " , true , true ) ;
2019-01-24 17:09:46 +00:00
m_return_to_ring3_from_signal_trampoline = region - > laddr ( ) ;
byte * code_ptr = m_return_to_ring3_from_signal_trampoline . as_ptr ( ) ;
2018-11-06 09:46:40 +00:00
* code_ptr + + = 0x61 ; // popa
* code_ptr + + = 0x9d ; // popf
* code_ptr + + = 0xc3 ; // ret
* code_ptr + + = 0x0f ; // ud2
* code_ptr + + = 0x0b ;
2018-11-07 20:19:47 +00:00
m_return_to_ring0_from_signal_trampoline = LinearAddress ( ( dword ) code_ptr ) ;
* code_ptr + + = 0x61 ; // popa
* code_ptr + + = 0xb8 ; // mov eax, <dword>
* ( dword * ) code_ptr = Syscall : : SC_sigreturn ;
code_ptr + = sizeof ( dword ) ;
* code_ptr + + = 0xcd ; // int 0x80
* code_ptr + + = 0x80 ;
* code_ptr + + = 0x0f ; // ud2
* code_ptr + + = 0x0b ;
2018-11-07 17:30:59 +00:00
// FIXME: For !SA_NODEFER, maybe we could do something like emitting an int 0x80 syscall here that
// unmasks the signal so it can be received again? I guess then I would need one trampoline
// per signal number if it's hard-coded, but it's just a few bytes per each.
2018-11-06 09:46:40 +00:00
}
2018-11-07 20:19:47 +00:00
if ( interrupting_in_kernel )
push_value_on_stack ( m_return_to_ring0_from_signal_trampoline . get ( ) ) ;
else
push_value_on_stack ( m_return_to_ring3_from_signal_trampoline . get ( ) ) ;
2018-11-06 09:46:40 +00:00
2018-11-07 23:07:56 +00:00
// FIXME: This state is such a hack. It avoids trouble if 'current' is the process receiving a signal.
set_state ( Skip1SchedulerPass ) ;
2018-11-07 20:19:47 +00:00
# ifdef SIGNAL_DEBUG
2019-01-31 16:31:23 +00:00
dbgprintf ( " signal: Okay, %s(%u) {%s} has been primed with signal handler %w:%x \n " , name ( ) . characters ( ) , pid ( ) , to_string ( state ( ) ) , m_tss . cs , m_tss . eip ) ;
2018-11-07 20:19:47 +00:00
# endif
2019-02-04 13:06:38 +00:00
return ShouldUnblockProcess : : Yes ;
2018-11-07 20:19:47 +00:00
}
void Process : : sys $ sigreturn ( )
{
InterruptDisabler disabler ;
2018-11-07 22:59:49 +00:00
Scheduler : : prepare_to_modify_tss ( * this ) ;
2018-11-07 20:19:47 +00:00
m_tss = m_tss_to_resume_kernel ;
# ifdef SIGNAL_DEBUG
dbgprintf ( " sys$sigreturn in %s(%u) \n " , name ( ) . characters ( ) , pid ( ) ) ;
dbgprintf ( " -> resuming execution at %w:%x \n " , m_tss . cs , m_tss . eip ) ;
# endif
2018-11-07 22:21:32 +00:00
set_state ( Skip1SchedulerPass ) ;
2018-11-07 21:15:02 +00:00
Scheduler : : yield ( ) ;
2018-11-07 20:19:47 +00:00
kprintf ( " sys$sigreturn failed in %s(%u) \n " , name ( ) . characters ( ) , pid ( ) ) ;
ASSERT_NOT_REACHED ( ) ;
2018-11-06 09:46:40 +00:00
}
void Process : : push_value_on_stack ( dword value )
{
m_tss . esp - = 4 ;
dword * stack_ptr = ( dword * ) m_tss . esp ;
* stack_ptr = value ;
}
2018-11-07 17:30:59 +00:00
void Process : : crash ( )
2018-10-17 22:26:30 +00:00
{
2018-10-25 08:33:10 +00:00
ASSERT_INTERRUPTS_DISABLED ( ) ;
2018-11-07 17:30:59 +00:00
ASSERT ( state ( ) ! = Dead ) ;
m_termination_signal = SIGSEGV ;
2019-01-31 16:31:23 +00:00
dump_regions ( ) ;
2019-02-08 08:45:53 +00:00
ASSERT ( is_ring3 ( ) ) ;
2019-01-30 17:26:19 +00:00
die ( ) ;
2018-11-07 21:15:02 +00:00
ASSERT_NOT_REACHED ( ) ;
2018-10-17 22:26:30 +00:00
}
2018-11-07 20:38:18 +00:00
Process * Process : : from_pid ( pid_t pid )
2018-10-16 09:01:38 +00:00
{
2018-10-26 13:11:29 +00:00
ASSERT_INTERRUPTS_DISABLED ( ) ;
2018-11-07 21:15:02 +00:00
for ( auto * process = g_processes - > head ( ) ; process ; process = process - > next ( ) ) {
2018-11-01 12:15:46 +00:00
if ( process - > pid ( ) = = pid )
return process ;
2018-10-16 09:01:38 +00:00
}
return nullptr ;
}
2018-11-07 10:37:54 +00:00
FileDescriptor * Process : : file_descriptor ( int fd )
2018-10-16 09:01:38 +00:00
{
if ( fd < 0 )
return nullptr ;
2018-11-13 00:36:31 +00:00
if ( ( size_t ) fd < m_fds . size ( ) )
return m_fds [ fd ] . descriptor . ptr ( ) ;
2018-11-07 10:37:54 +00:00
return nullptr ;
}
const FileDescriptor * Process : : file_descriptor ( int fd ) const
{
if ( fd < 0 )
return nullptr ;
2018-11-13 00:36:31 +00:00
if ( ( size_t ) fd < m_fds . size ( ) )
return m_fds [ fd ] . descriptor . ptr ( ) ;
2018-10-16 09:01:38 +00:00
return nullptr ;
}
2018-11-01 12:15:46 +00:00
ssize_t Process : : sys $ get_dir_entries ( int fd , void * buffer , size_t size )
2018-10-24 10:43:52 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2018-11-07 10:37:54 +00:00
return descriptor - > get_dir_entries ( ( byte * ) buffer , size ) ;
2018-10-24 10:43:52 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ lseek ( int fd , off_t offset , int whence )
2018-10-16 09:01:38 +00:00
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-31 16:50:43 +00:00
return - EBADF ;
2018-11-07 10:37:54 +00:00
return descriptor - > seek ( offset , whence ) ;
2018-10-16 09:01:38 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ ttyname_r ( int fd , char * buffer , size_t size )
2018-10-30 21:03:02 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2018-12-02 23:39:25 +00:00
if ( ! descriptor - > is_tty ( ) )
2018-10-30 21:03:02 +00:00
return - ENOTTY ;
2019-01-31 16:31:23 +00:00
auto tty_name = descriptor - > tty ( ) - > tty_name ( ) ;
if ( size < tty_name . length ( ) + 1 )
2018-10-30 21:03:02 +00:00
return - ERANGE ;
2019-01-31 16:31:23 +00:00
strcpy ( buffer , tty_name . characters ( ) ) ;
2018-10-30 21:03:02 +00:00
return 0 ;
}
2019-01-15 05:30:19 +00:00
int Process : : sys $ ptsname_r ( int fd , char * buffer , size_t size )
{
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
auto * master_pty = descriptor - > master_pty ( ) ;
if ( ! master_pty )
return - ENOTTY ;
auto pts_name = master_pty - > pts_name ( ) ;
if ( size < pts_name . length ( ) + 1 )
return - ERANGE ;
strcpy ( buffer , pts_name . characters ( ) ) ;
return 0 ;
}
2018-11-01 12:15:46 +00:00
ssize_t Process : : sys $ write ( int fd , const void * data , size_t size )
2018-10-30 14:33:37 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_read ( data , size ) )
return - EFAULT ;
2018-10-30 14:33:37 +00:00
# ifdef DEBUG_IO
2018-11-11 14:36:40 +00:00
dbgprintf ( " %s(%u): sys$write(%d, %p, %u) \n " , name ( ) . characters ( ) , pid ( ) , fd , data , size ) ;
2018-10-30 14:33:37 +00:00
# endif
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 14:33:37 +00:00
return - EBADF ;
2018-11-12 00:28:46 +00:00
ssize_t nwritten = 0 ;
2018-12-02 23:39:25 +00:00
if ( descriptor - > is_blocking ( ) ) {
2018-11-12 00:28:46 +00:00
while ( nwritten < ( ssize_t ) size ) {
# ifdef IO_DEBUG
dbgprintf ( " while %u < %u \n " , nwritten , size ) ;
# endif
2019-01-15 08:17:22 +00:00
if ( ! descriptor - > can_write ( * this ) ) {
2018-11-12 00:28:46 +00:00
# ifdef IO_DEBUG
dbgprintf ( " block write on %d \n " , fd ) ;
# endif
m_blocked_fd = fd ;
block ( BlockedWrite ) ;
Scheduler : : yield ( ) ;
}
2019-01-15 23:20:38 +00:00
ssize_t rc = descriptor - > write ( * this , ( const byte * ) data + nwritten , size - nwritten ) ;
2018-11-12 00:28:46 +00:00
# ifdef IO_DEBUG
dbgprintf ( " -> write returned %d \n " , rc ) ;
# endif
if ( rc < 0 ) {
// FIXME: Support returning partial nwritten with errno.
ASSERT ( nwritten = = 0 ) ;
return rc ;
}
if ( rc = = 0 )
break ;
if ( has_unmasked_pending_signals ( ) ) {
block ( BlockedSignal ) ;
Scheduler : : yield ( ) ;
if ( nwritten = = 0 )
return - EINTR ;
}
nwritten + = rc ;
}
} else {
2019-01-15 23:20:38 +00:00
nwritten = descriptor - > write ( * this , ( const byte * ) data , size ) ;
2018-11-12 00:28:46 +00:00
}
2018-11-10 01:43:33 +00:00
if ( has_unmasked_pending_signals ( ) ) {
block ( BlockedSignal ) ;
Scheduler : : yield ( ) ;
if ( nwritten = = 0 )
return - EINTR ;
}
2018-10-30 14:33:37 +00:00
# ifdef DEBUG_IO
2018-11-11 14:36:40 +00:00
dbgprintf ( " %s(%u) sys$write: nwritten=%u \n " , name ( ) . characters ( ) , pid ( ) , nwritten ) ;
2018-10-30 14:33:37 +00:00
# endif
return nwritten ;
}
2018-11-01 12:15:46 +00:00
ssize_t Process : : sys $ read ( int fd , void * outbuf , size_t nread )
2018-10-16 09:01:38 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( outbuf , nread ) )
return - EFAULT ;
2018-10-23 08:12:50 +00:00
# ifdef DEBUG_IO
2018-11-11 14:36:40 +00:00
dbgprintf ( " %s(%u) sys$read(%d, %p, %u) \n " , name ( ) . characters ( ) , pid ( ) , fd , outbuf , nread ) ;
2018-10-23 08:12:50 +00:00
# endif
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 14:33:37 +00:00
return - EBADF ;
2019-01-16 11:57:07 +00:00
# ifdef DEBUG_IO
dbgprintf ( " > descriptor:%p, is_blocking:%u, can_read:%u \n " , descriptor , descriptor - > is_blocking ( ) , descriptor - > can_read ( * this ) ) ;
dbgprintf ( " > inode:K%x, device:K%x \n " , descriptor - > inode ( ) , descriptor - > character_device ( ) ) ;
# endif
2018-12-02 23:39:25 +00:00
if ( descriptor - > is_blocking ( ) ) {
2019-01-15 23:47:00 +00:00
if ( ! descriptor - > can_read ( * this ) ) {
2018-12-02 23:42:48 +00:00
m_blocked_fd = fd ;
2018-10-25 11:07:59 +00:00
block ( BlockedRead ) ;
2019-02-06 14:05:47 +00:00
Scheduler : : yield ( ) ;
2018-11-07 20:19:47 +00:00
if ( m_was_interrupted_while_blocked )
return - EINTR ;
2018-10-25 11:07:59 +00:00
}
}
2019-01-15 23:20:38 +00:00
nread = descriptor - > read ( * this , ( byte * ) outbuf , nread ) ;
2018-10-23 08:12:50 +00:00
# ifdef DEBUG_IO
2018-11-11 14:36:40 +00:00
dbgprintf ( " %s(%u) Process::sys$read: nread=%u \n " , name ( ) . characters ( ) , pid ( ) , nread ) ;
2018-10-23 08:12:50 +00:00
# endif
2018-10-16 09:01:38 +00:00
return nread ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ close ( int fd )
2018-10-16 09:01:38 +00:00
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2018-11-07 10:37:54 +00:00
int rc = descriptor - > close ( ) ;
2018-11-13 00:36:31 +00:00
m_fds [ fd ] = { } ;
2018-11-01 13:00:28 +00:00
return rc ;
2018-10-16 09:01:38 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ utime ( const char * pathname , const utimbuf * buf )
2018-12-19 20:14:55 +00:00
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
if ( buf & & ! validate_read_typed ( buf ) )
return - EFAULT ;
String path ( pathname ) ;
int error ;
2019-02-01 14:36:45 +00:00
auto descriptor = VFS : : the ( ) . open ( move ( path ) , error , 0 , 0 , * cwd_inode ( ) ) ;
2018-12-19 20:14:55 +00:00
if ( ! descriptor )
return error ;
2018-12-19 20:56:45 +00:00
auto & inode = * descriptor - > inode ( ) ;
if ( inode . fs ( ) . is_readonly ( ) )
return - EROFS ;
2019-01-23 05:53:01 +00:00
time_t atime ;
time_t mtime ;
2018-12-19 20:14:55 +00:00
if ( buf ) {
atime = buf - > actime ;
mtime = buf - > modtime ;
} else {
auto now = RTC : : now ( ) ;
mtime = now ;
atime = now ;
}
2019-02-21 12:26:40 +00:00
error = inode . set_atime ( atime ) ;
if ( error )
return error ;
error = inode . set_mtime ( mtime ) ;
return error ;
2018-12-19 20:14:55 +00:00
}
2018-11-10 23:20:53 +00:00
int Process : : sys $ access ( const char * pathname , int mode )
{
( void ) mode ;
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( pathname ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-10 23:20:53 +00:00
ASSERT_NOT_REACHED ( ) ;
}
2018-11-11 14:36:40 +00:00
int Process : : sys $ fcntl ( int fd , int cmd , dword arg )
2018-11-11 09:38:33 +00:00
{
( void ) cmd ;
2018-11-11 14:36:40 +00:00
( void ) arg ;
dbgprintf ( " sys$fcntl: fd=%d, cmd=%d, arg=%u \n " , fd , cmd , arg ) ;
2018-11-11 09:38:33 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
2018-11-13 00:36:31 +00:00
// NOTE: The FD flags are not shared between FileDescriptor objects.
// This means that dup() doesn't copy the FD_CLOEXEC flag!
2018-11-11 14:36:40 +00:00
switch ( cmd ) {
2018-11-16 21:14:40 +00:00
case F_DUPFD : {
int arg_fd = ( int ) arg ;
if ( arg_fd < 0 )
return - EINVAL ;
int new_fd = - 1 ;
for ( int i = arg_fd ; i < ( int ) m_max_open_file_descriptors ; + + i ) {
if ( ! m_fds [ i ] ) {
new_fd = i ;
break ;
}
}
if ( new_fd = = - 1 )
return - EMFILE ;
m_fds [ new_fd ] . set ( descriptor ) ;
break ;
}
2018-11-11 14:36:40 +00:00
case F_GETFD :
2018-11-13 00:36:31 +00:00
return m_fds [ fd ] . flags ;
2018-11-11 14:36:40 +00:00
case F_SETFD :
2018-11-13 00:36:31 +00:00
m_fds [ fd ] . flags = arg ;
break ;
2018-11-11 14:36:40 +00:00
case F_GETFL :
return descriptor - > file_flags ( ) ;
case F_SETFL :
2019-01-15 05:49:52 +00:00
// FIXME: Support changing O_NONBLOCK
2018-11-13 00:36:31 +00:00
descriptor - > set_file_flags ( arg ) ;
break ;
2018-11-11 14:36:40 +00:00
default :
ASSERT_NOT_REACHED ( ) ;
}
return 0 ;
2018-11-11 09:38:33 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ fstat ( int fd , stat * statbuf )
2018-11-10 23:20:53 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( statbuf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-10 23:20:53 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
2019-02-03 05:26:48 +00:00
return descriptor - > fstat ( statbuf ) ;
2018-11-10 23:20:53 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ lstat ( const char * path , stat * statbuf )
2018-10-24 11:19:36 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( statbuf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-28 13:25:51 +00:00
int error ;
2019-02-21 15:09:12 +00:00
if ( ! VFS : : the ( ) . stat ( move ( path ) , error , O_NOFOLLOW_NOERROR , * cwd_inode ( ) , * statbuf ) )
2018-10-28 13:25:51 +00:00
return error ;
2019-02-21 15:09:12 +00:00
return 0 ;
2018-10-24 11:19:36 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ stat ( const char * path , stat * statbuf )
2018-10-31 09:14:56 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( statbuf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-31 09:14:56 +00:00
int error ;
2019-02-21 15:09:12 +00:00
if ( ! VFS : : the ( ) . stat ( move ( path ) , error , 0 , * cwd_inode ( ) , * statbuf ) )
2018-10-31 09:14:56 +00:00
return error ;
2019-02-21 15:09:12 +00:00
return 0 ;
2018-10-31 09:14:56 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ readlink ( const char * path , char * buffer , size_t size )
2018-10-28 13:11:51 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( path ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2018-10-28 13:11:51 +00:00
2018-10-28 13:25:51 +00:00
int error ;
2019-02-01 14:36:45 +00:00
auto descriptor = VFS : : the ( ) . open ( path , error , O_RDONLY | O_NOFOLLOW_NOERROR , 0 , * cwd_inode ( ) ) ;
2018-11-07 10:37:54 +00:00
if ( ! descriptor )
2018-10-28 13:25:51 +00:00
return error ;
2018-10-28 13:11:51 +00:00
2019-01-31 16:31:23 +00:00
if ( ! descriptor - > metadata ( ) . is_symlink ( ) )
2018-10-28 13:11:51 +00:00
return - EINVAL ;
2019-01-15 23:20:38 +00:00
auto contents = descriptor - > read_entire_file ( * this ) ;
2018-10-28 13:11:51 +00:00
if ( ! contents )
return - EIO ; // FIXME: Get a more detailed error from VFS.
memcpy ( buffer , contents . pointer ( ) , min ( size , contents . size ( ) ) ) ;
if ( contents . size ( ) + 1 < size )
buffer [ contents . size ( ) ] = ' \0 ' ;
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ chdir ( const char * path )
2018-10-24 12:28:22 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( path ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-28 13:25:51 +00:00
int error ;
2019-02-01 14:36:45 +00:00
auto descriptor = VFS : : the ( ) . open ( path , error , 0 , 0 , * cwd_inode ( ) ) ;
2018-11-07 10:37:54 +00:00
if ( ! descriptor )
2018-10-28 13:25:51 +00:00
return error ;
2018-12-02 23:39:25 +00:00
if ( ! descriptor - > is_directory ( ) )
2018-10-26 12:24:11 +00:00
return - ENOTDIR ;
2019-01-16 11:57:07 +00:00
m_cwd = descriptor - > inode ( ) ;
2018-10-24 12:28:22 +00:00
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ getcwd ( char * buffer , size_t size )
2018-10-26 12:24:11 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2018-11-13 22:44:54 +00:00
ASSERT ( cwd_inode ( ) ) ;
2018-11-15 13:43:10 +00:00
auto path = VFS : : the ( ) . absolute_path ( * cwd_inode ( ) ) ;
2018-12-21 01:10:45 +00:00
if ( path . is_null ( ) )
2018-10-29 23:06:31 +00:00
return - EINVAL ;
if ( size < path . length ( ) + 1 )
return - ERANGE ;
strcpy ( buffer , path . characters ( ) ) ;
2018-11-11 14:36:40 +00:00
return 0 ;
2018-10-26 12:24:11 +00:00
}
2018-11-01 12:39:28 +00:00
size_t Process : : number_of_open_file_descriptors ( ) const
{
size_t count = 0 ;
2018-11-13 00:36:31 +00:00
for ( auto & descriptor : m_fds ) {
2018-11-07 10:37:54 +00:00
if ( descriptor )
2018-11-01 12:39:28 +00:00
+ + count ;
}
return count ;
}
2019-01-21 23:58:13 +00:00
int Process : : sys $ open ( const char * path , int options , mode_t mode )
2018-10-16 09:01:38 +00:00
{
2018-10-23 08:12:50 +00:00
# ifdef DEBUG_IO
2018-11-11 14:36:40 +00:00
dbgprintf ( " %s(%u) sys$open( \" %s \" ) \n " , name ( ) . characters ( ) , pid ( ) , path ) ;
2018-10-23 08:12:50 +00:00
# endif
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( path ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-01 12:39:28 +00:00
if ( number_of_open_file_descriptors ( ) > = m_max_open_file_descriptors )
2018-10-26 12:30:13 +00:00
return - EMFILE ;
2019-01-15 05:30:19 +00:00
int error = - EWHYTHO ;
2019-01-16 16:20:58 +00:00
ASSERT ( cwd_inode ( ) ) ;
2019-02-01 14:36:45 +00:00
auto descriptor = VFS : : the ( ) . open ( path , error , options , mode , * cwd_inode ( ) ) ;
2018-11-07 10:37:54 +00:00
if ( ! descriptor )
2018-10-28 13:25:51 +00:00
return error ;
2018-12-02 23:39:25 +00:00
if ( options & O_DIRECTORY & & ! descriptor - > is_directory ( ) )
2018-10-28 13:11:51 +00:00
return - ENOTDIR ; // FIXME: This should be handled by VFS::open.
2019-01-15 05:49:52 +00:00
if ( options & O_NONBLOCK )
descriptor - > set_blocking ( false ) ;
2018-10-28 13:11:51 +00:00
2018-11-01 13:00:28 +00:00
int fd = 0 ;
2018-11-09 09:03:21 +00:00
for ( ; fd < ( int ) m_max_open_file_descriptors ; + + fd ) {
2018-11-13 00:36:31 +00:00
if ( ! m_fds [ fd ] )
2018-11-01 13:00:28 +00:00
break ;
}
2018-11-13 00:36:31 +00:00
dword flags = ( options & O_CLOEXEC ) ? FD_CLOEXEC : 0 ;
m_fds [ fd ] . set ( move ( descriptor ) , flags ) ;
2018-10-26 12:30:13 +00:00
return fd ;
2018-10-16 09:01:38 +00:00
}
2018-11-12 00:28:46 +00:00
int Process : : alloc_fd ( )
{
int fd = - 1 ;
for ( int i = 0 ; i < ( int ) m_max_open_file_descriptors ; + + i ) {
2018-11-13 00:36:31 +00:00
if ( ! m_fds [ i ] ) {
2018-11-12 00:28:46 +00:00
fd = i ;
break ;
}
}
return fd ;
}
2018-11-16 15:23:39 +00:00
int Process : : sys $ pipe ( int pipefd [ 2 ] )
2018-11-10 23:20:53 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( pipefd ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-12 00:28:46 +00:00
if ( number_of_open_file_descriptors ( ) + 2 > max_open_file_descriptors ( ) )
return - EMFILE ;
auto fifo = FIFO : : create ( ) ;
int reader_fd = alloc_fd ( ) ;
2018-11-13 00:36:31 +00:00
m_fds [ reader_fd ] . set ( FileDescriptor : : create_pipe_reader ( * fifo ) ) ;
2018-11-12 00:28:46 +00:00
pipefd [ 0 ] = reader_fd ;
int writer_fd = alloc_fd ( ) ;
2018-11-13 00:36:31 +00:00
m_fds [ writer_fd ] . set ( FileDescriptor : : create_pipe_writer ( * fifo ) ) ;
2018-11-12 00:28:46 +00:00
pipefd [ 1 ] = writer_fd ;
return 0 ;
2018-11-10 23:20:53 +00:00
}
int Process : : sys $ killpg ( int pgrp , int signum )
{
if ( signum < 1 | | signum > = 32 )
return - EINVAL ;
( void ) pgrp ;
ASSERT_NOT_REACHED ( ) ;
}
int Process : : sys $ setuid ( uid_t )
{
ASSERT_NOT_REACHED ( ) ;
}
int Process : : sys $ setgid ( gid_t )
{
ASSERT_NOT_REACHED ( ) ;
}
unsigned Process : : sys $ alarm ( unsigned seconds )
{
( void ) seconds ;
ASSERT_NOT_REACHED ( ) ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ uname ( utsname * buf )
2018-10-26 12:56:21 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( buf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-26 12:56:21 +00:00
strcpy ( buf - > sysname , " Serenity " ) ;
strcpy ( buf - > release , " 1.0-dev " ) ;
strcpy ( buf - > version , " FIXME " ) ;
strcpy ( buf - > machine , " i386 " ) ;
2019-02-07 09:29:26 +00:00
LOCKER ( * s_hostname_lock ) ;
strncpy ( buf - > nodename , s_hostname - > characters ( ) , sizeof ( utsname : : nodename ) ) ;
2018-10-26 12:56:21 +00:00
return 0 ;
}
2018-11-05 17:16:00 +00:00
int Process : : sys $ isatty ( int fd )
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-11-05 17:16:00 +00:00
return - EBADF ;
2018-12-02 23:39:25 +00:00
if ( ! descriptor - > is_tty ( ) )
2018-11-05 17:16:00 +00:00
return - ENOTTY ;
return 1 ;
}
2018-11-02 13:06:48 +00:00
int Process : : sys $ kill ( pid_t pid , int signal )
2018-10-16 09:01:38 +00:00
{
if ( pid = = 0 ) {
// FIXME: Send to same-group processes.
ASSERT ( pid ! = 0 ) ;
}
if ( pid = = - 1 ) {
// FIXME: Send to all processes.
ASSERT ( pid ! = - 1 ) ;
}
2018-10-31 00:06:57 +00:00
ASSERT ( pid ! = current - > pid ( ) ) ; // FIXME: Support this scenario.
2019-02-07 10:24:09 +00:00
Process * peer = nullptr ;
{
InterruptDisabler disabler ;
peer = Process : : from_pid ( pid ) ;
}
2018-10-31 00:06:57 +00:00
if ( ! peer )
return - ESRCH ;
2018-11-02 13:06:48 +00:00
peer - > send_signal ( signal , this ) ;
return 0 ;
2018-10-16 09:01:38 +00:00
}
2019-02-03 15:11:28 +00:00
int Process : : sys $ usleep ( useconds_t usec )
{
if ( ! usec )
return 0 ;
sleep ( usec / 1000 ) ;
if ( m_wakeup_time > system . uptime ) {
ASSERT ( m_was_interrupted_while_blocked ) ;
dword ticks_left_until_original_wakeup_time = m_wakeup_time - system . uptime ;
return ticks_left_until_original_wakeup_time / TICKS_PER_SECOND ;
}
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ sleep ( unsigned seconds )
2018-10-25 11:53:49 +00:00
{
if ( ! seconds )
return 0 ;
sleep ( seconds * TICKS_PER_SECOND ) ;
2019-01-31 16:31:23 +00:00
if ( m_wakeup_time > system . uptime ) {
2018-11-07 20:19:47 +00:00
ASSERT ( m_was_interrupted_while_blocked ) ;
2019-01-31 16:31:23 +00:00
dword ticks_left_until_original_wakeup_time = m_wakeup_time - system . uptime ;
2018-11-07 20:19:47 +00:00
return ticks_left_until_original_wakeup_time / TICKS_PER_SECOND ;
}
2018-10-25 11:53:49 +00:00
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ gettimeofday ( timeval * tv )
2018-10-25 15:29:49 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( tv ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-25 15:29:49 +00:00
auto now = RTC : : now ( ) ;
tv - > tv_sec = now ;
2019-02-01 02:50:06 +00:00
tv - > tv_usec = PIT : : ticks_since_boot ( ) % 1000 ;
2018-10-25 15:29:49 +00:00
return 0 ;
}
2018-11-01 12:15:46 +00:00
uid_t Process : : sys $ getuid ( )
2018-10-16 09:01:38 +00:00
{
return m_uid ;
}
2018-11-01 12:15:46 +00:00
gid_t Process : : sys $ getgid ( )
2018-10-22 11:55:11 +00:00
{
return m_gid ;
}
2018-11-05 14:04:19 +00:00
uid_t Process : : sys $ geteuid ( )
{
return m_euid ;
}
gid_t Process : : sys $ getegid ( )
{
return m_egid ;
}
2018-11-01 12:15:46 +00:00
pid_t Process : : sys $ getpid ( )
2018-10-22 11:55:11 +00:00
{
return m_pid ;
}
2018-11-06 12:33:06 +00:00
pid_t Process : : sys $ getppid ( )
{
return m_ppid ;
}
2018-11-06 12:40:23 +00:00
mode_t Process : : sys $ umask ( mode_t mask )
{
auto old_mask = m_umask ;
m_umask = mask ;
return old_mask ;
}
2018-11-28 21:01:24 +00:00
int Process : : reap ( Process & process )
2018-11-07 22:59:49 +00:00
{
InterruptDisabler disabler ;
2018-11-28 21:01:24 +00:00
int exit_status = ( process . m_termination_status < < 8 ) | process . m_termination_signal ;
2018-12-03 00:12:26 +00:00
if ( process . ppid ( ) ) {
auto * parent = Process : : from_pid ( process . ppid ( ) ) ;
2019-01-30 18:35:38 +00:00
if ( parent ) {
parent - > m_ticks_in_user_for_dead_children + = process . m_ticks_in_user + process . m_ticks_in_user_for_dead_children ;
parent - > m_ticks_in_kernel_for_dead_children + = process . m_ticks_in_kernel + process . m_ticks_in_kernel_for_dead_children ;
}
2018-12-03 00:12:26 +00:00
}
2019-01-31 16:31:23 +00:00
dbgprintf ( " reap: %s(%u) {%s} \n " , process . name ( ) . characters ( ) , process . pid ( ) , to_string ( process . state ( ) ) ) ;
2018-11-09 00:25:31 +00:00
ASSERT ( process . state ( ) = = Dead ) ;
g_processes - > remove ( & process ) ;
delete & process ;
2018-11-28 21:01:24 +00:00
return exit_status ;
2018-11-07 22:59:49 +00:00
}
2018-11-01 12:15:46 +00:00
pid_t Process : : sys $ waitpid ( pid_t waitee , int * wstatus , int options )
2018-10-23 22:20:34 +00:00
{
2018-11-16 23:11:08 +00:00
dbgprintf ( " sys$waitpid(%d, %p, %d) \n " , waitee , wstatus , options ) ;
2018-11-09 09:03:21 +00:00
// FIXME: Respect options
( void ) options ;
2018-10-26 23:24:22 +00:00
if ( wstatus )
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( wstatus ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-26 23:24:22 +00:00
2018-11-28 21:01:24 +00:00
int dummy_wstatus ;
int & exit_status = wstatus ? * wstatus : dummy_wstatus ;
2018-11-07 22:59:49 +00:00
{
InterruptDisabler disabler ;
2018-11-11 14:36:40 +00:00
if ( waitee ! = - 1 & & ! Process : : from_pid ( waitee ) )
2018-11-07 22:59:49 +00:00
return - ECHILD ;
}
2018-11-16 23:11:08 +00:00
if ( options & WNOHANG ) {
if ( waitee = = - 1 ) {
pid_t reaped_pid = 0 ;
InterruptDisabler disabler ;
2018-11-28 21:01:24 +00:00
for_each_child ( [ & reaped_pid , & exit_status ] ( Process & process ) {
2018-11-16 23:11:08 +00:00
if ( process . state ( ) = = Dead ) {
reaped_pid = process . pid ( ) ;
2018-11-28 21:01:24 +00:00
exit_status = reap ( process ) ;
2018-11-16 23:11:08 +00:00
}
return true ;
} ) ;
return reaped_pid ;
} else {
2019-02-04 13:06:38 +00:00
ASSERT ( waitee > 0 ) ; // FIXME: Implement other PID specs.
2018-11-16 23:11:08 +00:00
auto * waitee_process = Process : : from_pid ( waitee ) ;
if ( ! waitee_process )
return - ECHILD ;
if ( waitee_process - > state ( ) = = Dead ) {
2018-11-28 21:01:24 +00:00
exit_status = reap ( * waitee_process ) ;
2018-11-16 23:11:08 +00:00
return waitee ;
}
return 0 ;
}
}
2018-11-28 22:30:06 +00:00
m_waitee_pid = waitee ;
2018-10-23 22:20:34 +00:00
block ( BlockedWait ) ;
2019-02-06 14:05:47 +00:00
Scheduler : : yield ( ) ;
2018-11-07 20:19:47 +00:00
if ( m_was_interrupted_while_blocked )
return - EINTR ;
2018-11-09 00:25:31 +00:00
Process * waitee_process ;
{
InterruptDisabler disabler ;
2018-11-11 14:36:40 +00:00
// NOTE: If waitee was -1, m_waitee will have been filled in by the scheduler.
2018-11-28 22:30:06 +00:00
waitee_process = Process : : from_pid ( m_waitee_pid ) ;
2018-11-09 00:25:31 +00:00
}
ASSERT ( waitee_process ) ;
2018-11-28 21:01:24 +00:00
exit_status = reap ( * waitee_process ) ;
2018-11-28 22:30:06 +00:00
return m_waitee_pid ;
2018-10-23 22:20:34 +00:00
}
2018-11-01 12:15:46 +00:00
void Process : : unblock ( )
2018-10-16 09:01:38 +00:00
{
2018-11-28 22:30:06 +00:00
if ( current = = this ) {
2019-01-16 16:47:18 +00:00
system . nblocked - - ;
m_state = Process : : Running ;
2018-11-28 22:30:06 +00:00
return ;
}
2018-11-01 12:15:46 +00:00
ASSERT ( m_state ! = Process : : Runnable & & m_state ! = Process : : Running ) ;
2018-10-16 09:01:38 +00:00
system . nblocked - - ;
2018-11-01 12:15:46 +00:00
m_state = Process : : Runnable ;
2018-10-16 09:01:38 +00:00
}
2018-11-12 00:28:46 +00:00
void Process : : block ( Process : : State new_state )
2018-10-16 09:01:38 +00:00
{
2018-11-12 00:28:46 +00:00
if ( state ( ) ! = Process : : Running ) {
2019-01-31 16:31:23 +00:00
kprintf ( " Process::block: %s(%u) block(%u/%s) with state=%u/%s \n " , name ( ) . characters ( ) , pid ( ) , new_state , to_string ( new_state ) , state ( ) , to_string ( state ( ) ) ) ;
2018-11-12 00:28:46 +00:00
}
ASSERT ( state ( ) = = Process : : Running ) ;
2018-10-16 09:01:38 +00:00
system . nblocked + + ;
2018-11-07 20:19:47 +00:00
m_was_interrupted_while_blocked = false ;
2018-11-12 00:28:46 +00:00
set_state ( new_state ) ;
2018-10-16 09:01:38 +00:00
}
2018-11-01 12:15:46 +00:00
void block ( Process : : State state )
2018-10-16 09:01:38 +00:00
{
current - > block ( state ) ;
2019-02-06 14:05:47 +00:00
Scheduler : : yield ( ) ;
2018-10-16 09:01:38 +00:00
}
2018-11-16 23:11:08 +00:00
void sleep ( dword ticks )
2018-10-16 09:01:38 +00:00
{
2018-11-01 12:15:46 +00:00
ASSERT ( current - > state ( ) = = Process : : Running ) ;
2019-01-31 16:31:23 +00:00
current - > set_wakeup_time ( system . uptime + ticks ) ;
2018-11-01 12:15:46 +00:00
current - > block ( Process : : BlockedSleep ) ;
2019-02-06 14:05:47 +00:00
Scheduler : : yield ( ) ;
2018-10-16 09:01:38 +00:00
}
2019-02-11 05:03:30 +00:00
enum class KernelMemoryCheckResult {
NotInsideKernelMemory ,
AccessGranted ,
AccessDenied
} ;
static KernelMemoryCheckResult check_kernel_memory_access ( LinearAddress laddr , bool is_write )
2019-01-27 09:17:56 +00:00
{
2019-02-06 16:28:14 +00:00
auto * kernel_elf_header = ( Elf32_Ehdr * ) 0xf000 ;
auto * kernel_program_headers = ( Elf32_Phdr * ) ( 0xf000 + kernel_elf_header - > e_phoff ) ;
for ( unsigned i = 0 ; i < kernel_elf_header - > e_phnum ; + + i ) {
auto & segment = kernel_program_headers [ i ] ;
2019-02-11 05:03:30 +00:00
if ( segment . p_type ! = PT_LOAD | | ! segment . p_vaddr | | ! segment . p_memsz )
continue ;
2019-02-06 16:28:14 +00:00
if ( laddr . get ( ) < segment . p_vaddr | | laddr . get ( ) > ( segment . p_vaddr + segment . p_memsz ) )
continue ;
if ( is_write & & ! ( kernel_program_headers [ i ] . p_flags & PF_W ) )
2019-02-11 05:03:30 +00:00
return KernelMemoryCheckResult : : AccessDenied ;
2019-02-06 16:28:14 +00:00
if ( ! is_write & & ! ( kernel_program_headers [ i ] . p_flags & PF_R ) )
2019-02-11 05:03:30 +00:00
return KernelMemoryCheckResult : : AccessDenied ;
return KernelMemoryCheckResult : : AccessGranted ;
2019-02-06 16:28:14 +00:00
}
2019-02-11 05:03:30 +00:00
return KernelMemoryCheckResult : : NotInsideKernelMemory ;
2019-01-27 09:17:56 +00:00
}
2019-01-01 01:20:01 +00:00
bool Process : : validate_read_from_kernel ( LinearAddress laddr ) const
2018-10-26 22:14:24 +00:00
{
2018-11-01 11:45:51 +00:00
// We check extra carefully here since the first 4MB of the address space is identity-mapped.
// This code allows access outside of the known used address ranges to get caught.
2019-02-11 05:03:30 +00:00
auto kmc_result = check_kernel_memory_access ( laddr , false ) ;
if ( kmc_result = = KernelMemoryCheckResult : : AccessGranted )
2018-10-26 22:14:24 +00:00
return true ;
2019-02-11 05:03:30 +00:00
if ( kmc_result = = KernelMemoryCheckResult : : AccessDenied )
return false ;
2019-01-24 17:09:46 +00:00
if ( is_kmalloc_address ( laddr . as_ptr ( ) ) )
2018-10-26 22:14:24 +00:00
return true ;
2019-01-24 17:09:46 +00:00
return validate_read ( laddr . as_ptr ( ) , 1 ) ;
2018-10-26 22:14:24 +00:00
}
2019-02-07 23:10:01 +00:00
bool Process : : validate_read_str ( const char * str )
{
if ( ! validate_read ( str , 1 ) )
return false ;
return validate_read ( str , strlen ( str ) + 1 ) ;
}
2018-11-16 15:10:59 +00:00
bool Process : : validate_read ( const void * address , size_t size ) const
2018-11-16 14:41:48 +00:00
{
2019-02-11 05:03:30 +00:00
LinearAddress first_address ( ( dword ) address ) ;
LinearAddress last_address = first_address . offset ( size - 1 ) ;
2019-01-31 16:31:23 +00:00
if ( is_ring0 ( ) ) {
2019-02-11 05:03:30 +00:00
auto kmc_result = check_kernel_memory_access ( first_address , false ) ;
if ( kmc_result = = KernelMemoryCheckResult : : AccessGranted )
2019-01-27 09:17:56 +00:00
return true ;
2019-02-11 05:03:30 +00:00
if ( kmc_result = = KernelMemoryCheckResult : : AccessDenied )
return false ;
2019-01-27 09:17:56 +00:00
if ( is_kmalloc_address ( address ) )
return true ;
}
2019-01-25 00:39:15 +00:00
ASSERT ( size ) ;
if ( ! size )
return false ;
if ( first_address . page_base ( ) ! = last_address . page_base ( ) ) {
if ( ! MM . validate_user_read ( * this , last_address ) )
2018-11-16 14:41:48 +00:00
return false ;
}
2019-01-25 00:39:15 +00:00
return MM . validate_user_read ( * this , first_address ) ;
2018-11-16 14:41:48 +00:00
}
bool Process : : validate_write ( void * address , size_t size ) const
{
2019-02-11 05:03:30 +00:00
LinearAddress first_address ( ( dword ) address ) ;
LinearAddress last_address = first_address . offset ( size - 1 ) ;
2019-01-31 16:31:23 +00:00
if ( is_ring0 ( ) ) {
2019-01-27 09:17:56 +00:00
if ( is_kmalloc_address ( address ) )
return true ;
2019-02-11 05:03:30 +00:00
auto kmc_result = check_kernel_memory_access ( first_address , true ) ;
if ( kmc_result = = KernelMemoryCheckResult : : AccessGranted )
2019-02-06 16:28:14 +00:00
return true ;
2019-02-11 05:03:30 +00:00
if ( kmc_result = = KernelMemoryCheckResult : : AccessDenied )
return false ;
2019-01-27 09:17:56 +00:00
}
2019-01-25 00:39:15 +00:00
if ( ! size )
return false ;
if ( first_address . page_base ( ) ! = last_address . page_base ( ) ) {
if ( ! MM . validate_user_write ( * this , last_address ) )
2018-11-16 14:41:48 +00:00
return false ;
}
2019-01-25 00:39:15 +00:00
return MM . validate_user_write ( * this , last_address ) ;
2018-11-16 14:41:48 +00:00
}
2018-11-02 11:56:51 +00:00
pid_t Process : : sys $ getsid ( pid_t pid )
{
if ( pid = = 0 )
return m_sid ;
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
auto * process = Process : : from_pid ( pid ) ;
2018-11-02 11:56:51 +00:00
if ( ! process )
return - ESRCH ;
if ( m_sid ! = process - > m_sid )
return - EPERM ;
return process - > m_sid ;
}
pid_t Process : : sys $ setsid ( )
{
InterruptDisabler disabler ;
bool found_process_with_same_pgid_as_my_pid = false ;
2018-11-08 20:20:09 +00:00
Process : : for_each_in_pgrp ( pid ( ) , [ & ] ( auto & ) {
2018-11-07 20:38:18 +00:00
found_process_with_same_pgid_as_my_pid = true ;
return false ;
2018-11-02 11:56:51 +00:00
} ) ;
if ( found_process_with_same_pgid_as_my_pid )
return - EPERM ;
m_sid = m_pid ;
m_pgid = m_pid ;
return m_sid ;
}
pid_t Process : : sys $ getpgid ( pid_t pid )
{
if ( pid = = 0 )
return m_pgid ;
InterruptDisabler disabler ; // FIXME: Use a ProcessHandle
2018-11-07 20:38:18 +00:00
auto * process = Process : : from_pid ( pid ) ;
2018-11-02 11:56:51 +00:00
if ( ! process )
return - ESRCH ;
return process - > m_pgid ;
}
pid_t Process : : sys $ getpgrp ( )
{
return m_pgid ;
}
static pid_t get_sid_from_pgid ( pid_t pgid )
{
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
auto * group_leader = Process : : from_pid ( pgid ) ;
2018-11-02 11:56:51 +00:00
if ( ! group_leader )
return - 1 ;
return group_leader - > sid ( ) ;
}
int Process : : sys $ setpgid ( pid_t specified_pid , pid_t specified_pgid )
{
InterruptDisabler disabler ; // FIXME: Use a ProcessHandle
pid_t pid = specified_pid ? specified_pid : m_pid ;
if ( specified_pgid < 0 )
return - EINVAL ;
2018-11-07 20:38:18 +00:00
auto * process = Process : : from_pid ( pid ) ;
2018-11-02 11:56:51 +00:00
if ( ! process )
return - ESRCH ;
pid_t new_pgid = specified_pgid ? specified_pgid : process - > m_pid ;
pid_t current_sid = get_sid_from_pgid ( process - > m_pgid ) ;
pid_t new_sid = get_sid_from_pgid ( new_pgid ) ;
if ( current_sid ! = new_sid ) {
// Can't move a process between sessions.
return - EPERM ;
}
// FIXME: There are more EPERM conditions to check for here..
process - > m_pgid = new_pgid ;
return 0 ;
}
2018-11-02 12:14:25 +00:00
2018-11-16 12:11:21 +00:00
int Process : : sys $ ioctl ( int fd , unsigned request , unsigned arg )
2018-11-02 12:14:25 +00:00
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-11-02 12:14:25 +00:00
return - EBADF ;
2019-02-14 16:18:35 +00:00
if ( descriptor - > is_socket ( ) & & request = = 413 ) {
auto * pid = ( pid_t * ) arg ;
if ( ! validate_write_typed ( pid ) )
return - EFAULT ;
* pid = descriptor - > socket ( ) - > origin_pid ( ) ;
return 0 ;
}
2019-02-16 09:24:55 +00:00
if ( ! descriptor - > is_device ( ) )
2018-11-02 12:14:25 +00:00
return - ENOTTY ;
2019-02-16 09:24:55 +00:00
return descriptor - > device ( ) - > ioctl ( * this , request , arg ) ;
2018-11-02 12:14:25 +00:00
}
2018-11-05 18:01:22 +00:00
int Process : : sys $ getdtablesize ( )
{
return m_max_open_file_descriptors ;
}
int Process : : sys $ dup ( int old_fd )
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( old_fd ) ;
if ( ! descriptor )
2018-11-05 18:01:22 +00:00
return - EBADF ;
if ( number_of_open_file_descriptors ( ) = = m_max_open_file_descriptors )
return - EMFILE ;
int new_fd = 0 ;
2018-11-09 09:03:21 +00:00
for ( ; new_fd < ( int ) m_max_open_file_descriptors ; + + new_fd ) {
2018-11-13 00:36:31 +00:00
if ( ! m_fds [ new_fd ] )
2018-11-05 18:01:22 +00:00
break ;
}
2018-11-13 00:36:31 +00:00
m_fds [ new_fd ] . set ( descriptor ) ;
2018-11-05 18:01:22 +00:00
return new_fd ;
}
int Process : : sys $ dup2 ( int old_fd , int new_fd )
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( old_fd ) ;
if ( ! descriptor )
2018-11-05 18:01:22 +00:00
return - EBADF ;
if ( number_of_open_file_descriptors ( ) = = m_max_open_file_descriptors )
return - EMFILE ;
2018-11-13 00:36:31 +00:00
m_fds [ new_fd ] . set ( descriptor ) ;
2018-11-05 18:01:22 +00:00
return new_fd ;
}
2018-11-06 09:46:40 +00:00
2019-01-23 05:53:01 +00:00
int Process : : sys $ sigprocmask ( int how , const sigset_t * set , sigset_t * old_set )
2018-11-10 22:29:07 +00:00
{
2018-11-11 14:36:40 +00:00
if ( old_set ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( old_set ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-11 14:36:40 +00:00
* old_set = m_signal_mask ;
}
if ( set ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( set ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-11 14:36:40 +00:00
switch ( how ) {
case SIG_BLOCK :
m_signal_mask & = ~ ( * set ) ;
break ;
case SIG_UNBLOCK :
m_signal_mask | = * set ;
break ;
case SIG_SETMASK :
m_signal_mask = * set ;
break ;
default :
return - EINVAL ;
}
2018-11-10 22:29:07 +00:00
}
return 0 ;
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ sigpending ( sigset_t * set )
2018-11-10 22:29:07 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( set ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-10 22:29:07 +00:00
* set = m_pending_signals ;
return 0 ;
}
2019-02-04 13:06:38 +00:00
void Process : : set_default_signal_dispositions ( )
{
// FIXME: Set up all the right default actions. See signal(7).
memset ( & m_signal_action_data , 0 , sizeof ( m_signal_action_data ) ) ;
m_signal_action_data [ SIGCHLD ] . handler_or_sigaction = LinearAddress ( ( dword ) SIG_IGN ) ;
2019-02-20 22:32:33 +00:00
m_signal_action_data [ SIGWINCH ] . handler_or_sigaction = LinearAddress ( ( dword ) SIG_IGN ) ;
2019-02-04 13:06:38 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ sigaction ( int signum , const sigaction * act , sigaction * old_act )
2018-11-06 09:46:40 +00:00
{
2018-12-24 21:22:19 +00:00
if ( signum < 1 | | signum > = 32 | | signum = = SIGKILL | | signum = = SIGSTOP )
2018-11-06 09:46:40 +00:00
return - EINVAL ;
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( act ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-02-07 10:24:09 +00:00
InterruptDisabler disabler ; // FIXME: This should use a narrower lock. Maybe a way to ignore signals temporarily?
2018-11-06 09:46:40 +00:00
auto & action = m_signal_action_data [ signum ] ;
2018-11-07 09:48:44 +00:00
if ( old_act ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( old_act ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-07 09:48:44 +00:00
old_act - > sa_flags = action . flags ;
old_act - > sa_restorer = ( decltype ( old_act - > sa_restorer ) ) action . restorer . get ( ) ;
old_act - > sa_sigaction = ( decltype ( old_act - > sa_sigaction ) ) action . handler_or_sigaction . get ( ) ;
}
2018-11-06 09:46:40 +00:00
action . restorer = LinearAddress ( ( dword ) act - > sa_restorer ) ;
action . flags = act - > sa_flags ;
action . handler_or_sigaction = LinearAddress ( ( dword ) act - > sa_sigaction ) ;
return 0 ;
}
2018-11-07 00:38:51 +00:00
int Process : : sys $ getgroups ( int count , gid_t * gids )
{
if ( count < 0 )
return - EINVAL ;
ASSERT ( m_gids . size ( ) < MAX_PROCESS_GIDS ) ;
if ( ! count )
return m_gids . size ( ) ;
2018-11-09 09:03:21 +00:00
if ( count ! = ( int ) m_gids . size ( ) )
2018-11-07 00:38:51 +00:00
return - EINVAL ;
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( gids , m_gids . size ( ) ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-07 00:38:51 +00:00
size_t i = 0 ;
for ( auto gid : m_gids )
gids [ i + + ] = gid ;
return 0 ;
}
int Process : : sys $ setgroups ( size_t count , const gid_t * gids )
{
if ( ! is_root ( ) )
return - EPERM ;
if ( count > = MAX_PROCESS_GIDS )
return - EINVAL ;
2018-11-16 15:23:39 +00:00
if ( ! validate_read ( gids , count ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-07 00:38:51 +00:00
m_gids . clear ( ) ;
m_gids . set ( m_gid ) ;
for ( size_t i = 0 ; i < count ; + + i )
m_gids . set ( gids [ i ] ) ;
return 0 ;
}
2018-11-18 13:57:41 +00:00
int Process : : sys $ mkdir ( const char * pathname , mode_t mode )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
2019-02-01 14:24:42 +00:00
size_t pathname_length = strlen ( pathname ) ;
if ( pathname_length = = 0 )
return - EINVAL ;
if ( pathname_length > = 255 )
2018-11-18 13:57:41 +00:00
return - ENAMETOOLONG ;
int error ;
2019-02-01 14:29:11 +00:00
if ( ! VFS : : the ( ) . mkdir ( String ( pathname , pathname_length ) , mode , * cwd_inode ( ) , error ) )
2018-11-18 13:57:41 +00:00
return error ;
return 0 ;
}
2018-12-03 00:12:26 +00:00
2019-01-23 05:53:01 +00:00
clock_t Process : : sys $ times ( tms * times )
2018-12-03 00:12:26 +00:00
{
if ( ! validate_write_typed ( times ) )
return - EFAULT ;
times - > tms_utime = m_ticks_in_user ;
times - > tms_stime = m_ticks_in_kernel ;
times - > tms_cutime = m_ticks_in_user_for_dead_children ;
times - > tms_cstime = m_ticks_in_kernel_for_dead_children ;
return 0 ;
}
2019-01-09 01:29:11 +00:00
2019-01-15 22:12:20 +00:00
int Process : : sys $ select ( const Syscall : : SC_select_params * params )
{
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
if ( params - > writefds & & ! validate_read_typed ( params - > writefds ) )
return - EFAULT ;
if ( params - > readfds & & ! validate_read_typed ( params - > readfds ) )
return - EFAULT ;
if ( params - > exceptfds & & ! validate_read_typed ( params - > exceptfds ) )
return - EFAULT ;
if ( params - > timeout & & ! validate_read_typed ( params - > timeout ) )
return - EFAULT ;
int nfds = params - > nfds ;
fd_set * writefds = params - > writefds ;
fd_set * readfds = params - > readfds ;
fd_set * exceptfds = params - > exceptfds ;
auto * timeout = params - > timeout ;
// FIXME: Implement exceptfds support.
ASSERT ( ! exceptfds ) ;
2019-02-01 02:50:06 +00:00
if ( timeout ) {
m_select_timeout = * timeout ;
m_select_has_timeout = true ;
} else {
m_select_has_timeout = false ;
}
2019-01-15 22:12:20 +00:00
if ( nfds < 0 )
return - EINVAL ;
// FIXME: Return -EINTR if a signal is caught.
// FIXME: Return -EINVAL if timeout is invalid.
2019-01-30 18:01:31 +00:00
auto transfer_fds = [ this , nfds ] ( fd_set * set , auto & vector ) - > int {
2019-01-15 22:12:20 +00:00
if ( ! set )
2019-01-30 18:01:31 +00:00
return 0 ;
2019-01-15 22:12:20 +00:00
vector . clear_with_capacity ( ) ;
auto bitmap = Bitmap : : wrap ( ( byte * ) set , FD_SETSIZE ) ;
for ( int i = 0 ; i < nfds ; + + i ) {
2019-01-30 18:01:31 +00:00
if ( bitmap . get ( i ) ) {
if ( ! file_descriptor ( i ) )
return - EBADF ;
2019-01-15 22:12:20 +00:00
vector . append ( i ) ;
2019-01-30 18:01:31 +00:00
}
2019-01-15 22:12:20 +00:00
}
2019-01-30 18:01:31 +00:00
return 0 ;
2019-01-15 22:12:20 +00:00
} ;
2019-01-30 18:01:31 +00:00
int error = 0 ;
error = transfer_fds ( writefds , m_select_write_fds ) ;
if ( error )
return error ;
error = transfer_fds ( readfds , m_select_read_fds ) ;
if ( error )
return error ;
2019-01-15 22:12:20 +00:00
2019-01-16 16:20:58 +00:00
# ifdef DEBUG_IO
2019-01-18 04:26:45 +00:00
dbgprintf ( " %s<%u> selecting on (read:%u, write:%u), wakeup_req:%u, timeout=%p \n " , name ( ) . characters ( ) , pid ( ) , m_select_read_fds . size ( ) , m_select_write_fds . size ( ) , m_wakeup_requested , timeout ) ;
2019-01-16 16:20:58 +00:00
# endif
2019-01-18 04:26:45 +00:00
if ( ! m_wakeup_requested & & ( ! timeout | | ( timeout - > tv_sec | | timeout - > tv_usec ) ) ) {
2019-01-16 16:20:58 +00:00
block ( BlockedSelect ) ;
Scheduler : : yield ( ) ;
}
m_wakeup_requested = false ;
2019-01-15 22:12:20 +00:00
int markedfds = 0 ;
if ( readfds ) {
memset ( readfds , 0 , sizeof ( fd_set ) ) ;
auto bitmap = Bitmap : : wrap ( ( byte * ) readfds , FD_SETSIZE ) ;
for ( int fd : m_select_read_fds ) {
2019-01-23 07:03:31 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
continue ;
if ( descriptor - > can_read ( * this ) ) {
2019-01-15 22:12:20 +00:00
bitmap . set ( fd , true ) ;
+ + markedfds ;
}
}
}
if ( writefds ) {
memset ( writefds , 0 , sizeof ( fd_set ) ) ;
auto bitmap = Bitmap : : wrap ( ( byte * ) writefds , FD_SETSIZE ) ;
for ( int fd : m_select_write_fds ) {
2019-01-23 07:03:31 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
continue ;
if ( descriptor - > can_write ( * this ) ) {
2019-01-15 22:12:20 +00:00
bitmap . set ( fd , true ) ;
+ + markedfds ;
}
}
}
return markedfds ;
}
2019-01-16 16:20:58 +00:00
2019-01-23 06:27:41 +00:00
int Process : : sys $ poll ( pollfd * fds , int nfds , int timeout )
{
if ( ! validate_read_typed ( fds ) )
return - EFAULT ;
2019-01-23 07:03:31 +00:00
m_select_write_fds . clear_with_capacity ( ) ;
m_select_read_fds . clear_with_capacity ( ) ;
for ( int i = 0 ; i < nfds ; + + i ) {
if ( fds [ i ] . events & POLLIN )
m_select_read_fds . append ( fds [ i ] . fd ) ;
if ( fds [ i ] . events & POLLOUT )
m_select_write_fds . append ( fds [ i ] . fd ) ;
}
if ( ! m_wakeup_requested & & timeout < 0 ) {
block ( BlockedSelect ) ;
Scheduler : : yield ( ) ;
}
m_wakeup_requested = false ;
int fds_with_revents = 0 ;
for ( int i = 0 ; i < nfds ; + + i ) {
auto * descriptor = file_descriptor ( fds [ i ] . fd ) ;
if ( ! descriptor ) {
fds [ i ] . revents = POLLNVAL ;
continue ;
}
fds [ i ] . revents = 0 ;
if ( fds [ i ] . events & POLLIN & & descriptor - > can_read ( * this ) )
fds [ i ] . revents | = POLLIN ;
if ( fds [ i ] . events & POLLOUT & & descriptor - > can_write ( * this ) )
fds [ i ] . revents | = POLLOUT ;
if ( fds [ i ] . revents )
+ + fds_with_revents ;
}
return fds_with_revents ;
2019-01-23 06:27:41 +00:00
}
2019-01-16 16:20:58 +00:00
Inode * Process : : cwd_inode ( )
{
// FIXME: This is retarded factoring.
if ( ! m_cwd )
m_cwd = VFS : : the ( ) . root_inode ( ) ;
return m_cwd . ptr ( ) ;
}
2019-01-22 06:03:44 +00:00
2019-02-21 12:26:40 +00:00
int Process : : sys $ link ( const char * old_path , const char * new_path )
{
if ( ! validate_read_str ( old_path ) )
return - EFAULT ;
if ( ! validate_read_str ( new_path ) )
return - EFAULT ;
int error ;
if ( ! VFS : : the ( ) . link ( String ( old_path ) , String ( new_path ) , * cwd_inode ( ) , error ) )
return error ;
return 0 ;
}
2019-01-22 06:03:44 +00:00
int Process : : sys $ unlink ( const char * pathname )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
int error ;
if ( ! VFS : : the ( ) . unlink ( String ( pathname ) , * cwd_inode ( ) , error ) )
return error ;
return 0 ;
}
2019-01-25 01:09:29 +00:00
2019-01-28 03:16:01 +00:00
int Process : : sys $ rmdir ( const char * pathname )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
int error ;
if ( ! VFS : : the ( ) . rmdir ( String ( pathname ) , * cwd_inode ( ) , error ) )
return error ;
return 0 ;
}
2019-01-25 01:09:29 +00:00
int Process : : sys $ read_tsc ( dword * lsw , dword * msw )
{
if ( ! validate_write_typed ( lsw ) )
return - EFAULT ;
if ( ! validate_write_typed ( msw ) )
return - EFAULT ;
read_tsc ( * lsw , * msw ) ;
return 0 ;
}
2019-01-29 03:55:08 +00:00
int Process : : sys $ chmod ( const char * pathname , mode_t mode )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
int error ;
if ( ! VFS : : the ( ) . chmod ( String ( pathname ) , mode , * cwd_inode ( ) , error ) )
return error ;
return 0 ;
}
2019-01-30 17:26:19 +00:00
2019-02-06 17:45:21 +00:00
void Process : : finalize ( )
2019-01-30 17:26:19 +00:00
{
2019-02-06 17:45:21 +00:00
ASSERT ( current = = g_finalizer ) ;
2019-02-06 16:28:14 +00:00
2019-01-30 17:26:19 +00:00
m_fds . clear ( ) ;
2019-02-04 09:21:15 +00:00
m_tty = nullptr ;
2019-02-16 11:13:43 +00:00
disown_all_shared_buffers ( ) ;
2019-02-06 17:45:21 +00:00
{
InterruptDisabler disabler ;
if ( auto * parent_process = Process : : from_pid ( m_ppid ) ) {
parent_process - > send_signal ( SIGCHLD , this ) ;
}
2019-02-04 12:30:03 +00:00
}
2019-02-06 16:28:14 +00:00
set_state ( Dead ) ;
2019-01-30 17:26:19 +00:00
}
2019-02-03 17:53:18 +00:00
2019-02-06 17:45:21 +00:00
void Process : : die ( )
{
set_state ( Dying ) ;
if ( ! Scheduler : : is_active ( ) )
Scheduler : : pick_next_and_switch_now ( ) ;
}
2019-02-03 17:53:18 +00:00
size_t Process : : amount_virtual ( ) const
{
size_t amount = 0 ;
for ( auto & region : m_regions ) {
amount + = region - > size ( ) ;
}
return amount ;
}
size_t Process : : amount_resident ( ) const
{
// FIXME: This will double count if multiple regions use the same physical page.
size_t amount = 0 ;
for ( auto & region : m_regions ) {
amount + = region - > amount_resident ( ) ;
}
return amount ;
}
size_t Process : : amount_shared ( ) const
{
// FIXME: This will double count if multiple regions use the same physical page.
// FIXME: It doesn't work at the moment, since it relies on PhysicalPage retain counts,
// and each PhysicalPage is only retained by its VMObject. This needs to be refactored
// so that every Region contributes +1 retain to each of its PhysicalPages.
size_t amount = 0 ;
for ( auto & region : m_regions ) {
amount + = region - > amount_shared ( ) ;
}
return amount ;
}
2019-02-06 17:45:21 +00:00
void Process : : finalize_dying_processes ( )
{
Vector < Process * > dying_processes ;
{
InterruptDisabler disabler ;
dying_processes . ensure_capacity ( system . nprocess ) ;
for ( auto * process = g_processes - > head ( ) ; process ; process = process - > next ( ) ) {
if ( process - > state ( ) = = Process : : Dying )
dying_processes . append ( process ) ;
}
}
for ( auto * process : dying_processes )
process - > finalize ( ) ;
}
2019-02-07 10:12:23 +00:00
bool Process : : tick ( )
{
+ + m_ticks ;
if ( tss ( ) . cs & 3 )
+ + m_ticks_in_user ;
else
+ + m_ticks_in_kernel ;
return - - m_ticks_left ;
}
2019-02-14 09:39:26 +00:00
2019-02-14 13:17:38 +00:00
int Process : : sys $ socket ( int domain , int type , int protocol )
{
if ( number_of_open_file_descriptors ( ) > = m_max_open_file_descriptors )
return - EMFILE ;
int fd = 0 ;
for ( ; fd < ( int ) m_max_open_file_descriptors ; + + fd ) {
if ( ! m_fds [ fd ] )
break ;
}
int error ;
auto socket = Socket : : create ( domain , type , protocol , error ) ;
if ( ! socket )
return error ;
auto descriptor = FileDescriptor : : create ( move ( socket ) ) ;
2019-02-14 14:17:30 +00:00
unsigned flags = 0 ;
if ( type & SOCK_CLOEXEC )
2019-02-17 09:41:37 +00:00
flags | = FD_CLOEXEC ;
2019-02-14 14:17:30 +00:00
if ( type & SOCK_NONBLOCK )
descriptor - > set_blocking ( false ) ;
m_fds [ fd ] . set ( move ( descriptor ) , flags ) ;
2019-02-14 13:17:38 +00:00
return fd ;
}
2019-02-14 13:38:30 +00:00
int Process : : sys $ bind ( int sockfd , const sockaddr * address , socklen_t address_length )
2019-02-14 13:17:38 +00:00
{
2019-02-14 13:38:30 +00:00
if ( ! validate_read ( address , address_length ) )
return - EFAULT ;
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
int error ;
if ( ! socket . bind ( address , address_length , error ) )
return error ;
return 0 ;
2019-02-14 13:17:38 +00:00
}
int Process : : sys $ listen ( int sockfd , int backlog )
{
2019-02-14 14:17:30 +00:00
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
int error ;
if ( ! socket . listen ( backlog , error ) )
return error ;
2019-02-17 08:40:52 +00:00
descriptor - > set_socket_role ( SocketRole : : Listener ) ;
2019-02-14 14:17:30 +00:00
return 0 ;
2019-02-14 13:17:38 +00:00
}
2019-02-15 10:43:43 +00:00
int Process : : sys $ accept ( int accepting_socket_fd , sockaddr * address , socklen_t * address_size )
2019-02-14 13:17:38 +00:00
{
2019-02-14 14:17:30 +00:00
if ( ! validate_write_typed ( address_size ) )
return - EFAULT ;
if ( ! validate_write ( address , * address_size ) )
return - EFAULT ;
2019-02-14 14:40:04 +00:00
if ( number_of_open_file_descriptors ( ) > = m_max_open_file_descriptors )
return - EMFILE ;
2019-02-15 10:43:43 +00:00
int accepted_socket_fd = 0 ;
for ( ; accepted_socket_fd < ( int ) m_max_open_file_descriptors ; + + accepted_socket_fd ) {
if ( ! m_fds [ accepted_socket_fd ] )
2019-02-14 14:40:04 +00:00
break ;
}
2019-02-15 10:43:43 +00:00
auto * accepting_socket_descriptor = file_descriptor ( accepting_socket_fd ) ;
if ( ! accepting_socket_descriptor )
2019-02-14 14:17:30 +00:00
return - EBADF ;
2019-02-15 10:43:43 +00:00
if ( ! accepting_socket_descriptor - > is_socket ( ) )
2019-02-14 14:17:30 +00:00
return - ENOTSOCK ;
2019-02-15 10:43:43 +00:00
auto & socket = * accepting_socket_descriptor - > socket ( ) ;
2019-02-14 14:17:30 +00:00
if ( ! socket . can_accept ( ) ) {
2019-02-15 10:43:43 +00:00
ASSERT ( ! accepting_socket_descriptor - > is_blocking ( ) ) ;
2019-02-14 14:17:30 +00:00
return - EAGAIN ;
}
2019-02-15 10:43:43 +00:00
auto accepted_socket = socket . accept ( ) ;
ASSERT ( accepted_socket ) ;
bool success = accepted_socket - > get_address ( address , address_size ) ;
2019-02-14 14:40:04 +00:00
ASSERT ( success ) ;
2019-02-15 10:43:43 +00:00
auto accepted_socket_descriptor = FileDescriptor : : create ( move ( accepted_socket ) , SocketRole : : Accepted ) ;
// NOTE: The accepted socket inherits fd flags from the accepting socket.
// I'm not sure if this matches other systems but it makes sense to me.
accepted_socket_descriptor - > set_blocking ( accepting_socket_descriptor - > is_blocking ( ) ) ;
m_fds [ accepted_socket_fd ] . set ( move ( accepted_socket_descriptor ) , m_fds [ accepting_socket_fd ] . flags ) ;
return accepted_socket_fd ;
2019-02-14 13:17:38 +00:00
}
2019-02-14 14:55:19 +00:00
int Process : : sys $ connect ( int sockfd , const sockaddr * address , socklen_t address_size )
2019-02-14 13:17:38 +00:00
{
2019-02-14 14:55:19 +00:00
if ( ! validate_read ( address , address_size ) )
return - EFAULT ;
if ( number_of_open_file_descriptors ( ) > = m_max_open_file_descriptors )
return - EMFILE ;
int fd = 0 ;
for ( ; fd < ( int ) m_max_open_file_descriptors ; + + fd ) {
if ( ! m_fds [ fd ] )
break ;
}
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
int error ;
2019-02-14 16:18:35 +00:00
if ( ! socket . connect ( address , address_size , error ) )
2019-02-14 14:55:19 +00:00
return error ;
2019-02-14 16:18:35 +00:00
descriptor - > set_socket_role ( SocketRole : : Connected ) ;
return 0 ;
}
bool Process : : wait_for_connect ( Socket & socket , int & error )
{
if ( socket . is_connected ( ) )
return true ;
m_blocked_connecting_socket = socket ;
block ( BlockedConnect ) ;
Scheduler : : yield ( ) ;
m_blocked_connecting_socket = nullptr ;
if ( ! socket . is_connected ( ) ) {
error = - ECONNREFUSED ;
return false ;
}
return true ;
2019-02-14 13:17:38 +00:00
}
2019-02-16 11:13:43 +00:00
struct SharedBuffer {
SharedBuffer ( pid_t pid1 , pid_t pid2 , size_t size )
: m_pid1 ( pid1 )
, m_pid2 ( pid2 )
, m_vmo ( VMObject : : create_anonymous ( size ) )
{
ASSERT ( pid1 ! = pid2 ) ;
}
void * retain ( Process & process )
{
if ( m_pid1 = = process . pid ( ) ) {
+ + m_pid1_retain_count ;
2019-02-16 23:13:47 +00:00
if ( ! m_pid1_region ) {
2019-02-16 11:13:43 +00:00
m_pid1_region = process . allocate_region_with_vmo ( LinearAddress ( ) , size ( ) , m_vmo . copy_ref ( ) , 0 , " SharedBuffer " , true , true ) ;
2019-02-16 23:13:47 +00:00
m_pid1_region - > set_shared ( true ) ;
}
2019-02-16 11:13:43 +00:00
return m_pid1_region - > laddr ( ) . as_ptr ( ) ;
} else if ( m_pid2 = = process . pid ( ) ) {
+ + m_pid2_retain_count ;
2019-02-16 23:13:47 +00:00
if ( ! m_pid2_region ) {
2019-02-16 11:13:43 +00:00
m_pid2_region = process . allocate_region_with_vmo ( LinearAddress ( ) , size ( ) , m_vmo . copy_ref ( ) , 0 , " SharedBuffer " , true , true ) ;
2019-02-16 23:13:47 +00:00
m_pid2_region - > set_shared ( true ) ;
}
2019-02-16 11:13:43 +00:00
return m_pid2_region - > laddr ( ) . as_ptr ( ) ;
}
return nullptr ;
}
void release ( Process & process )
{
if ( m_pid1 = = process . pid ( ) ) {
ASSERT ( m_pid1_retain_count ) ;
- - m_pid1_retain_count ;
if ( ! m_pid1_retain_count ) {
if ( m_pid1_region )
process . deallocate_region ( * m_pid1_region ) ;
m_pid1_region = nullptr ;
}
destroy_if_unused ( ) ;
} else if ( m_pid2 = = process . pid ( ) ) {
ASSERT ( m_pid2_retain_count ) ;
- - m_pid2_retain_count ;
if ( ! m_pid2_retain_count ) {
if ( m_pid2_region )
process . deallocate_region ( * m_pid2_region ) ;
m_pid2_region = nullptr ;
}
destroy_if_unused ( ) ;
}
}
void disown ( pid_t pid )
{
if ( m_pid1 = = pid ) {
m_pid1 = 0 ;
m_pid1_retain_count = 0 ;
destroy_if_unused ( ) ;
} else if ( m_pid2 = = pid ) {
m_pid2 = 0 ;
m_pid2_retain_count = 0 ;
destroy_if_unused ( ) ;
}
}
pid_t pid1 ( ) const { return m_pid1 ; }
pid_t pid2 ( ) const { return m_pid2 ; }
unsigned pid1_retain_count ( ) const { return m_pid1_retain_count ; }
unsigned pid2_retain_count ( ) const { return m_pid2_retain_count ; }
size_t size ( ) const { return m_vmo - > size ( ) ; }
void destroy_if_unused ( ) ;
int m_shared_buffer_id { - 1 } ;
pid_t m_pid1 ;
pid_t m_pid2 ;
unsigned m_pid1_retain_count { 1 } ;
unsigned m_pid2_retain_count { 0 } ;
Region * m_pid1_region { nullptr } ;
Region * m_pid2_region { nullptr } ;
RetainPtr < VMObject > m_vmo ;
} ;
static int s_next_shared_buffer_id ;
Lockable < HashMap < int , OwnPtr < SharedBuffer > > > & shared_buffers ( )
{
static Lockable < HashMap < int , OwnPtr < SharedBuffer > > > * map ;
if ( ! map )
map = new Lockable < HashMap < int , OwnPtr < SharedBuffer > > > ;
return * map ;
}
void SharedBuffer : : destroy_if_unused ( )
{
if ( ! m_pid1_retain_count & & ! m_pid2_retain_count ) {
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-02-20 14:34:55 +00:00
dbgprintf ( " Destroying unused SharedBuffer{%p} id: %d (pid1: %d, pid2: %d) \n " , this , m_shared_buffer_id , m_pid1 , m_pid2 ) ;
2019-02-16 23:13:47 +00:00
# endif
2019-02-20 14:34:55 +00:00
size_t count_before = shared_buffers ( ) . resource ( ) . size ( ) ;
2019-02-16 11:13:43 +00:00
shared_buffers ( ) . resource ( ) . remove ( m_shared_buffer_id ) ;
2019-02-20 14:34:55 +00:00
ASSERT ( count_before ! = shared_buffers ( ) . resource ( ) . size ( ) ) ;
2019-02-16 11:13:43 +00:00
}
}
void Process : : disown_all_shared_buffers ( )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
2019-02-20 20:31:52 +00:00
Vector < SharedBuffer * > buffers_to_disown ;
for ( auto & it : shared_buffers ( ) . resource ( ) )
buffers_to_disown . append ( it . value . ptr ( ) ) ;
for ( auto * shared_buffer : buffers_to_disown )
shared_buffer - > disown ( m_pid ) ;
2019-02-16 11:13:43 +00:00
}
int Process : : sys $ create_shared_buffer ( pid_t peer_pid , size_t size , void * * buffer )
{
2019-02-20 20:31:52 +00:00
if ( ! size )
return - EINVAL ;
size = PAGE_ROUND_UP ( size ) ;
2019-02-16 11:13:43 +00:00
if ( ! peer_pid | | peer_pid < 0 | | peer_pid = = m_pid )
return - EINVAL ;
if ( ! validate_write_typed ( buffer ) )
return - EFAULT ;
{
InterruptDisabler disabler ;
auto * peer = Process : : from_pid ( peer_pid ) ;
if ( ! peer )
return - ESRCH ;
}
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
int shared_buffer_id = + + s_next_shared_buffer_id ;
auto shared_buffer = make < SharedBuffer > ( m_pid , peer_pid , size ) ;
2019-02-20 14:34:55 +00:00
shared_buffer - > m_shared_buffer_id = shared_buffer_id ;
2019-02-20 20:31:52 +00:00
ASSERT ( shared_buffer - > size ( ) > = size ) ;
2019-02-16 11:13:43 +00:00
shared_buffer - > m_pid1_region = allocate_region_with_vmo ( LinearAddress ( ) , shared_buffer - > size ( ) , shared_buffer - > m_vmo . copy_ref ( ) , 0 , " SharedBuffer " , true , true ) ;
2019-02-16 23:13:47 +00:00
shared_buffer - > m_pid1_region - > set_shared ( true ) ;
2019-02-16 11:13:43 +00:00
* buffer = shared_buffer - > m_pid1_region - > laddr ( ) . as_ptr ( ) ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
dbgprintf ( " %s(%u): Created shared buffer %d (%u bytes, vmo is %u) for sharing with %d \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , size , shared_buffer - > size ( ) , peer_pid ) ;
# endif
2019-02-16 11:13:43 +00:00
shared_buffers ( ) . resource ( ) . set ( shared_buffer_id , move ( shared_buffer ) ) ;
return shared_buffer_id ;
}
int Process : : sys $ release_shared_buffer ( int shared_buffer_id )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
auto it = shared_buffers ( ) . resource ( ) . find ( shared_buffer_id ) ;
if ( it = = shared_buffers ( ) . resource ( ) . end ( ) )
return - EINVAL ;
auto & shared_buffer = * ( * it ) . value ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-02-20 14:34:55 +00:00
dbgprintf ( " %s(%u): Releasing shared buffer %d, buffer count: %u \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , shared_buffers ( ) . resource ( ) . size ( ) ) ;
2019-02-16 23:13:47 +00:00
# endif
2019-02-16 11:13:43 +00:00
shared_buffer . release ( * this ) ;
return 0 ;
}
void * Process : : sys $ get_shared_buffer ( int shared_buffer_id )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
auto it = shared_buffers ( ) . resource ( ) . find ( shared_buffer_id ) ;
if ( it = = shared_buffers ( ) . resource ( ) . end ( ) )
return ( void * ) - EINVAL ;
auto & shared_buffer = * ( * it ) . value ;
if ( shared_buffer . pid1 ( ) ! = m_pid & & shared_buffer . pid2 ( ) ! = m_pid )
return ( void * ) - EINVAL ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-02-20 14:34:55 +00:00
dbgprintf ( " %s(%u): Retaining shared buffer %d, buffer count: %u \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , shared_buffers ( ) . resource ( ) . size ( ) ) ;
2019-02-16 23:13:47 +00:00
# endif
2019-02-16 11:13:43 +00:00
return shared_buffer . retain ( * this ) ;
}