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/StorageDevice.cpp
kernel/Syscall.cpp
kernel/Syscall.S
kernel/Thread.cpp
kernel/Terminal/TTY.cpp
kernel/Terminal/VesaTerminalDriver.cpp

View File

@ -17,4 +17,8 @@
#define read_rsp(rsp) asm volatile("movl %%esp, %0" : "=r"(rsp))
#define push_callee_saved() asm volatile("pushal")
#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; }
BAN::ErrorOr<Process*> fork(uintptr_t rsp, uintptr_t rip);
BAN::ErrorOr<int> open(BAN::StringView, int);
BAN::ErrorOr<void> close(int fd);
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**);
~Thread();
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t rsp, uintptr_t rip);
pid_t tid() const { return m_tid; }
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++)
{
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);
}
m_mmu.unmap_page(0);
m_mmu.invalidate(0);
return result;
}

View File

@ -129,6 +129,8 @@ namespace Kernel
MMU::kernel().load();
delete m_mmu;
}
dprintln("process {} exit", pid());
}
void Process::add_thread(Thread* thread)
@ -167,8 +169,6 @@ namespace Kernel
m_general_allocator = nullptr;
}
dprintln("process {} exit", pid());
s_process_lock.lock();
for (size_t i = 0; i < s_processes.size(); i++)
if (s_processes[i] == this)
@ -197,6 +197,40 @@ namespace Kernel
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)
{
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 continue_thread(uintptr_t rsp, uintptr_t rip);
extern "C" uintptr_t read_rip();
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;
}
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)
{
Thread::current().set_in_syscall(true);
@ -149,6 +159,9 @@ namespace Kernel
case SYS_SET_TERMIOS:
ret = sys_set_termios((const ::termios*)arg1);
break;
case SYS_FORK:
ret = sys_fork_trampoline();
break;
default:
Kernel::panic("Unknown syscall {}", syscall);
}

View File

@ -111,13 +111,38 @@ namespace Kernel
Thread::~Thread()
{
dprintln("thread {} ({}) exit", tid(), m_process->pid());
if (m_stack)
delete m_stack;
m_stack = nullptr;
if (m_interrupt_stack)
delete m_interrupt_stack;
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

View File

@ -126,7 +126,7 @@ extern "C" void kernel_main()
dprintln("GDT initialized");
IDT::initialize();
dprintln("IDT initialized");
dprintln("IDT initialized");
MMU::initialize();
dprintln("MMU initialized");
@ -180,7 +180,7 @@ static void init2(void* tty1)
((TTY*)tty1)->initialize_device();
MUST(Process::create_userspace("/usr/bin/Shell"sv));
MUST(Process::create_userspace("/usr/bin/test"sv));
return;
Process::create_kernel(

View File

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

View File

@ -103,6 +103,11 @@ long syscall(long syscall, ...)
ret = Kernel::syscall(SYS_SET_TERMIOS, (uintptr_t)termios);
break;
}
case SYS_FORK:
{
ret = Kernel::syscall(SYS_FORK);
break;
}
default:
puts("LibC: Unhandeled syscall");
ret = -ENOSYS;
@ -122,25 +127,5 @@ long syscall(long syscall, ...)
pid_t fork(void)
{
return -1;
}
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;
return syscall(SYS_FORK);
}

View File

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