The Pedigree Project 0.1
KernelElf.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
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"
26#if THREADS
27#include "pedigree/kernel/process/Scheduler.h"
28#endif
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"
38
40
47#define EXTENSION_ADDEND 0xFFFFFFFF00000000ULL
48
49template <class T>
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);
56 }
57
58 return p;
59}
60
61template <class T>
62static uintptr_t extend(T p) {
63 EMIT_IF(X86_COMMON && !BITS_32) {
64 // Must assign to a possibly-larger type before arithmetic.
65 uintptr_t u = p;
66 if (u < EXTENSION_ADDEND)
67 u += EXTENSION_ADDEND;
68 return u;
69 }
70
71 return p;
72}
73
75 // Do we even have section headers to peek at?
76 if (pBootstrap.getSectionHeaderCount() == 0) {
77 WARNING("No ELF object available to extract symbol table from.");
78
79 // Hosted dynamic modules can resolve exported kernel symbols from the
80 // process linker. Darwin kernels are Mach-O, so there is intentionally
81 // no ELF image from which to import a second symbol table.
82 return (STATIC_DRIVERS == 1) || (HOSTED == 1);
83 }
84
85 EMIT_IF(X86_COMMON && BITS_32) {
87 size_t pageSz = PhysicalMemoryManager::getPageSize();
88
89 m_AdditionalSectionHeaders = new MemoryRegion("Kernel ELF Section Headers");
90
91 // Map in section headers.
92 size_t sectionHeadersLength =
93 pBootstrap.getSectionHeaderCount() * pBootstrap.getSectionHeaderEntrySize();
94 if ((sectionHeadersLength % pageSz) > 0) {
95 sectionHeadersLength += pageSz;
96 }
97 if (physicalMemoryManager.allocateRegion(
98 *m_AdditionalSectionHeaders, sectionHeadersLength / pageSz,
101 pBootstrap.getSectionHeaders()) == false) {
102 ERROR(
103 "KernelElf::initialise failed to allocate for "
104 "m_AdditionalSectionHeaders");
105 return false;
106 }
107
108 // Determine the layout of the contents of non-code sections.
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();
115 m_AdditionalSectionHeaders->convertPhysicalPointer<KernelElfSectionHeader_t>(shdr_addr);
116
117 if ((pSh->flags & SHF_ALLOC) != SHF_ALLOC) {
118 if (pSh->addr <= start) {
119 start = pSh->addr;
120 }
121
122 if ((pSh->addr + pSh->size) >= end) {
123 end = pSh->addr + pSh->size;
124 }
125 }
126 }
127
128 // Is there an overlap between headers and section data?
129 if ((start & ~(pageSz - 1)) == (pBootstrap.getSectionHeaders() & ~(pageSz - 1))) {
130 // Yes, there is. Point the section headers MemoryRegion to the
131 // Contents.
132 delete m_AdditionalSectionHeaders;
133 m_AdditionalSectionHeaders = &m_AdditionalSectionContents;
134 }
135
136 // Map in all non-alloc sections.
137 uintptr_t alignedStart = start & ~(pageSz - 1);
138 uintptr_t allocSize = end - alignedStart;
139 if ((allocSize % pageSz) > 0) {
140 allocSize += pageSz;
141 }
142 size_t additionalContentsPages = allocSize / pageSz;
143 if (physicalMemoryManager.allocateRegion(
146 ERROR(
147 "KernelElf::initialise failed to allocate for "
148 "m_AdditionalSectionContents");
149 return false;
150 }
151 }
152
153 // Get the string table
154 uintptr_t stringTableHeader =
155 (pBootstrap.getSectionHeaders() +
156 pBootstrap.getSectionHeaderStringTableIndex() * pBootstrap.getSectionHeaderEntrySize());
157 KernelElfSectionHeader_t* stringTableShdr =
158 reinterpret_cast<KernelElfSectionHeader_t*>(stringTableHeader);
159
160 const char* tmpStringTable;
161
162 EMIT_IF(X86_COMMON && BITS_32) {
163 tmpStringTable =
164 m_AdditionalSectionContents.convertPhysicalPointer<const char>(stringTableShdr->addr);
165 }
166 else {
167 tmpStringTable = reinterpret_cast<const char*>(stringTableShdr->addr);
168 }
169
170 // Search for the symbol/string table and adjust sections
171 for (size_t i = 1; i < pBootstrap.getSectionHeaderCount(); i++) {
172 uintptr_t shdr_addr =
173 pBootstrap.getSectionHeaders() + i * pBootstrap.getSectionHeaderEntrySize();
174
175 // The expanded x86 header must live until the section has been inspected.
177 ElfSectionHeader_t* pSh = 0;
178
179 EMIT_IF(X86_COMMON && BITS_32) {
180 KernelElfSectionHeader_t* pTruncatedSh =
181 m_AdditionalSectionHeaders->convertPhysicalPointer<KernelElfSectionHeader_t>(shdr_addr);
182
183 // Copy into larger format for analysis
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;
194
195 pSh = &sh;
196
197 // Adjust the section
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>(
201 m_AdditionalSectionContents.convertPhysicalPointer<void>(pSh->addr));
202 NOTICE(" to " << Hex << pSh->addr);
203 pSh->offset = pSh->addr;
204 }
205 }
206 else {
207 pSh = reinterpret_cast<ElfSectionHeader_t*>(shdr_addr);
208 }
209
210 // Save the symbol/string table
211 const char* pStr = tmpStringTable + pSh->name;
212
213 if (pSh->type == SHT_SYMTAB) {
214 m_pSymbolTable = reinterpret_cast<KernelElfSymbol_t*>(pSh->addr);
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;
224 }
225 }
226
227 // Initialise remaining member variables
228 m_pSectionHeaders = reinterpret_cast<KernelElfSectionHeader_t*>(pBootstrap.getSectionHeaders());
229 m_nSectionHeaders = pBootstrap.getSectionHeaderCount();
230
231 // Dynamic modules need the kernel's exports even without an interactive debugger.
232 if (m_pSymbolTable && m_pStringTable && m_pShstrtab) {
233 KernelElfSymbol_t* pSymbol = m_pSymbolTable;
234
235 const char* pStrtab = reinterpret_cast<const char*>(m_pStringTable);
236 const char* pShstrtab = reinterpret_cast<const char*>(m_pShstrtab);
237
238 // quick pass to preallocate for the symbol table
239 size_t numLocal = 0;
240 size_t numWeak = 0;
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)) {
244 case STB_LOCAL:
245 ++numLocal;
246 break;
247 case STB_GLOBAL:
248 ++numGlobal;
249 break;
250 case STB_WEAK:
251 ++numWeak;
252 break;
253 default:
254 ++numGlobal;
255 }
256 }
257
258 NOTICE("KERNELELF: preallocating symbol table with "
259 << numGlobal << " global " << numWeak << " weak and " << numLocal << " local symbols.");
260 m_SymbolTable.preallocate(numGlobal, numWeak, this, numLocal);
261
262 for (size_t i = 1; i < m_nSymbolTableSize / sizeof(*pSymbol); i++) {
263 const char* pStr = 0;
264
265 if (ST_TYPE(pSymbol->info) == STT_SECTION) {
266 // Section type - the name will be the name of the section
267 // header it refers to.
268 KernelElfSectionHeader_t* pSh = &m_pSectionHeaders[pSymbol->shndx];
269 // If it's not allocated, it's a link-once-only section that we
270 // can ignore.
271 if (!(pSh->flags & SHF_ALLOC)) {
272 pSymbol++;
273 continue;
274 }
275 // Grab the shstrtab
276 pStr = pShstrtab + pSh->name;
277 } else {
278 pStr = pStrtab + pSymbol->name;
279 }
280
281 // Insert the symbol into the symbol table.
282 SymbolTable::Binding binding;
283 switch (ST_BIND(pSymbol->info)) {
284 case STB_LOCAL:
285 binding = SymbolTable::Local;
286 break;
287 case STB_GLOBAL:
288 binding = SymbolTable::Global;
289 break;
290 case STB_WEAK:
291 binding = SymbolTable::Weak;
292 break;
293 default:
294 binding = SymbolTable::Global;
295 }
296
297 EMIT_IF(!TRACK_HIDDEN_SYMBOLS) {
298 // Don't insert hidden symbols to the main symbol table.
299 if (pSymbol->other == STV_HIDDEN) {
300 ++pSymbol;
301 continue;
302 }
303 }
304
305 if (pStr && (*pStr != '\0')) {
306 EMIT_IF(HOSTED) {
307 // If name starts with __wrap_, rewrite it in flight as it's
308 // a wrapped symbol on hosted systems.
309 if (!StringCompareN(pStr, "__wrap_", 7)) {
310 pStr += 7;
311 }
312 }
313
314 m_SymbolTable.insert(String(pStr), binding, this, extend(pSymbol->value));
315 }
316 pSymbol++;
317 }
318 }
319
320 return true;
321}
322
324 : m_AdditionalSectionContents("Kernel ELF Section Data"),
325 m_AdditionalSectionHeaders(0),
326 m_Modules(),
327 m_ModuleAllocator(),
328 m_ModuleAllocatorInitialised(false),
329 m_RuntimeModulesPrepared(false),
330 m_pSectionHeaders(0),
331 m_pSymbolTable(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) {}
343
345 delete m_AdditionalSectionHeaders;
346
347 // All of these non-alloc sections are just pointers into the loaded kernel
348 // ELF, which is not heap allocated. In normal Elf objects these are
349 // allocated and then copied into. Not so here.
350 m_pSymbolTable = nullptr;
351 m_pStringTable = nullptr;
352 m_pShstrtab = nullptr;
353 m_pDebugTable = nullptr;
354}
355
356bool KernelElf::beginModuleLoad() {
357 lockModules();
358 const bool admitted = !m_ModuleShutdown && !m_ModuleLoading && !m_UnloadingModule;
359 if (admitted) {
360 m_ModuleLoading = true;
361 }
363 return admitted;
364}
365
366void KernelElf::finishModuleLoad() {
367 lockModules();
368 m_ModuleLoading = false;
370}
371
372Module* KernelElf::loadModule(uint8_t* pModule, size_t len, bool silent) {
373 MemoryCount guard(__PRETTY_FUNCTION__);
374
375 if (!beginModuleLoad()) {
376 WARNING("KERNELELF: Rejecting concurrent module load or load during shutdown");
377 return nullptr;
378 }
379
380 // The module memory allocator requires dynamic memory - this isn't
381 // initialised until after our constructor is called, so check here if we've
382 // loaded any modules yet. If not, we can initialise our memory allocator.
383 if (!m_ModuleAllocatorInitialised) {
386 m_ModuleAllocator.free(start, end - start);
387 m_ModuleAllocatorInitialised = true;
388 }
389
390 Module* module = new Module;
391
392 module->elf = new Elf();
393 module->buffer = pModule;
394 module->buflen = len;
395
396 if (!module->elf->create(pModule, len)) {
397 FATAL("Module load failed (1)");
398 delete module;
399 finishModuleLoad();
400 return 0;
401 }
402
403 if (!module->elf->loadModule(pModule, len, module->loadBase, module->loadSize, &m_SymbolTable)) {
404 FATAL("Module load failed (2)");
405 delete module;
406 finishModuleLoad();
407 return 0;
408 }
409
410 // Load the module debug table (if any)
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)];
416 if (UNLIKELY(!pDebug)) {
417 ERROR("Could not load module debug frame information.");
418 } else {
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.");
426 }
427 }
428
429 // Look up the module's name and entry/exit functions, and dependency list.
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");
433 finishModuleLoad();
434 return 0;
435 }
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"));
440 // Readjust entry/exit functions for the loaded module if needed
441 if (entryPoint) {
442 entryPoint = adjust_pointer(entryPoint, module->loadBase);
443 }
444 if (exitPoint) {
445 exitPoint = adjust_pointer(exitPoint, module->loadBase);
446 }
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"));
453 // Older modules predate explicit-unload policy metadata.
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");
462
463 {
464 size_t i = 0;
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]));
468 ++i;
469 }
470
471 i = 0;
472 while (module->depends && rebase(module, module->depends)[i]) {
473 DEBUG_LOG("KERNELELF: Module " << module->name << " depends on "
474 << rebase(module, rebase(module, module->depends)[i]));
475 ++i;
476 }
477 }
478
479 EMIT_IF(MEMORY_TRACING) {
480 traceMetadata(NormalStaticString(module->name), reinterpret_cast<void*>(module->loadBase),
481 reinterpret_cast<void*>(module->loadBase + module->loadSize));
482 }
483
484 const bool initModule = !StringCompare(module->name.cstr(), "init");
485 lockModules();
486 if (initModule) {
487 m_InitModule = module;
488 } else {
489 module->status = Module::Preloaded;
490 m_Modules.pushBack(module);
491 ++module->progressCredits;
492 ++g_BootProgressCurrent;
493 }
495
496 if (!initModule) {
497 if (g_BootProgressUpdate && !silent)
498 g_BootProgressUpdate("moduleload");
499 }
500 finishModuleLoad();
501
502 return module;
503}
504
505void KernelElf::executeModules(bool silent, bool progress) {
506 lockModules();
507 if (m_ModuleShutdown) {
509 WARNING("KERNELELF: Rejecting module execution after shutdown began");
510 return;
511 }
512 ++m_ModuleExecutionPasses;
513 const size_t moduleCount = m_Modules.count();
515 NOTICE("KERNELELF: executing " << moduleCount << " modules...");
516
517 while (true) {
518 Module* module = nullptr;
519 bool executing = false;
520 bool updateProgress = false;
521 lockModules();
522 if (m_ModuleShutdown) {
524 break;
525 }
526 if (m_ModuleLoading || m_UnloadingModule) {
528#if THREADS
530 continue;
531#else
532 FATAL("KERNELELF: Concurrent module adjustment without scheduler support");
533 break;
534#endif
535 }
536 executing = m_ModuleExecutions != 0;
537 for (auto candidate : m_Modules) {
538 if (claimModuleExecutionLocked(candidate)) {
539 if (progress) {
540 ++candidate->progressCredits;
541 ++g_BootProgressCurrent;
542 updateProgress = true;
543 }
544 module = candidate;
545 break;
546 }
547 }
549
550 if (!module) {
551 if (executing) {
552#if THREADS
554 continue;
555#endif
556 }
557 break;
558 }
559
560 if (updateProgress && g_BootProgressUpdate && !silent) {
561 g_BootProgressUpdate("moduleexec");
562 }
563 executeModule(module);
564 }
565
566 lockModules();
567 if (!m_ModuleExecutionPasses) {
569 FATAL("KERNELELF: Module execution-pass accounting underflow");
570 return;
571 }
572 --m_ModuleExecutionPasses;
574}
575
576Module* KernelElf::loadModule(struct ModuleInfo* info, bool silent) {
578 if (!beginModuleLoad()) {
579 WARNING("KERNELELF: Rejecting concurrent static module load or load during shutdown");
580 return nullptr;
581 }
582
583 Module* module = new Module;
584
585 module->buffer = 0;
586 module->buflen = 0;
587
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);
596
597 {
598 size_t i = 0;
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]));
602 ++i;
603 }
604
605 i = 0;
606 while (module->depends && rebase(module, module->depends)[i]) {
607 DEBUG_LOG("KERNELELF: Module " << module->name << " depends on "
608 << rebase(module, rebase(module, module->depends)[i]));
609 ++i;
610 }
611 }
612
613 EMIT_IF(MEMORY_TRACING) {
614 traceMetadata(NormalStaticString(module->name), reinterpret_cast<void*>(module->loadBase),
615 reinterpret_cast<void*>(module->loadBase + module->loadSize));
616 }
617
618 const bool initModule = !StringCompare(module->name.cstr(), "init");
619 lockModules();
620 if (initModule) {
621 m_InitModule = module;
622 } else {
623 module->status = Module::Preloaded;
624 m_Modules.pushBack(module);
625 ++module->progressCredits;
626 ++g_BootProgressCurrent;
627 }
629
630 if (!initModule) {
631 if (g_BootProgressUpdate && !silent)
632 g_BootProgressUpdate("moduleload");
633 }
634 finishModuleLoad();
635
636 return module;
637}
638
639bool KernelElf::moduleRegisteredLocked(Module* module) const {
640 for (auto registered : m_Modules) {
641 if (registered == module) {
642 return true;
643 }
644 }
645 return false;
646}
647
648Module* KernelElf::findModuleByName(const Vector<Module*>& modules, const String& name) {
649 for (auto module : modules) {
650 if (module->name == name) {
651 return module;
652 }
653 }
654 return nullptr;
655}
656
657bool KernelElf::moduleDependsOn(Module* consumer, Module* provider) {
658 const char** dependencyLists[] = {consumer->depends, consumer->depends_opt};
659 for (const char** dependencies : dependencyLists) {
660 if (!dependencies) {
661 continue;
662 }
663
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())) {
668 return true;
669 }
670 }
671 }
672 return false;
673}
674
675bool KernelElf::hasLiveDependent(const Vector<Module*>& modules, Module* provider) {
676 for (auto consumer : modules) {
677 if (consumer == provider || consumer->unloadComplete || consumer->status == Module::Unloaded) {
678 continue;
679 }
680 if (moduleDependsOn(consumer, provider)) {
681 return true;
682 }
683 }
684 return false;
685}
686
687Module* KernelElf::findUnloadCandidate(const Vector<Module*>& modules, bool& waiting) {
688 waiting = false;
689 for (auto module : modules) {
690 if (module->isExecuting() || module->isUnloading()) {
691 waiting = true;
692 return nullptr;
693 }
694 }
695
696 for (auto module : modules) {
697 if (module->unloadComplete || module->status == Module::Unloaded || !module->unloadable) {
698 continue;
699 }
700 if (!hasLiveDependent(modules, module)) {
701 return module;
702 }
703 }
704 return nullptr;
705}
706
707KernelElf::ModuleUnloadClaim KernelElf::claimModuleUnloadLocked(Module* module, bool allowShutdown,
708 bool requireMembership,
709 bool enforceDependencies,
710 bool& wasFailed,
711 bool& runLifecycle) {
712 wasFailed = false;
713 runLifecycle = false;
714
715 if (!module || (requireMembership && !moduleRegisteredLocked(module))) {
716 return UnloadUnknown;
717 }
718 if (module->unloadComplete || module->status == Module::Unloaded) {
719 return UnloadComplete;
720 }
721 if (m_ModuleShutdown && !allowShutdown) {
722 return UnloadShutdown;
723 }
724 if (!module->unloadable) {
725 return UnloadPinned;
726 }
727 if (!allowShutdown && !module->runtimeUnloadable) {
728 return UnloadRuntimePinned;
729 }
730 if (module == m_TerminalQuiesceOwner && m_TerminalQuiesceHook) {
731 return UnloadBusy;
732 }
733 if (m_ModuleLoading || m_UnloadingModule) {
734 return UnloadBusy;
735 }
736 if (requireMembership) {
737 for (auto registered : m_Modules) {
738 if (registered->isExecuting()) {
739 return UnloadBusy;
740 }
741 }
742 }
743 if (enforceDependencies && hasLiveDependent(m_Modules, module)) {
744 return UnloadDependedOn;
745 }
746
747 wasFailed = module->isFailed();
748 runLifecycle = module->isActive() || wasFailed;
749 module->status = Module::Unloading;
750 m_UnloadingModule = module;
751 return UnloadClaimed;
752}
753
754void KernelElf::finishClaimedUnload(Module* module, bool wasFailed) {
755 lockModules();
756 if (m_UnloadingModule == module) {
757 module->unloadComplete = true;
758 module->status = wasFailed ? Module::Failed : Module::Unloaded;
759 m_UnloadingModule = nullptr;
760 }
762}
763
764bool KernelElf::completeUnloadAttempt(Module* module, ModuleUnloadClaim claim, bool wasFailed,
765 bool runLifecycle, bool silent, bool progress,
766 bool terminal) {
767 switch (claim) {
768 case UnloadComplete:
769 return true;
770 case UnloadBusy:
771 WARNING("KERNELELF: Module unload is busy; retry later");
772 return false;
773 case UnloadPinned:
774 WARNING("KERNELELF: Module " << module->name << " is pinned and cannot be unloaded");
775 return false;
776 case UnloadRuntimePinned:
777 WARNING("KERNELELF: Module " << module->name
778 << " cannot be unloaded while the system is running");
779 return false;
780 case UnloadDependedOn:
781 WARNING("KERNELELF: Module " << module->name << " still has a live dependent");
782 return false;
783 case UnloadShutdown:
784 WARNING("KERNELELF: Module unload rejected after shutdown began");
785 return false;
786 case UnloadUnknown:
787 ERROR("KERNELELF: Module unload target is not registered");
788 return false;
789 case UnloadClaimed:
790 break;
791 }
792
793 auto reportShutdown = [&](const char* step) {
794 if (terminal) {
795 NormalStaticString detail;
796 detail += module->name;
797 detail += ": ";
798 detail += step;
799 Machine::setShutdownPhase(Machine::ShutdownPhase::Modules, detail);
800 }
801 };
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) {
806 lockModules();
807 module->status = wasFailed ? Module::Failed : Module::Active;
808 if (terminal)
809 module->unloadable = false;
810 if (terminal && admission == Module::UnloadAdmission::Busy)
811 m_ModuleShutdownStatus = ShutdownFailed;
812 m_UnloadingModule = nullptr;
814 if (terminal)
815 WARNING("KERNELELF: Retaining module with live resources " << module->name);
816 return false;
817 }
818
819 NOTICE("KERNELELF: Unloading module " << module->name);
820
821 bool progressUpdated = false;
822 if (progress) {
823 lockModules();
824 if (module->progressCredits) {
825 --module->progressCredits;
826 if (g_BootProgressCurrent) {
827 --g_BootProgressCurrent;
828 }
829 progressUpdated = true;
830 }
832 if (progressUpdated && g_BootProgressUpdate && !silent)
833 g_BootProgressUpdate("moduleunload");
834 }
835
836 reportShutdown("stopping driver");
837 if (module->runtime) {
838 const bool retired = retireRuntimeModule(module, runLifecycle);
839 finishClaimedUnload(module, wasFailed);
840 return retired;
841 }
842
843 if (runLifecycle && module->exit)
844 module->exit();
845
846 reportShutdown("running destructors");
847 // Check for a destructors list and execute.
848 // Note: static drivers have their ctors/dtors all shared.
849 EMIT_IF(!STATIC_DRIVERS) {
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");
855 }
856
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) {
861 ++iterator;
862 continue;
863 } else if ((*iterator) == 0) {
864 // End of table.
865 break;
866 }
867
868 uintptr_t dtor = *iterator;
869 void (*fp)(void) = reinterpret_cast<void (*)(void)>(dtor);
870 fp();
871 iterator++;
872 }
873 }
874
875 if (module->elf) {
876 m_SymbolTable.eraseByElf(module->elf);
877 }
878 }
879
880 progressUpdated = false;
881 if (progress) {
882 lockModules();
883 if (module->progressCredits) {
884 --module->progressCredits;
885 if (g_BootProgressCurrent) {
886 --g_BootProgressCurrent;
887 }
888 progressUpdated = true;
889 }
891 if (progressUpdated && g_BootProgressUpdate && !silent)
892 g_BootProgressUpdate("moduleunloaded");
893 }
894
895 NOTICE("KERNELELF: Module " << module->name << " unloaded.");
896
897 reportShutdown("releasing module memory");
898 EMIT_IF(!STATIC_DRIVERS) {
899 size_t pageSz = PhysicalMemoryManager::getPageSize();
900 size_t numPages = (module->loadSize / pageSz) + (module->loadSize % pageSz ? 1 : 0);
901
902 // Unmap!
903 VirtualAddressSpace& va = Processor::information().getVirtualAddressSpace();
904 for (size_t i = 0; i < numPages; i++) {
905 void* unmapAddr = reinterpret_cast<void*>(module->loadBase + (i * pageSz));
906 if (va.isMapped(unmapAddr)) {
907 // Unmap the virtual address
908 physical_uintptr_t phys = 0;
909 size_t flags = 0;
910 va.getMapping(unmapAddr, phys, flags);
911 va.unmap(unmapAddr);
912
913 // Free the physical page
915 }
916 }
917
918 m_ModuleAllocator.free(module->loadBase, module->loadSize);
919 }
920
921 delete module->elf;
922 module->elf = nullptr;
923 module->unloadAdmission = nullptr;
924
925 finishClaimedUnload(module, wasFailed);
926 return true;
927}
928
929bool KernelElf::unloadModule(const char* name, bool silent, bool progress) {
930 String findName(name);
931 Module* module = nullptr;
932 ModuleUnloadClaim claim = UnloadUnknown;
933 bool wasFailed = false;
934 bool runLifecycle = false;
935
936 lockModules();
937 module = findModuleByName(m_Modules, findName);
938 if (module) {
939 claim = claimModuleUnloadLocked(module, false, true, true, wasFailed, runLifecycle);
940 }
942
943 if (!module) {
944 ERROR("KERNELELF: Module " << name << " not found");
945 return false;
946 }
947 return completeUnloadAttempt(module, claim, wasFailed, runLifecycle, silent, progress);
948}
949
950bool KernelElf::unloadModule(Module* module, bool silent, bool progress) {
951 bool wasFailed = false;
952 bool runLifecycle = false;
953 lockModules();
954 const ModuleUnloadClaim claim =
955 claimModuleUnloadLocked(module, false, true, true, wasFailed, runLifecycle);
957 return completeUnloadAttempt(module, claim, wasFailed, runLifecycle, silent, progress);
958}
959
960KernelElf::RuntimeUnloadResult KernelElf::unloadModuleRuntime(const char* name) {
961 String findName(name);
962 Module* module = nullptr;
963 ModuleUnloadClaim claim = UnloadUnknown;
964 bool wasFailed = false;
965 bool runLifecycle = false;
966
967 lockModules();
968 for (auto candidate : m_Modules) {
969 // Completed records remain for boot diagnostics and must not hide a reload.
970 if (!module && !candidate->isUnloaded() && candidate->name == findName) {
971 module = candidate;
972 break;
973 }
974 }
975 if (module) {
976 if (!module->isActive()) {
977 claim = UnloadBusy;
978 } else if (module->entry && !module->exit) {
979 claim = UnloadPinned;
980 } else {
981 claim = claimModuleUnloadLocked(module, false, true, true, wasFailed, runLifecycle);
982 }
983 }
985
986 switch (claim) {
987 case UnloadClaimed:
988 return completeUnloadAttempt(module, claim, wasFailed, runLifecycle, true, false)
989 ? RuntimeUnloadResult::Unloaded
990 : RuntimeUnloadResult::Busy;
991 case UnloadUnknown:
992 case UnloadComplete:
993 return RuntimeUnloadResult::NotFound;
994 case UnloadBusy:
995 return RuntimeUnloadResult::Busy;
996 case UnloadPinned:
997 case UnloadRuntimePinned:
998 return RuntimeUnloadResult::Pinned;
999 case UnloadDependedOn:
1000 return RuntimeUnloadResult::DependedOn;
1001 case UnloadShutdown:
1002 return RuntimeUnloadResult::Shutdown;
1003 }
1004 return RuntimeUnloadResult::Busy;
1005}
1006
1007bool KernelElf::registerUnloadAdmission(ModuleEntry ownerEntry, Module::UnloadAdmissionHook hook) {
1008 if (!ownerEntry || !hook)
1009 return false;
1010 lockModules();
1011 if (m_ModuleShutdown || m_UnloadingModule) {
1012 unlockModules();
1013 return false;
1014 }
1015 for (auto module : m_Modules) {
1016 if (module->entry == ownerEntry && (module->isExecuting() || module->isActive())) {
1017 const bool accepted = !module->unloadAdmission || module->unloadAdmission == hook;
1018 if (accepted)
1019 module->unloadAdmission = hook;
1020 unlockModules();
1021 return accepted;
1022 }
1023 }
1024 unlockModules();
1025 return false;
1026}
1027
1028bool KernelElf::registerTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook) {
1029 if (!ownerEntry || !hook) {
1030 return false;
1031 }
1032
1033 lockModules();
1034 if (m_ModuleShutdown || m_TerminalQuiesceStatus != QuiesceOpen) {
1035 unlockModules();
1036 return false;
1037 }
1038 if (m_TerminalQuiesceHook) {
1039 const bool alreadyRegistered = m_TerminalQuiesceOwner &&
1040 m_TerminalQuiesceOwner->entry == ownerEntry &&
1041 m_TerminalQuiesceHook == hook;
1042 unlockModules();
1043 return alreadyRegistered;
1044 }
1045
1046 Module* owner = nullptr;
1047 for (auto module : m_Modules) {
1048 if (module->entry != ownerEntry || !(module->isExecuting() || module->isActive())) {
1049 continue;
1050 }
1051 if (owner) {
1052 unlockModules();
1053 return false;
1054 }
1055 owner = module;
1056 }
1057 if (!owner) {
1058 unlockModules();
1059 return false;
1060 }
1061
1062 m_TerminalQuiesceOwner = owner;
1063 m_TerminalQuiesceHook = hook;
1064 unlockModules();
1065 return true;
1066}
1067
1068bool KernelElf::unregisterTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook) {
1069 lockModules();
1070 if (!m_TerminalQuiesceHook) {
1071 unlockModules();
1072 return true;
1073 }
1074 if (!m_TerminalQuiesceOwner || m_TerminalQuiesceOwner->entry != ownerEntry ||
1075 m_TerminalQuiesceHook != hook || m_TerminalQuiesceStatus != QuiesceOpen) {
1076 unlockModules();
1077 return false;
1078 }
1079
1080 m_TerminalQuiesceOwner = nullptr;
1081 m_TerminalQuiesceHook = nullptr;
1082 unlockModules();
1083 return true;
1084}
1085
1087 while (true) {
1088 bool waiting = false;
1089 bool failed = false;
1090
1091 lockModules();
1092 if (m_ModuleShutdownStatus == ShutdownOpen) {
1093 __atomic_store_n(&m_ModuleShutdown, true, __ATOMIC_RELEASE);
1094 m_ModuleShutdownStatus = ShutdownRunning;
1095 unlockModules();
1096 break;
1097 }
1098 if (m_ModuleShutdownStatus == ShutdownComplete) {
1099 unlockModules();
1100 return true;
1101 }
1102 failed = m_ModuleShutdownStatus == ShutdownFailed;
1103 waiting = m_ModuleShutdownStatus == ShutdownRunning;
1104 unlockModules();
1105
1106 if (failed) {
1107 ERROR("KERNELELF: Module shutdown previously failed");
1108 return false;
1109 }
1110 if (waiting) {
1111#if THREADS
1113 continue;
1114#else
1115 ERROR("KERNELELF: Concurrent module shutdown without scheduler support");
1116 return false;
1117#endif
1118 }
1119 }
1120
1121 if (g_BootProgressUpdate) {
1122 g_BootProgressUpdate("unload");
1123 }
1124
1125 while (true) {
1126 TerminalQuiesceHook hook = nullptr;
1127 bool waiting = false;
1128 bool failed = false;
1129
1130 lockModules();
1131 if (m_TerminalQuiesceStatus == QuiesceComplete) {
1132 unlockModules();
1133 break;
1134 }
1135 if (m_TerminalQuiesceStatus == QuiesceFailed) {
1136 failed = true;
1137 } else if (m_TerminalQuiesceStatus == QuiesceInvoking || m_ModuleLoading || m_UnloadingModule ||
1138 m_ModuleExecutions || m_ModuleExecutionPasses) {
1139 waiting = true;
1140 } else {
1141 m_TerminalQuiesceStatus = QuiesceInvoking;
1142 hook = m_TerminalQuiesceHook;
1143 m_TerminalQuiesceOwner = nullptr;
1144 m_TerminalQuiesceHook = nullptr;
1145 if (!hook) {
1146 m_TerminalQuiesceStatus = QuiesceComplete;
1147 }
1148 }
1149 unlockModules();
1150
1151 if (failed) {
1152 lockModules();
1153 m_ModuleShutdownStatus = ShutdownFailed;
1154 unlockModules();
1155 ERROR("KERNELELF: Terminal module quiesce failed; refusing to unload modules");
1156 return false;
1157 }
1158 if (hook) {
1159 const bool quiesced = hook();
1160 lockModules();
1161 m_TerminalQuiesceStatus = quiesced ? QuiesceComplete : QuiesceFailed;
1162 unlockModules();
1163 if (!quiesced) {
1164 lockModules();
1165 m_ModuleShutdownStatus = ShutdownFailed;
1166 unlockModules();
1167 ERROR("KERNELELF: Terminal module quiesce failed; refusing to unload modules");
1168 return false;
1169 }
1170 break;
1171 }
1172 if (!waiting) {
1173 break;
1174 }
1175#if THREADS
1177#else
1178 lockModules();
1179 m_ModuleShutdownStatus = ShutdownFailed;
1180 unlockModules();
1181 ERROR("KERNELELF: Terminal quiesce encountered an in-flight module operation");
1182 return false;
1183#endif
1184 }
1185
1186 Machine::setShutdownPhase(Machine::ShutdownPhase::Modules);
1187 while (true) {
1188 Module* candidate = nullptr;
1189 ModuleUnloadClaim claim = UnloadBusy;
1190 bool wasFailed = false;
1191 bool runLifecycle = false;
1192 bool waiting = false;
1193
1194 lockModules();
1195 if (m_ModuleLoading || m_UnloadingModule || m_ModuleExecutions || m_ModuleExecutionPasses) {
1196 waiting = true;
1197 } else {
1198 if (m_InitModule) {
1199 // The init image is held aside until userspace launch, but a
1200 // controlled shutdown can begin before that point. Transfer it only
1201 // after any admitted load has published its result.
1202 m_InitModule->status = Module::Preloaded;
1204 m_InitModule = nullptr;
1205 }
1206 candidate = findUnloadCandidate(m_Modules, waiting);
1207 if (candidate) {
1208 claim = claimModuleUnloadLocked(candidate, true, true, false, wasFailed, runLifecycle);
1209 }
1210 }
1211 unlockModules();
1212
1213 if (candidate && claim == UnloadClaimed) {
1214 const bool completed =
1215 completeUnloadAttempt(candidate, claim, wasFailed, runLifecycle, false, false, true);
1216 lockModules();
1217 const bool failed =
1218 m_ModuleShutdownStatus == ShutdownFailed || (!completed && candidate->unloadable);
1219 if (failed)
1220 m_ModuleShutdownStatus = ShutdownFailed;
1221 unlockModules();
1222 if (failed)
1223 return false;
1224 continue;
1225 }
1226 if (waiting || (candidate && claim == UnloadBusy)) {
1227#if THREADS
1229 continue;
1230#else
1231 lockModules();
1232 m_ModuleShutdownStatus = ShutdownFailed;
1233 unlockModules();
1234 ERROR("KERNELELF: Module shutdown encountered an in-flight module operation");
1235 return false;
1236#endif
1237 }
1238 break;
1239 }
1240
1241 for (auto module : m_Modules) {
1242 if (!module->unloadComplete && module->status != Module::Unloaded) {
1243 // A live dependency can prevent a resource-owning module's admission
1244 // hook from running at all. It must not bypass terminal quiescence.
1245 if (module->unloadable && module->unloadAdmission &&
1246 module->unloadAdmission(true) != Module::UnloadAdmission::KeepMapped) {
1247 ERROR("KERNELELF: Shutdown blocked by retained resources in " << module->name);
1248 lockModules();
1249 m_ModuleShutdownStatus = ShutdownFailed;
1250 unlockModules();
1251 return false;
1252 }
1253 if (!module->unloadable) {
1254 WARNING("KERNELELF: Leaving permanently pinned module " << module->name
1255 << " mapped at shutdown");
1256 } else {
1257 WARNING("KERNELELF: Leaving module " << module->name
1258 << " mapped because its shutdown dependencies remain");
1259 }
1260 }
1261 }
1262
1263 // Module records are tombstones for repeat/concurrent callers until this
1264 // terminal shutdown point. The kernel is terminating, so dropping the
1265 // pointer list is safer than freeing records another CPU may still name.
1266 lockModules();
1267 m_Modules.clear();
1268 m_ModuleShutdownStatus = ShutdownComplete;
1269 unlockModules();
1270 return true;
1271}
1272
1273#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
1274size_t KernelElf::planModuleUnloadOrderForTest(Module** modules, size_t count, Module** order,
1275 size_t capacity) {
1276 Vector<Module*> pending;
1277 for (size_t i = 0; i < count; ++i) {
1278 pending.pushBack(modules[i]);
1279 }
1280
1281 size_t planned = 0;
1282 while (true) {
1283 bool waiting = false;
1284 Module* candidate = findUnloadCandidate(pending, waiting);
1285 if (!candidate || waiting) {
1286 break;
1287 }
1288 if (planned < capacity) {
1289 order[planned] = candidate;
1290 }
1291 ++planned;
1292 candidate->unloadComplete = true;
1293 candidate->status = Module::Unloaded;
1294 }
1295 return planned;
1296}
1297
1298KernelElf::TestModuleUnloadClaim KernelElf::claimModuleUnloadForTest(Module* module,
1299 bool allowShutdown,
1300 bool* lifecycle) {
1301 bool wasFailed = false;
1302 bool runLifecycle = false;
1303 KernelElf& kernelElf = instance();
1304 kernelElf.lockModules();
1305 const ModuleUnloadClaim claim = kernelElf.claimModuleUnloadLocked(module, allowShutdown, false,
1306 false, wasFailed, runLifecycle);
1307 kernelElf.unlockModules();
1308 if (lifecycle) {
1309 *lifecycle = runLifecycle;
1310 }
1311 return static_cast<TestModuleUnloadClaim>(claim);
1312}
1313
1314KernelElf::TestModuleUnloadClaim KernelElf::claimNamedModuleUnloadForTest(Module** modules,
1315 size_t count,
1316 const char* name) {
1317 Vector<Module*> fixtures;
1318 for (size_t i = 0; i < count; ++i) {
1319 fixtures.pushBack(modules[i]);
1320 }
1321
1322 KernelElf& kernelElf = instance();
1323 bool wasFailed = false;
1324 bool runLifecycle = false;
1325 kernelElf.lockModules();
1326 Module* module = findModuleByName(fixtures, String(name));
1327 ModuleUnloadClaim claim = UnloadUnknown;
1328 if (module) {
1329 claim = kernelElf.claimModuleUnloadLocked(module, true, false, false, wasFailed, runLifecycle);
1330 }
1331 kernelElf.unlockModules();
1332 return static_cast<TestModuleUnloadClaim>(claim);
1333}
1334
1335void KernelElf::completeModuleUnloadForTest(Module* module, bool wasFailed, bool runLifecycle) {
1336 instance().completeUnloadAttempt(module, UnloadClaimed, wasFailed, runLifecycle, true, false);
1337}
1338
1339bool KernelElf::completeGuardedModuleUnloadForTest(Module* module, bool terminal) {
1340 return instance().completeUnloadAttempt(module, UnloadClaimed, false, true, true, false,
1341 terminal);
1342}
1343
1344bool KernelElf::moduleExecutionWaitsForUnloadForTest() {
1345 Module unloading;
1346 unloading.name.assign("hosted-unload-admission-owner");
1347 unloading.status = Module::Active;
1348 Module pending;
1349 pending.name.assign("hosted-execution-admission-probe");
1350 pending.status = Module::Preloaded;
1351
1352 KernelElf& kernelElf = instance();
1353 bool wasFailed = false;
1354 bool runLifecycle = false;
1355 kernelElf.lockModules();
1356 const ModuleUnloadClaim claim =
1357 kernelElf.claimModuleUnloadLocked(&unloading, true, false, false, wasFailed, runLifecycle);
1358 if (claim != UnloadClaimed) {
1359 kernelElf.unlockModules();
1360 return false;
1361 }
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;
1367 }
1368 kernelElf.unlockModules();
1369 kernelElf.finishClaimedUnload(&unloading, false);
1370
1371 kernelElf.lockModules();
1372 const bool admittedAfterUnload = kernelElf.claimModuleExecutionLocked(&pending);
1373 const bool admittedTwice = kernelElf.claimModuleExecutionLocked(&pending);
1374 if (admittedAfterUnload) {
1375 --kernelElf.m_ModuleExecutions;
1376 }
1377 if (admittedTwice) {
1378 --kernelElf.m_ModuleExecutions;
1379 }
1380 kernelElf.unlockModules();
1381 return !admittedDuringUnload && remainedPending && admittedAfterUnload && !admittedTwice &&
1382 unloading.isUnloaded();
1383}
1384#endif
1385
1387 // this should hash the name and make comparisons super fast
1388 String compName(name);
1389
1390 bool loaded = false;
1391 lockModules();
1392 for (auto module : m_Modules) {
1393 if (module->isLoaded() && module->name == compName) {
1394 loaded = true;
1395 break;
1396 }
1397 }
1398 unlockModules();
1399 return loaded;
1400}
1401
1403 char* result = nullptr;
1404 lockModules();
1405 for (auto module : m_Modules) {
1406 if (!module->isLoaded()) {
1407 // can't depend on unloaded modules - might be unmapped
1408 continue;
1409 } else if (module->depends == 0) {
1410 continue;
1411 }
1412
1413 size_t i = 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));
1418 break;
1419 }
1420
1421 ++i;
1422 }
1423 if (result) {
1424 break;
1425 }
1426 }
1427 unlockModules();
1428 return result;
1429}
1430
1431bool KernelElf::claimModuleExecutionLocked(Module* module) {
1432 if (m_ModuleShutdown || m_ModuleLoading || m_UnloadingModule || !module->isPending() ||
1434 return false;
1435 }
1436 // Eligibility and ownership are one claim, before any module code can run.
1437 module->status = Module::Executing;
1438 ++m_ModuleExecutions;
1439 return true;
1440}
1441
1443 int i = 0;
1444
1445 // First pass: optional dependencies.
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]);
1449
1450 bool exists = false;
1451 bool attempted = false;
1452 for (auto mod : m_Modules) {
1453 if (!mod->isUnloaded() && !StringCompare(mod->name.cstr(), depname)) {
1454 exists = true;
1455 attempted = mod->wasAttempted() && !mod->isExecuting() && !mod->isUnloading();
1456 break;
1457 }
1458 }
1459
1460 if (exists) {
1461 if (!attempted) {
1462 // Consumers need a completed probe, including a failed probe's cleanup.
1463 return false;
1464 }
1465 }
1466
1467 ++i;
1468 }
1469 }
1470
1471 // Second pass: mandatory dependencies.
1472 i = 0;
1473 if (!module->depends) {
1474 return true;
1475 }
1476
1477 while (rebase(module, module->depends)[i]) {
1478 const char* depname = rebase(module, rebase(module, module->depends)[i]);
1479
1480 bool exists = false;
1481 for (auto mod : m_Modules) {
1482 if (!mod->isUnloaded() && !StringCompare(mod->name.cstr(), depname)) {
1483 exists = true;
1484 if (!mod->isActive()) {
1485 // module dependency is not yet active
1486 return false;
1487 }
1488 break;
1489 }
1490 }
1491 if (!exists) {
1492 return false;
1493 }
1494
1495 ++i;
1496 }
1497 return true;
1498}
1499
1500static int executeModuleThread(void* mod) {
1501 Module* module = reinterpret_cast<Module*>(mod);
1502
1503 NOTICE("running module: " << module->name);
1504
1505 if (module->buffer) {
1506 if (!module->elf->finaliseModule(module->buffer, module->buflen)) {
1507 FATAL("KERNELELF: Module relocation failed for module " << module->name);
1508 KernelElf::instance().updateModuleStatus(module, false, false);
1509 return false;
1510 }
1511
1512 // Check for a constructors list and execute.
1513 uintptr_t startCtors = module->elf->lookupSymbol("start_ctors");
1514 uintptr_t endCtors = module->elf->lookupSymbol("end_ctors");
1515
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) {
1520 ++iterator;
1521 continue;
1522 } else if ((*iterator) == 0) {
1523 // End of table.
1524 break;
1525 }
1526
1527 uintptr_t ctor = *iterator;
1528 void (*fp)(void) = reinterpret_cast<void (*)(void)>(ctor);
1529 fp();
1530 iterator++;
1531 }
1532 } else {
1533 WARNING("KERNELELF: Module " << module->name << " had no ctors!");
1534 }
1535
1536 uintptr_t optionalDeps = module->elf->lookupSymbol("__add_optional_deps");
1537 if (optionalDeps) {
1538 NOTICE("KERNELELF: Running module " << module->name << " optional dependencies function.");
1539 void (*fp)(void) = reinterpret_cast<void (*)(void)>(optionalDeps);
1540 fp();
1541 }
1542 }
1543
1544 NOTICE("KERNELELF: Executing module " << module->name);
1545
1546 bool bSuccess = !module->entry;
1547 String moduleName(module->name);
1548 if (module->entry) {
1549 bSuccess = module->entry();
1550 }
1551
1552 KernelElf::instance().updateModuleStatus(module, bSuccess);
1553
1554 return 0;
1555}
1556
1557bool KernelElf::executeModule(Module* module) {
1558 executeModuleThread(module);
1559
1560 return true;
1561}
1562
1563void KernelElf::updateModuleStatus(Module* module, bool status, bool runFailureLifecycle) {
1564 String moduleName(module->name);
1565 if (status) {
1566 NOTICE("KERNELELF: Module " << moduleName << " finished executing");
1567 lockModules();
1568 module->status = Module::Active;
1569 if (!m_ModuleExecutions) {
1570 unlockModules();
1571 FATAL("KERNELELF: Module execution accounting underflow");
1572 return;
1573 }
1574 --m_ModuleExecutions;
1575 unlockModules();
1576 } else {
1577 NOTICE("KERNELELF: Module " << moduleName << " failed, unloading.");
1578 bool wasFailed = false;
1579 bool runLifecycle = false;
1580 ModuleUnloadClaim claim = UnloadBusy;
1581 lockModules();
1582 module->status = Module::Failed;
1583 claim = claimModuleUnloadLocked(module, true, false, false, wasFailed, runLifecycle);
1584 unlockModules();
1585 runLifecycle = runLifecycle && runFailureLifecycle;
1586 completeUnloadAttempt(module, claim, wasFailed, runLifecycle, true, false);
1587 lockModules();
1588 if (!m_ModuleExecutions) {
1589 unlockModules();
1590 FATAL("KERNELELF: Module execution accounting underflow");
1591 return;
1592 }
1593 --m_ModuleExecutions;
1594 unlockModules();
1595 }
1596}
1597
1599 while (true) {
1600 lockModules();
1601 const bool executing =
1602 m_ModuleLoading || m_UnloadingModule || m_ModuleExecutions || m_ModuleExecutionPasses;
1603 unlockModules();
1604 if (!executing) {
1605 break;
1606 }
1607#if THREADS
1609#else
1610 FATAL("Module execution remained active without scheduler support.");
1611 return;
1612#endif
1613 }
1614
1615 lockModules();
1616 const size_t moduleCount = m_Modules.count();
1617 unlockModules();
1618
1619 NOTICE("SUCCESSFUL MODULES:");
1620 for (size_t i = 0; i < moduleCount; ++i) {
1621 Module* module = nullptr;
1622 bool active = false;
1623 lockModules();
1624 if (i < m_Modules.count()) {
1625 module = m_Modules[i];
1626 active = module->isActive();
1627 }
1628 unlockModules();
1629 if (module && active) {
1630 NOTICE(" - " << module->name);
1631 }
1632 }
1633
1634 NOTICE("UNSUCCESSFUL MODULES:");
1635 for (size_t i = 0; i < moduleCount; ++i) {
1636 Module* module = nullptr;
1637 bool failed = false;
1638 lockModules();
1639 if (i < m_Modules.count()) {
1640 module = m_Modules[i];
1641 failed = module->isFailed();
1642 }
1643 unlockModules();
1644 if (module && failed) {
1645 NOTICE(" - " << module->name);
1646 }
1647 }
1648}
1649
1651 if (!prepareRuntimeModules()) {
1652 WARNING("KernelElf: runtime module arena unavailable");
1653 }
1654 bool updateProgress = false;
1655 lockModules();
1656 Module* mod = m_InitModule;
1657 if (mod == nullptr) {
1658 unlockModules();
1659 WARNING("KernelElf: no init module was ever preloaded, cannot invoke init");
1660 return;
1661 }
1662
1663 if (m_ModuleShutdown || m_ModuleLoading || m_UnloadingModule) {
1664 unlockModules();
1665 WARNING("KernelElf: refusing to invoke init during another module transition");
1666 return;
1667 }
1668
1670 unlockModules();
1671 FATAL("init module could not be invoked - its dependencies were not satisfied");
1672 return;
1673 }
1674
1675 // Init is held aside only during dependency loading. Once it can execute it
1676 // must participate in ordinary unload ownership and dependency ordering.
1677 m_InitModule = nullptr;
1678 m_Modules.pushBack(mod);
1679 mod->status = Module::Executing;
1680 ++m_ModuleExecutions;
1681 // The init module is held aside while the other modules are loaded, so its
1682 // load and execution credits must be accounted for when it joins the pass.
1683 if (g_BootProgressTotal) {
1684 g_BootProgressCurrent += 2;
1685 updateProgress = g_BootProgressUpdate != nullptr;
1686 }
1687 unlockModules();
1688
1689 if (updateProgress && g_BootProgressUpdate)
1690 g_BootProgressUpdate("moduleexec");
1691
1692 executeModuleThread(reinterpret_cast<void*>(mod));
1693}
1694
1695uintptr_t KernelElf::globalLookupSymbol(const char* pName) {
1696 const uintptr_t legacy = m_SymbolTable.lookup(HashedStringView(pName), this);
1697 if (legacy) {
1698 return legacy;
1699 }
1700 lockModules();
1701 const uintptr_t result = runtimeExportLocked(pName);
1702 unlockModules();
1703 return result;
1704}
1705
1706const char* KernelElf::globalLookupSymbol(uintptr_t addr, uintptr_t* startAddr) {
1707 // Try a lookup in the kernel.
1708 const char* ret;
1709 if ((ret = lookupSymbol(addr, startAddr, m_pSymbolTable))) {
1710 return ret;
1711 }
1712
1713 // OK, that didn't work. Try every module.
1714 lockModules();
1715 for (auto it : m_Modules) {
1716 if (!(it->isActive() || it->isExecuting())) {
1717 continue;
1718 }
1719
1720 if (it->elf && (ret = it->elf->lookupSymbol(addr, startAddr))) {
1721 unlockModules();
1722 return ret;
1723 }
1724 if (it->runtime && (ret = runtimeLookupSymbolLocked(addr, startAddr))) {
1725 unlockModules();
1726 return ret;
1727 }
1728 }
1729 unlockModules();
1730 WARNING_NOLOCK("KERNELELF: GlobalLookupSymbol(" << Hex << addr << ") failed.");
1731 return 0;
1732}
1733
1735 lockModules();
1736 const size_t count = m_Modules.count();
1737 unlockModules();
1738 return count;
1739}
1740
1741const Module* KernelElf::getModule(size_t index) {
1742 lockModules();
1743 const Module* module = index < m_Modules.count() ? m_Modules[index] : nullptr;
1744 unlockModules();
1745 return module;
1746}
1747
1749 bool hasPending = false;
1750 for (auto it : m_Modules) {
1751 if (it->isPending()) {
1752 NOTICE("Pending module: " << it->name);
1753 hasPending = true;
1754 }
1755 }
1756 return hasPending;
1757}
1758
1760 EMIT_IF(THREADS) {
1761 m_ModuleAdjustmentLock.acquire();
1762 }
1763}
1764
1766 EMIT_IF(THREADS) {
1767 m_ModuleAdjustmentLock.release();
1768 }
1769}
bool finaliseModule(uint8_t *pBuffer, size_t length)
const char * lookupSymbol(uintptr_t addr, uintptr_t *startAddr, T *symbolTable)
KernelElf() INITIALISATION_ONLY
Definition KernelElf.cc:323
static T * rebase(Module *module, T *ptr)
Definition KernelElf.h:363
MemoryAllocator m_ModuleAllocator
Definition KernelElf.h:398
char * getDependingModule(char *name)
bool unloadModule(const char *name, bool silent=false, bool progress=true)
Definition KernelElf.cc:929
void executeModules(bool silent=false, bool progress=true)
Definition KernelElf.cc:505
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
Definition KernelElf.h:396
bool registerUnloadAdmission(ModuleEntry ownerEntry, Module::UnloadAdmissionHook hook)
MUST_USE_RESULT bool unloadModules()
bool prepareRuntimeModules()
Module * m_InitModule
Definition KernelElf.h:420
bool registerTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook)
void unlockModules()
static KernelElf & instance()
Definition KernelElf.h:135
Module * loadModule(uint8_t *pModule, size_t len, bool silent=false)
Definition KernelElf.cc:372
size_t getModuleCount()
bool moduleDependenciesSatisfiedLocked(Module *module) const
RuntimeUnloadResult unloadModuleRuntime(const char *name)
Definition KernelElf.cc:960
bool unregisterTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook)
virtual ~KernelElf()
Definition KernelElf.cc:344
static KernelElf m_Instance
Definition KernelElf.h:393
void lockModules()
MemoryRegion m_AdditionalSectionContents
Definition KernelElf.h:389
uintptr_t globalLookupSymbol(const char *pName)
bool initialise(const BootstrapStruct_t &pBootstrap) INITIALISATION_ONLY
Definition KernelElf.cc:74
const Module * getModule(size_t index)
void updateModuleStatus(Module *module, bool status, bool runFailureLifecycle=true)
static void setShutdownPhase(ShutdownPhase phase, const char *detail=nullptr)
Definition Machine.cc:33
Special memory entity in the kernel's virtual address space.
static PhysicalMemoryManager & instance()
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)
Definition RangeList.h:157
static Scheduler & instance()
Definition Scheduler.h:96
void yield()
Definition Scheduler.cc:236
void release()
Definition Spinlock.cc:168
bool acquire(bool recurse=false, bool safe=true)
Definition Spinlock.cc:36
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.
Definition Vector.h:33
virtual bool isMapped(void *virtualAddress)=0
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual uintptr_t getKernelModulesEnd() const =0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual void unmap(void *virtualAddress)=0
virtual uintptr_t getKernelModulesStart() const =0
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
void pushBack(const T &value)
Definition Vector.h:275
void clear(bool freeMem=false)
Definition Vector.h:378
size_t count() const
Definition Vector.h:270