Add initial release patches

This commit is contained in:
Joel Severin 2025-10-31 18:38:01 +01:00
parent 6fa54d5671
commit de0118ef2a
19 changed files with 14888 additions and 0 deletions

View File

@ -0,0 +1,8 @@
# Busybox Kernel Headers
Read repo root README.md for an explanation of what this is.
## Origin
This patch comes from the patch set at https://github.com/sabotage-linux/kernel-headers/tree/4.4.2/patches but is slightly modified to fit a 6.4 kernel. Note that patch 2 in that set fails but can be ignored, patch 4, 6 and 8 partially works and partially needs some merge conflict resolving. All of this is combined into one patch in this repo. It would probably be better to offer a complete new patch set, oh well...
## License
The same license as for the original source files apply, i.e. "GPL-2.0 WITH Linux-syscall-note".

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

14
patches/initramfs/init Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo
echo "Welcome to Linux running on Wasm!"
echo "Known bugs:"
echo " * Terminal input freezes after a while (timer issue)."
echo " * dup_fd, wq_worker_comm, rcu_os crash (memory corruption (fixed?))."
echo " * longjmp() does not work (not implemented yet)."
echo
exec /sbin/init -s

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
From 99fe993477b73fab9aeffb8ed96c79319f2abfff Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 14 Sep 2025 17:03:25 +0200
Subject: [PATCH] Allow architecture-specific panic handling
Debugging panics can be made much easier in hosted architectures (like
Wasm) if they can intercept panic() calls right when they happen.
---
include/asm-generic/Kbuild | 1 +
include/asm-generic/panic.h | 12 ++++++++++++
kernel/panic.c | 3 +++
3 files changed, 16 insertions(+)
create mode 100644 include/asm-generic/panic.h
diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild
index 941be574b..f1feb32a4 100644
--- a/include/asm-generic/Kbuild
+++ b/include/asm-generic/Kbuild
@@ -42,6 +42,7 @@ mandatory-y += mmu_context.h
mandatory-y += module.h
mandatory-y += module.lds.h
mandatory-y += msi.h
+mandatory-y += panic.h
mandatory-y += pci.h
mandatory-y += percpu.h
mandatory-y += pgalloc.h
diff --git a/include/asm-generic/panic.h b/include/asm-generic/panic.h
new file mode 100644
index 000000000..5f1a0ac69
--- /dev/null
+++ b/include/asm-generic/panic.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_GENERIC_PANIC_H
+#define _ASM_GENERIC_PANIC_H
+
+#ifndef CONFIG_ARCH_HAVE_PANIC_NOTIFY
+static inline void arch_panic_notify(const char *msg)
+{
+}
+#endif
+
+#endif /* _ASM_GENERIC_PANIC_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c990ada85..c2343cfc9 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -36,6 +36,7 @@
#include <linux/sysfs.h>
#include <linux/context_tracking.h>
#include <trace/events/error_report.h>
+#include <asm/panic.h>
#include <asm/sections.h>
#define PANIC_TIMER_STEP 100
@@ -397,6 +398,8 @@ void panic(const char *fmt, ...)
panic_print_sys_info(true);
+ arch_panic_notify(buf);
+
if (!panic_blink)
panic_blink = no_blink;
--
2.25.1

View File

@ -0,0 +1,26 @@
From 8d9649b899cd680ad4f5f57069eeceed72acc162 Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 14 Sep 2025 17:29:37 +0200
Subject: [PATCH] Add missing processor.h include for asm-generic/barrier.h
The default implementation of smp_cond_load_relaxed() uses cpu_relax(),
which is defined in the arch-specific processor.h header.
---
include/asm-generic/barrier.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index 961f4d88f..2fd9233f0 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -15,6 +15,7 @@
#include <linux/compiler.h>
#include <linux/kcsan-checks.h>
+#include <asm/processor.h>
#include <asm/rwonce.h>
#ifndef nop
--
2.25.1

View File

@ -0,0 +1,29 @@
From 29413574b48c2f12120b65573d28324d74129ee5 Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 14 Sep 2025 18:21:14 +0200
Subject: [PATCH] Align dot instead of section in vmlinux.lds.h
The rudimentary linker script support in wasm-ld does not permit a section
to be aligned directly. This workaround overcomes that limitation by
immediately aligning the dot at the start of each section instead.
---
include/asm-generic/vmlinux.lds.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index da9e5629e..b331a3947 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -865,7 +865,8 @@
/* Built-in firmware blobs */
#ifdef CONFIG_FW_LOADER
#define FW_LOADER_BUILT_IN_DATA \
- .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) ALIGN(8) { \
+ . = ALIGN(8); \
+ .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
BOUNDED_SECTION_PRE_LABEL(.builtin_fw, _builtin_fw, __start, __end) \
}
#else
--
2.25.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,517 @@
From 66c917eaad32544aaf992bffa61f1dac0ad37746 Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 12 May 2024 17:15:17 +0200
Subject: [PATCH] Add Wasm binfmt
While ELF is used for basically every other Linux-supported
architecture, current Wasm toolchains produce binaries in the .wasm
format. The .wasm file format is also the format all major Wasm
runtimes/VMs (e.g. browsers) consumes.
---
arch/wasm/Kconfig | 2 +
fs/Kconfig.binfmt | 9 +
fs/Makefile | 1 +
fs/binfmt_wasm.c | 446 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 458 insertions(+)
create mode 100644 fs/binfmt_wasm.c
diff --git a/arch/wasm/Kconfig b/arch/wasm/Kconfig
index f6e566f50..744e8c676 100644
--- a/arch/wasm/Kconfig
+++ b/arch/wasm/Kconfig
@@ -40,6 +40,8 @@ config WASM
select ARCH_SUPPORTS_LTO_CLANG
select ARCH_SUPPORTS_LTO_CLANG_THIN
+ select ARCH_HAS_BINFMT_WASM
+
# TODO: Very inefficient, replace with native stuff. Our atomic impl.
# of xchg and cmpxchg already supports 64-bit integers, we could use it.
select GENERIC_ATOMIC64
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 93539aac0..cbddea6a0 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -142,6 +142,15 @@ config BINFMT_ZFLAT
help
Support FLAT format compressed binaries
+config ARCH_HAS_BINFMT_WASM
+ bool
+
+config BINFMT_WASM
+ bool "Kernel support for Wasm binaries"
+ depends on ARCH_HAS_BINFMT_WASM
+ help
+ Support WebAssembly format binaries.
+
config BINFMT_MISC
tristate "Kernel support for MISC binaries"
help
diff --git a/fs/Makefile b/fs/Makefile
index 5bfdbf0d7..ab4581f7d 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o
obj-$(CONFIG_COMPAT_BINFMT_ELF) += compat_binfmt_elf.o
obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o
obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o
+obj-$(CONFIG_BINFMT_WASM) += binfmt_wasm.o
obj-$(CONFIG_FS_MBCACHE) += mbcache.o
obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o
diff --git a/fs/binfmt_wasm.c b/fs/binfmt_wasm.c
new file mode 100644
index 000000000..51f268246
--- /dev/null
+++ b/fs/binfmt_wasm.c
@@ -0,0 +1,446 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Somewhat based on binfmt_flat.c and binfmt_elf_fdpic.c */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/slab.h>
+#include <linux/binfmts.h>
+#include <linux/personality.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+
+#define WASM_STACK_SIZE (2UL * PAGE_SIZE)
+
+/*
+ * Userland expects the stack to be page aligned as of now, which allows it to
+ * find the initial stack pointer by rounding up the current stack pointer to
+ * the next page in the _start function. This allows _start to be written in C.
+ * If this restriction can be lifted we could instead use something like this:
+ * max_t(unsigned long, sizeof(void *), ARCH_SLAB_MINALIGN)
+ */
+#define WASM_STACK_ALIGN PAGE_SIZE
+
+#define WASM_DYLINK_MEMINFO (0x01)
+
+/*
+ * Parse the env- and arg-strings in new user memory and create the pointer
+ * tables from them, and put their addresses on the "stack", recording the new
+ * stack pointer value.
+ */
+static int create_wasm_tables(struct linux_binprm *bprm, unsigned long arg_start)
+{
+ char __user *p;
+ unsigned long __user *sp;
+ long i, len;
+ const struct cred *cred = current_cred();
+
+ // We emulate common ELF auxillary vectors to help userland out a bit.
+ const u32 wasm_auxv[] = {
+ AT_NOTELF, 1U,
+ AT_PAGESZ, PAGE_SIZE,
+ AT_UID, from_kuid_munged(cred->user_ns, cred->uid),
+ AT_EUID, from_kuid_munged(cred->user_ns, cred->euid),
+ AT_GID, from_kgid_munged(cred->user_ns, cred->gid),
+ AT_EGID, from_kgid_munged(cred->user_ns, cred->gid),
+ AT_SECURE, bprm->secureexec,
+ AT_NULL, 0U /* end */
+ };
+
+ p = (char __user *)arg_start;
+ sp = (unsigned long __user *)current->mm->start_stack;
+
+ sp -= (sizeof(wasm_auxv) + (sizeof(unsigned long) - 1U)) /
+ sizeof(unsigned long);
+ sp -= bprm->envc + 1;
+ sp -= bprm->argc + 1;
+ sp -= 1; /* &argc */
+
+ current->mm->start_stack = (unsigned long)sp & -WASM_STACK_ALIGN;
+ sp = (unsigned long __user *)current->mm->start_stack;
+
+ if (put_user(bprm->argc, sp++))
+ return -EFAULT;
+
+ current->mm->arg_start = (unsigned long)p;
+ for (i = bprm->argc; i > 0; i--) {
+ if (put_user((unsigned long)p, sp++))
+ return -EFAULT;
+ len = strnlen_user(p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
+ return -EINVAL;
+ p += len;
+ }
+ if (put_user(0, sp++))
+ return -EFAULT;
+ current->mm->arg_end = (unsigned long)p;
+
+ current->mm->env_start = (unsigned long)p;
+ for (i = bprm->envc; i > 0; i--) {
+ if (put_user((unsigned long)p, sp++))
+ return -EFAULT;
+ len = strnlen_user(p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
+ return -EINVAL;
+ p += len;
+ }
+ if (put_user(0, sp++))
+ return -EFAULT;
+ current->mm->env_end = (unsigned long)p;
+
+ memcpy(sp, wasm_auxv, sizeof(wasm_auxv));
+
+ return 0;
+}
+
+/*
+ * Read unsigned LEB128 encoded value, encoding a maximum of 32 bits, limited to
+ * a certain length. The input can be anywhere from 0 to 5 bytes in length,
+ * unless limited by the count artgument. A count of 5 should normally be used.
+ */
+static bool
+wasm_consume_varU32(char **bufp, unsigned int *output, unsigned long count)
+{
+ unsigned int result = 0;
+ char* buf = *bufp;
+ char* end = buf + count;
+ unsigned char chunk;
+ int shift = 0;
+
+ while (buf != end) {
+ chunk = *(buf++);
+
+ result |= (chunk & 0x7F) << shift;
+ shift += 7;
+
+ if (!(chunk & 0x80))
+ break;
+ }
+
+ *output = result;
+ *bufp = buf;
+
+ /*
+ * Return false to signal if the "continue bit" was set on the last
+ * byte, indicating faulty input data, or premature exit if count < 5.
+ */
+ return !(chunk & 0x80);
+}
+
+/*
+ * User data version of wasm_consume_varU32.
+ */
+static bool wasm_consume_varU32_user(
+ unsigned long *bufp, unsigned int *output, unsigned long count)
+{
+ unsigned int result = 0;
+ unsigned long buf = *bufp;
+ unsigned long end = buf + count;
+ unsigned char chunk;
+ int shift = 0;
+
+ while (buf != end) {
+ if (get_user(chunk, (unsigned char __user *)(buf++)))
+ return false;
+
+ result |= (chunk & 0x7F) << shift;
+ shift += 7;
+
+ if (!(chunk & 0x80))
+ break;
+ }
+
+ *output = result;
+ *bufp = buf;
+
+ /*
+ * Return false to signal if the "continue bit" was set on the last
+ * byte, indicating faulty input data, or premature exit if count < 5.
+ */
+ return !(chunk & 0x80);
+}
+
+static int load_wasm_file(struct linux_binprm *bprm, unsigned long extra_stack)
+{
+ unsigned long data_start = 0; /* Will contain data and bss */
+ unsigned long stack_size;
+ unsigned long whole_start, whole_p, whole_size, whole_end;
+ loff_t whole_size_ll;
+ char *parsed = bprm->buf;
+ int ret;
+
+ /* Related to Wasm dylink.0 parsing: */
+ unsigned int dylink_0_length;
+ unsigned long count;
+ u8 subsection_id;
+ unsigned int subsection_length;
+ unsigned long subsection_end;
+
+ /* Related to WASM_DYLINK_MEMINFO parsing: */
+ bool has_meminfo = false;
+ unsigned int data_size; /* memorysize */
+ unsigned int data_align; /* memoryalignment unpacked */
+ unsigned int table_size; /* tablesize */
+ unsigned int table_align; /* tablealign unpacked */
+
+ if (memcmp(parsed, "\x00" "asm", 4UL)) { /* Wasm binary magic header */
+ return -ENOEXEC;
+ }
+ parsed += 4UL;
+
+ /* We only know version 1 of the format. */
+ if (memcmp(parsed, "\x01\x00\x00\x00", 4UL)) { /* Version 0x1 (MVP) */
+ return -ENOEXEC;
+ }
+ parsed += 4UL;
+
+ /*
+ * We can only allow position independent code since Wasm has no MMU.
+ * This is currently flagged by a "dylink.0" custom section (first type
+ * byte 0), and should come as the first section in the file. If not, we
+ * can't run this file. However, we could allow some other magic binfmt
+ * to handle this (e.g. emulate support), so don't hard fail.
+ */
+ if (*(parsed++) != 0x00
+ || !wasm_consume_varU32(&parsed, &dylink_0_length, 5UL)
+ || dylink_0_length < 9U
+ || memcmp(parsed, "\x08" "dylink.0", 9UL)) {
+ return -ENOEXEC;
+ }
+ parsed += 9UL;
+
+ /*
+ * Map the whole file into memory so we can read it and hand it off to
+ * the host. We will unmap this as soon as the host has made its copy
+ * (the host would not be able to use a shared buffer as source anyway).
+ */
+ whole_size_ll = i_size_read(file_inode(bprm->file));
+ if (whole_size_ll > (loff_t)ULONG_MAX)
+ return -ENOMEM;
+
+ whole_size = (unsigned long)whole_size_ll;
+ if (whole_size < (unsigned long)(parsed - bprm->buf))
+ return -ENOEXEC;
+
+ /*
+ * This would be a placed to check RLIMITs, but since Wasm can allocate
+ * as much memory it wants on its own stack that makes little sense.
+ */
+
+ ret = begin_new_exec(bprm);
+ if (ret)
+ return ret;
+
+ set_personality(PER_LINUX_32BIT);
+ setup_new_exec(bprm);
+
+ whole_start = vm_mmap(bprm->file, 0, whole_size,
+ PROT_READ | PROT_EXEC, MAP_PRIVATE, 0);
+ if (!whole_start || IS_ERR_VALUE(whole_start)) {
+ ret = whole_start ? (int)whole_start : -ENOMEM;
+ pr_err("Unable to mmap process binary, errno: %d\n", ret);
+ return ret;
+ }
+ whole_end = whole_start + whole_size;
+
+ /* Move parsed to the whole file, since bprm->buf is cut off. */
+ whole_p = whole_start +
+ ((unsigned long)parsed - (unsigned long)bprm->buf);
+
+ /* Time to read some subsections of the dylink.0 section! */
+ while (!has_meminfo) {
+ if (whole_p == whole_end) {
+ pr_err("No dylink.0 subsection id");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ } else if (get_user(subsection_id, (u8 __user *)(whole_p++))) {
+ pr_err("Failed to read dylink.0 subsection id");
+ ret = -EFAULT;
+ goto out_unmap;
+ }
+
+ count = min_t(unsigned long, 5UL, whole_end - whole_p);
+ if (!wasm_consume_varU32_user(&whole_p, &subsection_length, count)) {
+ pr_err("Failed to read dylink.0 subsection length");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ }
+
+ subsection_end = whole_p + subsection_length;
+ if (subsection_end < whole_p /* overflow */
+ || subsection_end > whole_end) {
+ pr_err("dylink.0 subsection length overflow");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ }
+
+ if (subsection_id == WASM_DYLINK_MEMINFO) {
+ count = min_t(unsigned long, 5UL, subsection_end - whole_p);
+ if (!wasm_consume_varU32_user(&whole_p, &data_size, count)) {
+ pr_err("Failed to read dylink.0 meminfo memory size");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ }
+ data_size = PAGE_ALIGN(data_size);
+
+ count = min_t(unsigned long, 5UL, subsection_end - whole_p);
+ if (!wasm_consume_varU32_user(&whole_p, &data_align, count)) {
+ pr_err("Failed to read dylink.0 meminfo memory alignment");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ } else if (data_align > 31U) {
+ pr_err("dylink.0 meminfo memory alignment too large");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ }
+ data_align = 1UL << (int)data_align;
+
+ count = min_t(unsigned long, 5UL, subsection_end - whole_p);
+ if (!wasm_consume_varU32_user(&whole_p, &table_size, count)) {
+ pr_err("Failed to read dylink.0 meminfo table size");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ }
+ table_size = PAGE_ALIGN(table_size);
+
+ count = min_t(unsigned long, 5UL, subsection_end - whole_p);
+ if (!wasm_consume_varU32_user(&whole_p, &table_align, count)) {
+ pr_err("Failed to read dylink.0 meminfo table alignment");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ } else if (table_align > 31U) {
+ pr_err("dylink.0 meminfo table alignment too large");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ }
+ table_align = 1UL << (int)table_align;
+
+ has_meminfo = true;
+ }
+
+ whole_p = subsection_end;
+ }
+
+ if (!has_meminfo) {
+ pr_err("No dylink.0 meminfo found");
+ ret = -ENOEXEC;
+ goto out_unmap;
+ }
+
+ /*
+ * MAP_ANMONYMOUS clears the data (and bss). In Wasm, the runtime
+ * manages bss inside the data area. The runtime may rely on the data
+ * being zeroed as it is placing bss inside (or rather not touchhing bss
+ * pages at all). Thus data and bss are the same and zeroed.
+ */
+ data_start = vm_mmap(NULL, 0, data_size,
+ PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0);
+ if (!data_start || IS_ERR_VALUE(data_start)) {
+ ret = data_start ? (int)data_start : -ENOMEM;
+ pr_err("Unable to allocate RAM for process data, errno: %d\n",
+ ret);
+ goto out_unmap;
+ }
+
+ /*
+ * Create a stack, and put the brk at the start of this area.
+ */
+ stack_size = PAGE_ALIGN(WASM_STACK_SIZE + extra_stack);
+ current->mm->start_brk = vm_mmap(NULL, 0, stack_size,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, 0);
+ if (!current->mm->start_brk || IS_ERR_VALUE(current->mm->start_brk)) {
+ ret = current->mm->start_brk ?
+ (int)current->mm->start_brk : -ENOMEM;
+ pr_err("Unable to allocate RAM for stack, errno: %d\n", ret);
+ current->mm->start_brk = 0;
+ goto out_unmap;
+ }
+ current->mm->brk = current->mm->start_brk; /* Already page aligned... */
+#ifndef CONFIG_MMU
+ current->mm->context.end_brk = current->mm->start_brk + stack_size;
+#endif
+ current->mm->start_stack = current->mm->start_brk + stack_size;
+
+ /* Only set these if the above succeeds. */
+ current->mm->start_code = whole_start;
+ current->mm->end_code = whole_end;
+ current->mm->start_data = data_start;
+ current->mm->end_data = data_start + data_size;
+
+ return 0;
+
+out_unmap:
+ vm_munmap(whole_start, whole_size);
+ if (data_start)
+ vm_munmap(data_start, data_size);
+ return ret;
+}
+
+static int load_wasm_binary(struct linux_binprm *bprm);
+
+static struct linux_binfmt wasm_format = {
+ .module = THIS_MODULE,
+ .load_binary = load_wasm_binary,
+};
+
+static int load_wasm_binary(struct linux_binprm *bprm)
+{
+ struct pt_regs *regs = current_pt_regs();
+ unsigned long extra_stack = 0;
+ int res;
+
+ /*
+ * We have to add the size of our arguments to our stack size
+ * otherwise it's too easy for users to create stack overflows
+ * by passing in a huge argument list. And yes, we have to be
+ * pedantic and include space for the argv/envp array as it may have
+ * a lot of entries.
+ */
+#ifndef CONFIG_MMU
+ extra_stack += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
+#endif
+ extra_stack += (bprm->argc + 1) * sizeof(char *); /* the argv array */
+ extra_stack += (bprm->envc + 1) * sizeof(char *); /* the envp array */
+ extra_stack = ALIGN(extra_stack, WASM_STACK_ALIGN);
+
+ res = load_wasm_file(bprm, extra_stack);
+ if (res < 0)
+ return res;
+
+ set_binfmt(&wasm_format);
+
+#ifdef CONFIG_MMU
+ res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
+ if (!res)
+ res = create_wasm_tables(bprm, bprm->p);
+#else
+ res = transfer_args_to_stack(bprm, &current->mm->start_stack);
+ if (!res)
+ res = create_wasm_tables(bprm, current->mm->start_stack);
+#endif
+ if (res)
+ return res;
+
+ finalize_exec(bprm);
+ start_thread(regs, current->mm->start_stack);
+
+ return 0;
+}
+
+static int __init init_wasm_binfmt(void)
+{
+ register_binfmt(&wasm_format);
+ return 0;
+}
+core_initcall(init_wasm_binfmt);
--
2.25.1

View File

@ -0,0 +1,170 @@
From 18c7f0ad07fdf735784c0125e5e05095c01c31eb Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 12 May 2024 17:27:43 +0200
Subject: [PATCH] Use .section format compatible with LLVM as when targeting
Wasm
LLVM as does apparently need sizes and no "a" flag for sections when
assembling Wasm files. This seems to differ from other targets.
---
scripts/kallsyms.c | 38 +++++++++++++++++++++++++++-----------
usr/initramfs_data.S | 7 +++++--
2 files changed, 32 insertions(+), 13 deletions(-)
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 13af6d0ff..f090766f5 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -287,13 +287,18 @@ static void read_map(const char *in)
fclose(fp);
}
-static void output_label(const char *label)
+static void output_label_begin(const char *label)
{
printf(".globl %s\n", label);
printf("\tALGN\n");
printf("%s:\n", label);
}
+static void output_label_end(const char *label)
+{
+ printf(".size\t%s,.-%s\n", label, label);
+}
+
/* Provide proper symbols relocatability by their '_text' relativeness. */
static void output_address(unsigned long long addr)
{
@@ -395,10 +400,11 @@ static void write_src(void)
printf("#define ALGN .balign 4\n");
printf("#endif\n");
- printf("\t.section .rodata, \"a\"\n");
+ printf("\t.section .rodata, \"\", @\n");
- output_label("kallsyms_num_syms");
+ output_label_begin("kallsyms_num_syms");
printf("\t.long\t%u\n", table_cnt);
+ output_label_end("kallsyms_num_syms");
printf("\n");
/* table of offset markers, that give the offset in the compressed stream
@@ -410,7 +416,7 @@ static void write_src(void)
exit(EXIT_FAILURE);
}
- output_label("kallsyms_names");
+ output_label_begin("kallsyms_names");
off = 0;
for (i = 0; i < table_cnt; i++) {
if ((i & 0xFF) == 0)
@@ -447,6 +453,7 @@ static void write_src(void)
printf(", 0x%02x", table[i]->sym[k]);
printf("\n");
}
+ output_label_end("kallsyms_names");
printf("\n");
/*
@@ -458,14 +465,15 @@ static void write_src(void)
strcpy((char *)table[i]->sym, buf);
}
- output_label("kallsyms_markers");
+ output_label_begin("kallsyms_markers");
for (i = 0; i < ((table_cnt + 255) >> 8); i++)
printf("\t.long\t%u\n", markers[i]);
+ output_label_end("kallsyms_markers");
printf("\n");
free(markers);
- output_label("kallsyms_token_table");
+ output_label_begin("kallsyms_token_table");
off = 0;
for (i = 0; i < 256; i++) {
best_idx[i] = off;
@@ -473,17 +481,19 @@ static void write_src(void)
printf("\t.asciz\t\"%s\"\n", buf);
off += strlen(buf) + 1;
}
+ output_label_end("kallsyms_token_table");
printf("\n");
- output_label("kallsyms_token_index");
+ output_label_begin("kallsyms_token_index");
for (i = 0; i < 256; i++)
printf("\t.short\t%d\n", best_idx[i]);
+ output_label_end("kallsyms_token_index");
printf("\n");
if (!base_relative)
- output_label("kallsyms_addresses");
+ output_label_begin("kallsyms_addresses");
else
- output_label("kallsyms_offsets");
+ output_label_begin("kallsyms_offsets");
for (i = 0; i < table_cnt; i++) {
if (base_relative) {
@@ -521,11 +531,16 @@ static void write_src(void)
printf("\tPTR\t%#llx\n", table[i]->addr);
}
}
+ if (!base_relative)
+ output_label_end("kallsyms_addresses");
+ else
+ output_label_end("kallsyms_offsets");
printf("\n");
if (base_relative) {
- output_label("kallsyms_relative_base");
+ output_label_begin("kallsyms_relative_base");
output_address(relative_base);
+ output_label_end("kallsyms_relative_base");
printf("\n");
}
@@ -534,12 +549,13 @@ static void write_src(void)
cleanup_symbol_name((char *)table[i]->sym);
sort_symbols_by_name();
- output_label("kallsyms_seqs_of_names");
+ output_label_begin("kallsyms_seqs_of_names");
for (i = 0; i < table_cnt; i++)
printf("\t.byte 0x%02x, 0x%02x, 0x%02x\n",
(unsigned char)(table[i]->seq >> 16),
(unsigned char)(table[i]->seq >> 8),
(unsigned char)(table[i]->seq >> 0));
+ output_label_end("kallsyms_seqs_of_names");
printf("\n");
}
diff --git a/usr/initramfs_data.S b/usr/initramfs_data.S
index cd67edc38..dd1990aaf 100644
--- a/usr/initramfs_data.S
+++ b/usr/initramfs_data.S
@@ -22,11 +22,13 @@
in the ELF header, as required by certain architectures.
*/
-.section .init.ramfs,"a"
+.section .init.ramfs,"",@
__irf_start:
.incbin "usr/initramfs_inc_data"
+.size __irf_start,.-__irf_start
__irf_end:
-.section .init.ramfs.info,"a"
+.size __irf_end,0
+.section .init.ramfs.info,"",@
.globl __initramfs_size
__initramfs_size:
#ifdef CONFIG_64BIT
@@ -34,3 +36,4 @@ __initramfs_size:
#else
.long __irf_end - __irf_start
#endif
+.size __initramfs_size,.-__initramfs_size
--
2.25.1

View File

@ -0,0 +1,75 @@
From dd91ef3a67b1034191966eccdee8f583a69db9fa Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 12 May 2024 19:22:35 +0200
Subject: [PATCH] Provide Wasm support in mk_elfconfig
This is some kind of emulation for the modpost parts of Kbuild which
currently assumes that ELF is used by all targets.
---
scripts/mod/mk_elfconfig.c | 48 +++++++++++++++++++++-----------------
1 file changed, 27 insertions(+), 21 deletions(-)
diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c
index 680eade89..782522b23 100644
--- a/scripts/mod/mk_elfconfig.c
+++ b/scripts/mod/mk_elfconfig.c
@@ -14,29 +14,35 @@ main(int argc, char **argv)
fprintf(stderr, "Error: input truncated\n");
return 1;
}
- if (memcmp(ei, ELFMAG, SELFMAG) != 0) {
- fprintf(stderr, "Error: not ELF\n");
- return 1;
- }
- switch (ei[EI_CLASS]) {
- case ELFCLASS32:
+
+ if (memcmp(ei, "\x00" "asm", 4UL) == 0) {
+ /* Wasm (not ELF) - provide some emulation. */
printf("#define KERNEL_ELFCLASS ELFCLASS32\n");
- break;
- case ELFCLASS64:
- printf("#define KERNEL_ELFCLASS ELFCLASS64\n");
- break;
- default:
- exit(1);
- }
- switch (ei[EI_DATA]) {
- case ELFDATA2LSB:
printf("#define KERNEL_ELFDATA ELFDATA2LSB\n");
- break;
- case ELFDATA2MSB:
- printf("#define KERNEL_ELFDATA ELFDATA2MSB\n");
- break;
- default:
- exit(1);
+ } else if (memcmp(ei, ELFMAG, SELFMAG) != 0) {
+ fprintf(stderr, "Error: not ELF, nor Wasm\n");
+ return 1;
+ } else {
+ switch (ei[EI_CLASS]) {
+ case ELFCLASS32:
+ printf("#define KERNEL_ELFCLASS ELFCLASS32\n");
+ break;
+ case ELFCLASS64:
+ printf("#define KERNEL_ELFCLASS ELFCLASS64\n");
+ break;
+ default:
+ exit(1);
+ }
+ switch (ei[EI_DATA]) {
+ case ELFDATA2LSB:
+ printf("#define KERNEL_ELFDATA ELFDATA2LSB\n");
+ break;
+ case ELFDATA2MSB:
+ printf("#define KERNEL_ELFDATA ELFDATA2MSB\n");
+ break;
+ default:
+ exit(1);
+ }
}
if (sizeof(unsigned long) == 4) {
--
2.25.1

View File

@ -0,0 +1,101 @@
From 452439e4c22ae6cb0c3f9055a572ba862c78271a Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 12 May 2024 19:26:03 +0200
Subject: [PATCH] Add dummy ELF constants for Wasm
The kernel needs ELF to build, but Wasm currently only support for the
.wasm file format. Some dummy ELF constants are added as a workaround.
---
arch/wasm/include/uapi/asm/elf.h | 80 ++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
create mode 100644 arch/wasm/include/uapi/asm/elf.h
diff --git a/arch/wasm/include/uapi/asm/elf.h b/arch/wasm/include/uapi/asm/elf.h
new file mode 100644
index 000000000..853cd3786
--- /dev/null
+++ b/arch/wasm/include/uapi/asm/elf.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+
+#ifndef _UAPI_ASM_WASM_ELF_H
+#define _UAPI_ASM_WASM_ELF_H
+
+#include <asm/ptrace.h>
+
+/* ELF register definitions */
+typedef unsigned long elf_greg_t;
+typedef struct user_regs_struct elf_gregset_t;
+#define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t))
+
+/* We don't support f without d, or q. */
+typedef __u64 elf_fpreg_t;
+typedef union __wasm_fp_state elf_fpregset_t;
+#define ELF_NFPREG (sizeof(struct __wasm_d_ext_state) / sizeof(elf_fpreg_t))
+
+//#define ELF_WASM_R_SYM(r_info) ELF32_R_SYM(r_info)
+//#define ELF_WASM_R_TYPE(r_info) ELF32_R_TYPE(r_info)
+
+/* Relocation types used by the dynamic linker */
+#define R_WASM_NONE 0
+#define R_WASM_32 1
+#define R_WASM_64 2
+#define R_WASM_RELATIVE 3
+#define R_WASM_COPY 4
+#define R_WASM_JUMP_SLOT 5
+#define R_WASM_TLS_DTPMOD32 6
+#define R_WASM_TLS_DTPMOD64 7
+#define R_WASM_TLS_DTPREL32 8
+#define R_WASM_TLS_DTPREL64 9
+#define R_WASM_TLS_TPREL32 10
+#define R_WASM_TLS_TPREL64 11
+
+/* Relocation types not used by the dynamic linker */
+#define R_WASM_BRANCH 16
+#define R_WASM_JAL 17
+#define R_WASM_CALL 18
+#define R_WASM_CALL_PLT 19
+#define R_WASM_GOT_HI20 20
+#define R_WASM_TLS_GOT_HI20 21
+#define R_WASM_TLS_GD_HI20 22
+#define R_WASM_PCREL_HI20 23
+#define R_WASM_PCREL_LO12_I 24
+#define R_WASM_PCREL_LO12_S 25
+#define R_WASM_HI20 26
+#define R_WASM_LO12_I 27
+#define R_WASM_LO12_S 28
+#define R_WASM_TPREL_HI20 29
+#define R_WASM_TPREL_LO12_I 30
+#define R_WASM_TPREL_LO12_S 31
+#define R_WASM_TPREL_ADD 32
+#define R_WASM_ADD8 33
+#define R_WASM_ADD16 34
+#define R_WASM_ADD32 35
+#define R_WASM_ADD64 36
+#define R_WASM_SUB8 37
+#define R_WASM_SUB16 38
+#define R_WASM_SUB32 39
+#define R_WASM_SUB64 40
+#define R_WASM_GNU_VTINHERIT 41
+#define R_WASM_GNU_VTENTRY 42
+#define R_WASM_ALIGN 43
+#define R_WASM_RVC_BRANCH 44
+#define R_WASM_RVC_JUMP 45
+#define R_WASM_LUI 46
+#define R_WASM_GPREL_I 47
+#define R_WASM_GPREL_S 48
+#define R_WASM_TPREL_I 49
+#define R_WASM_TPREL_S 50
+#define R_WASM_RELAX 51
+#define R_WASM_SUB6 52
+#define R_WASM_SET6 53
+#define R_WASM_SET8 54
+#define R_WASM_SET16 55
+#define R_WASM_SET32 56
+#define R_WASM_32_PCREL 57
+
+
+#endif /* _UAPI_ASM_WASM_ELF_H */
--
2.25.1

View File

@ -0,0 +1,121 @@
From 2a52409cba31a1d5709451eceedfa7c8868bcfb8 Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 30 Jun 2024 00:47:26 +0200
Subject: [PATCH] Add Wasm console support
Adds a simple HVC + earlycon tty driver that calls out to the Wasm host
using simple exported functions on the vmlinux Module for reads/writes.
---
arch/wasm/Kconfig | 2 +-
arch/wasm/Makefile | 1 +
arch/wasm/drivers/Kconfig | 22 ++++++++++++++++++++++
arch/wasm/drivers/Makefile | 3 +++
arch/wasm/drivers/hvc_wasm.c | 35 +++++++++++++++++++++++++++++++++++
5 files changed, 62 insertions(+), 1 deletion(-)
create mode 100644 arch/wasm/drivers/Kconfig
create mode 100644 arch/wasm/drivers/Makefile
create mode 100644 arch/wasm/drivers/hvc_wasm.c
diff --git a/arch/wasm/Kconfig b/arch/wasm/Kconfig
index 744e8c676..2e01d91b3 100644
--- a/arch/wasm/Kconfig
+++ b/arch/wasm/Kconfig
@@ -77,4 +77,4 @@ config ARCH_HAVE_PANIC_NOTIFY
endmenu
-source "drivers/Kconfig"
+source "arch/wasm/drivers/Kconfig"
diff --git a/arch/wasm/Makefile b/arch/wasm/Makefile
index b86103e0b..841f3b006 100644
--- a/arch/wasm/Makefile
+++ b/arch/wasm/Makefile
@@ -12,6 +12,7 @@ KCFLAGS += -Xclang -target-feature -Xclang +bulk-memory
core-y += arch/wasm/kernel/
core-y += arch/wasm/mm/
libs-y += arch/wasm/lib/
+drivers-y += arch/wasm/drivers/
PHONY += bzImage
diff --git a/arch/wasm/drivers/Kconfig b/arch/wasm/drivers/Kconfig
new file mode 100644
index 000000000..be8b75496
--- /dev/null
+++ b/arch/wasm/drivers/Kconfig
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menu "Wasm Character Devices"
+
+config HVC_WASM
+ bool "Wasm console support"
+ select HVC_DRIVER
+ help
+ This config option enables support for a console managed by the Wasm
+ host, for example to read printk output during boot as well as
+ receiving user input. It works both as an earlycon and a tty. As an
+ earlycon, very early debug logging is output. As a tty (enabled later
+ on in the boot process), it also supports user input from the host.
+
+ In addition to enabling this config option at build time, you also
+ need to specify console=hvc as a parameter on the kernel command line
+ to activate the feature at runtime. Just specifying console=hvc is
+ enough to enable the earlycon aspects of this console driver as well.
+
+ If you don't know what to do here, say Y.
+
+endmenu
diff --git a/arch/wasm/drivers/Makefile b/arch/wasm/drivers/Makefile
new file mode 100644
index 000000000..0ebdc20a8
--- /dev/null
+++ b/arch/wasm/drivers/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_HVC_WASM) += hvc_wasm.o
diff --git a/arch/wasm/drivers/hvc_wasm.c b/arch/wasm/drivers/hvc_wasm.c
new file mode 100644
index 000000000..78f34c060
--- /dev/null
+++ b/arch/wasm/drivers/hvc_wasm.c
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include "../../../drivers/tty/hvc/hvc_console.h"
+
+extern int wasm_driver_hvc_put(const char *buf, int count);
+extern int wasm_driver_hvc_get(char *buf, int count);
+
+static int hvc_wasm_put_chars(uint32_t vtermno, const char *buf, int count)
+{
+ return wasm_driver_hvc_put(buf, count);
+}
+
+static int hvc_wasm_get_chars(uint32_t vtermno, char *buf, int count)
+{
+ return wasm_driver_hvc_get(buf, count);
+}
+
+static const struct hv_ops hvc_wasm_ops = {
+ .get_chars = hvc_wasm_get_chars,
+ .put_chars = hvc_wasm_put_chars,
+};
+
+static int __init hvc_wasm_init(void)
+{
+ return PTR_ERR_OR_ZERO(hvc_alloc(0, 0, &hvc_wasm_ops, PAGE_SIZE));
+}
+device_initcall(hvc_wasm_init);
+
+static int __init hvc_wasm_console_init(void)
+{
+ hvc_instantiate(0, 0, &hvc_wasm_ops);
+
+ return 0;
+}
+console_initcall(hvc_wasm_console_init);
--
2.25.1

View File

@ -0,0 +1,41 @@
From d1f576fb102da92fe3392c12125b5f0be03601f1 Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sun, 12 May 2024 19:31:55 +0200
Subject: [PATCH] Add wasm_defconfig
This patch needs to be updated to use an auto-generated config instead.
---
arch/wasm/configs/wasm_defconfig | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 arch/wasm/configs/wasm_defconfig
diff --git a/arch/wasm/configs/wasm_defconfig b/arch/wasm/configs/wasm_defconfig
new file mode 100644
index 000000000..10fb9e0ab
--- /dev/null
+++ b/arch/wasm/configs/wasm_defconfig
@@ -0,0 +1,21 @@
+CONFIG_SLAB=y
+
+CONFIG_NO_HZ_FULL=y
+
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_INFO_DWARF5=y
+CONFIG_HVC_WASM=y
+
+CONFIG_BLK_DEV_INITRD=y
+
+CONFIG_BINFMT_WASM=y
+CONFIG_BINFMT_MISC=m
+
+#CONFIG_MODULES=y
+#CONFIG_MODULE_UNLOAD=y
+
+#CONFIG_NET=y
+#CONFIG_PACKET=y
+#CONFIG_UNIX=y
+#CONFIG_INET=y
--
2.25.1

View File

@ -0,0 +1,29 @@
From f3e782cb608b0bdb63bc3a2280cfbbb8acf464c0 Mon Sep 17 00:00:00 2001
From: Joel Severin <joel.severin@icemanor.se>
Date: Sat, 13 Sep 2025 21:55:10 +0200
Subject: [PATCH] HACK: Workaround broken wq_worker_comm
worker->pool seems to be corrupted somehow, root cause unknown. This
likely happens due to an unrelated memory corruption bug.
---
kernel/workqueue.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index c913e333c..317e62987 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -5129,7 +5129,9 @@ void wq_worker_comm(char *buf, size_t size, struct task_struct *task)
struct worker *worker = kthread_data(task);
struct worker_pool *pool = worker->pool;
- if (pool) {
+ if ((unsigned long)pool == -1UL)
+ scnprintf(buf + off, size - off, "-BROKEN");
+ else if (pool) {
raw_spin_lock_irq(&pool->lock);
/*
* ->desc tracks information (wq name or
--
2.25.1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff