Kernel: Add argc and argv to process entry

This commit is contained in:
Bananymous 2023-05-16 00:27:49 +03:00
parent e0a7e242f8
commit e0a72defa2
10 changed files with 165 additions and 92 deletions

View File

@ -25,13 +25,14 @@ continue_thread:
movq $0, %rax movq $0, %rax
jmp *%rsi jmp *%rsi
# void thread_jump_userspace(uint64_t rsp, uint64_t rip) # void thread_userspace_trampoline(uint64_t rsp, uint64_t rip, int argc, char** argv)
.global thread_jump_userspace .global thread_userspace_trampoline
thread_jump_userspace: thread_userspace_trampoline:
pushq $0x23 pushq $0x23
pushq %rdi pushq %rdi
pushfq pushfq
pushq $0x1B pushq $0x1B
pushq %rsi pushq %rsi
movq $0, %rdi movq %rdx, %rdi
movq %rcx, %rsi
iretq iretq

View File

@ -2,6 +2,7 @@
#include <BAN/NoCopyMove.h> #include <BAN/NoCopyMove.h>
#include <BAN/RefPtr.h> #include <BAN/RefPtr.h>
#include <kernel/Memory/Heap.h>
#include <sys/types.h> #include <sys/types.h>
@ -27,11 +28,9 @@ namespace Kernel
public: public:
static BAN::ErrorOr<Thread*> create(entry_t, void*, Process*); static BAN::ErrorOr<Thread*> create(entry_t, void*, Process*);
static BAN::ErrorOr<Thread*> create_userspace(uintptr_t, Process*); static BAN::ErrorOr<Thread*> create_userspace(uintptr_t, Process*, int, char**);
~Thread(); ~Thread();
void jump_userspace(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(); }
@ -44,7 +43,7 @@ namespace Kernel
void terminate() { m_state = State::Terminating; } void terminate() { m_state = State::Terminating; }
uintptr_t stack_base() const { return (uintptr_t)m_stack_base; } uintptr_t stack_base() const { return (uintptr_t)m_stack_base; }
size_t stack_size() const { return m_stack_size; } size_t stack_size() const { return m_is_userspace ? m_userspace_stack_size : m_kernel_stack_size; }
uintptr_t interrupt_stack_base() const { return (uintptr_t)m_interrupt_stack; } uintptr_t interrupt_stack_base() const { return (uintptr_t)m_interrupt_stack; }
uintptr_t interrupt_stack_size() const { return m_interrupt_stack_size; } uintptr_t interrupt_stack_size() const { return m_interrupt_stack_size; }
@ -57,23 +56,33 @@ namespace Kernel
private: private:
Thread(pid_t tid, Process*); Thread(pid_t tid, Process*);
void on_exit();
void validate_stack() const; void validate_stack() const;
BAN::ErrorOr<void> initialize(entry_t, void*); private:
void on_exit(); struct userspace_entry_t
{
uintptr_t entry;
int argc { 0 };
char** argv { 0 };
};
private: private:
static constexpr size_t m_stack_size = 4096 * 1; static constexpr size_t m_kernel_stack_size = PAGE_SIZE * 1;
static constexpr size_t m_interrupt_stack_size = 4096; static constexpr size_t m_userspace_stack_size = PAGE_SIZE * 1;
void* m_interrupt_stack { nullptr }; static constexpr size_t m_interrupt_stack_size = PAGE_SIZE;
void* m_stack_base { nullptr }; vaddr_t m_interrupt_stack { 0 };
vaddr_t m_stack_base { 0 };
uintptr_t m_rip { 0 }; uintptr_t m_rip { 0 };
uintptr_t m_rsp { 0 }; uintptr_t m_rsp { 0 };
const pid_t m_tid { 0 }; const pid_t m_tid { 0 };
State m_state { State::NotStarted }; State m_state { State::NotStarted };
Process* m_process { nullptr }; Process* m_process { nullptr };
bool m_in_syscall { false }; bool m_in_syscall { false };
bool m_is_userspace { false };
userspace_entry_t m_userspace_entry;
friend class Scheduler; friend class Scheduler;
}; };

