Przeglądaj źródła

Kernel: Implement basic module unloading :^)

Kernel modules can now be unloaded via a syscall. They get a chance to
run some code of course. Before deallocating them, we call their
"module_fini" symbol.
Andreas Kling 5 lat temu
rodzic
commit
a43b115a6c

+ 6 - 3
Kernel/Module.h

@@ -4,10 +4,13 @@
 #include <AK/Vector.h>
 #include <Kernel/KBuffer.h>
 
+typedef void* (*ModuleInitPtr)();
+typedef void* (*ModuleFiniPtr)();
+
 struct Module {
     String name;
     Vector<KBuffer> sections;
-};
 
-typedef void* (*ModuleInitPtr)();
-typedef void* (*ModuleFiniPtr)();
+    ModuleInitPtr module_init { nullptr };
+    ModuleFiniPtr module_fini { nullptr };
+};

+ 14 - 6
Kernel/Process.cpp

@@ -3418,8 +3418,6 @@ int Process::sys$module_load(const char* path, size_t path_length)
     if (!elf_image->parse())
         return -ENOEXEC;
 
-    ModuleInitPtr module_init = nullptr;
-
     HashMap<String, u8*> section_storage_by_name;
 
     auto module = make<Module>();
@@ -3469,15 +3467,17 @@ int Process::sys$module_load(const char* path, size_t path_length)
     elf_image->for_each_symbol([&](const ELFImage::Symbol& symbol) {
         dbg() << " - " << symbol.type() << " '" << symbol.name() << "' @ " << (void*)symbol.value() << ", size=" << symbol.size();
         if (!strcmp(symbol.name(), "module_init")) {
-            module_init = (ModuleInitPtr)(text_base + symbol.value());
+            module->module_init = (ModuleInitPtr)(text_base + symbol.value());
+        } else if (!strcmp(symbol.name(), "module_fini")) {
+            module->module_fini = (ModuleFiniPtr)(text_base + symbol.value());
         }
         return IterationDecision::Continue;
     });
 
-    if (!module_init)
+    if (!module->module_init)
         return -EINVAL;
 
-    module_init();
+    module->module_init();
 
     auto name = module->name;
     g_modules->set(name, move(module));
@@ -3493,6 +3493,14 @@ int Process::sys$module_unload(const char* name, size_t name_length)
 #endif
     if (!validate_read(name, name_length))
         return -EFAULT;
-    // FIXME: Implement this syscall!
+
+    auto it = g_modules->find(name);
+    if (it == g_modules->end())
+        return -ENOENT;
+
+    if (it->value->module_fini)
+        it->value->module_fini();
+
+    g_modules->remove(it);
     return 0;
 }

+ 5 - 2
Kernel/TestModule.cpp

@@ -1,7 +1,5 @@
 #include <Kernel/kstdio.h>
 
-extern "C" void outside_func();
-
 extern "C" void module_init()
 {
     kprintf("TestModule has booted!\n");
@@ -10,3 +8,8 @@ extern "C" void module_init()
         kprintf("i is now %d\n", i);
     }
 }
+
+extern "C" void module_fini()
+{
+    kprintf("TestModule is being removed!\n");
+}

+ 2 - 2
Kernel/build-root-filesystem.sh

@@ -134,13 +134,13 @@ ln -s SoundPlayer mnt/bin/sp
 ln -s Help mnt/bin/help
 ln -s Browser mnt/bin/br
 ln -s HackStudio mnt/bin/hs
-ln -s modload mnt/bin/m
 echo "done"
 
 mkdir -p mnt/boot/
 cp kernel mnt/boot/
 
-cp TestModule.o mnt/
+mkdir -p mnt/mod/
+cp TestModule.o mnt/mod
 
 # Run local sync script, if it exists
 if [ -f sync-local.sh ]; then

+ 1 - 1
Userland/modload.cpp

@@ -5,7 +5,7 @@ int main(int argc, char** argv)
 {
     (void)argc;
     (void)argv;
-    const char* path = "/TestModule.o";
+    const char* path = "/mod/TestModule.o";
     int rc = module_load(path, strlen(path));
     if (rc < 0) {
         perror("module_load");

+ 15 - 0
Userland/modunload.cpp

@@ -0,0 +1,15 @@
+#include <serenity.h>
+#include <string.h>
+
+int main(int argc, char** argv)
+{
+    (void)argc;
+    (void)argv;
+    const char* name = "FIXME";
+    int rc = module_unload(name, strlen(name));
+    if (rc < 0) {
+        perror("module_unload");
+        return 1;
+    }
+    return 0;
+}