Kernel: Add argc and argv to process entry

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

View File

@ -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

View File

@ -2,6 +2,7 @@
#include <BAN/NoCopyMove.h>
#include <BAN/RefPtr.h>
#include <kernel/Memory/Heap.h>
#include <sys/types.h>
@ -27,11 +28,9 @@ namespace Kernel
public:
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();
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<void> 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;
};

View File

@ -1,6 +1,7 @@
#include <kernel/CriticalScope.h>
#include <kernel/Memory/FixedWidthAllocator.h>
#include <kernel/Memory/MMU.h>
#include <kernel/Memory/MMUScope.h>
#include <kernel/Process.h>
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()

View File

@ -3,6 +3,7 @@
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/MMUScope.h>
#include <kernel/Process.h>
#include <kernel/Scheduler.h>
#include <LibELF/ELF.h>
@ -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;

View File

@ -1,16 +1,15 @@
#include <BAN/Errors.h>
#include <kernel/CriticalScope.h>
#include <kernel/InterruptController.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Process.h>
#include <kernel/Scheduler.h>
#include <kernel/Thread.h>
#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<size_t size, typename T>
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*> 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<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;
}
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(
[](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<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;
}
@ -63,32 +96,13 @@ namespace Kernel
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()
{
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

View File

@ -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(

View File

@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.26)
project(userspace CXX)
set(USERSPACE_PROJECTS
cat
test
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 <stdlib.h>
#include <string.h>
#include <math.h>
#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");