View File

@ -1,6 +1,7 @@
#include <kernel/CriticalScope.h> #include <kernel/CriticalScope.h>
#include <kernel/Memory/FixedWidthAllocator.h> #include <kernel/Memory/FixedWidthAllocator.h>
#include <kernel/Memory/MMU.h> #include <kernel/Memory/MMU.h>
#include <kernel/Memory/MMUScope.h>
#include <kernel/Process.h> #include <kernel/Process.h>
namespace Kernel namespace Kernel
@ -20,9 +21,7 @@ namespace Kernel
m_allocated_pages = m_mmu.get_free_page(); m_allocated_pages = m_mmu.get_free_page();
m_mmu.map_page_at(allocated_pages_paddr, m_allocated_pages, MMU::Flags::ReadWrite | MMU::Flags::Present); m_mmu.map_page_at(allocated_pages_paddr, m_allocated_pages, MMU::Flags::ReadWrite | MMU::Flags::Present);
CriticalScope _; MMUScope _(m_mmu);
m_mmu.load();
memset((void*)m_nodes_page, 0, PAGE_SIZE); memset((void*)m_nodes_page, 0, PAGE_SIZE);
memset((void*)m_allocated_pages, 0, PAGE_SIZE); memset((void*)m_allocated_pages, 0, PAGE_SIZE);
@ -38,8 +37,6 @@ namespace Kernel
m_free_list = node_table; m_free_list = node_table;
m_used_list = nullptr; m_used_list = nullptr;
Process::current().mmu().load();
} }
FixedWidthAllocator::~FixedWidthAllocator() FixedWidthAllocator::~FixedWidthAllocator()

View File

@ -3,6 +3,7 @@
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h> #include <kernel/LockGuard.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/MMUScope.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <LibELF/ELF.h> #include <LibELF/ELF.h>
@ -87,11 +88,9 @@ namespace Kernel
} }
{ {
CriticalScope _; MMUScope _(process->mmu());
process->mmu().load();
memcpy((void*)elf_program_header.p_vaddr, elf->data() + elf_program_header.p_offset, elf_program_header.p_filesz); memcpy((void*)elf_program_header.p_vaddr, elf->data() + elf_program_header.p_offset, elf_program_header.p_filesz);
memset((void*)(elf_program_header.p_vaddr + elf_program_header.p_filesz), 0, elf_program_header.p_memsz - elf_program_header.p_filesz); memset((void*)(elf_program_header.p_vaddr + elf_program_header.p_filesz), 0, elf_program_header.p_memsz - elf_program_header.p_filesz);
Process::current().mmu().load();
} }
break; break;
} }
@ -100,7 +99,16 @@ namespace Kernel
} }
} }
auto* thread = MUST(Thread::create_userspace(elf_file_header.e_entry, process)); char** argv = nullptr;
{
MMUScope _(process->mmu());
argv = (char**)MUST(process->allocate(sizeof(char**) * 1));
argv[0] = (char*)MUST(process->allocate(path.size() + 1));
memcpy(argv[0], path.data(), path.size());
argv[0][path.size()] = '\0';
}
auto* thread = MUST(Thread::create_userspace(elf_file_header.e_entry, process, 1, argv));
process->add_thread(thread); process->add_thread(thread);
delete elf; delete elf;

View File

