From e0a72defa2003a985d4bf8d523ba7dce7ff578d4 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 16 May 2023 00:27:49 +0300 Subject: [PATCH] Kernel: Add argc and argv to process entry --- kernel/arch/x86_64/Thread.S | 9 +- kernel/include/kernel/Thread.h | 33 ++++--- kernel/kernel/Memory/FixedWidthAllocator.cpp | 7 +- kernel/kernel/Process.cpp | 16 +++- kernel/kernel/Thread.cpp | 98 +++++++++++--------- kernel/kernel/kernel.cpp | 2 +- userspace/CMakeLists.txt | 1 + userspace/cat/CMakeLists.txt | 17 ++++ userspace/cat/main.cpp | 50 ++++++++++ userspace/test/test.cpp | 24 ----- 10 files changed, 165 insertions(+), 92 deletions(-) create mode 100644 userspace/cat/CMakeLists.txt create mode 100644 userspace/cat/main.cpp diff --git a/kernel/arch/x86_64/Thread.S b/kernel/arch/x86_64/Thread.S index 6ca2e202..3a5a934e 100644 --- a/kernel/arch/x86_64/Thread.S +++ b/kernel/arch/x86_64/Thread.S @@ -25,13 +25,14 @@ continue_thread: movq $0, %rax jmp *%rsi -# void thread_jump_userspace(uint64_t rsp, uint64_t rip) -.global thread_jump_userspace -thread_jump_userspace: +# void thread_userspace_trampoline(uint64_t rsp, uint64_t rip, int argc, char** argv) +.global thread_userspace_trampoline +thread_userspace_trampoline: pushq $0x23 pushq %rdi pushfq pushq $0x1B pushq %rsi - movq $0, %rdi + movq %rdx, %rdi + movq %rcx, %rsi iretq diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index ce99d8c6..12e28dcf 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -27,11 +28,9 @@ namespace Kernel public: static BAN::ErrorOr create(entry_t, void*, Process*); - static BAN::ErrorOr create_userspace(uintptr_t, Process*); + static BAN::ErrorOr create_userspace(uintptr_t, Process*, int, char**); ~Thread(); - void jump_userspace(uintptr_t rip); - pid_t tid() const { return m_tid; } void set_rsp(uintptr_t rsp) { m_rsp = rsp; validate_stack(); } @@ -44,7 +43,7 @@ namespace Kernel void terminate() { m_state = State::Terminating; } 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_size() const { return m_interrupt_stack_size; } @@ -57,23 +56,33 @@ namespace Kernel private: Thread(pid_t tid, Process*); - - void validate_stack() const; - - BAN::ErrorOr initialize(entry_t, void*); void on_exit(); + void validate_stack() const; + private: - static constexpr size_t m_stack_size = 4096 * 1; - static constexpr size_t m_interrupt_stack_size = 4096; - void* m_interrupt_stack { nullptr }; - void* m_stack_base { nullptr }; + struct userspace_entry_t + { + uintptr_t entry; + int argc { 0 }; + char** argv { 0 }; + }; + + private: + static constexpr size_t m_kernel_stack_size = PAGE_SIZE * 1; + static constexpr size_t m_userspace_stack_size = PAGE_SIZE * 1; + static constexpr size_t m_interrupt_stack_size = PAGE_SIZE; + vaddr_t m_interrupt_stack { 0 }; + vaddr_t m_stack_base { 0 }; uintptr_t m_rip { 0 }; uintptr_t m_rsp { 0 }; const pid_t m_tid { 0 }; State m_state { State::NotStarted }; Process* m_process { nullptr }; bool m_in_syscall { false }; + bool m_is_userspace { false }; + + userspace_entry_t m_userspace_entry; friend class Scheduler; }; diff --git a/kernel/kernel/Memory/FixedWidthAllocator.cpp b/kernel/kernel/Memory/FixedWidthAllocator.cpp index 06cded09..3b92c190 100644 --- a/kernel/kernel/Memory/FixedWidthAllocator.cpp +++ b/kernel/kernel/Memory/FixedWidthAllocator.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace Kernel @@ -20,9 +21,7 @@ namespace Kernel 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); - CriticalScope _; - - m_mmu.load(); + MMUScope _(m_mmu); memset((void*)m_nodes_page, 0, PAGE_SIZE); memset((void*)m_allocated_pages, 0, PAGE_SIZE); @@ -38,8 +37,6 @@ namespace Kernel m_free_list = node_table; m_used_list = nullptr; - - Process::current().mmu().load(); } FixedWidthAllocator::~FixedWidthAllocator() diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index a3c9b0d8..fa197fa5 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -87,11 +88,9 @@ namespace Kernel } { - CriticalScope _; - process->mmu().load(); + MMUScope _(process->mmu()); 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); - Process::current().mmu().load(); } 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); delete elf; diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index bfb5adbd..4ae9dc7a 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -1,16 +1,15 @@ #include +#include #include #include #include #include #include -#define PAGE_SIZE 4096 - 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 static void write_to_stack(uintptr_t& rsp, const T& value) @@ -19,32 +18,66 @@ namespace Kernel memcpy((void*)rsp, (void*)&value, size); } + static pid_t s_next_tid = 1; + BAN::ErrorOr Thread::create(entry_t entry, void* data, Process* process) { - static pid_t next_tid = 1; - auto* thread = new Thread(next_tid++, process); + // Create the thread object + Thread* thread = new Thread(s_next_tid++, process); if (thread == nullptr) 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(thread->m_rsp, thread); + write_to_stack(thread->m_rsp, &Thread::on_exit); + write_to_stack(thread->m_rsp, data); + return thread; } - BAN::ErrorOr Thread::create_userspace(uintptr_t entry, Process* process) + BAN::ErrorOr Thread::create_userspace(uintptr_t entry, Process* process, int argc, char** argv) { - Thread* thread = TRY(Thread::create( - [](void* entry) - { - 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; + // Create the thread object + Thread* thread = new Thread(s_next_tid++, process); + if (thread == nullptr) return BAN::Error::from_errno(ENOMEM); - } - process->mmu().identity_map_range(thread->stack_base(), thread->stack_size(), MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present); + thread->m_is_userspace = true; + + // 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(thread->m_rsp, thread); + write_to_stack(thread->m_rsp, &Thread::on_exit); + write_to_stack(thread->m_rsp, nullptr); + return thread; } @@ -63,32 +96,13 @@ namespace Kernel return *m_process; } - BAN::ErrorOr 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(m_rsp, this); - write_to_stack(m_rsp, &Thread::on_exit); - write_to_stack(m_rsp, data); - - return {}; - } - Thread::~Thread() { 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) - { - thread_jump_userspace(rsp(), rip); + if (m_interrupt_stack) + kfree((void*)m_interrupt_stack); + kfree((void*)m_stack_base); } void Thread::validate_stack() const diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 2d238fd0..71b8eab6 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -180,7 +180,7 @@ static void init2(void* tty1) ((TTY*)tty1)->initialize_device(); - MUST(Process::create_userspace("/usr/bin/test"sv)); + MUST(Process::create_userspace("/usr/bin/cat"sv)); return; Process::create_kernel( diff --git a/userspace/CMakeLists.txt b/userspace/CMakeLists.txt index 45c23650..add6c6be 100644 --- a/userspace/CMakeLists.txt +++ b/userspace/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.26) project(userspace CXX) set(USERSPACE_PROJECTS + cat test yes ) diff --git a/userspace/cat/CMakeLists.txt b/userspace/cat/CMakeLists.txt new file mode 100644 index 00000000..27cb999c --- /dev/null +++ b/userspace/cat/CMakeLists.txt @@ -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 +) diff --git a/userspace/cat/main.cpp b/userspace/cat/main.cpp new file mode 100644 index 00000000..ce1d3da9 --- /dev/null +++ b/userspace/cat/main.cpp @@ -0,0 +1,50 @@ +#include + +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; +} diff --git a/userspace/test/test.cpp b/userspace/test/test.cpp index 5bcb589f..9da8479b 100644 --- a/userspace/test/test.cpp +++ b/userspace/test/test.cpp @@ -1,36 +1,12 @@ #include #include #include -#include #define ERROR(msg) { perror(msg); return 1; } #define BUF_SIZE 1024 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"); if (fp == NULL) ERROR("fopen");