20#include "pedigree/kernel/BootstrapInfo.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/linker/KernelElf.h"
24#include "pedigree/kernel/linker/SymbolTable.h"
25#include "pedigree/kernel/machine/Machine.h"
27#include "pedigree/kernel/process/Scheduler.h"
29#include "pedigree/kernel/process/Thread.h"
30#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
31#include "pedigree/kernel/processor/Processor.h"
32#include "pedigree/kernel/processor/ProcessorInformation.h"
33#include "pedigree/kernel/processor/VirtualAddressSpace.h"
34#include "pedigree/kernel/utilities/MemoryCount.h"
35#include "pedigree/kernel/utilities/MemoryTracing.h"
36#include "pedigree/kernel/utilities/String.h"
37#include "pedigree/kernel/utilities/utility.h"
47#define EXTENSION_ADDEND 0xFFFFFFFF00000000ULL
50static T* extend(T* p) {
51 EMIT_IF(X86_COMMON && !BITS_32) {
52 uintptr_t u =
reinterpret_cast<uintptr_t
>(p);
53 if (u < EXTENSION_ADDEND)
54 u += EXTENSION_ADDEND;
55 return reinterpret_cast<T*
>(u);
62static uintptr_t extend(T p) {
63 EMIT_IF(X86_COMMON && !BITS_32) {
66 if (u < EXTENSION_ADDEND)
67 u += EXTENSION_ADDEND;
76 if (pBootstrap.getSectionHeaderCount() == 0) {
77 WARNING(
"No ELF object available to extract symbol table from.");
82 return (STATIC_DRIVERS == 1) || (HOSTED == 1);
85 EMIT_IF(X86_COMMON && BITS_32) {
89 m_AdditionalSectionHeaders =
new MemoryRegion(
"Kernel ELF Section Headers");
92 size_t sectionHeadersLength =
93 pBootstrap.getSectionHeaderCount() * pBootstrap.getSectionHeaderEntrySize();
94 if ((sectionHeadersLength % pageSz) > 0) {
95 sectionHeadersLength += pageSz;
98 *m_AdditionalSectionHeaders, sectionHeadersLength / pageSz,
101 pBootstrap.getSectionHeaders()) ==
false) {
103 "KernelElf::initialise failed to allocate for "
104 "m_AdditionalSectionHeaders");
109 physical_uintptr_t start = ~0;
110 physical_uintptr_t end = 0;
111 for (
size_t i = 1; i < pBootstrap.getSectionHeaderCount(); i++) {
112 uintptr_t shdr_addr =
113 pBootstrap.getSectionHeaders() + i * pBootstrap.getSectionHeaderEntrySize();
117 if ((pSh->flags & SHF_ALLOC) != SHF_ALLOC) {
118 if (pSh->addr <= start) {
122 if ((pSh->addr + pSh->size) >= end) {
123 end = pSh->addr + pSh->size;
129 if ((start & ~(pageSz - 1)) == (pBootstrap.getSectionHeaders() & ~(pageSz - 1))) {
132 delete m_AdditionalSectionHeaders;
137 uintptr_t alignedStart = start & ~(pageSz - 1);
138 uintptr_t allocSize = end - alignedStart;
139 if ((allocSize % pageSz) > 0) {
142 size_t additionalContentsPages = allocSize / pageSz;
147 "KernelElf::initialise failed to allocate for "
148 "m_AdditionalSectionContents");
154 uintptr_t stringTableHeader =
155 (pBootstrap.getSectionHeaders() +
156 pBootstrap.getSectionHeaderStringTableIndex() * pBootstrap.getSectionHeaderEntrySize());
160 const char* tmpStringTable;
162 EMIT_IF(X86_COMMON && BITS_32) {
167 tmpStringTable =
reinterpret_cast<const char*
>(stringTableShdr->addr);
171 for (
size_t i = 1; i < pBootstrap.getSectionHeaderCount(); i++) {
172 uintptr_t shdr_addr =
173 pBootstrap.getSectionHeaders() + i * pBootstrap.getSectionHeaderEntrySize();
179 EMIT_IF(X86_COMMON && BITS_32) {
184 sh.name = pTruncatedSh->name;
185 sh.type = pTruncatedSh->type;
186 sh.flags = pTruncatedSh->flags;
187 sh.addr = pTruncatedSh->addr;
188 sh.offset = pTruncatedSh->offset;
189 sh.size = pTruncatedSh->size;
190 sh.link = pTruncatedSh->link;
191 sh.info = pTruncatedSh->info;
192 sh.addralign = pTruncatedSh->addralign;
193 sh.entsize = pTruncatedSh->entsize;
198 if ((pSh->flags & SHF_ALLOC) != SHF_ALLOC) {
199 NOTICE(
"Converting shdr " <<
Hex << pSh->addr <<
" -> " << pSh->addr + pSh->size);
200 pSh->addr =
reinterpret_cast<uintptr_t
>(
202 NOTICE(
" to " <<
Hex << pSh->addr);
203 pSh->offset = pSh->addr;
211 const char* pStr = tmpStringTable + pSh->name;
213 if (pSh->type == SHT_SYMTAB) {
215 m_nSymbolTableSize = pSh->size;
216 }
else if (!StringCompare(pStr,
".strtab")) {
217 m_pStringTable =
reinterpret_cast<char*
>(pSh->addr);
218 m_nStringTableSize = pSh->size;
219 }
else if (!StringCompare(pStr,
".shstrtab")) {
220 m_pShstrtab =
reinterpret_cast<char*
>(pSh->addr);
221 }
else if (!StringCompare(pStr,
".debug_frame")) {
222 m_pDebugTable =
reinterpret_cast<uint32_t*
>(pSh->addr);
223 m_nDebugTableSize = pSh->size;
229 m_nSectionHeaders = pBootstrap.getSectionHeaderCount();
232 if (m_pSymbolTable && m_pStringTable && m_pShstrtab) {
235 const char* pStrtab =
reinterpret_cast<const char*
>(m_pStringTable);
236 const char* pShstrtab =
reinterpret_cast<const char*
>(m_pShstrtab);
241 size_t numGlobal = 0;
242 for (
size_t i = 0; i < m_nSymbolTableSize /
sizeof(*pSymbol); i++) {
243 switch (ST_BIND(m_pSymbolTable[i].info)) {
258 NOTICE(
"KERNELELF: preallocating symbol table with "
259 << numGlobal <<
" global " << numWeak <<
" weak and " << numLocal <<
" local symbols.");
260 m_SymbolTable.
preallocate(numGlobal, numWeak,
this, numLocal);
262 for (
size_t i = 1; i < m_nSymbolTableSize /
sizeof(*pSymbol); i++) {
263 const char* pStr = 0;
265 if (ST_TYPE(pSymbol->info) == STT_SECTION) {
271 if (!(pSh->flags & SHF_ALLOC)) {
276 pStr = pShstrtab + pSh->name;
278 pStr = pStrtab + pSymbol->name;
283 switch (ST_BIND(pSymbol->info)) {
285 binding = SymbolTable::Local;
288 binding = SymbolTable::Global;
291 binding = SymbolTable::Weak;
294 binding = SymbolTable::Global;
297 EMIT_IF(!TRACK_HIDDEN_SYMBOLS) {
299 if (pSymbol->other == STV_HIDDEN) {
305 if (pStr && (*pStr !=
'\0')) {
309 if (!StringCompareN(pStr,
"__wrap_", 7)) {
314 m_SymbolTable.
insert(
String(pStr), binding,
this, extend(pSymbol->value));
324 : m_AdditionalSectionContents(
"Kernel ELF Section Data"),
325 m_AdditionalSectionHeaders(0),
328 m_ModuleAllocatorInitialised(false),
329 m_RuntimeModulesPrepared(false),
330 m_pSectionHeaders(0),
332 m_ModuleAdjustmentLock(false),
333 m_ModuleShutdown(false),
334 m_ModuleShutdownStatus(ShutdownOpen),
335 m_ModuleLoading(false),
336 m_UnloadingModule(nullptr),
337 m_ModuleExecutions(0),
338 m_ModuleExecutionPasses(0),
339 m_TerminalQuiesceOwner(nullptr),
340 m_TerminalQuiesceHook(nullptr),
341 m_TerminalQuiesceStatus(QuiesceOpen),
342 m_InitModule(nullptr) {}
345 delete m_AdditionalSectionHeaders;
350 m_pSymbolTable =
nullptr;
351 m_pStringTable =
nullptr;
352 m_pShstrtab =
nullptr;
353 m_pDebugTable =
nullptr;
356bool KernelElf::beginModuleLoad() {
358 const bool admitted = !m_ModuleShutdown && !m_ModuleLoading && !m_UnloadingModule;
360 m_ModuleLoading =
true;
366void KernelElf::finishModuleLoad() {
368 m_ModuleLoading =
false;
375 if (!beginModuleLoad()) {
376 WARNING(
"KERNELELF: Rejecting concurrent module load or load during shutdown");
383 if (!m_ModuleAllocatorInitialised) {
387 m_ModuleAllocatorInitialised =
true;
390 Module*
module = new Module;
392 module->elf = new Elf();
393 module->buffer = pModule;
394 module->buflen = len;
396 if (!module->elf->create(pModule, len)) {
397 FATAL(
"Module load failed (1)");
403 if (!module->elf->loadModule(pModule, len, module->loadBase, module->loadSize, &m_SymbolTable)) {
404 FATAL(
"Module load failed (2)");
411 if (module->elf->debugFrameTableLength()) {
412 size_t sz = m_nDebugTableSize +
module->elf->debugFrameTableLength();
413 if (sz %
sizeof(uint32_t))
414 sz +=
sizeof(uint32_t);
415 uint32_t* pDebug =
new uint32_t[sz /
sizeof(uint32_t)];
417 ERROR(
"Could not load module debug frame information.");
419 MemoryCopy(pDebug, m_pDebugTable, m_nDebugTableSize);
420 MemoryCopy(pDebug + m_nDebugTableSize,
421 reinterpret_cast<const void*
>(module->elf->debugFrameTable()),
422 module->elf->debugFrameTableLength());
423 m_nDebugTableSize +=
module->elf->debugFrameTableLength();
424 m_pDebugTable = pDebug;
425 NOTICE(
"Added debug module debug frame information.");
430 const char** pName =
reinterpret_cast<const char**
>(
module->elf->lookupSymbol("g_pModuleName"));
431 if ((!pName) || (!*pName)) {
432 ERROR(
"KERNELELF: Hit an invalid module, ignoring");
436 module->name.assign(rebase(module, *pName));
437 module->elf->setName(module->name);
438 auto entryPoint = *
reinterpret_cast<bool (**)()
>(
module->elf->lookupSymbol("g_pModuleEntry"));
439 auto exitPoint = *
reinterpret_cast<void (**)()
>(
module->elf->lookupSymbol("g_pModuleExit"));
442 entryPoint = adjust_pointer(entryPoint, module->loadBase);
445 exitPoint = adjust_pointer(exitPoint, module->loadBase);
447 module->entry = entryPoint;
448 module->exit = exitPoint;
449 bool* unloadable =
reinterpret_cast<bool*
>(
module->elf->lookupSymbol("g_bModuleUnloadable"));
450 module->unloadable = unloadable ? *unloadable : true;
451 bool* runtimeUnloadable =
452 reinterpret_cast<bool*
>(
module->elf->lookupSymbol("g_bModuleRuntimeUnloadable"));
454 module->runtimeUnloadable = runtimeUnloadable ? *runtimeUnloadable : true;
455 module->depends = reinterpret_cast<const char**>(module->elf->lookupSymbol("g_pDepends"));
456 module->depends_opt =
457 reinterpret_cast<const char**>(module->elf->lookupSymbol("g_pOptionalDepends"));
458 DEBUG_LOG(
"KERNELELF: Preloaded module " << module->name <<
" at " <<
Hex << module->loadBase
459 <<
" to " << (module->loadBase + module->loadSize));
460 DEBUG_LOG(
"KERNELELF: Module " << module->name <<
" consumes " <<
Dec << (module->loadSize / 1024)
461 <<
Hex <<
"K of memory");
465 while (module->depends_opt &&
rebase(module, module->depends_opt)[i]) {
466 DEBUG_LOG(
"KERNELELF: Module " << module->name <<
" optdepends on "
467 <<
rebase(module,
rebase(module, module->depends_opt)[i]));
472 while (module->depends &&
rebase(module, module->depends)[i]) {
473 DEBUG_LOG(
"KERNELELF: Module " << module->name <<
" depends on "
480 traceMetadata(
NormalStaticString(module->name),
reinterpret_cast<void*
>(module->loadBase),
481 reinterpret_cast<void*
>(module->loadBase + module->loadSize));
484 const bool initModule = !StringCompare(module->name.cstr(),
"init");
489 module->status = Module::Preloaded;
491 ++
module->progressCredits;
492 ++g_BootProgressCurrent;
497 if (g_BootProgressUpdate && !silent)
498 g_BootProgressUpdate(
"moduleload");
507 if (m_ModuleShutdown) {
509 WARNING(
"KERNELELF: Rejecting module execution after shutdown began");
512 ++m_ModuleExecutionPasses;
515 NOTICE(
"KERNELELF: executing " << moduleCount <<
" modules...");
519 bool executing =
false;
520 bool updateProgress =
false;
522 if (m_ModuleShutdown) {
526 if (m_ModuleLoading || m_UnloadingModule) {
532 FATAL(
"KERNELELF: Concurrent module adjustment without scheduler support");
536 executing = m_ModuleExecutions != 0;
538 if (claimModuleExecutionLocked(candidate)) {
540 ++candidate->progressCredits;
541 ++g_BootProgressCurrent;
542 updateProgress =
true;
560 if (updateProgress && g_BootProgressUpdate && !silent) {
561 g_BootProgressUpdate(
"moduleexec");
563 executeModule(module);
567 if (!m_ModuleExecutionPasses) {
569 FATAL(
"KERNELELF: Module execution-pass accounting underflow");
572 --m_ModuleExecutionPasses;
578 if (!beginModuleLoad()) {
579 WARNING(
"KERNELELF: Rejecting concurrent static module load or load during shutdown");
583 Module*
module = new Module;
588 module->name.assign(info->name);
589 module->entry = info->entry;
590 module->exit = info->exit;
591 module->unloadable = info->unloadable;
592 module->runtimeUnloadable = info->runtimeUnloadable;
593 module->depends = info->dependencies;
594 module->depends_opt = info->opt_dependencies;
595 DEBUG_LOG(
"KERNELELF: Preloaded module " << module->name);
599 while (module->depends_opt &&
rebase(module, module->depends_opt)[i]) {
600 DEBUG_LOG(
"KERNELELF: Module " << module->name <<
" optdepends on "
601 <<
rebase(module,
rebase(module, module->depends_opt)[i]));
606 while (module->depends &&
rebase(module, module->depends)[i]) {
607 DEBUG_LOG(
"KERNELELF: Module " << module->name <<
" depends on "
614 traceMetadata(
NormalStaticString(module->name),
reinterpret_cast<void*
>(module->loadBase),
615 reinterpret_cast<void*
>(module->loadBase + module->loadSize));
618 const bool initModule = !StringCompare(module->name.cstr(),
"init");
623 module->status = Module::Preloaded;
625 ++
module->progressCredits;
626 ++g_BootProgressCurrent;
631 if (g_BootProgressUpdate && !silent)
632 g_BootProgressUpdate(
"moduleload");
639bool KernelElf::moduleRegisteredLocked(
Module* module)
const {
641 if (registered == module) {
649 for (
auto module : modules) {
650 if (module->name == name) {
657bool KernelElf::moduleDependsOn(
Module* consumer,
Module* provider) {
658 const char** dependencyLists[] = {consumer->depends, consumer->depends_opt};
659 for (
const char** dependencies : dependencyLists) {
664 const char** rebasedDependencies =
rebase(consumer, dependencies);
665 for (
size_t i = 0; rebasedDependencies[i]; ++i) {
666 const char* dependency =
rebase(consumer, rebasedDependencies[i]);
667 if (!StringCompare(dependency, provider->name.cstr())) {
676 for (
auto consumer : modules) {
677 if (consumer == provider || consumer->unloadComplete || consumer->status == Module::Unloaded) {
680 if (moduleDependsOn(consumer, provider)) {
689 for (
auto module : modules) {
690 if (module->isExecuting() || module->isUnloading()) {
696 for (
auto module : modules) {
697 if (module->unloadComplete || module->status == Module::Unloaded || !module->unloadable) {
700 if (!hasLiveDependent(modules, module)) {
707KernelElf::ModuleUnloadClaim KernelElf::claimModuleUnloadLocked(
Module* module,
bool allowShutdown,
708 bool requireMembership,
709 bool enforceDependencies,
711 bool& runLifecycle) {
713 runLifecycle =
false;
715 if (!module || (requireMembership && !moduleRegisteredLocked(module))) {
716 return UnloadUnknown;
718 if (module->unloadComplete || module->status == Module::Unloaded) {
719 return UnloadComplete;
721 if (m_ModuleShutdown && !allowShutdown) {
722 return UnloadShutdown;
724 if (!module->unloadable) {
727 if (!allowShutdown && !module->runtimeUnloadable) {
728 return UnloadRuntimePinned;
730 if (module == m_TerminalQuiesceOwner && m_TerminalQuiesceHook) {
733 if (m_ModuleLoading || m_UnloadingModule) {
736 if (requireMembership) {
738 if (registered->isExecuting()) {
743 if (enforceDependencies && hasLiveDependent(
m_Modules, module)) {
744 return UnloadDependedOn;
747 wasFailed =
module->isFailed();
748 runLifecycle =
module->isActive() || wasFailed;
749 module->status = Module::Unloading;
750 m_UnloadingModule =
module;
751 return UnloadClaimed;
754void KernelElf::finishClaimedUnload(
Module* module,
bool wasFailed) {
756 if (m_UnloadingModule == module) {
757 module->unloadComplete = true;
758 module->status = wasFailed ? Module::Failed : Module::Unloaded;
759 m_UnloadingModule =
nullptr;
764bool KernelElf::completeUnloadAttempt(
Module* module, ModuleUnloadClaim claim,
bool wasFailed,
765 bool runLifecycle,
bool silent,
bool progress,
771 WARNING(
"KERNELELF: Module unload is busy; retry later");
774 WARNING(
"KERNELELF: Module " << module->name <<
" is pinned and cannot be unloaded");
776 case UnloadRuntimePinned:
777 WARNING(
"KERNELELF: Module " << module->name
778 <<
" cannot be unloaded while the system is running");
780 case UnloadDependedOn:
781 WARNING(
"KERNELELF: Module " << module->name <<
" still has a live dependent");
784 WARNING(
"KERNELELF: Module unload rejected after shutdown began");
787 ERROR(
"KERNELELF: Module unload target is not registered");
793 auto reportShutdown = [&](
const char* step) {
796 detail +=
module->name;
802 reportShutdown(
"checking live resources");
803 const auto admission = runLifecycle &&
module->unloadAdmission ? module->unloadAdmission(terminal)
804 : Module::UnloadAdmission::Ready;
805 if (admission != Module::UnloadAdmission::Ready) {
807 module->status = wasFailed ? Module::Failed : Module::Active;
809 module->unloadable = false;
810 if (terminal && admission == Module::UnloadAdmission::Busy)
811 m_ModuleShutdownStatus = ShutdownFailed;
812 m_UnloadingModule =
nullptr;
815 WARNING(
"KERNELELF: Retaining module with live resources " << module->name);
819 NOTICE(
"KERNELELF: Unloading module " << module->name);
821 bool progressUpdated =
false;
824 if (module->progressCredits) {
825 --
module->progressCredits;
826 if (g_BootProgressCurrent) {
827 --g_BootProgressCurrent;
829 progressUpdated =
true;
832 if (progressUpdated && g_BootProgressUpdate && !silent)
833 g_BootProgressUpdate(
"moduleunload");
836 reportShutdown(
"stopping driver");
837 if (module->runtime) {
838 const bool retired = retireRuntimeModule(module, runLifecycle);
839 finishClaimedUnload(module, wasFailed);
843 if (runLifecycle && module->exit)
846 reportShutdown(
"running destructors");
850 uintptr_t startDtors = 0;
851 uintptr_t endDtors = 0;
852 if (runLifecycle && module->elf) {
853 startDtors =
module->elf->lookupSymbol("start_dtors");
854 endDtors =
module->elf->lookupSymbol("end_dtors");
857 if (startDtors && endDtors) {
858 uintptr_t* iterator =
reinterpret_cast<uintptr_t*
>(startDtors);
859 while (iterator <
reinterpret_cast<uintptr_t*
>(endDtors)) {
860 if (
static_cast<intptr_t
>(*iterator) == -1) {
863 }
else if ((*iterator) == 0) {
868 uintptr_t dtor = *iterator;
869 void (*fp)(void) =
reinterpret_cast<void (*)(
void)
>(dtor);
876 m_SymbolTable.eraseByElf(module->elf);
880 progressUpdated =
false;
883 if (module->progressCredits) {
884 --
module->progressCredits;
885 if (g_BootProgressCurrent) {
886 --g_BootProgressCurrent;
888 progressUpdated =
true;
891 if (progressUpdated && g_BootProgressUpdate && !silent)
892 g_BootProgressUpdate(
"moduleunloaded");
895 NOTICE(
"KERNELELF: Module " << module->name <<
" unloaded.");
897 reportShutdown(
"releasing module memory");
900 size_t numPages = (
module->loadSize / pageSz) + (module->loadSize % pageSz ? 1 : 0);
904 for (
size_t i = 0; i < numPages; i++) {
905 void* unmapAddr =
reinterpret_cast<void*
>(
module->loadBase + (i * pageSz));
908 physical_uintptr_t phys = 0;
922 module->elf = nullptr;
923 module->unloadAdmission = nullptr;
925 finishClaimedUnload(module, wasFailed);
932 ModuleUnloadClaim claim = UnloadUnknown;
933 bool wasFailed =
false;
934 bool runLifecycle =
false;
937 module = findModuleByName(m_Modules, findName);
939 claim = claimModuleUnloadLocked(module,
false,
true,
true, wasFailed, runLifecycle);
944 ERROR(
"KERNELELF: Module " << name <<
" not found");
947 return completeUnloadAttempt(module, claim, wasFailed, runLifecycle, silent, progress);
951 bool wasFailed =
false;
952 bool runLifecycle =
false;
954 const ModuleUnloadClaim claim =
955 claimModuleUnloadLocked(module,
false,
true,
true, wasFailed, runLifecycle);
957 return completeUnloadAttempt(module, claim, wasFailed, runLifecycle, silent, progress);
963 ModuleUnloadClaim claim = UnloadUnknown;
964 bool wasFailed =
false;
965 bool runLifecycle =
false;
970 if (!module && !candidate->isUnloaded() && candidate->name == findName) {
976 if (!module->isActive()) {
978 }
else if (module->entry && !module->exit) {
979 claim = UnloadPinned;
981 claim = claimModuleUnloadLocked(module,
false,
true,
true, wasFailed, runLifecycle);
988 return completeUnloadAttempt(module, claim, wasFailed, runLifecycle,
true,
false)
989 ? RuntimeUnloadResult::Unloaded
990 : RuntimeUnloadResult::Busy;
993 return RuntimeUnloadResult::NotFound;
995 return RuntimeUnloadResult::Busy;
997 case UnloadRuntimePinned:
998 return RuntimeUnloadResult::Pinned;
999 case UnloadDependedOn:
1000 return RuntimeUnloadResult::DependedOn;
1001 case UnloadShutdown:
1002 return RuntimeUnloadResult::Shutdown;
1004 return RuntimeUnloadResult::Busy;
1008 if (!ownerEntry || !hook)
1011 if (m_ModuleShutdown || m_UnloadingModule) {
1016 if (module->entry == ownerEntry && (module->isExecuting() || module->isActive())) {
1017 const bool accepted = !
module->unloadAdmission || module->unloadAdmission == hook;
1019 module->unloadAdmission = hook;
1029 if (!ownerEntry || !hook) {
1034 if (m_ModuleShutdown || m_TerminalQuiesceStatus != QuiesceOpen) {
1038 if (m_TerminalQuiesceHook) {
1039 const bool alreadyRegistered = m_TerminalQuiesceOwner &&
1040 m_TerminalQuiesceOwner->entry == ownerEntry &&
1041 m_TerminalQuiesceHook == hook;
1043 return alreadyRegistered;
1048 if (module->entry != ownerEntry || !(module->isExecuting() || module->isActive())) {
1062 m_TerminalQuiesceOwner = owner;
1063 m_TerminalQuiesceHook = hook;
1070 if (!m_TerminalQuiesceHook) {
1074 if (!m_TerminalQuiesceOwner || m_TerminalQuiesceOwner->entry != ownerEntry ||
1075 m_TerminalQuiesceHook != hook || m_TerminalQuiesceStatus != QuiesceOpen) {
1080 m_TerminalQuiesceOwner =
nullptr;
1081 m_TerminalQuiesceHook =
nullptr;
1088 bool waiting =
false;
1089 bool failed =
false;
1092 if (m_ModuleShutdownStatus == ShutdownOpen) {
1093 __atomic_store_n(&m_ModuleShutdown,
true, __ATOMIC_RELEASE);
1094 m_ModuleShutdownStatus = ShutdownRunning;
1098 if (m_ModuleShutdownStatus == ShutdownComplete) {
1102 failed = m_ModuleShutdownStatus == ShutdownFailed;
1103 waiting = m_ModuleShutdownStatus == ShutdownRunning;
1107 ERROR(
"KERNELELF: Module shutdown previously failed");
1115 ERROR(
"KERNELELF: Concurrent module shutdown without scheduler support");
1121 if (g_BootProgressUpdate) {
1122 g_BootProgressUpdate(
"unload");
1126 TerminalQuiesceHook hook =
nullptr;
1127 bool waiting =
false;
1128 bool failed =
false;
1131 if (m_TerminalQuiesceStatus == QuiesceComplete) {
1135 if (m_TerminalQuiesceStatus == QuiesceFailed) {
1137 }
else if (m_TerminalQuiesceStatus == QuiesceInvoking || m_ModuleLoading || m_UnloadingModule ||
1138 m_ModuleExecutions || m_ModuleExecutionPasses) {
1141 m_TerminalQuiesceStatus = QuiesceInvoking;
1142 hook = m_TerminalQuiesceHook;
1143 m_TerminalQuiesceOwner =
nullptr;
1144 m_TerminalQuiesceHook =
nullptr;
1146 m_TerminalQuiesceStatus = QuiesceComplete;
1153 m_ModuleShutdownStatus = ShutdownFailed;
1155 ERROR(
"KERNELELF: Terminal module quiesce failed; refusing to unload modules");
1159 const bool quiesced = hook();
1161 m_TerminalQuiesceStatus = quiesced ? QuiesceComplete : QuiesceFailed;
1165 m_ModuleShutdownStatus = ShutdownFailed;
1167 ERROR(
"KERNELELF: Terminal module quiesce failed; refusing to unload modules");
1179 m_ModuleShutdownStatus = ShutdownFailed;
1181 ERROR(
"KERNELELF: Terminal quiesce encountered an in-flight module operation");
1188 Module* candidate =
nullptr;
1189 ModuleUnloadClaim claim = UnloadBusy;
1190 bool wasFailed =
false;
1191 bool runLifecycle =
false;
1192 bool waiting =
false;
1195 if (m_ModuleLoading || m_UnloadingModule || m_ModuleExecutions || m_ModuleExecutionPasses) {
1206 candidate = findUnloadCandidate(
m_Modules, waiting);
1208 claim = claimModuleUnloadLocked(candidate,
true,
true,
false, wasFailed, runLifecycle);
1213 if (candidate && claim == UnloadClaimed) {
1214 const bool completed =
1215 completeUnloadAttempt(candidate, claim, wasFailed, runLifecycle,
false,
false,
true);
1218 m_ModuleShutdownStatus == ShutdownFailed || (!completed && candidate->unloadable);
1220 m_ModuleShutdownStatus = ShutdownFailed;
1226 if (waiting || (candidate && claim == UnloadBusy)) {
1232 m_ModuleShutdownStatus = ShutdownFailed;
1234 ERROR(
"KERNELELF: Module shutdown encountered an in-flight module operation");
1242 if (!module->unloadComplete && module->status != Module::Unloaded) {
1245 if (module->unloadable && module->unloadAdmission &&
1246 module->unloadAdmission(
true) != Module::UnloadAdmission::KeepMapped) {
1247 ERROR(
"KERNELELF: Shutdown blocked by retained resources in " << module->name);
1249 m_ModuleShutdownStatus = ShutdownFailed;
1253 if (!module->unloadable) {
1254 WARNING(
"KERNELELF: Leaving permanently pinned module " << module->name
1255 <<
" mapped at shutdown");
1257 WARNING(
"KERNELELF: Leaving module " << module->name
1258 <<
" mapped because its shutdown dependencies remain");
1268 m_ModuleShutdownStatus = ShutdownComplete;
1273#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
1274size_t KernelElf::planModuleUnloadOrderForTest(
Module** modules,
size_t count,
Module** order,
1277 for (
size_t i = 0; i < count; ++i) {
1283 bool waiting =
false;
1284 Module* candidate = findUnloadCandidate(pending, waiting);
1285 if (!candidate || waiting) {
1288 if (planned < capacity) {
1289 order[planned] = candidate;
1292 candidate->unloadComplete =
true;
1293 candidate->status = Module::Unloaded;
1298KernelElf::TestModuleUnloadClaim KernelElf::claimModuleUnloadForTest(
Module* module,
1301 bool wasFailed =
false;
1302 bool runLifecycle =
false;
1305 const ModuleUnloadClaim claim = kernelElf.claimModuleUnloadLocked(module, allowShutdown,
false,
1306 false, wasFailed, runLifecycle);
1309 *lifecycle = runLifecycle;
1311 return static_cast<TestModuleUnloadClaim
>(claim);
1314KernelElf::TestModuleUnloadClaim KernelElf::claimNamedModuleUnloadForTest(
Module** modules,
1318 for (
size_t i = 0; i < count; ++i) {
1323 bool wasFailed =
false;
1324 bool runLifecycle =
false;
1326 Module*
module = findModuleByName(fixtures, String(name));
1327 ModuleUnloadClaim claim = UnloadUnknown;
1329 claim = kernelElf.claimModuleUnloadLocked(module,
true,
false,
false, wasFailed, runLifecycle);
1332 return static_cast<TestModuleUnloadClaim
>(claim);
1335void KernelElf::completeModuleUnloadForTest(
Module* module,
bool wasFailed,
bool runLifecycle) {
1336 instance().completeUnloadAttempt(module, UnloadClaimed, wasFailed, runLifecycle,
true,
false);
1339bool KernelElf::completeGuardedModuleUnloadForTest(
Module* module,
bool terminal) {
1340 return instance().completeUnloadAttempt(module, UnloadClaimed,
false,
true,
true,
false,
1344bool KernelElf::moduleExecutionWaitsForUnloadForTest() {
1346 unloading.name.assign(
"hosted-unload-admission-owner");
1347 unloading.status = Module::Active;
1349 pending.name.assign(
"hosted-execution-admission-probe");
1350 pending.status = Module::Preloaded;
1353 bool wasFailed =
false;
1354 bool runLifecycle =
false;
1356 const ModuleUnloadClaim claim =
1357 kernelElf.claimModuleUnloadLocked(&unloading,
true,
false,
false, wasFailed, runLifecycle);
1358 if (claim != UnloadClaimed) {
1362 const bool admittedDuringUnload = kernelElf.claimModuleExecutionLocked(&pending);
1363 const bool remainedPending = pending.isPending();
1364 if (admittedDuringUnload) {
1365 --kernelElf.m_ModuleExecutions;
1366 pending.status = Module::Preloaded;
1369 kernelElf.finishClaimedUnload(&unloading,
false);
1372 const bool admittedAfterUnload = kernelElf.claimModuleExecutionLocked(&pending);
1373 const bool admittedTwice = kernelElf.claimModuleExecutionLocked(&pending);
1374 if (admittedAfterUnload) {
1375 --kernelElf.m_ModuleExecutions;
1377 if (admittedTwice) {
1378 --kernelElf.m_ModuleExecutions;
1381 return !admittedDuringUnload && remainedPending && admittedAfterUnload && !admittedTwice &&
1382 unloading.isUnloaded();
1390 bool loaded =
false;
1393 if (module->isLoaded() &&
module->name == compName) {
1403 char* result =
nullptr;
1406 if (!module->isLoaded()) {
1409 }
else if (module->depends == 0) {
1414 while (
rebase(module, module->depends)[i]) {
1415 const char* rebased =
rebase(module,
rebase(module, module->depends)[i]);
1416 if (!StringCompare(rebased, name)) {
1417 result =
const_cast<char*
>(
static_cast<const char*
>(
module->name));
1431bool KernelElf::claimModuleExecutionLocked(
Module* module) {
1432 if (m_ModuleShutdown || m_ModuleLoading || m_UnloadingModule || !module->isPending() ||
1437 module->status = Module::Executing;
1438 ++m_ModuleExecutions;
1446 if (module->depends_opt) {
1447 while (
rebase(module, module->depends_opt)[i]) {
1448 const char* depname =
rebase(module,
rebase(module, module->depends_opt)[i]);
1450 bool exists =
false;
1451 bool attempted =
false;
1453 if (!mod->isUnloaded() && !StringCompare(mod->name.cstr(), depname)) {
1455 attempted = mod->wasAttempted() && !mod->isExecuting() && !mod->isUnloading();
1473 if (!module->depends) {
1477 while (
rebase(module, module->depends)[i]) {
1478 const char* depname =
rebase(module,
rebase(module, module->depends)[i]);
1480 bool exists =
false;
1482 if (!mod->isUnloaded() && !StringCompare(mod->name.cstr(), depname)) {
1484 if (!mod->isActive()) {
1500static int executeModuleThread(
void* mod) {
1501 Module*
module = reinterpret_cast<Module*>(mod);
1503 NOTICE(
"running module: " << module->name);
1505 if (module->buffer) {
1506 if (!module->elf->
finaliseModule(module->buffer, module->buflen)) {
1507 FATAL(
"KERNELELF: Module relocation failed for module " << module->name);
1513 uintptr_t startCtors =
module->elf->lookupSymbol("start_ctors");
1514 uintptr_t endCtors =
module->elf->lookupSymbol("end_ctors");
1516 if (startCtors && endCtors) {
1517 uintptr_t* iterator =
reinterpret_cast<uintptr_t*
>(startCtors);
1518 while (iterator <
reinterpret_cast<uintptr_t*
>(endCtors)) {
1519 if (
static_cast<intptr_t
>(*iterator) == -1) {
1522 }
else if ((*iterator) == 0) {
1527 uintptr_t ctor = *iterator;
1528 void (*fp)(void) =
reinterpret_cast<void (*)(
void)
>(ctor);
1533 WARNING(
"KERNELELF: Module " << module->name <<
" had no ctors!");
1536 uintptr_t optionalDeps =
module->elf->lookupSymbol("__add_optional_deps");
1538 NOTICE(
"KERNELELF: Running module " << module->name <<
" optional dependencies function.");
1539 void (*fp)(void) =
reinterpret_cast<void (*)(
void)
>(optionalDeps);
1544 NOTICE(
"KERNELELF: Executing module " << module->name);
1546 bool bSuccess = !
module->entry;
1547 String moduleName(module->name);
1548 if (module->entry) {
1549 bSuccess =
module->entry();
1557bool KernelElf::executeModule(
Module* module) {
1558 executeModuleThread(module);
1564 String moduleName(module->name);
1566 NOTICE(
"KERNELELF: Module " << moduleName <<
" finished executing");
1568 module->status = Module::Active;
1569 if (!m_ModuleExecutions) {
1571 FATAL(
"KERNELELF: Module execution accounting underflow");
1574 --m_ModuleExecutions;
1577 NOTICE(
"KERNELELF: Module " << moduleName <<
" failed, unloading.");
1578 bool wasFailed =
false;
1579 bool runLifecycle =
false;
1580 ModuleUnloadClaim claim = UnloadBusy;
1582 module->status = Module::Failed;
1583 claim = claimModuleUnloadLocked(module,
true,
false,
false, wasFailed, runLifecycle);
1585 runLifecycle = runLifecycle && runFailureLifecycle;
1586 completeUnloadAttempt(module, claim, wasFailed, runLifecycle,
true,
false);
1588 if (!m_ModuleExecutions) {
1590 FATAL(
"KERNELELF: Module execution accounting underflow");
1593 --m_ModuleExecutions;
1601 const bool executing =
1602 m_ModuleLoading || m_UnloadingModule || m_ModuleExecutions || m_ModuleExecutionPasses;
1610 FATAL(
"Module execution remained active without scheduler support.");
1619 NOTICE(
"SUCCESSFUL MODULES:");
1620 for (
size_t i = 0; i < moduleCount; ++i) {
1621 Module*
module = nullptr;
1622 bool active =
false;
1625 module = m_Modules[i];
1626 active =
module->isActive();
1629 if (module && active) {
1630 NOTICE(
" - " << module->name);
1634 NOTICE(
"UNSUCCESSFUL MODULES:");
1635 for (
size_t i = 0; i < moduleCount; ++i) {
1636 Module*
module = nullptr;
1637 bool failed =
false;
1640 module = m_Modules[i];
1641 failed =
module->isFailed();
1644 if (module && failed) {
1645 NOTICE(
" - " << module->name);
1652 WARNING(
"KernelElf: runtime module arena unavailable");
1654 bool updateProgress =
false;
1657 if (mod ==
nullptr) {
1659 WARNING(
"KernelElf: no init module was ever preloaded, cannot invoke init");
1663 if (m_ModuleShutdown || m_ModuleLoading || m_UnloadingModule) {
1665 WARNING(
"KernelElf: refusing to invoke init during another module transition");
1671 FATAL(
"init module could not be invoked - its dependencies were not satisfied");
1679 mod->status = Module::Executing;
1680 ++m_ModuleExecutions;
1683 if (g_BootProgressTotal) {
1684 g_BootProgressCurrent += 2;
1685 updateProgress = g_BootProgressUpdate !=
nullptr;
1689 if (updateProgress && g_BootProgressUpdate)
1690 g_BootProgressUpdate(
"moduleexec");
1692 executeModuleThread(
reinterpret_cast<void*
>(mod));
1701 const uintptr_t result = runtimeExportLocked(pName);
1709 if ((ret =
lookupSymbol(addr, startAddr, m_pSymbolTable))) {
1716 if (!(it->isActive() || it->isExecuting())) {
1720 if (it->elf && (ret = it->elf->lookupSymbol(addr, startAddr))) {
1730 WARNING_NOLOCK(
"KERNELELF: GlobalLookupSymbol(" <<
Hex << addr <<
") failed.");
1743 const Module*
module = index < m_Modules.count() ? m_Modules[index] : nullptr;
1749 bool hasPending =
false;
1751 if (it->isPending()) {
1752 NOTICE(
"Pending module: " << it->name);
1761 m_ModuleAdjustmentLock.
acquire();
1767 m_ModuleAdjustmentLock.
release();
bool finaliseModule(uint8_t *pBuffer, size_t length)
const char * lookupSymbol(uintptr_t addr, uintptr_t *startAddr, T *symbolTable)
KernelElf() INITIALISATION_ONLY
static T * rebase(Module *module, T *ptr)
MemoryAllocator m_ModuleAllocator
char * getDependingModule(char *name)
bool unloadModule(const char *name, bool silent=false, bool progress=true)
void executeModules(bool silent=false, bool progress=true)
void waitForModulesToLoad()
const char * runtimeLookupSymbolLocked(uintptr_t addr, uintptr_t *startAddr) const
void invokeInitModule()
Invokes the module named 'init'. When a module named init is discovered, rather than executing it in ...
bool hasPendingModules() const
bool moduleIsLoaded(char *name)
Vector< Module * > m_Modules
bool registerUnloadAdmission(ModuleEntry ownerEntry, Module::UnloadAdmissionHook hook)
MUST_USE_RESULT bool unloadModules()
bool prepareRuntimeModules()
bool registerTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook)
static KernelElf & instance()
Module * loadModule(uint8_t *pModule, size_t len, bool silent=false)
bool moduleDependenciesSatisfiedLocked(Module *module) const
RuntimeUnloadResult unloadModuleRuntime(const char *name)
bool unregisterTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook)
static KernelElf m_Instance
MemoryRegion m_AdditionalSectionContents
uintptr_t globalLookupSymbol(const char *pName)
bool initialise(const BootstrapStruct_t &pBootstrap) INITIALISATION_ONLY
const Module * getModule(size_t index)
void updateModuleStatus(Module *module, bool status, bool runFailureLifecycle=true)
static void setShutdownPhase(ShutdownPhase phase, const char *detail=nullptr)
Special memory entity in the kernel's virtual address space.
static const size_t continuous
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
virtual void freePage(physical_uintptr_t page)=0
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
static ProcessorInformation & information()
void free(T address, T length, bool merge=true)
static Scheduler & instance()
bool acquire(bool recurse=false, bool safe=true)
void insert(const String &name, Binding binding, Elf *pParent, uintptr_t value)
void preallocate(size_t numGlobal, size_t numWeak, Elf *localElf, size_t numLocal)
uintptr_t EXPORTED_PUBLIC lookup(const HashedStringView &name, Elf *pElf, Policy policy=LocalFirst, Binding *pBinding=0)
A vector / dynamic array.
virtual bool isMapped(void *virtualAddress)=0
static const size_t KernelMode
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
static const size_t Write
virtual uintptr_t getKernelModulesEnd() const =0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual void unmap(void *virtualAddress)=0
virtual uintptr_t getKernelModulesStart() const =0
void pushBack(const T &value)
void clear(bool freeMem=false)