@ -1,16 +1,15 @@
#include <BAN/Errors.h> #include <BAN/Errors.h>
#include <kernel/CriticalScope.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/Memory/kmalloc.h> #include <kernel/Memory/kmalloc.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
#define PAGE_SIZE 4096
namespace Kernel namespace Kernel
{ {
extern "C" void thread_jump_userspace(uintptr_t rsp, uintptr_t rip); extern "C" void thread_userspace_trampoline(uint64_t rsp, uint64_t rip, int argc, char** argv);
template<size_t size, typename T> template<size_t size, typename T>
static void write_to_stack(uintptr_t& rsp, const T& value) static void write_to_stack(uintptr_t& rsp, const T& value)
@ -19,32 +18,66 @@ namespace Kernel
memcpy((void*)rsp, (void*)&value, size); memcpy((void*)rsp, (void*)&value, size);
} }
static pid_t s_next_tid = 1;
BAN::ErrorOr<Thread*> Thread::create(entry_t entry, void* data, Process* process) BAN::ErrorOr<Thread*> Thread::create(entry_t entry, void* data, Process* process)
{ {
static pid_t next_tid = 1; // Create the thread object
auto* thread = new Thread(next_tid++, process); Thread* thread = new Thread(s_next_tid++, process);
if (thread == nullptr) if (thread == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
TRY(thread->initialize(entry, data));
// Initialize stack and registers
thread->m_stack_base = (vaddr_t)kmalloc(m_kernel_stack_size, PAGE_SIZE);
if (thread->m_stack_base == 0)
return BAN::Error::from_errno(ENOMEM);
thread->m_rsp = (uintptr_t)thread->m_stack_base + m_kernel_stack_size;
thread->m_rip = (uintptr_t)entry;
// Initialize stack for returning
write_to_stack<sizeof(void*)>(thread->m_rsp, thread);
write_to_stack<sizeof(void*)>(thread->m_rsp, &Thread::on_exit);
write_to_stack<sizeof(void*)>(thread->m_rsp, data);
return thread; return thread;
} }
BAN::ErrorOr<Thread*> Thread::create_userspace(uintptr_t entry, Process* process) BAN::ErrorOr<Thread*> Thread::create_userspace(uintptr_t entry, Process* process, int argc, char** argv)
{ {
Thread* thread = TRY(Thread::create( // Create the thread object
[](void* entry) Thread* thread = new Thread(s_next_tid++, process);
{ if (thread == nullptr)
Thread::current().jump_userspace((uintptr_t)entry);
ASSERT_NOT_REACHED();
}, (void*)entry, process
));
thread->m_interrupt_stack = kmalloc(m_interrupt_stack_size, PAGE_SIZE);
if (thread->m_interrupt_stack == nullptr)
{
delete thread;
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
} thread->m_is_userspace = true;
process->mmu().identity_map_range(thread->stack_base(), thread->stack_size(), MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present);
// Allocate stack
thread->m_stack_base = (uintptr_t)kmalloc(m_userspace_stack_size, PAGE_SIZE);
ASSERT(thread->m_stack_base);
process->mmu().identity_map_range(thread->m_stack_base, m_userspace_stack_size, MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present);
// Allocate interrupt stack
thread->m_interrupt_stack = (vaddr_t)kmalloc(m_interrupt_stack_size, PAGE_SIZE);
ASSERT(thread->m_interrupt_stack);
thread->m_userspace_entry = { .entry = entry, .argc = argc, .argv = argv };
// Setup registers and entry
static entry_t entry_trampoline(
[](void*)
{
userspace_entry_t& entry = Thread::current().m_userspace_entry;
thread_userspace_trampoline(Thread::current().rsp(), entry.entry, entry.argc, entry.argv);
ASSERT_NOT_REACHED();
}
);
thread->m_rsp = thread->m_stack_base + m_userspace_stack_size;
thread->m_rip = (uintptr_t)entry_trampoline;
// Setup stack for returning
write_to_stack<sizeof(void*)>(thread->m_rsp, thread);
write_to_stack<sizeof(void*)>(thread->m_rsp, &Thread::on_exit);
write_to_stack<sizeof(void*)>(thread->m_rsp, nullptr);
return thread; return thread;
} }
@ -63,32 +96,13 @@ namespace Kernel
return *m_process; return *m_process;
} }
BAN::ErrorOr<void> Thread::initialize(entry_t entry, void* data)
{
m_stack_base = kmalloc(m_stack_size, PAGE_SIZE);
if (m_stack_base == nullptr)
return BAN::Error::from_errno(ENOMEM);
m_rsp = (uintptr_t)m_stack_base + m_stack_size;
m_rip = (uintptr_t)entry;
write_to_stack<sizeof(void*)>(m_rsp, this);
write_to_stack<sizeof(void*)>(m_rsp, &Thread::on_exit);
write_to_stack<sizeof(void*)>(m_rsp, data);
return {};
}
Thread::~Thread() Thread::~Thread()
{ {
dprintln("thread {} ({}) exit", tid(), m_process->pid()); dprintln("thread {} ({}) exit", tid(), m_process->pid());
if (m_interrupt_stack)
kfree(m_interrupt_stack);
kfree(m_stack_base);
}
void Thread::jump_userspace(uintptr_t rip) if (m_interrupt_stack)
{ kfree((void*)m_interrupt_stack);
thread_jump_userspace(rsp(), rip); kfree((void*)m_stack_base);
} }
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/test"sv)); MUST(Process::create_userspace("/usr/bin/cat"sv));
return; return;
Process::create_kernel( Process::create_kernel(

View File

@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.26)
project(userspace CXX) project(userspace CXX)
set(USERSPACE_PROJECTS set(USERSPACE_PROJECTS
cat
test test
yes yes
) )

View File

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.26)
project(cat CXX)
set(SOURCES
main.cpp
)
add_executable(cat ${SOURCES})
target_compile_options(cat PUBLIC -O2 -g)
add_dependencies(cat libc-install)
target_link_options(cat PUBLIC -nodefaultlibs -lc)
add_custom_target(cat-install
COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/cat ${BANAN_BIN}/
DEPENDS cat
)

