The Pedigree Project 0.1
KernelElf.h
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#ifndef KERNEL_LINKER_KERNELELF_H
21#define KERNEL_LINKER_KERNELELF_H
22#include "pedigree/kernel/Spinlock.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/linker/Elf.h"
25#include "pedigree/kernel/process/TerminationDeferral.h"
26#include "pedigree/kernel/processor/MemoryRegion.h"
27#include "pedigree/kernel/processor/types.h"
28#include "pedigree/kernel/utilities/MemoryAllocator.h"
29#include "pedigree/kernel/utilities/SharedPointer.h"
30#include "pedigree/kernel/utilities/Vector.h"
31#include "pedigree/kernel/utilities/utility.h"
32
33#include <config.h>
34
35#include "modules/Module.h"
36
38class String;
40
44class Module {
45 public:
46 enum class UnloadAdmission { Ready, Busy, KeepMapped };
47 using UnloadAdmissionHook = UnloadAdmission (*)(bool terminal);
48 Module()
49 : elf(nullptr),
50 runtime(nullptr),
51 name(0),
52 entry(0),
53 exit(0),
54 unloadAdmission(nullptr),
55 depends(0),
56 depends_opt(0),
57 buffer(0),
58 buflen(0),
59 loadBase(0),
60 loadSize(0),
61 unloadable(true),
62 runtimeUnloadable(true),
63 unloadComplete(false),
64 progressCredits(0),
65 status(Unknown) {}
66
67 ~Module() {
68 delete elf;
69 }
70
71 Elf* elf;
72 RuntimeModuleSlot* runtime;
73 String name;
74 bool (*entry)();
75 void (*exit)();
76 UnloadAdmissionHook unloadAdmission;
77 const char** depends;
78 const char** depends_opt;
79 uint8_t* buffer;
80 size_t buflen;
81 uintptr_t loadBase;
82 size_t loadSize;
83 bool unloadable;
84 bool runtimeUnloadable;
85 bool unloadComplete;
86 size_t progressCredits;
87
88 enum ModuleStatus { Unknown, Preloaded, Executing, Active, Failed, Unloading, Unloaded } status;
89
90 bool isPending() const {
91 return status == Preloaded;
92 }
93
94 bool isLoaded() const {
95 return status == Preloaded || status == Active;
96 }
97
98 bool isUnloaded() const {
99 return status == Unloaded || (status == Failed && unloadComplete);
100 }
101
102 bool isFailed() const {
103 return status == Failed;
104 }
105
106 bool isActive() const {
107 return status == Active;
108 }
109
110 bool isExecuting() const {
111 return status == Executing;
112 }
113
114 bool isUnloading() const {
115 return status == Unloading;
116 }
117
118 bool wasAttempted() const {
119 return status == Executing || isActive() || isFailed() || isUnloading() || isUnloaded();
120 }
121
122 protected:
123 Module(const Module&);
124 Module& operator=(const Module&);
125};
126
127class EXPORTED_PUBLIC KernelElf : public Elf {
128 friend void _cxx_main(BootstrapStruct_t&);
129
130 public:
131 typedef bool (*TerminalQuiesceHook)();
132
135 inline static KernelElf& instance() {
136 return m_Instance;
137 }
138
141 bool initialise(const BootstrapStruct_t& pBootstrap) INITIALISATION_ONLY;
142
149 Module* loadModule(uint8_t* pModule, size_t len, bool silent = false);
151 Module* loadModule(struct ModuleInfo* info, bool silent = false);
152
154 void executeModules(bool silent = false, bool progress = true);
155
157 bool unloadModule(const char* name, bool silent = false, bool progress = true);
158 bool unloadModule(Module* module, bool silent = false, bool progress = true);
159
160 enum class RuntimeUnloadResult { Unloaded, NotFound, Busy, Pinned, DependedOn, Shutdown };
161
163 RuntimeUnloadResult unloadModuleRuntime(const char* name);
164
165 enum class RuntimeLoadResult {
166 Ready,
167 Loaded,
168 InvalidImage,
169 UnsupportedImage,
170 ImageTooLarge,
171 NoMemory,
172 Busy,
173 Shutdown,
174 Duplicate,
175 MissingDependency,
176 EntryFailed,
177 ProtectionFailed
178 };
179
181 class EXPORTED_PUBLIC RuntimeLoad {
182 public:
183 RuntimeLoad();
184 ~RuntimeLoad();
185 uint8_t* data() const;
186
187 private:
188 friend class KernelElf;
189 RuntimeLoad(const RuntimeLoad&) = delete;
190 RuntimeLoad& operator=(const RuntimeLoad&) = delete;
191 TerminationDeferral lifetime;
192 RuntimeModuleSlot* slot;
193 size_t length;
194 };
195
197 bool prepareRuntimeModules();
198 RuntimeLoadResult beginRuntimeModuleLoad(size_t length, RuntimeLoad& load);
199 RuntimeLoadResult loadModuleRuntime(RuntimeLoad& load);
200
201#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
203 static void failRuntimeProtectionForTest(size_t operationsBeforeFailure);
204#endif
205
207 MUST_USE_RESULT bool unloadModules();
208 bool isShuttingDown() const {
209 return __atomic_load_n(&m_ModuleShutdown, __ATOMIC_ACQUIRE);
210 }
211
217 bool registerTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook);
218
223 bool registerUnloadAdmission(ModuleEntry ownerEntry, Module::UnloadAdmissionHook hook);
224
226 bool unregisterTerminalQuiesce(ModuleEntry ownerEntry, TerminalQuiesceHook hook);
227
228#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
229 enum TestModuleUnloadClaim {
230 TestUnloadClaimed,
231 TestUnloadComplete,
232 TestUnloadBusy,
233 TestUnloadPinned,
234 TestUnloadRuntimePinned,
235 TestUnloadDependedOn,
236 TestUnloadUnknown,
237 TestUnloadShutdown,
238 };
239
241 static size_t planModuleUnloadOrderForTest(Module** modules, size_t count, Module** order,
242 size_t capacity);
243
245 static TestModuleUnloadClaim claimModuleUnloadForTest(Module* module, bool allowShutdown = true,
246 bool* runLifecycle = nullptr);
247 static TestModuleUnloadClaim claimNamedModuleUnloadForTest(Module** modules, size_t count,
248 const char* name);
249 static void completeModuleUnloadForTest(Module* module, bool wasFailed = false,
250 bool runLifecycle = false);
251 static bool moduleExecutionWaitsForUnloadForTest();
252 static bool completeGuardedModuleUnloadForTest(Module* module, bool terminal);
253#endif
254
256 bool moduleIsLoaded(char* name);
257
260 char* getDependingModule(char* name);
261
264 uintptr_t globalLookupSymbol(const char* pName);
265 const char* globalLookupSymbol(uintptr_t addr, uintptr_t* startAddr = 0);
266
268 size_t getModuleCount();
269
271 const Module* getModule(size_t index);
272
275 return m_ModuleAllocator;
276 }
277
279 bool hasPendingModules() const;
280
282 void updateModuleStatus(Module* module, bool status, bool runFailureLifecycle = true);
283
285 void waitForModulesToLoad();
286
296 void invokeInitModule();
297
298 private:
305 virtual ~KernelElf();
308 KernelElf& operator=(const KernelElf&);
309
311 bool moduleDependenciesSatisfiedLocked(Module* module) const;
312 bool claimModuleExecutionLocked(Module* module);
313 bool executeModule(Module* module);
314
315 enum ModuleUnloadClaim {
316 UnloadClaimed,
317 UnloadComplete,
318 UnloadBusy,
319 UnloadPinned,
320 UnloadRuntimePinned,
321 UnloadDependedOn,
322 UnloadUnknown,
323 UnloadShutdown,
324 };
325
326 enum TerminalQuiesceState {
327 QuiesceOpen,
328 QuiesceInvoking,
329 QuiesceComplete,
330 QuiesceFailed,
331 };
332
333 enum ModuleShutdownState {
334 ShutdownOpen,
335 ShutdownRunning,
336 ShutdownComplete,
337 ShutdownFailed,
338 };
339
340 void abandonRuntimeModuleLoad(RuntimeLoad& load);
341 bool retireRuntimeModule(Module* module, bool runLifecycle);
342 uintptr_t runtimeExportLocked(const char* name, Module* owner = nullptr) const;
344 const char* runtimeLookupSymbolLocked(uintptr_t addr, uintptr_t* startAddr) const;
346 uintptr_t resolveRuntimeImport(const char* name, Module* consumer);
347 bool beginModuleLoad();
348 void finishModuleLoad();
349 bool moduleRegisteredLocked(Module* module) const;
350 static Module* findModuleByName(const Vector<Module*>& modules, const String& name);
351 static bool moduleDependsOn(Module* consumer, Module* provider);
352 static bool hasLiveDependent(const Vector<Module*>& modules, Module* provider);
353 static Module* findUnloadCandidate(const Vector<Module*>& modules, bool& waiting);
354 ModuleUnloadClaim claimModuleUnloadLocked(Module* module, bool allowShutdown,
355 bool requireMembership, bool enforceDependencies,
356 bool& wasFailed, bool& runLifecycle);
357 bool completeUnloadAttempt(Module* module, ModuleUnloadClaim claim, bool wasFailed,
358 bool runLifecycle, bool silent, bool progress, bool terminal = false);
359 void finishClaimedUnload(Module* module, bool wasFailed);
360
362 template <class T>
363 static T* rebase(Module* module, T* ptr) {
364 EMIT_IF(STATIC_DRIVERS) {
365 return ptr;
366 }
367
368 if (module->runtime) {
369 return ptr;
370 }
371
372 uintptr_t value = reinterpret_cast<uintptr_t>(ptr);
373
374 // Don't rebase pointers that are already rebased
375 if (module->loadBase <= value && value <= (module->loadBase + module->loadSize)) {
376 return ptr;
377 }
378
379 return adjust_pointer(ptr, module->loadBase);
380 }
381
383 void lockModules();
384
386 void unlockModules();
387
390 MemoryRegion* m_AdditionalSectionHeaders;
391
394
399 bool m_ModuleAllocatorInitialised;
400 bool m_RuntimeModulesPrepared;
401
402 ElfSectionHeader_t* m_pSectionHeaders;
403 ElfSymbol_t* m_pSymbolTable;
404
407
408 Spinlock m_ModuleAdjustmentLock;
409 bool m_ModuleShutdown;
410 ModuleShutdownState m_ModuleShutdownStatus;
411 bool m_ModuleLoading;
412 Module* m_UnloadingModule;
413 size_t m_ModuleExecutions;
414 size_t m_ModuleExecutionPasses;
415 Module* m_TerminalQuiesceOwner;
416 TerminalQuiesceHook m_TerminalQuiesceHook;
417 TerminalQuiesceState m_TerminalQuiesceStatus;
418
421};
422
425#endif
Definition Elf.h:201
bool loadModule(uint8_t *pBuffer, size_t length, uintptr_t &loadBase, size_t &loadSize, SymbolTable *pSymbolTableCopy=0)
Elf & operator=(const Elf &)
static T * rebase(Module *module, T *ptr)
Definition KernelElf.h:363
MemoryAllocator m_ModuleAllocator
Definition KernelElf.h:398
Vector< Module * > m_Modules
Definition KernelElf.h:396
MemoryAllocator & getModuleAllocator()
Definition KernelElf.h:274
Module * m_InitModule
Definition KernelElf.h:420
static KernelElf & instance()
Definition KernelElf.h:135
static KernelElf m_Instance
Definition KernelElf.h:393
MemoryRegion m_AdditionalSectionContents
Definition KernelElf.h:389
Special memory entity in the kernel's virtual address space.
A vector / dynamic array.
Definition Vector.h:33