Kernel: Add bareboness fork() function

This commit is contained in:
Bananymous 2023-05-28 18:08:26 +03:00
parent 3e93dae53c
commit f2d767b799
14 changed files with 125 additions and 44 deletions

View File

@ -48,6 +48,7 @@ set(KERNEL_SOURCES
kernel/Storage/ATADevice.cpp kernel/Storage/ATADevice.cpp
kernel/Storage/StorageDevice.cpp kernel/Storage/StorageDevice.cpp
kernel/Syscall.cpp kernel/Syscall.cpp
kernel/Syscall.S
kernel/Thread.cpp kernel/Thread.cpp
kernel/Terminal/TTY.cpp kernel/Terminal/TTY.cpp
kernel/Terminal/VesaTerminalDriver.cpp kernel/Terminal/VesaTerminalDriver.cpp

View File

@ -18,3 +18,7 @@
#define push_callee_saved() asm volatile("pushal") #define push_callee_saved() asm volatile("pushal")
#define pop_callee_saved() asm volatile("popal") #define pop_callee_saved() asm volatile("popal")
#endif #endif
#include <stdint.h>
extern "C" uintptr_t read_rip();

View File

@ -41,6 +41,8 @@ namespace Kernel
pid_t pid() const { return m_pid; } pid_t pid() const { return m_pid; }
BAN::ErrorOr<Process*> fork(uintptr_t rsp, uintptr_t rip);
BAN::ErrorOr<int> open(BAN::StringView, int); BAN::ErrorOr<int> open(BAN::StringView, int);
BAN::ErrorOr<void> close(int fd); BAN::ErrorOr<void> close(int fd);
BAN::ErrorOr<size_t> read(int fd, void* buffer, size_t count); BAN::ErrorOr<size_t> read(int fd, void* buffer, size_t count);

View File

@ -31,6 +31,8 @@ namespace Kernel
static BAN::ErrorOr<Thread*> create_userspace(uintptr_t, Process*, int, char**); static BAN::ErrorOr<Thread*> create_userspace(uintptr_t, Process*, int, char**);
~Thread(); ~Thread();
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t rsp, uintptr_t rip);
pid_t tid() const { return m_tid; } pid_t tid() const { return m_tid; }
void set_rsp(uintptr_t rsp) { m_rsp = rsp; validate_stack(); } void set_rsp(uintptr_t rsp) { m_rsp = rsp; validate_stack(); }

View File

@ -83,9 +83,11 @@ namespace Kernel
for (size_t i = 0; i < result->m_physical_pages.size(); i++) for (size_t i = 0; i < result->m_physical_pages.size(); i++)
{ {
m_mmu.map_page_at(result->m_physical_pages[i], 0, MMU::Flags::ReadWrite | MMU::Flags::Present); m_mmu.map_page_at(result->m_physical_pages[i], 0, MMU::Flags::ReadWrite | MMU::Flags::Present);
m_mmu.invalidate(0);
memcpy((void*)0, (void*)(vaddr() + i * PAGE_SIZE), PAGE_SIZE); memcpy((void*)0, (void*)(vaddr() + i * PAGE_SIZE), PAGE_SIZE);
} }
m_mmu.unmap_page(0); m_mmu.unmap_page(0);
m_mmu.invalidate(0);
return result; return result;
} }

View File

@ -129,6 +129,8 @@ namespace Kernel
MMU::kernel().load(); MMU::kernel().load();
delete m_mmu; delete m_mmu;
} }
dprintln("process {} exit", pid());
} }
void Process::add_thread(Thread* thread) void Process::add_thread(Thread* thread)
@ -167,8 +169,6 @@ namespace Kernel
m_general_allocator = nullptr; m_general_allocator = nullptr;
} }
dprintln("process {} exit", pid());
s_process_lock.lock(); s_process_lock.lock();
for (size_t i = 0; i < s_processes.size(); i++) for (size_t i = 0; i < s_processes.size(); i++)
if (s_processes[i] == this) if (s_processes[i] == this)
@ -197,6 +197,40 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<Process*> Process::fork(uintptr_t rsp, uintptr_t rip)
{
LockGuard _(m_lock);
Process* forked = create_process();
forked->m_tty = m_tty;
forked->m_working_directory = m_working_directory;
forked->m_open_files = m_open_files;
forked->m_mmu = new MMU();
ASSERT(forked->m_mmu);
for (auto* mapped_range : m_mapped_ranges)
MUST(forked->m_mapped_ranges.push_back(mapped_range->clone(forked->mmu())));
ASSERT(m_threads.size() == 1);
ASSERT(m_threads.front() == &Thread::current());
//for (auto& allocator : m_fixed_width_allocators)
// MUST(forked->m_fixed_width_allocators.push_back(allocator.clone()));
//if (m_general_allocator)
// forked->m_general_allocator = m_general_allocator->clone();
Thread* thread = MUST(m_threads.front()->clone(forked, rsp, rip));
forked->add_thread(thread);
register_process(forked);
return forked;
}
BAN::ErrorOr<int> Process::open(BAN::StringView path, int flags) BAN::ErrorOr<int> Process::open(BAN::StringView path, int flags)
{ {
if (flags & ~O_RDWR) if (flags & ~O_RDWR)

View File

@ -19,7 +19,6 @@ namespace Kernel
extern "C" [[noreturn]] void start_thread(uintptr_t rsp, uintptr_t rip); extern "C" [[noreturn]] void start_thread(uintptr_t rsp, uintptr_t rip);
extern "C" [[noreturn]] void continue_thread(uintptr_t rsp, uintptr_t rip); extern "C" [[noreturn]] void continue_thread(uintptr_t rsp, uintptr_t rip);
extern "C" uintptr_t read_rip();
static Scheduler* s_instance = nullptr; static Scheduler* s_instance = nullptr;

22
kernel/kernel/Syscall.S Normal file
View File

@ -0,0 +1,22 @@
.global sys_fork_trampoline
sys_fork_trampoline:
pushq %rbx
pushq %rbp
pushq %r12
pushq %r13
pushq %r14
pushq %r15
call read_rip
testq %rax, %rax
je .done
movq %rax, %rsi
movq %rsp, %rdi
call sys_fork
.done:
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbp
popq %rbx
ret

View File

@ -98,6 +98,16 @@ namespace Kernel
return 0; return 0;
} }
extern "C" long sys_fork(uintptr_t rsp, uintptr_t rip)
{
auto ret = Process::current().fork(rsp, rip);
if (ret.is_error())
return -ret.error().get_error_code();
return ret.value()->pid();
}
extern "C" long sys_fork_trampoline();
extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5) extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
{ {
Thread::current().set_in_syscall(true); Thread::current().set_in_syscall(true);
@ -149,6 +159,9 @@ namespace Kernel
case SYS_SET_TERMIOS: case SYS_SET_TERMIOS:
ret = sys_set_termios((const ::termios*)arg1); ret = sys_set_termios((const ::termios*)arg1);
break; break;
case SYS_FORK:
ret = sys_fork_trampoline();
break;
default: default:
Kernel::panic("Unknown syscall {}", syscall); Kernel::panic("Unknown syscall {}", syscall);
} }

