Kernel: Add argc and argv to process entry
This commit is contained in:
parent
e0a7e242f8
commit
e0a72defa2
|
@ -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
|
||||
|
|
|
@ -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 on_exit();
|
||||
|
||||
void validate_stack() const;
|
||||
|
||||
BAN::ErrorOr<void> initialize(entry_t, void*);
|
||||
void on_exit();
|
||||
private:
|
||||
struct userspace_entry_t
|
||||
{
|
||||
uintptr_t entry;
|
||||
int argc { 0 };
|
||||
char** argv { 0 };
|
||||
};
|
||||
|
||||
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 };
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.26)
|
|||
project(userspace CXX)
|
||||
|
||||
set(USERSPACE_PROJECTS
|
||||
cat
|
||||
test
|
||||
yes
|
||||
)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue