123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- /*
- * process.c
- *
- * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <process.h>
- #include <thread.h>
- #include <heap.h>
- #include <syscalls.h>
- #include <exception.h>
- #include <exec/aout.h>
- #include <cpu.h>
- typedef dword_t (*loader_proc)(handle_t, process_params_t*, thread_state_t*);
- static dword_t pid_alloc_bitmap[MAX_PROCESSES / 32];
- static lock_t pid_bitmap_lock = 0;
- static loader_proc loaders[] =
- {
- load_aout,
- NULL
- };
- process_t *kernel_process;
- static dword_t alloc_pid()
- {
- int i;
- dword_t pid = (dword_t)-1;
- acquire_lock(&pid_bitmap_lock);
- for (i = 0; i < MAX_PROCESSES; i++)
- {
- if (!test_bit(pid_alloc_bitmap, i))
- {
- pid = i;
- set_bit(pid_alloc_bitmap, pid);
- break;
- }
- }
- release_lock(&pid_bitmap_lock);
- return pid;
- }
- void destroy_process(process_t *proc)
- {
- int i;
- proc->terminating = TRUE;
- delete_address_space(&proc->memory_space);
- acquire_resource_exclusive(&proc->handle_table_res);
- for (i = 0; i < proc->handle_table_size / sizeof(object_t*); i++)
- {
- if (proc->handle_table[i].obj)
- {
- close_object_internal(proc->handle_table[i].obj);
- proc->handle_table[i].obj = NULL;
- proc->handle_count--;
- }
- }
- release_resource(&proc->handle_table_res);
- proc->terminated = TRUE;
- dereference(&proc->header);
- }
- void process_cleanup(object_t *obj)
- {
- process_t *proc = (process_t*)obj;
- free(proc->name);
- dereference(&proc->current_user->header);
- acquire_lock(&pid_bitmap_lock);
- clear_bit(pid_alloc_bitmap, proc->pid);
- release_lock(&pid_bitmap_lock);
- }
- process_t *get_current_process()
- {
- thread_t *thread = get_current_thread();
- if (thread == NULL) return NULL;
- return thread->owner_process;
- }
- sysret_t syscall_open_process(dword_t pid, handle_t *handle)
- {
- dword_t ret;
- process_t *proc = NULL;
- ret = enum_objects_by_type(OBJECT_PROCESS, (object_t**)&proc);
- ASSERT(ret == ERR_SUCCESS || ret == ERR_NOMORE);
- while (ret == ERR_SUCCESS)
- {
- if (proc->pid == pid) break;
- ret = enum_objects_by_type(OBJECT_PROCESS, (object_t**)&proc);
- }
- ASSERT(ret == ERR_SUCCESS || ret == ERR_NOMORE);
- if (ret == ERR_NOMORE) ret = ERR_NOTFOUND;
- if (ret == ERR_SUCCESS)
- {
- if (proc->current_user->uid == syscall_get_user_id() || check_privileges(PRIVILEGE_PROCESS_CONTROL))
- {
- ret = open_object(&proc->header, 0, handle);
- }
- else
- {
- ret = ERR_FORBIDDEN;
- }
- dereference(&proc->header);
- }
- return ret;
- }
- dword_t load_executable(handle_t file, process_params_t *parameters, thread_state_t *initial_state)
- {
- loader_proc *loader = loaders;
- while (*loader)
- {
- dword_t ret = (*loader++)(file, parameters, initial_state);
- if (ret == ERR_INVALID) continue;
- return ret;
- }
- return ERR_INVALID;
- }
- void init_user_stack(uintptr_t *stack_pointer, process_params_t *parameters)
- {
- static const byte_t program_end_code[] = {
- /* push eax */
- 0x50,
- /* push INVALID_HANDLE */
- 0x68,
- INVALID_HANDLE & 0xFF,
- (INVALID_HANDLE >> 8) & 0xFF,
- (INVALID_HANDLE >> 16) & 0xFF,
- (INVALID_HANDLE >> 24) & 0xFF,
- /* mov eax, SYSCALL_TERMINATE */
- 0xB8,
- SYSCALL_TERMINATE & 0xFF,
- (SYSCALL_TERMINATE >> 8) & 0xFF,
- (SYSCALL_TERMINATE >> 16) & 0xFF,
- SYSCALL_TERMINATE >> 24,
- /* mov edx, esp */
- 0x8B, 0xD4,
- /* int SYSCALL_INTERRUPT */
- 0xCD, SYSCALL_INTERRUPT
- };
- uintptr_t stack_top = *stack_pointer;
- *stack_pointer -= (sizeof(process_params_t) + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
- *(process_params_t*)*stack_pointer = *parameters;
- uintptr_t parameters_addr = *stack_pointer;
- *stack_pointer -= (sizeof(program_end_code) + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
- memcpy((void*)*stack_pointer, program_end_code, sizeof(program_end_code));
- uintptr_t end_code_addr = *stack_pointer;
- if ((stack_top - *stack_pointer) < MAX_PARAMETERS * sizeof(uintptr_t))
- {
- *stack_pointer = stack_top - MAX_PARAMETERS * sizeof(uintptr_t);
- }
- push_to_stack(stack_pointer, parameters_addr);
- push_to_stack(stack_pointer, end_code_addr);
- }
- sysret_t syscall_create_process(const char *path, dword_t flags, process_params_t *parameters, handle_t *process_handle, handle_t *thread_handle)
- {
- dword_t ret;
- handle_t file = INVALID_HANDLE;
- process_t *current = get_current_process();
- char *safe_path = NULL;
- process_params_t safe_params;
- handle_t safe_process_handle = INVALID_HANDLE;
- handle_t safe_thread_handle = INVALID_HANDLE;
- bool_t object_created = FALSE;
- if (get_previous_mode() == USER_MODE)
- {
- if (!check_usermode(process_handle, sizeof(handle_t))) return ERR_BADPTR;
- if (!check_usermode(thread_handle, sizeof(handle_t))) return ERR_BADPTR;
- if (path)
- {
- safe_path = copy_user_string(path);
- if (safe_path == NULL) return ERR_BADPTR;
- }
- if (parameters)
- {
- if (!check_usermode(parameters, sizeof(process_params_t))) return ERR_BADPTR;
- EH_TRY safe_params = *parameters;
- EH_CATCH EH_ESCAPE(return ERR_BADPTR);
- EH_DONE;
- }
- }
- else
- {
- safe_path = (char*)path;
- if (parameters) safe_params = *parameters;
- }
- if (safe_path)
- {
- ret = syscall(SYSCALL_OPEN_FILE, safe_path, &file, FILE_MODE_READ, 0);
- if (ret != ERR_SUCCESS) return ret;
- }
- process_t *proc = (process_t*)malloc(sizeof(process_t));
- if (proc == NULL) return ERR_NOMEMORY;
- memset(proc, 0, sizeof(process_t));
- proc->header.name = NULL;
- proc->header.type = OBJECT_PROCESS;
- proc->pid = alloc_pid();
- if (proc->pid == (dword_t)-1)
- {
- ret = ERR_NOMEMORY;
- goto cleanup;
- }
- proc->name = strdup(path ? path : get_current_process()->name);
- list_init(&proc->threads);
- proc->thread_list_res = 0;
- reference(¤t->current_user->header);
- proc->original_user = proc->current_user = current->current_user;
- if (!(flags & PROCESS_CREATE_NO_INHERIT) && current != kernel_process)
- {
- dword_t i;
- acquire_resource_shared(¤t->handle_table_res);
- proc->handle_table = (handle_info_t*)malloc(current->handle_table_size);
- memset(proc->handle_table, 0, current->handle_table_size);
- proc->handle_table_size = current->handle_table_size;
- proc->handle_count = current->handle_count;
- proc->handle_table_res = 0;
- for (i = 0; i < current->handle_table_size; i++)
- {
- if (current->handle_table[i].obj)
- {
- reference(current->handle_table[i].obj);
- current->handle_table[i].obj->open_count++;
- proc->handle_table[i] = current->handle_table[i];
- }
- }
- release_resource(¤t->handle_table_res);
- }
- else
- {
- proc->handle_table = (handle_info_t*)heap_alloc(&evictable_heap, STARTUP_HANDLE_TABLE_SIZE);
- memset(proc->handle_table, 0, STARTUP_HANDLE_TABLE_SIZE);
- proc->handle_table_size = STARTUP_HANDLE_TABLE_SIZE;
- proc->handle_count = 0;
- proc->handle_table_res = 0;
- }
- if (safe_path)
- {
- ret = create_address_space(PROCESS_POOL_ADDRESS, PROCESS_POOL_SIZE, &proc->memory_space);
- if (ret != ERR_SUCCESS) goto cleanup;
- }
- else
- {
- ret = clone_address_space(¤t->memory_space, &proc->memory_space);
- if (ret != ERR_SUCCESS) goto cleanup;
- }
- syscall_clock_get_time(&proc->start_time);
- ret = create_object(&proc->header);
- if (ret != ERR_SUCCESS) goto cleanup;
- object_created = TRUE;
- thread_state_t initial_state;
- memset(&initial_state, 0, sizeof(initial_state));
- ret = open_object(&proc->header, 0, &safe_process_handle);
- if (ret != ERR_SUCCESS) goto cleanup;
- if (file != INVALID_HANDLE)
- {
- process_t *old_process = switch_process(proc);
- ret = load_executable(file, parameters ? &safe_params : NULL, &initial_state);
- switch_process(old_process);
- if (ret != ERR_SUCCESS) goto cleanup;
- }
- else
- {
- initial_state.regs = *get_current_thread()->syscall_regs;
- fpu_save(initial_state.fpu_state);
- initial_state.regs.eax = CLONE_MAGIC;
- }
- if (!(flags & PROCESS_CREATE_NO_THREADS))
- {
- thread_t *thread;
- void *kernel_stack = malloc(KERNEL_STACK_SIZE + sizeof(uintptr_t) - 1);
- if (kernel_stack == NULL)
- {
- ret = ERR_NOMEMORY;
- goto cleanup;
- }
- ret = commit_pages(kernel_stack, KERNEL_STACK_SIZE);
- if (ret != ERR_SUCCESS) goto cleanup;
- ret = create_thread_internal(proc,
- &initial_state,
- (flags & PROCESS_CREATE_FROZEN_THREAD) ? THREAD_CREATE_FROZEN : 0,
- THREAD_PRIORITY_MID,
- kernel_stack,
- &thread);
- if (ret != ERR_SUCCESS)
- {
- free(kernel_stack);
- goto cleanup;
- }
- ret = open_object(&thread->header, 0, &safe_thread_handle);
- if (ret != ERR_SUCCESS)
- {
- dereference(&thread->header);
- goto cleanup;
- }
- }
- EH_TRY
- {
- *process_handle = safe_process_handle;
- *thread_handle = safe_thread_handle;
- }
- EH_CATCH
- {
- ret = ERR_BADPTR;
- }
- EH_DONE;
- cleanup:
- if (file != INVALID_HANDLE) syscall(SYSCALL_CLOSE_OBJECT, file);
- if (object_created)
- {
- if (ret != ERR_SUCCESS)
- {
- syscall(SYSCALL_TERMINATE, proc->pid, 1);
- if (safe_process_handle != INVALID_HANDLE) syscall_close_object(safe_process_handle);
- if (safe_thread_handle != INVALID_HANDLE) syscall_close_object(safe_thread_handle);
- }
- dereference(&proc->header);
- }
- else
- {
- ASSERT(ret != ERR_SUCCESS);
- if (proc->pid != (dword_t)-1)
- {
- acquire_lock(&pid_bitmap_lock);
- clear_bit(pid_alloc_bitmap, proc->pid);
- release_lock(&pid_bitmap_lock);
- }
- if (proc->name) free(proc->name);
- free(proc);
- }
- if (get_previous_mode() == USER_MODE && path != NULL) free(safe_path);
- return ret;
- }
- sysret_t syscall_terminate(handle_t handle, dword_t exit_code)
- {
- process_t *proc;
- thread_t *current_thread = get_current_thread();
- if (handle == INVALID_HANDLE)
- {
- proc = get_current_process();
- reference(&proc->header);
- }
- else
- {
- if (!reference_by_handle(handle, OBJECT_PROCESS, (object_t**)&proc)) return ERR_INVALID;
- }
- proc->terminating = TRUE;
- proc->exit_code = exit_code;
- syscall_clock_get_time(&proc->end_time);
- acquire_resource_shared(&proc->thread_list_res);
- while (proc->threads.next != &proc->threads)
- {
- list_entry_t *ptr;
- thread_t *thread = NULL;
- for (ptr = proc->threads.next; ptr != &proc->threads; ptr = ptr->next)
- {
- thread = CONTAINER_OF(ptr, thread_t, in_process_list);
- if (thread != current_thread) break;
- }
- if (ptr != &proc->threads)
- {
- release_resource(&proc->thread_list_res);
- terminate_thread_internal(thread, exit_code);
- acquire_resource_shared(&proc->thread_list_res);
- }
- else
- {
- break;
- }
- }
- release_resource(&proc->thread_list_res);
- if (proc->threads.next == &proc->threads) destroy_process(proc);
- dereference(&proc->header);
- if (proc->threads.next == &proc->threads) return ERR_SUCCESS;
- else return terminate_thread_internal(current_thread, exit_code);
- }
- sysret_t syscall_get_process_id()
- {
- process_t *proc = get_current_process();
- return proc->pid;
- }
- sysret_t syscall_query_process(handle_t handle, process_info_t info_type, void *buffer, dword_t size)
- {
- dword_t ret = ERR_SUCCESS;
- void *safe_buffer;
- if (get_previous_mode() == USER_MODE)
- {
- if (!check_usermode(buffer, size)) return ERR_BADPTR;
- safe_buffer = malloc(size);
- if (safe_buffer == NULL) return ERR_NOMEMORY;
- memset(safe_buffer, 0, size);
- }
- else
- {
- safe_buffer = buffer;
- }
- process_t *proc;
- if (handle == INVALID_HANDLE)
- {
- proc = get_current_process();
- reference(&proc->header);
- }
- else
- {
- if (!reference_by_handle(handle, OBJECT_PROCESS, (object_t**)&proc))
- {
- if (get_previous_mode() == USER_MODE) free(safe_buffer);
- return ERR_INVALID;
- }
- }
- switch (info_type)
- {
- case PROCESS_PID_INFO:
- {
- if (size >= sizeof(dword_t)) *((dword_t*)safe_buffer) = proc->pid;
- else ret = ERR_SMALLBUF;
- break;
- }
- case PROCESS_NAME_INFO:
- {
- if (size >= strlen(proc->name) + 1) strcpy(safe_buffer, proc->name);
- else ret = ERR_SMALLBUF;
- break;
- }
- case PROCESS_MEMORY_INFO:
- {
- ret = ERR_NOSYSCALL; // TODO
- break;
- }
- case PROCESS_START_TIME_INFO:
- {
- if (size >= sizeof(clock_time_t)) *((clock_time_t*)safe_buffer) = proc->start_time;
- else ret = ERR_SMALLBUF;
- break;
- }
- case PROCESS_EXIT_CODE_INFO:
- {
- if (size >= sizeof(dword_t)) *((dword_t*)safe_buffer) = proc->exit_code;
- else ret = ERR_SMALLBUF;
- break;
- }
- case PROCESS_USER_INFO:
- {
- if (size >= 2 * sizeof(dword_t))
- {
- ((dword_t*)safe_buffer)[0] = proc->original_user->uid;
- ((dword_t*)safe_buffer)[1] = proc->current_user->uid;
- }
- else
- {
- ret = ERR_SMALLBUF;
- }
- break;
- }
- case PROCESS_THREAD_INFO:
- {
- if (size >= sizeof(dword_t))
- {
- list_entry_t *ptr;
- dword_t i = 1, count = 0;
- acquire_resource_shared(&proc->thread_list_res);
- for (ptr = proc->threads.next; ptr != &proc->threads; ptr = ptr->next) count++;
- *((dword_t*)safe_buffer) = count;
- for (ptr = proc->threads.next; ptr != &proc->threads && i < (size / sizeof(dword_t)); ptr = ptr->next)
- {
- ((dword_t*)safe_buffer)[i++] = CONTAINER_OF(ptr, thread_t, in_process_list)->tid;
- }
- if (ptr != &proc->threads) ret = ERR_SMALLBUF;
- release_resource(&proc->thread_list_res);
- }
- else
- {
- ret = ERR_SMALLBUF;
- }
- break;
- }
- case PROCESS_HANDLE_INFO:
- {
- if (size >= sizeof(dword_t))
- {
- dword_t i, j = 1;
- acquire_resource_shared(&proc->handle_table_res);
- *((dword_t*)safe_buffer) = proc->handle_count;
- for (i = 0; i < proc->handle_table_size && j < (size / sizeof(dword_t)); i++)
- {
- if (proc->handle_table[i].obj) ((dword_t*)safe_buffer)[j++] = i;
- }
- if (i != proc->handle_table_size) ret = ERR_SMALLBUF;
- release_resource(&proc->handle_table_res);
- }
- else
- {
- ret = ERR_SMALLBUF;
- }
- break;
- }
- default:
- {
- ret = ERR_INVALID;
- }
- }
- if (get_previous_mode() == USER_MODE)
- {
- EH_TRY memcpy(buffer, safe_buffer, size);
- EH_CATCH ret = ERR_BADPTR;
- EH_DONE;
- free(safe_buffer);
- }
- dereference(&proc->header);
- return ret;
- }
- sysret_t syscall_enum_processes(dword_t *pid_array, dword_t *count)
- {
- dword_t ret = ERR_SUCCESS;
- dword_t safe_count;
- dword_t cnt = 0;
- if (get_previous_mode() == USER_MODE)
- {
- if (!check_usermode(count, sizeof(*count))) return ERR_BADPTR;
- EH_TRY safe_count = *count;
- EH_CATCH EH_ESCAPE(return ERR_BADPTR);
- EH_DONE;
- if (!check_usermode(pid_array, sizeof(*pid_array) * safe_count))
- {
- ret = ERR_BADPTR;
- goto cleanup;
- }
- }
- else
- {
- safe_count = *count;
- }
- process_t *proc = NULL;
- ret = enum_objects_by_type(OBJECT_PROCESS, (object_t**)&proc);
- while (ret == ERR_SUCCESS)
- {
- if (cnt == safe_count)
- {
- ret = ERR_SMALLBUF;
- break;
- }
- EH_TRY
- {
- pid_array[cnt++] = proc->pid;
- }
- EH_CATCH
- {
- ret = ERR_BADPTR;
- EH_ESCAPE(break);
- }
- EH_DONE;
- ret = enum_objects_by_type(OBJECT_PROCESS, (object_t**)&proc);
- }
- if (ret == ERR_NOMORE)
- {
- ret = ERR_SUCCESS;
- }
- else if (ret == ERR_SUCCESS)
- {
- dereference(&proc->header);
- ret = ERR_SMALLBUF;
- }
- cleanup:
- EH_TRY *count = cnt;
- EH_CATCH ret = ERR_BADPTR;
- EH_DONE;
- return ret;
- }
- sysret_t syscall_wait_process(handle_t handle, dword_t timeout)
- {
- dword_t ret;
- process_t *proc;
- if (handle == INVALID_HANDLE)
- {
- proc = get_current_process();
- reference(&proc->header);
- }
- else
- {
- if (!reference_by_handle(handle, OBJECT_PROCESS, (object_t**)&proc)) return ERR_INVALID;
- }
- ret = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, &proc->terminated, 0);
- dereference(&proc->header);
- return ret;
- }
- process_t *switch_process(process_t *new_process)
- {
- thread_t *thread = get_current_thread();
- process_t *old_process = get_current_process();
- while (!__sync_bool_compare_and_swap(&thread->owner_process, old_process, new_process))
- {
- old_process = get_current_process();
- }
- set_page_directory(new_process->memory_space.page_directory);
- return old_process;
- }
- void process_init(char *root_directory)
- {
- memset(pid_alloc_bitmap, 0, sizeof(pid_alloc_bitmap));
- kernel_process = (process_t*)malloc(sizeof(process_t));
- ASSERT(kernel_process != NULL);
- memset(kernel_process, 0, sizeof(process_t));
- kernel_process->header.name = NULL;
- kernel_process->header.type = OBJECT_PROCESS;
- ASSERT(create_object(&kernel_process->header) == ERR_SUCCESS);
- kernel_process->pid = 0;
- set_bit(pid_alloc_bitmap, 0);
- kernel_process->name = strdup("system");
- memset(&kernel_process->memory_space, 0, sizeof(memory_address_space_t));
- kernel_process->memory_space.page_directory = get_page_directory();
- kernel_process->exit_code = 0;
- kernel_process->terminating = FALSE;
- kernel_process->terminated = FALSE;
- syscall_clock_get_time(&kernel_process->start_time);
- list_init(&kernel_process->threads);
- kernel_process->thread_list_res = 0;
- kernel_process->handle_table = (handle_info_t*)heap_alloc(&evictable_heap, STARTUP_HANDLE_TABLE_SIZE);
- kernel_process->handle_table_size = STARTUP_HANDLE_TABLE_SIZE;
- kernel_process->handle_count = 0;
- kernel_process->handle_table_res = 0;
- }
|