50
userspace/cat/main.cpp Normal file
View File

@ -0,0 +1,50 @@
#include <stdio.h>
bool cat_file(FILE* fp)
{
char buffer[1024];
size_t n_read;
while ((n_read = fread(buffer, 1, sizeof(buffer) - 1, fp)) > 0)
{
buffer[n_read] = '\0';
fputs(buffer, stdout);
}
if (ferror(fp))
{
perror("fread");
return false;
}
return true;
}
int main(int argc, char** argv)
{
int ret = 0;
printf("argc %d, argv %p\n", argc, argv);
for (int i = 0; i < argc; i++)
printf("%s\n", argv[i]);
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
FILE* fp = fopen(argv[i], "r");
if (fp == nullptr)
{
perror(argv[i]);
ret = 1;
continue;
}
if (cat_file(fp))
ret = 1;
fclose(fp);
}
}
else
{
ret = cat_file(stdin);
}
return ret;
}

View File

@ -1,36 +1,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.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()
{ {
printf("%.2e\n", 1230.0);
printf("%.2e\n", 123.0);
printf("%.2e\n", 12.3);
printf("%.2e\n", 1.23);
printf("%.2e\n", 0.123);
printf("%.2e\n", 0.0123);
printf("%.2e\n", 0.00123);
printf("%e\n", 123.456);
printf("%.2e\n", 123.456);
printf("%.0e\n", 123.456);
printf("%#.0e\n", 123.456);
printf("%e\n", -123.456);
printf("%.2e\n", -123.456);
printf("%.0e\n", -123.456);
printf("%#.0e\n", -123.456);
printf("%e\n", 0.0);
printf("%e\n", -0.0);
return 0;
FILE* fp = fopen("/usr/include/stdio.h", "r"); FILE* fp = fopen("/usr/include/stdio.h", "r");
if (fp == NULL) if (fp == NULL)
ERROR("fopen"); ERROR("fopen");