Kernel/LibC/DynamicLoader: Update process start ABI
We now use SysV abi for process startup
This commit is contained in:
parent
e6026cb0b8
commit
36baf7b0af
|
@ -41,15 +41,6 @@ start_userspace_thread:
|
|||
call get_thread_start_sp
|
||||
movl %eax, %esp
|
||||
|
||||
# STACK LAYOUT
|
||||
# entry
|
||||
# argc
|
||||
# argv
|
||||
# envp
|
||||
# userspace stack
|
||||
|
||||
call get_userspace_thread_stack_top
|
||||
|
||||
movw $(0x20 | 3), %bx
|
||||
movw %bx, %ds
|
||||
movw %bx, %es
|
||||
|
@ -57,15 +48,4 @@ start_userspace_thread:
|
|||
movw %bx, %gs
|
||||
xorw %bx, %bx
|
||||
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
|
||||
pushl $(0x20 | 3)
|
||||
pushl %eax
|
||||
pushl $0x202
|
||||
pushl $(0x18 | 3)
|
||||
pushl %ebx
|
||||
iret
|
||||
|
|
|
@ -32,24 +32,4 @@ start_userspace_thread:
|
|||
call get_thread_start_sp
|
||||
movq %rax, %rsp
|
||||
|
||||
# STACK LAYOUT
|
||||
# entry
|
||||
# argc
|
||||
# argv
|
||||
# envp
|
||||
# userspace stack
|
||||
|
||||
call get_userspace_thread_stack_top
|
||||
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rbx
|
||||
|
||||
pushq $(0x20 | 3)
|
||||
pushq %rax
|
||||
pushq $0x202
|
||||
pushq $(0x18 | 3)
|
||||
pushq %rbx
|
||||
iretq
|
||||
|
|
|
@ -34,15 +34,6 @@ namespace Kernel
|
|||
public:
|
||||
using entry_t = Thread::entry_t;
|
||||
|
||||
struct userspace_info_t
|
||||
{
|
||||
uintptr_t entry { 0 };
|
||||
int argc { 0 };
|
||||
char** argv { nullptr };
|
||||
char** envp { nullptr };
|
||||
int file_fd { -1 };
|
||||
};
|
||||
|
||||
public:
|
||||
static Process* create_kernel();
|
||||
static Process* create_kernel(entry_t, void*);
|
||||
|
@ -183,7 +174,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
|
||||
BAN::ErrorOr<long> sys_yield();
|
||||
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg);
|
||||
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg);
|
||||
BAN::ErrorOr<long> sys_pthread_exit(void* value);
|
||||
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
|
||||
BAN::ErrorOr<long> sys_pthread_self();
|
||||
|
@ -208,7 +199,6 @@ namespace Kernel
|
|||
size_t proc_environ(off_t offset, BAN::ByteSpan) const;
|
||||
|
||||
bool is_userspace() const { return m_is_userspace; }
|
||||
const userspace_info_t& userspace_info() const { return m_userspace_info; }
|
||||
|
||||
// Returns error if page could not be allocated
|
||||
// Returns true if the page was allocated successfully
|
||||
|
@ -315,7 +305,6 @@ namespace Kernel
|
|||
BAN::Vector<BAN::String> m_environ;
|
||||
|
||||
bool m_is_userspace { false };
|
||||
userspace_info_t m_userspace_info;
|
||||
|
||||
SpinLock m_child_exit_lock;
|
||||
BAN::Vector<ChildExitStatus> m_child_exit_statuses;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <kernel/Memory/VirtualRange.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
#include <LibELF/AuxiliaryVector.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -41,9 +43,10 @@ namespace Kernel
|
|||
BAN::ErrorOr<Thread*> pthread_create(entry_t, void*);
|
||||
|
||||
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
|
||||
void setup_exec();
|
||||
void setup_process_cleanup();
|
||||
|
||||
BAN::ErrorOr<void> initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
||||
|
||||
// Returns true, if thread is going to trigger signal
|
||||
bool is_interrupted_by_signal() const;
|
||||
|
||||
|
@ -100,7 +103,7 @@ namespace Kernel
|
|||
private:
|
||||
Thread(pid_t tid, Process*);
|
||||
|
||||
void setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
|
||||
void setup_exec(vaddr_t ip, vaddr_t sp);
|
||||
|
||||
static void on_exit_trampoline(Thread*);
|
||||
void on_exit();
|
||||
|
|
|
@ -248,11 +248,7 @@ namespace Kernel
|
|||
}
|
||||
|
||||
if (Thread::current().has_process() && Process::current().is_userspace())
|
||||
{
|
||||
const char* const* argv = Process::current().userspace_info().argv;
|
||||
if (argv && *argv)
|
||||
process_name = *argv;
|
||||
}
|
||||
process_name = Process::current().name();
|
||||
|
||||
#if ARCH(x86_64)
|
||||
dwarnln(
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <kernel/Terminal/PseudoTerminal.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#include <LibELF/AuxiliaryVector.h>
|
||||
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
@ -116,76 +118,51 @@ namespace Kernel
|
|||
process->m_working_directory = VirtualFileSystem::get().root_file();
|
||||
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));
|
||||
|
||||
TRY(process->m_cmdline.push_back({}));
|
||||
TRY(process->m_cmdline.emplace_back());
|
||||
TRY(process->m_cmdline.back().append(path));
|
||||
for (auto argument : arguments)
|
||||
{
|
||||
TRY(process->m_cmdline.emplace_back());
|
||||
TRY(process->m_cmdline.back().append(argument));
|
||||
}
|
||||
|
||||
LockGuard _(process->m_process_lock);
|
||||
|
||||
auto executable_inode = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC)).inode;
|
||||
auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC));
|
||||
auto executable_inode = executable_file.inode;
|
||||
|
||||
auto executable = TRY(ELF::load_from_inode(executable_inode, process->m_credentials, process->page_table()));
|
||||
process->m_mapped_regions = BAN::move(executable.regions);
|
||||
|
||||
char** argv_addr = nullptr;
|
||||
{
|
||||
size_t needed_bytes = sizeof(char*) + path.size() + 1;
|
||||
for (auto argument : arguments)
|
||||
needed_bytes += sizeof(char*) + argument.size() + 1;
|
||||
needed_bytes += sizeof(char*);
|
||||
|
||||
if (auto rem = needed_bytes % PAGE_SIZE)
|
||||
needed_bytes += PAGE_SIZE - rem;
|
||||
|
||||
auto argv_region = MUST(MemoryBackedRegion::create(
|
||||
process->page_table(),
|
||||
needed_bytes,
|
||||
{ .start = 0x400000, .end = KERNEL_OFFSET },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::Present
|
||||
));
|
||||
argv_addr = reinterpret_cast<char**>(argv_region->vaddr());
|
||||
|
||||
uintptr_t offset = sizeof(char*) * (1 + arguments.size() + 1);
|
||||
for (size_t i = 0; i <= arguments.size(); i++)
|
||||
{
|
||||
const uintptr_t addr = argv_region->vaddr() + offset;
|
||||
TRY(argv_region->copy_data_to_region(i * sizeof(char*), reinterpret_cast<const uint8_t*>(&addr), sizeof(char*)));
|
||||
|
||||
const auto current = (i == 0) ? path : arguments[i - 1];
|
||||
TRY(argv_region->copy_data_to_region(offset, reinterpret_cast<const uint8_t*>(current.data()), current.size()));
|
||||
|
||||
const uint8_t zero = 0;
|
||||
TRY(argv_region->copy_data_to_region(offset + current.size(), &zero, 1));
|
||||
|
||||
offset += current.size() + 1;
|
||||
}
|
||||
|
||||
const uintptr_t zero = 0;
|
||||
TRY(argv_region->copy_data_to_region((1 + arguments.size()) * sizeof(char*), reinterpret_cast<const uint8_t*>(&zero), sizeof(char*)));
|
||||
|
||||
TRY(process->m_mapped_regions.push_back(BAN::move(argv_region)));
|
||||
}
|
||||
|
||||
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
|
||||
process->m_credentials.set_euid(executable_inode->uid());
|
||||
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
|
||||
process->m_credentials.set_egid(executable_inode->gid());
|
||||
|
||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
|
||||
|
||||
if (executable.has_interpreter)
|
||||
{
|
||||
VirtualFileSystem::File file;
|
||||
TRY(file.canonical_path.append("<self>"));
|
||||
file.inode = executable_inode;
|
||||
process->m_userspace_info.file_fd = TRY(process->m_open_file_descriptors.open(BAN::move(file), O_RDONLY));
|
||||
const int execfd = TRY(process->m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_EXECFD,
|
||||
.a_un = { .a_val = static_cast<uint32_t>(execfd) },
|
||||
}));
|
||||
}
|
||||
|
||||
process->m_is_userspace = true;
|
||||
process->m_userspace_info.entry = executable.entry_point;
|
||||
process->m_userspace_info.argc = 1 + arguments.size();
|
||||
process->m_userspace_info.argv = argv_addr;
|
||||
process->m_userspace_info.envp = nullptr;
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_NULL,
|
||||
.a_un = { .a_val = 0 },
|
||||
}));
|
||||
|
||||
auto* thread = MUST(Thread::create_userspace(process, process->page_table()));
|
||||
thread->setup_exec();
|
||||
MUST(thread->initialize_userspace(
|
||||
executable.entry_point,
|
||||
process->m_cmdline.span(),
|
||||
process->m_environ.span(),
|
||||
auxiliary_vector.span()
|
||||
));
|
||||
|
||||
process->add_thread(thread);
|
||||
process->register_to_scheduler();
|
||||
|
@ -534,7 +511,6 @@ namespace Kernel
|
|||
forked->m_open_file_descriptors = BAN::move(*open_file_descriptors);
|
||||
forked->m_mapped_regions = BAN::move(mapped_regions);
|
||||
forked->m_is_userspace = m_is_userspace;
|
||||
forked->m_userspace_info = m_userspace_info;
|
||||
forked->m_has_called_exec = false;
|
||||
memcpy(forked->m_signal_handlers, m_signal_handlers, sizeof(m_signal_handlers));
|
||||
|
||||
|
@ -561,77 +537,62 @@ namespace Kernel
|
|||
|
||||
TRY(validate_string_access(path));
|
||||
|
||||
auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC));
|
||||
auto executable_inode = executable_file.inode;
|
||||
|
||||
BAN::Vector<BAN::String> str_argv;
|
||||
for (int i = 0; argv && argv[i]; i++)
|
||||
{
|
||||
TRY(validate_pointer_access(argv + i, sizeof(char*), false));
|
||||
TRY(validate_string_access(argv[i]));
|
||||
TRY(str_argv.emplace_back(argv[i]));
|
||||
TRY(str_argv.emplace_back());
|
||||
TRY(str_argv.back().append(argv[i]));
|
||||
}
|
||||
|
||||
BAN::Vector<BAN::String> str_envp;
|
||||
for (int i = 0; envp && envp[i]; i++)
|
||||
{
|
||||
TRY(validate_pointer_access(envp + 1, sizeof(char*), false));
|
||||
TRY(validate_pointer_access(envp + i, sizeof(char*), false));
|
||||
TRY(validate_string_access(envp[i]));
|
||||
TRY(str_envp.emplace_back(envp[i]));
|
||||
TRY(str_envp.emplace_back());
|
||||
TRY(str_envp.back().append(envp[i]));
|
||||
}
|
||||
|
||||
auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC));
|
||||
auto executable_inode = executable_file.inode;
|
||||
|
||||
auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, *new_page_table));
|
||||
auto new_mapped_regions = BAN::move(executable.regions);
|
||||
|
||||
int file_fd = -1;
|
||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
|
||||
|
||||
BAN::ScopeGuard execfd_guard([this, &auxiliary_vector] {
|
||||
if (auxiliary_vector.empty())
|
||||
return;
|
||||
if (auxiliary_vector.front().a_type != LibELF::AT_EXECFD)
|
||||
return;
|
||||
MUST(m_open_file_descriptors.close(auxiliary_vector.front().a_un.a_val));
|
||||
});
|
||||
|
||||
if (executable.has_interpreter)
|
||||
{
|
||||
VirtualFileSystem::File file;
|
||||
file.canonical_path = BAN::move(executable_file.canonical_path);
|
||||
file.inode = executable_inode;
|
||||
file_fd = TRY(m_open_file_descriptors.open(BAN::move(file), O_RDONLY));
|
||||
const int execfd = TRY(m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_EXECFD,
|
||||
.a_un = { .a_val = static_cast<uint32_t>(execfd) },
|
||||
}));
|
||||
}
|
||||
BAN::ScopeGuard file_closer([&] { if (file_fd != -1) MUST(m_open_file_descriptors.close(file_fd)); });
|
||||
|
||||
// allocate memory on the new process for arguments and environment
|
||||
auto create_region =
|
||||
[&](BAN::Span<BAN::String> container) -> BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>>
|
||||
{
|
||||
size_t bytes = sizeof(char*);
|
||||
for (auto& elem : container)
|
||||
bytes += sizeof(char*) + elem.size() + 1;
|
||||
|
||||
if (auto rem = bytes % PAGE_SIZE)
|
||||
bytes += PAGE_SIZE - rem;
|
||||
|
||||
auto region = TRY(MemoryBackedRegion::create(
|
||||
*new_page_table,
|
||||
bytes,
|
||||
{ .start = executable.entry_point, .end = KERNEL_OFFSET },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
|
||||
));
|
||||
|
||||
size_t data_offset = sizeof(char*) * (container.size() + 1);
|
||||
for (size_t i = 0; i < container.size(); i++)
|
||||
{
|
||||
uintptr_t ptr_addr = region->vaddr() + data_offset;
|
||||
TRY(region->copy_data_to_region(sizeof(char*) * i, (const uint8_t*)&ptr_addr, sizeof(char*)));
|
||||
TRY(region->copy_data_to_region(data_offset, (const uint8_t*)container[i].data(), container[i].size()));
|
||||
data_offset += container[i].size() + 1;
|
||||
}
|
||||
|
||||
uintptr_t null = 0;
|
||||
TRY(region->copy_data_to_region(sizeof(char*) * container.size(), (const uint8_t*)&null, sizeof(char*)));
|
||||
|
||||
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
|
||||
};
|
||||
|
||||
TRY(new_mapped_regions.reserve(new_mapped_regions.size() + 2));
|
||||
MUST(new_mapped_regions.push_back(TRY(create_region(str_argv.span()))));
|
||||
MUST(new_mapped_regions.push_back(TRY(create_region(str_envp.span()))));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_NULL,
|
||||
.a_un = { .a_val = 0 },
|
||||
}));
|
||||
|
||||
auto* new_thread = TRY(Thread::create_userspace(this, *new_page_table));
|
||||
TRY(new_thread->initialize_userspace(
|
||||
executable.entry_point,
|
||||
str_argv.span(),
|
||||
str_envp.span(),
|
||||
auxiliary_vector.span()
|
||||
));
|
||||
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
@ -655,8 +616,8 @@ namespace Kernel
|
|||
m_threads.front()->m_process = nullptr;
|
||||
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
|
||||
|
||||
MUST(Processor::scheduler().add_thread(new_thread));
|
||||
m_threads.front() = new_thread;
|
||||
MUST(Processor::scheduler().add_thread(m_threads.front()));
|
||||
|
||||
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
|
||||
{
|
||||
|
@ -673,21 +634,13 @@ namespace Kernel
|
|||
m_mapped_regions = BAN::move(new_mapped_regions);
|
||||
m_page_table = BAN::move(new_page_table);
|
||||
|
||||
file_closer.disable();
|
||||
|
||||
m_userspace_info.argc = str_argv.size();
|
||||
m_userspace_info.argv = reinterpret_cast<char**>(m_mapped_regions[m_mapped_regions.size() - 2]->vaddr());
|
||||
m_userspace_info.envp = reinterpret_cast<char**>(m_mapped_regions[m_mapped_regions.size() - 1]->vaddr());
|
||||
m_userspace_info.entry = executable.entry_point;
|
||||
m_userspace_info.file_fd = file_fd;
|
||||
execfd_guard.disable();
|
||||
|
||||
m_cmdline = BAN::move(str_argv);
|
||||
m_environ = BAN::move(str_envp);
|
||||
}
|
||||
|
||||
m_has_called_exec = true;
|
||||
|
||||
m_threads.front()->setup_exec();
|
||||
Processor::yield();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
@ -2084,7 +2037,7 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg)
|
||||
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg)
|
||||
{
|
||||
if (attr != nullptr)
|
||||
{
|
||||
|
|
|
@ -44,11 +44,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> ret = BAN::Error::from_errno(ENOSYS);
|
||||
|
||||
const char* process_path = nullptr;
|
||||
if (Process::current().userspace_info().argc > 0 && Process::current().userspace_info().argv)
|
||||
process_path = Process::current().userspace_info().argv[0];
|
||||
if (process_path == nullptr)
|
||||
process_path = "<null>";
|
||||
const char* process_path = Process::current().name();
|
||||
|
||||
#if DUMP_ALL_SYSCALLS
|
||||
dprintln("{} pid {}: {}", process_path, Process::current().pid(), s_syscall_names[syscall]);
|
||||
|
|
|
@ -29,11 +29,6 @@ namespace Kernel
|
|||
return Thread::current().interrupt_stack().sp;
|
||||
}
|
||||
|
||||
extern "C" uintptr_t get_userspace_thread_stack_top()
|
||||
{
|
||||
return Thread::current().userspace_stack_top() - 4 * sizeof(uintptr_t);
|
||||
}
|
||||
|
||||
extern "C" void load_thread_sse()
|
||||
{
|
||||
Thread::current().load_sse();
|
||||
|
@ -176,11 +171,12 @@ namespace Kernel
|
|||
save_sse();
|
||||
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
|
||||
|
||||
thread->setup_exec_impl(
|
||||
reinterpret_cast<uintptr_t>(entry),
|
||||
reinterpret_cast<uintptr_t>(arg),
|
||||
0, 0, 0
|
||||
);
|
||||
PageTable::with_fast_page(thread->userspace_stack().paddr_of(thread->userspace_stack_top() - PAGE_SIZE), [=] {
|
||||
PageTable::fast_page_as<void*>(PAGE_SIZE - sizeof(uintptr_t)) = arg;
|
||||
});
|
||||
|
||||
const vaddr_t entry_addr = reinterpret_cast<vaddr_t>(entry);
|
||||
thread->setup_exec(entry_addr, thread->userspace_stack_top() - sizeof(uintptr_t));
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
@ -222,21 +218,112 @@ namespace Kernel
|
|||
return thread;
|
||||
}
|
||||
|
||||
void Thread::setup_exec()
|
||||
BAN::ErrorOr<void> Thread::initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv)
|
||||
{
|
||||
const auto& userspace_info = process().userspace_info();
|
||||
ASSERT(userspace_info.entry);
|
||||
// System V ABI: Initial process stack
|
||||
|
||||
setup_exec_impl(
|
||||
userspace_info.entry,
|
||||
userspace_info.argc,
|
||||
reinterpret_cast<uintptr_t>(userspace_info.argv),
|
||||
reinterpret_cast<uintptr_t>(userspace_info.envp),
|
||||
userspace_info.file_fd
|
||||
);
|
||||
ASSERT(m_is_userspace);
|
||||
ASSERT(m_userspace_stack);
|
||||
|
||||
size_t needed_size = 0;
|
||||
|
||||
// argc
|
||||
needed_size += sizeof(uintptr_t);
|
||||
|
||||
// argv
|
||||
needed_size += (argv.size() + 1) * sizeof(uintptr_t);
|
||||
for (auto arg : argv)
|
||||
needed_size += arg.size() + 1;
|
||||
|
||||
// envp
|
||||
needed_size += (envp.size() + 1) * sizeof(uintptr_t);
|
||||
for (auto env : envp)
|
||||
needed_size += env.size() + 1;
|
||||
|
||||
// auxv
|
||||
needed_size += auxv.size() * sizeof(LibELF::AuxiliaryVector);
|
||||
|
||||
if (needed_size > m_userspace_stack->size())
|
||||
return BAN::Error::from_errno(ENOBUFS);
|
||||
|
||||
vaddr_t vaddr = userspace_stack_top() - needed_size;
|
||||
|
||||
const auto stack_copy_buf =
|
||||
[this](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void
|
||||
{
|
||||
ASSERT(vaddr + buffer.size() <= userspace_stack_top());
|
||||
|
||||
size_t bytes_copied = 0;
|
||||
while (bytes_copied < buffer.size())
|
||||
{
|
||||
const size_t to_copy = BAN::Math::min<size_t>(buffer.size() - bytes_copied, PAGE_SIZE - (vaddr % PAGE_SIZE));
|
||||
|
||||
PageTable::with_fast_page(userspace_stack().paddr_of(vaddr & PAGE_ADDR_MASK), [=]() {
|
||||
memcpy(PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), buffer.data() + bytes_copied, to_copy);
|
||||
});
|
||||
|
||||
vaddr += to_copy;
|
||||
bytes_copied += to_copy;
|
||||
}
|
||||
};
|
||||
|
||||
const auto stack_push_buf =
|
||||
[&stack_copy_buf, &vaddr](BAN::ConstByteSpan buffer) -> void
|
||||
{
|
||||
stack_copy_buf(buffer, vaddr);
|
||||
vaddr += buffer.size();
|
||||
};
|
||||
|
||||
const auto stack_push_uint =
|
||||
[&stack_push_buf](uintptr_t value) -> void
|
||||
{
|
||||
stack_push_buf(BAN::ConstByteSpan::from(value));
|
||||
};
|
||||
|
||||
const auto stack_push_str =
|
||||
[&stack_push_buf](BAN::StringView string) -> void
|
||||
{
|
||||
const uint8_t* string_u8 = reinterpret_cast<const uint8_t*>(string.data());
|
||||
stack_push_buf(BAN::ConstByteSpan(string_u8, string.size() + 1));
|
||||
};
|
||||
|
||||
// argc
|
||||
stack_push_uint(argv.size());
|
||||
|
||||
// argv
|
||||
const vaddr_t argv_vaddr = vaddr;
|
||||
vaddr += argv.size() * sizeof(uintptr_t);
|
||||
stack_push_uint(0);
|
||||
|
||||
// envp
|
||||
const vaddr_t envp_vaddr = vaddr;
|
||||
vaddr += envp.size() * sizeof(uintptr_t);
|
||||
stack_push_uint(0);
|
||||
|
||||
// auxv
|
||||
for (auto aux : auxv)
|
||||
stack_push_buf(BAN::ConstByteSpan::from(aux));
|
||||
|
||||
// information
|
||||
for (size_t i = 0; i < argv.size(); i++)
|
||||
{
|
||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), argv_vaddr + i * sizeof(uintptr_t));
|
||||
stack_push_str(argv[i]);
|
||||
}
|
||||
for (size_t i = 0; i < envp.size(); i++)
|
||||
{
|
||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), envp_vaddr + i * sizeof(uintptr_t));
|
||||
stack_push_str(envp[i]);
|
||||
}
|
||||
|
||||
ASSERT(vaddr == userspace_stack_top());
|
||||
|
||||
setup_exec(entry, userspace_stack_top() - needed_size);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void Thread::setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
|
||||
void Thread::setup_exec(vaddr_t ip, vaddr_t sp)
|
||||
{
|
||||
ASSERT(is_userspace());
|
||||
m_state = State::NotStarted;
|
||||
|
@ -244,13 +331,13 @@ namespace Kernel
|
|||
// Signal mask is inherited
|
||||
|
||||
// Initialize stack for returning
|
||||
PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] {
|
||||
uintptr_t sp = PageTable::fast_page() + PAGE_SIZE;
|
||||
write_to_stack(sp, entry);
|
||||
write_to_stack(sp, arg3);
|
||||
write_to_stack(sp, arg2);
|
||||
write_to_stack(sp, arg1);
|
||||
write_to_stack(sp, arg0);
|
||||
PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [=] {
|
||||
uintptr_t cur_sp = PageTable::fast_page() + PAGE_SIZE;
|
||||
write_to_stack(cur_sp, 0x20 | 3);
|
||||
write_to_stack(cur_sp, sp);
|
||||
write_to_stack(cur_sp, 0x202);
|
||||
write_to_stack(cur_sp, 0x18 | 3);
|
||||
write_to_stack(cur_sp, ip);
|
||||
});
|
||||
|
||||
m_interrupt_stack.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
||||
|
@ -286,7 +373,7 @@ namespace Kernel
|
|||
m_signal_pending_mask = 0;
|
||||
m_signal_block_mask = ~0ull;
|
||||
|
||||
PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] {
|
||||
PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [&] {
|
||||
uintptr_t sp = PageTable::fast_page() + PAGE_SIZE;
|
||||
write_to_stack(sp, this);
|
||||
write_to_stack(sp, &Thread::on_exit_trampoline);
|
||||
|
|
|
@ -2,18 +2,22 @@
|
|||
|
||||
.global _start
|
||||
_start:
|
||||
pushl $0
|
||||
# get argc, argv, envp
|
||||
movl (%esp), %edi
|
||||
leal 4(%esp), %esi
|
||||
leal 4(%esi, %edi, 4), %edx
|
||||
|
||||
# align stack
|
||||
andl $-16, %esp
|
||||
xorl %ebp, %ebp
|
||||
|
||||
# save argc, argv, envp
|
||||
subl $4, %esp
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
|
||||
# STACK LAYOUT
|
||||
# null
|
||||
# argc
|
||||
# argv
|
||||
# envp
|
||||
|
||||
xorl %ebp, %ebp
|
||||
subl $4, %esp
|
||||
|
||||
pushl $__fini_array_end
|
||||
pushl $__fini_array_start
|
||||
|
|
|
@ -2,21 +2,22 @@
|
|||
|
||||
.global _start
|
||||
_start:
|
||||
pushq $0
|
||||
# get argc, argv, envp
|
||||
movq (%rsp), %rdi
|
||||
leaq 8(%rsp), %rsi
|
||||
leaq 8(%rsi, %rdi, 8), %rdx
|
||||
|
||||
# align stack
|
||||
andq $-16, %rsp
|
||||
xorq %rbp, %rbp
|
||||
|
||||
# save argc, argv, envp
|
||||
subq $8, %rsp
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %rdx
|
||||
|
||||
# STACK LAYOUT
|
||||
# null
|
||||
# argc
|
||||
# argv
|
||||
# envp
|
||||
|
||||
xorq %rbp, %rbp
|
||||
|
||||
# init libc
|
||||
movq 0(%rsp), %rdi
|
||||
movq %rdx, %rdi # environ
|
||||
|
||||
pushq $__fini_array_end
|
||||
pushq $__fini_array_start
|
||||
|
@ -31,9 +32,10 @@ _start:
|
|||
addq $(6 * 8), %rsp
|
||||
|
||||
# call main
|
||||
movq 16(%rsp), %rdi
|
||||
movq 8(%rsp), %rsi
|
||||
movq 0(%rsp), %rdx
|
||||
popq %rdx
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
addq $8, %rsp
|
||||
call main
|
||||
|
||||
# call exit
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include <BAN/Atomic.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <kernel/Arch.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -16,15 +18,30 @@ struct pthread_trampoline_info_t
|
|||
};
|
||||
|
||||
// stack is 16 byte aligned on entry, this `call` is used to align it
|
||||
extern "C" void pthread_trampoline(void*);
|
||||
asm("pthread_trampoline: call pthread_trampoline_cpp");
|
||||
extern "C" void _pthread_trampoline(void*);
|
||||
asm(
|
||||
#if ARCH(x86_64)
|
||||
"_pthread_trampoline:"
|
||||
"popq %rdi;"
|
||||
"andq $-16, %rsp;"
|
||||
"xorq %rbp, %rbp;"
|
||||
"call _pthread_trampoline_cpp"
|
||||
#elif ARCH(i686)
|
||||
"_pthread_trampoline:"
|
||||
"ud2;"
|
||||
"popl %edi;"
|
||||
"andl $-16, %esp;"
|
||||
"xorl %ebp, %ebp;"
|
||||
"subl $12, %esp;"
|
||||
"pushl %edi;"
|
||||
"call _pthread_trampoline_cpp"
|
||||
#endif
|
||||
);
|
||||
|
||||
extern "C" void pthread_trampoline_cpp(void* arg)
|
||||
extern "C" void _pthread_trampoline_cpp(void* arg)
|
||||
{
|
||||
pthread_trampoline_info_t info;
|
||||
memcpy(&info, arg, sizeof(pthread_trampoline_info_t));
|
||||
auto info = *reinterpret_cast<pthread_trampoline_info_t*>(arg);
|
||||
free(arg);
|
||||
|
||||
pthread_exit(info.start_routine(info.arg));
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
@ -63,24 +80,30 @@ void pthread_cleanup_push(void (*routine)(void*), void* arg)
|
|||
s_cleanup_stack = cleanup;
|
||||
}
|
||||
|
||||
int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
|
||||
int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
|
||||
{
|
||||
auto* info = static_cast<pthread_trampoline_info_t*>(malloc(sizeof(pthread_trampoline_info_t)));
|
||||
if (info == nullptr)
|
||||
return -1;
|
||||
info->start_routine = start_routine;
|
||||
info->arg = arg;
|
||||
return errno;
|
||||
|
||||
*info = {
|
||||
.start_routine = start_routine,
|
||||
.arg = arg,
|
||||
};
|
||||
|
||||
const auto ret = syscall(SYS_PTHREAD_CREATE, attr, pthread_trampoline, info);
|
||||
if (ret == -1)
|
||||
{
|
||||
free(info);
|
||||
return -1;
|
||||
}
|
||||
goto pthread_create_error;
|
||||
|
||||
if (thread)
|
||||
*thread = ret;
|
||||
|
||||
if (thread_id)
|
||||
*thread_id = ret;
|
||||
return 0;
|
||||
|
||||
pthread_create_error:
|
||||
const int return_code = errno;
|
||||
free(info);
|
||||
return return_code;
|
||||
}
|
||||
|
||||
void pthread_exit(void* value_ptr)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "utils.h"
|
||||
|
||||
#include <LibELF/AuxiliaryVector.h>
|
||||
#include <LibELF/Types.h>
|
||||
#include <LibELF/Values.h>
|
||||
|
||||
|
@ -15,42 +16,44 @@ void _start()
|
|||
{
|
||||
#if defined(__x86_64__)
|
||||
asm volatile(
|
||||
"xorq %rbp, %rbp;"
|
||||
"movq (%rsp), %rdi;"
|
||||
"leaq 8(%rsp), %rsi;"
|
||||
"leaq 8(%rsi, %rdi, 8), %rdx;"
|
||||
|
||||
"movq %rsp, %rbp;"
|
||||
"andq $-16, %rsp;"
|
||||
|
||||
"call _entry;"
|
||||
|
||||
"movq %rbp, %rsp;"
|
||||
"xorq %rbp, %rbp;"
|
||||
|
||||
"jmp *%rax;"
|
||||
|
||||
"ud2;"
|
||||
);
|
||||
#elif defined(__i686__)
|
||||
asm volatile(
|
||||
"xorl %ebp, %ebp;"
|
||||
"pushl %ecx;"
|
||||
"movl (%esp), %edi;"
|
||||
"leal 4(%esp), %esi;"
|
||||
"leal 4(%esi, %edi, 4), %edx;"
|
||||
|
||||
"movl %esp, %ebp;"
|
||||
"andl $-16, %esp;"
|
||||
|
||||
"subl $4, %esp;"
|
||||
"pushl %edx;"
|
||||
"pushl %esi;"
|
||||
"pushl %edi;"
|
||||
"call _entry;"
|
||||
"ud2;"
|
||||
);
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((naked, noreturn))
|
||||
static void call_entry_point(int, char**, char**, uintptr_t)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
asm volatile(
|
||||
"andq $-16, %rsp;"
|
||||
"jmp *%rcx;"
|
||||
);
|
||||
#elif defined(__i686__)
|
||||
asm volatile(
|
||||
"addl $4, %esp;"
|
||||
"popl %edi;"
|
||||
"popl %esi;"
|
||||
"popl %edx;"
|
||||
"popl %ecx;"
|
||||
"andl $-16, %esp;"
|
||||
"jmp *%ecx;"
|
||||
"call _entry;"
|
||||
|
||||
"movl %ebp, %esp;"
|
||||
"xorl %ebp, %ebp;"
|
||||
|
||||
"jmp *%eax;"
|
||||
|
||||
"ud2;"
|
||||
);
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
|
@ -901,16 +904,33 @@ static void call_init_funcs(LoadedElf& elf, bool is_main_elf)
|
|||
reinterpret_cast<init_t>(elf.init)();
|
||||
for (size_t i = 0; i < elf.init_arraysz / sizeof(init_t); i++)
|
||||
reinterpret_cast<init_t*>(elf.init_array)[i]();
|
||||
}
|
||||
|
||||
static LibELF::AuxiliaryVector* find_auxv(char** envp)
|
||||
{
|
||||
if (envp == nullptr)
|
||||
return nullptr;
|
||||
|
||||
char** null_env = envp;
|
||||
while (*null_env)
|
||||
null_env++;
|
||||
|
||||
return reinterpret_cast<LibELF::AuxiliaryVector*>(null_env + 1);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
__attribute__((used, noreturn))
|
||||
int _entry(int argc, char** argv, char** envp, int fd)
|
||||
__attribute__((used))
|
||||
uintptr_t _entry(int argc, char* argv[], char* envp[])
|
||||
{
|
||||
const bool invoked_directly = (fd < 0);
|
||||
if (invoked_directly)
|
||||
int execfd = -1;
|
||||
if (auto* auxv = find_auxv(envp))
|
||||
for (auto* aux = auxv; aux->a_type != LibELF::AT_NULL; aux++)
|
||||
if (aux->a_type == LibELF::AT_EXECFD) {
|
||||
execfd = aux->a_un.a_val;
|
||||
aux->a_type = LibELF::AT_IGNORE;
|
||||
}
|
||||
|
||||
if (execfd == -1)
|
||||
{
|
||||
if (argc < 2)
|
||||
print_error_and_exit("missing program name", 0);
|
||||
|
@ -918,18 +938,19 @@ int _entry(int argc, char** argv, char** envp, int fd)
|
|||
argc--;
|
||||
argv++;
|
||||
|
||||
fd = syscall(SYS_OPENAT, AT_FDCWD, argv[0], O_RDONLY);
|
||||
if (fd < 0)
|
||||
print_error_and_exit("could not open program", fd);
|
||||
execfd = syscall(SYS_OPENAT, AT_FDCWD, argv[0], O_RDONLY);
|
||||
if (execfd < 0)
|
||||
print_error_and_exit("could not open program", execfd);
|
||||
}
|
||||
|
||||
init_random();
|
||||
auto& elf = load_elf(argv[0], fd);
|
||||
auto& elf = load_elf(argv[0], execfd);
|
||||
syscall(SYS_CLOSE, fd);
|
||||
fini_random();
|
||||
|
||||
relocate_elf(elf, true);
|
||||
initialize_environ(envp);
|
||||
call_init_funcs(elf, true);
|
||||
call_entry_point(argc, argv, envp, elf.base + elf.file_header.e_entry);
|
||||
|
||||
return elf.base + elf.file_header.e_entry;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue