summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-11-28 21:07:22 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-11-28 21:07:22 +0100
commita43b115a6c99881c964daa5012cd076e82a7d72f (patch)
treedbc28d95f716271b3790832f74cd8b6794b85af6
parent6b150c794a4c71e36bd1e5e545be171d0e3b45d0 (diff)
downloadserenity-a43b115a6c99881c964daa5012cd076e82a7d72f.zip
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.
-rw-r--r--Kernel/Module.h9
-rw-r--r--Kernel/Process.cpp20
-rw-r--r--Kernel/TestModule.cpp7
-rwxr-xr-xKernel/build-root-filesystem.sh4
-rw-r--r--Userland/modload.cpp2
-rw-r--r--Userland/modunload.cpp15
6 files changed, 43 insertions, 14 deletions
diff --git a/Kernel/Module.h b/Kernel/Module.h
index 8a27f41940..f06948b84d 100644
--- a/Kernel/Module.h
+++ b/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 };
+};
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 5822b69597..f7990af921 100644
--- a/Kernel/Process.cpp
+++ b/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;
}
diff --git a/Kernel/TestModule.cpp b/Kernel/TestModule.cpp
index a3a1296156..20603c2028 100644
--- a/Kernel/TestModule.cpp
+++ b/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");
+}
diff --git a/Kernel/build-root-filesystem.sh b/Kernel/build-root-filesystem.sh
index de79043b05..68e893bae6 100755
--- a/Kernel/build-root-filesystem.sh
+++ b/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
diff --git a/Userland/modload.cpp b/Userland/modload.cpp
index 180f9a1a73..d0412a0fcd 100644
--- a/Userland/modload.cpp
+++ b/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");
diff --git a/Userland/modunload.cpp b/Userland/modunload.cpp
new file mode 100644
index 0000000000..c65b5085a0
--- /dev/null
+++ b/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;
+}