2#include "pedigree/kernel/linker/KernelElf.h"
3#include "pedigree/kernel/linker/ModuleImage.h"
4#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
5#include "pedigree/kernel/processor/VirtualAddressSpace.h"
6#include "pedigree/kernel/utilities/StringView.h"
9namespace __pedigree_hosted {
15 enum State { Unavailable, Free, Reserved, Live, Quarantined } state = Unavailable;
18 uint8_t source[ModuleImage::MaximumImageBytes];
19 uintptr_t resolved[ModuleImage::MaximumSymbols];
20 const char* dependencies[ModuleImage::MaximumDependencies + 1];
21 const char* optionalDependencies[ModuleImage::MaximumDependencies + 1];
23 bool lifecycleStarted =
false;
24 bool lifecycleComplete =
true;
28constexpr size_t SlotCount = 4;
31#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
32size_t failProtectionAfter = ~size_t{0};
35bool protect(uintptr_t address,
size_t flags) {
36#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
37 if (failProtectionAfter != ~
size_t{0} && failProtectionAfter-- == 0) {
38 failProtectionAfter = ~size_t{0};
48 for (
size_t offset = 0; offset < ModuleImage::MaximumMappedBytes;
60 for (
size_t offset = 0; offset < ModuleImage::MaximumMappedBytes; offset += pageSize) {
62 for (
size_t i = 0; i < slot.plan.segmentCount; ++i) {
63 const auto& segment = slot.plan.segments[i];
64 if (segment.memsz && offset >= (segment.vaddr & ~(pageSize - 1)) &&
65 offset < segment.vaddr + segment.memsz) {
66 if (segment.flags & PF_W)
68 if (segment.flags & PF_X)
72 if (!protect(slot.base + offset, flags))
78bool addSigned(uintptr_t value, int64_t addend, uintptr_t& result) {
80 const uint64_t magnitude = uint64_t{0} -
static_cast<uint64_t
>(addend);
81 if (value < magnitude)
83 result = value - magnitude;
85 if (value > ~uintptr_t{0} -
static_cast<uint64_t
>(addend))
87 result = value + addend;
93KernelElf::RuntimeLoad::RuntimeLoad() : lifetime(), slot(nullptr), length(0) {}
94KernelElf::RuntimeLoad::~RuntimeLoad() {
98uint8_t* KernelElf::RuntimeLoad::data()
const {
99 return slot ? slot->source :
nullptr;
103#if STATIC_DRIVERS || !BITS_64 || (!X64 && !HOSTED)
106 if (!beginModuleLoad())
108 if (m_RuntimeModulesPrepared) {
109 bool available =
false;
110 for (
const auto* slot : slots) {
112 (slot->state == RuntimeModuleSlot::Free || slot->state == RuntimeModuleSlot::Live))
119 if (!m_ModuleAllocatorInitialised) {
120 const uintptr_t start = space.getKernelModulesStart();
122 m_ModuleAllocatorInitialised =
true;
130 size_t available = 0;
131 for (
size_t index = 0; index < SlotCount; ++index) {
135 auto& slot = *prepared;
141 for (; mapped < ModuleImage::MaximumMappedBytes; mapped += pageSize) {
143 if (!space.map(page,
reinterpret_cast<void*
>(slot.base + mapped),
149 if (mapped != ModuleImage::MaximumMappedBytes) {
150 for (
size_t offset = 0; offset < mapped; offset += pageSize) {
151 void* address =
reinterpret_cast<void*
>(slot.base + offset);
152 physical_uintptr_t page = 0;
154 space.getMapping(address, page, flags);
155 space.unmap(address);
162 slot.module.name.reserve(ModuleImage::NameBytes);
163 slot.module.runtime = &slot;
164 slot.module.status = Module::Unloaded;
165 slot.module.unloadComplete =
true;
166 slot.state = writable(slot) ? RuntimeModuleSlot::Free : RuntimeModuleSlot::Quarantined;
168 slots[index] = prepared;
171 if (slot.state == RuntimeModuleSlot::Free)
177 m_RuntimeModulesPrepared =
true;
180 return available != 0;
183KernelElf::RuntimeLoadResult KernelElf::beginRuntimeModuleLoad(
size_t length, RuntimeLoad&
load) {
185 return RuntimeLoadResult::Busy;
187 return RuntimeLoadResult::InvalidImage;
188 if (length > ModuleImage::MaximumImageBytes)
189 return RuntimeLoadResult::ImageTooLarge;
190#if STATIC_DRIVERS || !BITS_64 || (!X64 && !HOSTED)
191 return RuntimeLoadResult::UnsupportedImage;
194 RuntimeLoadResult result = RuntimeLoadResult::NoMemory;
195 if (m_ModuleShutdown)
196 result = RuntimeLoadResult::Shutdown;
197 else if (m_ModuleLoading || m_UnloadingModule || m_ModuleExecutions || m_ModuleExecutionPasses)
198 result = RuntimeLoadResult::Busy;
199 else if (m_RuntimeModulesPrepared) {
200 for (
auto* prepared : slots) {
201 if (!prepared || prepared->state != RuntimeModuleSlot::Free)
203 auto& slot = *prepared;
204 slot.state = RuntimeModuleSlot::Reserved;
205 slot.lifecycleStarted =
false;
206 slot.lifecycleComplete =
true;
208 load.length = length;
209 m_ModuleLoading =
true;
210 result = RuntimeLoadResult::Ready;
218uintptr_t KernelElf::runtimeExportLocked(
const char* name,
Module* owner)
const {
220 for (
const auto* prepared : slots) {
223 const auto& slot = *prepared;
224 if (!slot.module.isActive() || (owner && owner != &slot.module))
226 for (
size_t i = 1; i < slot.plan.symbolCount; ++i) {
228 if (!slot.plan.exportedSymbol(i,
symbol) || StringCompare(slot.plan.symbolName(
symbol), name))
230 const uintptr_t address = slot.base +
symbol.value;
231 if (ST_BIND(
symbol.info) == STB_GLOBAL)
241 for (
const auto* prepared : slots) {
242 if (!prepared || !(prepared->module.isActive() || prepared->module.isExecuting())) {
246 const auto& slot = *prepared;
248 for (
size_t i = 1; slot.plan.symbol(i,
symbol,
false); ++i) {
250 const unsigned type = ST_TYPE(
symbol.info);
251 if (!
symbol.shndx ||
symbol.shndx >= 0xff00 || (type != STT_FUNC && type != STT_NOTYPE) ||
252 ST_BIND(
symbol.info) > STB_WEAK ||
symbol.value > ~uintptr_t{0} - slot.base ||
257 const uintptr_t symbolAddress = slot.base +
symbol.value;
258 const size_t symbolSize =
symbol.size ?
symbol.size : 1;
259 if (addr >= symbolAddress && addr - symbolAddress < symbolSize) {
260 const char* name = slot.plan.symbolName(
symbol,
false);
263 *startAddr = symbolAddress;
278 result =
reinterpret_cast<uintptr_t
>(__pedigree_hosted::dlsym(RTLD_DEFAULT, name));
283 if (provider == consumer || !provider->isActive() || !moduleDependsOn(consumer, provider))
285 result = provider->runtime ? runtimeExportLocked(name, provider)
293KernelElf::RuntimeLoadResult KernelElf::loadModuleRuntime(RuntimeLoad&
load) {
295 return RuntimeLoadResult::Busy;
296 auto& slot = *
load.slot;
297 auto& plan = slot.plan;
298 auto&
module = slot.module;
299 const auto preflight = plan.preflight(slot.source,
load.length);
301 case ModuleImage::Result::Malformed:
302 return RuntimeLoadResult::InvalidImage;
303 case ModuleImage::Result::Unsupported:
304 return RuntimeLoadResult::UnsupportedImage;
305 case ModuleImage::Result::TooLarge:
306 return RuntimeLoadResult::ImageTooLarge;
307 case ModuleImage::Result::Valid:
312 if (!existing->isUnloaded() && !StringCompare(existing->name.cstr(), plan.name)) {
314 return RuntimeLoadResult::Duplicate;
317 module.name.assign(plan.name);
318 module.loadBase = slot.base;
319 module.loadSize = plan.mappedBytes;
320 module.depends = slot.dependencies;
321 module.depends_opt = slot.optionalDependencies;
322 for (
size_t i = 0; i <= plan.dependencyCount; ++i)
323 slot.dependencies[i] = i < plan.dependencyCount ? plan.dependencies[i] : nullptr;
324 for (
size_t i = 0; i <= plan.optionalDependencyCount; ++i)
325 slot.optionalDependencies[i] =
326 i < plan.optionalDependencyCount ? plan.optionalDependencies[i] : nullptr;
328 for (
size_t i = 0; i < plan.dependencyCount; ++i) {
331 if (provider->isActive() && !StringCompare(provider->name.cstr(), plan.dependencies[i]))
335 return RuntimeLoadResult::MissingDependency;
340 for (
size_t i = 0; i < plan.symbolCount; ++i) {
344 slot.resolved[i] = slot.base +
symbol.value;
347 if (!slot.resolved[i] && ST_BIND(
symbol.info) != STB_WEAK) {
348 return RuntimeLoadResult::MissingDependency;
351 slot.resolved[i] = 0;
353 ByteSet(
reinterpret_cast<void*
>(slot.base), 0, ModuleImage::MaximumMappedBytes);
354 for (
size_t i = 0; i < plan.segmentCount; ++i) {
355 const auto& segment = plan.segments[i];
356 MemoryCopy(
reinterpret_cast<void*
>(slot.base + segment.vaddr), plan.bytes + segment.offset,
359 for (
size_t i = 0; i < plan.relocationCount; ++i) {
361 plan.relocation(i, relocation);
363 if (!addSigned(R_TYPE(relocation.info) == 8 ? slot.base : slot.resolved[R_SYM(relocation.info)],
364 relocation.addend, value))
365 return RuntimeLoadResult::InvalidImage;
366 MemoryCopy(
reinterpret_cast<void*
>(slot.base + relocation.offset), &value,
sizeof(value));
368 if (!plan.validateMaterialized(slot.base))
369 return RuntimeLoadResult::InvalidImage;
371 return RuntimeLoadResult::ProtectionFailed;
373 module.entry = reinterpret_cast<ModuleEntry>(slot.base + plan.entry);
374 module.exit = reinterpret_cast<void (*)()>(slot.base + plan.exit);
375 module.unloadComplete = false;
376 module.status = Module::Executing;
377 module.unloadable = true;
378 module.runtimeUnloadable = true;
379 slot.lifecycleStarted =
true;
380 slot.lifecycleComplete =
false;
382 for (
size_t i = 0; i < plan.constructorCount; ++i)
383 reinterpret_cast<void (*)()
>(slot.base + plan.constructors[i])();
385 return RuntimeLoadResult::EntryFailed;
387 module.status = Module::Active;
388 slot.state = RuntimeModuleSlot::Live;
390 m_ModuleLoading =
false;
392 return RuntimeLoadResult::Loaded;
395bool KernelElf::retireRuntimeModule(
Module* module,
bool runLifecycle) {
396 auto& slot = *
module->runtime;
397 if (runLifecycle && slot.lifecycleStarted && !slot.lifecycleComplete) {
398 TerminalQuiesceHook hook =
nullptr;
400 if (m_TerminalQuiesceOwner == module)
401 hook = m_TerminalQuiesceHook;
403 if (hook && !hook()) {
404 slot.state = RuntimeModuleSlot::Quarantined;
405 module->unloadable = false;
406 module->runtimeUnloadable = false;
410 if (m_TerminalQuiesceOwner == module) {
411 m_TerminalQuiesceOwner =
nullptr;
412 m_TerminalQuiesceHook =
nullptr;
416 for (
size_t i = 0; i < slot.plan.destructorCount; ++i)
417 reinterpret_cast<void (*)()
>(slot.base + slot.plan.destructors[i])();
418 slot.lifecycleComplete =
true;
420 const bool restored = writable(slot);
422 ByteSet(
reinterpret_cast<void*
>(slot.base), 0, ModuleImage::MaximumMappedBytes);
423 ByteSet(slot.source, 0,
sizeof(slot.source));
426 slot.state = restored ? RuntimeModuleSlot::Free : RuntimeModuleSlot::Quarantined;
427 module->entry = nullptr;
428 module->exit = nullptr;
429 module->unloadAdmission = nullptr;
430 module->depends = nullptr;
431 module->depends_opt = nullptr;
436void KernelElf::abandonRuntimeModuleLoad(RuntimeLoad&
load) {
437 auto&
module = load.slot->module;
439 module.status = Module::Failed;
441 const bool admitted = !
load.slot->lifecycleStarted || !
module.unloadAdmission ||
442 module.unloadAdmission(false) == Module::UnloadAdmission::Ready;
444 retireRuntimeModule(&module,
load.slot->lifecycleStarted);
446 load.slot->state = RuntimeModuleSlot::Quarantined;
447 module.unloadable = false;
448 module.runtimeUnloadable = false;
451 module.status = Module::Failed;
452 module.unloadComplete = load.slot->lifecycleComplete;
454 m_ModuleLoading =
false;
458#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
459void KernelElf::failRuntimeProtectionForTest(
size_t operationsBeforeFailure) {
460 failProtectionAfter = operationsBeforeFailure;
bool load(uint8_t *pBuffer, size_t length, uintptr_t loadBase, SymbolTable *pSymtab=0, uintptr_t nStart=0, uintptr_t nEnd=~0, bool relocate=true, uintptr_t destinationBase=0)
uintptr_t resolveRuntimeImport(const char *name, Module *consumer)
MemoryAllocator m_ModuleAllocator
const char * runtimeLookupSymbolLocked(uintptr_t addr, uintptr_t *startAddr) const
Vector< Module * > m_Modules
bool prepareRuntimeModules()
static KernelElf & instance()
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
virtual void freePage(physical_uintptr_t page)=0
bool allocate(T length, T &address)
void free(T address, T length, bool merge=true)
uintptr_t lookupOwned(const HashedStringView &name, Elf *owner)
static const size_t KernelMode
static const size_t Write
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static const size_t Execute
virtual MUST_USE_RESULT bool trySetFlags(void *virtualAddress, size_t newFlags)
void reserve(size_t size, bool copy)
void pushBack(const T &value)