Kernel/LibC/DynamicLoader: Implement thread local storage
For some reason this does not work on 32 bit version, so it is disabled on that platform. I'll have to look into it later to find the bug :)
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace Kernel::ELF
|
||||
{
|
||||
@@ -108,13 +109,13 @@ namespace Kernel::ELF
|
||||
auto file_header = TRY(read_and_validate_file_header(inode));
|
||||
auto program_headers = TRY(read_program_headers(inode, file_header));
|
||||
|
||||
vaddr_t executable_end = 0;
|
||||
size_t exec_max_offset { 0 };
|
||||
BAN::String interpreter;
|
||||
|
||||
for (const auto& program_header : program_headers)
|
||||
{
|
||||
if (program_header.p_type == PT_LOAD)
|
||||
executable_end = BAN::Math::max<vaddr_t>(executable_end, program_header.p_vaddr + program_header.p_memsz);
|
||||
exec_max_offset = BAN::Math::max<vaddr_t>(exec_max_offset, program_header.p_vaddr + program_header.p_memsz);
|
||||
else if (program_header.p_type == PT_INTERP)
|
||||
{
|
||||
BAN::Vector<uint8_t> interp_buffer;
|
||||
@@ -140,9 +141,6 @@ namespace Kernel::ELF
|
||||
}
|
||||
}
|
||||
|
||||
if (file_header.e_type == ET_DYN)
|
||||
executable_end = 0x400000;
|
||||
|
||||
if (!interpreter.empty())
|
||||
{
|
||||
auto interpreter_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(credentials, interpreter, O_EXEC)).inode;
|
||||
@@ -164,15 +162,16 @@ namespace Kernel::ELF
|
||||
}
|
||||
|
||||
const vaddr_t load_base_vaddr =
|
||||
[&file_header, executable_end]() -> vaddr_t
|
||||
[&file_header, exec_max_offset]() -> vaddr_t
|
||||
{
|
||||
if (file_header.e_type == ET_EXEC)
|
||||
return 0;
|
||||
if (file_header.e_type == ET_DYN)
|
||||
return (executable_end + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
|
||||
return (exec_max_offset + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
|
||||
ASSERT_NOT_REACHED();
|
||||
}();
|
||||
|
||||
vaddr_t last_loaded_address = 0;
|
||||
BAN::Vector<BAN::UniqPtr<MemoryRegion>> memory_regions;
|
||||
for (const auto& program_header : program_headers)
|
||||
{
|
||||
@@ -241,10 +240,57 @@ namespace Kernel::ELF
|
||||
|
||||
TRY(memory_regions.emplace_back(BAN::move(region)));
|
||||
}
|
||||
|
||||
last_loaded_address = BAN::Math::max(last_loaded_address, pheader_base + program_header.p_memsz);
|
||||
}
|
||||
|
||||
LoadResult result;
|
||||
result.has_interpreter = !interpreter.empty();
|
||||
|
||||
for (const auto& program_header : program_headers)
|
||||
{
|
||||
if (program_header.p_type != PT_TLS)
|
||||
continue;
|
||||
|
||||
if (!BAN::Math::is_power_of_two(program_header.p_align))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
size_t region_size = program_header.p_memsz;
|
||||
if (auto rem = region_size % program_header.p_align)
|
||||
region_size += program_header.p_align - rem;
|
||||
|
||||
size_t offset = 0;
|
||||
if (auto rem = region_size % alignof(uthread))
|
||||
offset = alignof(uthread) - rem;
|
||||
|
||||
auto region = TRY(MemoryBackedRegion::create(
|
||||
page_table,
|
||||
offset + region_size,
|
||||
{ .start = last_loaded_address, .end = USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::Present
|
||||
));
|
||||
|
||||
for (vaddr_t vaddr = region->vaddr(); vaddr < region->vaddr() + offset + region->size(); vaddr += PAGE_SIZE)
|
||||
TRY(region->allocate_page_containing(vaddr, false));
|
||||
|
||||
if (program_header.p_filesz > 0)
|
||||
{
|
||||
BAN::Vector<uint8_t> file_data_buffer;
|
||||
TRY(file_data_buffer.resize(program_header.p_filesz));
|
||||
if (TRY(inode->read(program_header.p_offset, file_data_buffer.span())) != file_data_buffer.size())
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
TRY(region->copy_data_to_region(offset, file_data_buffer.data(), file_data_buffer.size()));
|
||||
}
|
||||
|
||||
result.master_tls = LoadResult::TLS {
|
||||
.addr = region->vaddr(),
|
||||
.size = region->size(),
|
||||
};
|
||||
|
||||
TRY(memory_regions.emplace_back(BAN::move(region)));
|
||||
}
|
||||
|
||||
result.open_execfd = !interpreter.empty();
|
||||
result.entry_point = load_base_vaddr + file_header.e_entry;
|
||||
result.regions = BAN::move(memory_regions);
|
||||
return BAN::move(result);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/banan-os.h>
|
||||
#include <sys/sysmacros.h>
|
||||
@@ -142,7 +143,7 @@ namespace Kernel
|
||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
|
||||
|
||||
if (executable.has_interpreter)
|
||||
if (executable.open_execfd)
|
||||
{
|
||||
const int execfd = TRY(process->m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
@@ -156,6 +157,14 @@ namespace Kernel
|
||||
.a_un = { .a_val = 0 },
|
||||
}));
|
||||
|
||||
BAN::Optional<vaddr_t> tls_addr;
|
||||
if (executable.master_tls.has_value())
|
||||
{
|
||||
auto tls_result = TRY(process->initialize_thread_local_storage(process->page_table(), *executable.master_tls));
|
||||
TRY(process->m_mapped_regions.emplace_back(BAN::move(tls_result.region)));
|
||||
tls_addr = tls_result.addr;
|
||||
}
|
||||
|
||||
auto* thread = MUST(Thread::create_userspace(process, process->page_table()));
|
||||
MUST(thread->initialize_userspace(
|
||||
executable.entry_point,
|
||||
@@ -163,6 +172,8 @@ namespace Kernel
|
||||
process->m_environ.span(),
|
||||
auxiliary_vector.span()
|
||||
));
|
||||
if (tls_addr.has_value())
|
||||
thread->set_tls(*tls_addr);
|
||||
|
||||
process->add_thread(thread);
|
||||
process->register_to_scheduler();
|
||||
@@ -295,6 +306,63 @@ namespace Kernel
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Process::TLSResult> Process::initialize_thread_local_storage(PageTable& page_table, ELF::LoadResult::TLS master_tls)
|
||||
{
|
||||
const auto [master_addr, master_size] = master_tls;
|
||||
ASSERT(master_size % alignof(uthread) == 0);
|
||||
|
||||
const size_t tls_size = master_size + PAGE_SIZE;
|
||||
|
||||
auto region = TRY(MemoryBackedRegion::create(
|
||||
page_table,
|
||||
tls_size,
|
||||
{ .start = master_addr, .end = USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
|
||||
));
|
||||
|
||||
BAN::Vector<uint8_t> temp_buffer;
|
||||
TRY(temp_buffer.resize(BAN::Math::min<size_t>(master_size, PAGE_SIZE)));
|
||||
|
||||
size_t bytes_copied = 0;
|
||||
while (bytes_copied < master_size)
|
||||
{
|
||||
const size_t to_copy = BAN::Math::min(master_size - bytes_copied, temp_buffer.size());
|
||||
|
||||
const vaddr_t vaddr = master_addr + bytes_copied;
|
||||
const paddr_t paddr = page_table.physical_address_of(vaddr & PAGE_ADDR_MASK);
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
memcpy(temp_buffer.data(), PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), to_copy);
|
||||
});
|
||||
|
||||
TRY(region->copy_data_to_region(bytes_copied, temp_buffer.data(), to_copy));
|
||||
bytes_copied += to_copy;
|
||||
}
|
||||
|
||||
const uthread uthread {
|
||||
.self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size),
|
||||
.master_tls_addr = reinterpret_cast<void*>(master_addr),
|
||||
.master_tls_size = master_size,
|
||||
};
|
||||
const uintptr_t dtv[2] { 1, region->vaddr() };
|
||||
|
||||
TRY(region->copy_data_to_region(
|
||||
master_size,
|
||||
reinterpret_cast<const uint8_t*>(&uthread),
|
||||
sizeof(uthread)
|
||||
));
|
||||
TRY(region->copy_data_to_region(
|
||||
master_size + sizeof(uthread),
|
||||
reinterpret_cast<const uint8_t*>(&dtv),
|
||||
sizeof(dtv)
|
||||
));
|
||||
|
||||
TLSResult result;
|
||||
result.addr = region->vaddr() + master_size;;
|
||||
result.region = BAN::move(region);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t Process::proc_meminfo(off_t offset, BAN::ByteSpan buffer) const
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
@@ -572,7 +640,7 @@ namespace Kernel
|
||||
MUST(m_open_file_descriptors.close(auxiliary_vector.front().a_un.a_val));
|
||||
});
|
||||
|
||||
if (executable.has_interpreter)
|
||||
if (executable.open_execfd)
|
||||
{
|
||||
const int execfd = TRY(m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
@@ -594,6 +662,13 @@ namespace Kernel
|
||||
auxiliary_vector.span()
|
||||
));
|
||||
|
||||
if (executable.master_tls.has_value())
|
||||
{
|
||||
auto tls_result = TRY(initialize_thread_local_storage(*new_page_table, *executable.master_tls));
|
||||
TRY(new_mapped_regions.emplace_back(BAN::move(tls_result.region)));
|
||||
new_thread->set_tls(tls_result.addr);
|
||||
}
|
||||
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user