View File

@ -111,13 +111,38 @@ namespace Kernel
Thread::~Thread() Thread::~Thread()
{ {
dprintln("thread {} ({}) exit", tid(), m_process->pid());
if (m_stack) if (m_stack)
delete m_stack; delete m_stack;
m_stack = nullptr; m_stack = nullptr;
if (m_interrupt_stack) if (m_interrupt_stack)
delete m_interrupt_stack; delete m_interrupt_stack;
m_interrupt_stack = nullptr; m_interrupt_stack = nullptr;
dprintln("thread {} ({}) exit", tid(), m_process->pid());
}
BAN::ErrorOr<Thread*> Thread::clone(Process* new_process, uintptr_t rsp, uintptr_t rip)
{
ASSERT(m_is_userspace);
ASSERT(m_state == State::Executing);
Thread* thread = new Thread(s_next_tid++, new_process);
if (thread == nullptr)
return BAN::Error::from_errno(ENOMEM);
thread->m_is_userspace = true;
thread->m_interrupt_stack = m_interrupt_stack->clone(new_process->mmu());
thread->m_stack = m_stack->clone(new_process->mmu());
thread->m_state = State::Executing;
thread->m_in_syscall = true;
thread->m_rip = rip;
thread->m_rsp = rsp;
thread->m_userspace_entry = {};
return thread;
} }
void Thread::validate_stack() const void Thread::validate_stack() const

View File

@ -180,7 +180,7 @@ static void init2(void* tty1)
((TTY*)tty1)->initialize_device(); ((TTY*)tty1)->initialize_device();
MUST(Process::create_userspace("/usr/bin/Shell"sv)); MUST(Process::create_userspace("/usr/bin/test"sv));
return; return;
Process::create_kernel( Process::create_kernel(

View File

@ -17,6 +17,7 @@ __BEGIN_DECLS
#define SYS_TELL 10 #define SYS_TELL 10
#define SYS_GET_TERMIOS 11 #define SYS_GET_TERMIOS 11
#define SYS_SET_TERMIOS 12 #define SYS_SET_TERMIOS 12
#define SYS_FORK 13
__END_DECLS __END_DECLS

View File

@ -103,6 +103,11 @@ long syscall(long syscall, ...)
ret = Kernel::syscall(SYS_SET_TERMIOS, (uintptr_t)termios); ret = Kernel::syscall(SYS_SET_TERMIOS, (uintptr_t)termios);
break; break;
} }
case SYS_FORK:
{
ret = Kernel::syscall(SYS_FORK);
break;
}
default: default:
puts("LibC: Unhandeled syscall"); puts("LibC: Unhandeled syscall");
ret = -ENOSYS; ret = -ENOSYS;
@ -122,25 +127,5 @@ long syscall(long syscall, ...)
pid_t fork(void) pid_t fork(void)
{ {
return -1; return syscall(SYS_FORK);
}
int execv(const char*, char* const[])
{
return -1;
}
int execve(const char*, char* const[], char* const[])
{
return -1;
}
int execvp(const char*, char* const[])
{
return -1;
}
pid_t getpid(void)
{
return -1;
} }

View File

@ -1,31 +1,22 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#define ERROR(msg) { perror(msg); return 1; } #define ERROR(msg) { perror(msg); return 1; }
#define BUF_SIZE 1024 #define BUF_SIZE 1024
int main() int main()
{ {
FILE* fp = fopen("/usr/include/stdio.h", "r"); printf("forking\n");
if (fp == NULL)
ERROR("fopen");
char* buffer = (char*)malloc(BUF_SIZE); pid_t pid = fork();
if (buffer == NULL) if (pid == 0)
ERROR("malloc");
for (;;)
{ {
size_t n_read = fread(buffer, 1, BUF_SIZE - 1, fp); printf("child\n");
if (n_read == 0) return 0;
break;
buffer[n_read] = '\0';
printf("%s", buffer);
} }
printf("parent\n");
free(buffer);
fclose(fp);
return 0; return 0;
} }