Kernel: Add bareboness fork() function
This commit is contained in:
parent
3e93dae53c
commit
f2d767b799
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue