diff --git a/arch/wasm/Kconfig b/arch/wasm/Kconfig index 827f7574609f6a..b7c1109900da4e 100644 --- a/arch/wasm/Kconfig +++ b/arch/wasm/Kconfig @@ -13,6 +13,7 @@ config WASM select GENERIC_HWEIGHT select GENERIC_IRQ_MIGRATION select GENERIC_IRQ_PROBE + select GENERIC_IRQ_SHOW select GENERIC_SMP_IDLE_THREAD select IRQ_DOMAIN select OF diff --git a/arch/wasm/configs/defconfig b/arch/wasm/configs/defconfig index 2f438ab0d72d54..f72d8d549b34f1 100644 --- a/arch/wasm/configs/defconfig +++ b/arch/wasm/configs/defconfig @@ -27,11 +27,11 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EMBEDDED=y CONFIG_VIRTIO_WASM=y # CONFIG_COMPAT_32BIT_TIME is not set -# CONFIG_BINFMT_SCRIPT is not set # CONFIG_COREDUMP is not set CONFIG_SLOB=y # CONFIG_COMPAT_BRK is not set # CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_FW_LOADER is not set @@ -50,8 +50,6 @@ CONFIG_EXT2_FS=y # CONFIG_FILE_LOCKING is not set # CONFIG_DNOTIFY is not set # CONFIG_INOTIFY_USER is not set -# CONFIG_PROC_FS is not set -# CONFIG_SYSFS is not set # CONFIG_DEBUG_MISC is not set # CONFIG_RCU_TRACE is not set # CONFIG_RUNTIME_TESTING_MENU is not set diff --git a/arch/wasm/include/asm/globals.h b/arch/wasm/include/asm/globals.h index 3327f5399c8751..9df1217fe7dc63 100644 --- a/arch/wasm/include/asm/globals.h +++ b/arch/wasm/include/asm/globals.h @@ -18,6 +18,7 @@ static inline void *get_stack_pointer(void) return ptr; } + void set_current_cpu(int cpu); int get_current_cpu(void); @@ -29,4 +30,7 @@ struct task_struct *get_current_task_on(int cpu); void set_irq_enabled(u32 flags); u32 get_irq_enabled(void); +void wasm_set_thread_done(int done); +int wasm_get_thread_done(void); + #endif diff --git a/arch/wasm/include/asm/wasm_imports.h b/arch/wasm/include/asm/wasm_imports.h index e7ae580cac8b20..fdbeaafe5d36d2 100644 --- a/arch/wasm/include/asm/wasm_imports.h +++ b/arch/wasm/include/asm/wasm_imports.h @@ -11,8 +11,7 @@ void wasm_import(boot, get_devicetree)(char *buf, size_t size); int wasm_import(boot, get_initramfs)(char *buf, size_t size); void wasm_import(kernel, breakpoint)(void); -void wasm_import(kernel, halt)(void); -void wasm_import(kernel, restart)(void); +void wasm_import(kernel, halt_worker)(void); void wasm_import(kernel, boot_console_write)(const char *msg, size_t len); void wasm_import(kernel, boot_console_close)(void); @@ -32,6 +31,8 @@ int wasm_import(user, compile)(u8 *bytes, u32 len); void wasm_import(user, instantiate)(void); void wasm_import(user, call)(void); void wasm_import(user, switch_entry)(u32 fn, u32 arg); +void wasm_import(user, call_signal_handler)(u32 fn, u32 sig); +void wasm_import(user, halt_signal_handler)(void); int wasm_import(user, read)(void *to, const void __user *from, unsigned long n); int wasm_import(user, write)(void __user *to, const void *from, unsigned long n); diff --git a/arch/wasm/kernel/globals.c b/arch/wasm/kernel/globals.c index 398da95f41c3e3..98e8e8c0d97a94 100644 --- a/arch/wasm/kernel/globals.c +++ b/arch/wasm/kernel/globals.c @@ -11,7 +11,8 @@ struct task_struct *current_tasks[NR_CPUS] = { 0 }; struct screen_info screen_info = {}; __asm__(".globaltype current_cpu, i32\ncurrent_cpu:\n" - ".globaltype current_task, i32\ncurrent_task:\n"); + ".globaltype current_task, i32\ncurrent_task:\n" + ".globaltype thread_done, i32\nthread_done:\n"); void set_current_cpu(int cpu) { @@ -45,3 +46,17 @@ struct task_struct *get_current_task_on(int cpu) { return current_tasks[cpu]; } + +void wasm_set_thread_done(int done) +{ + __asm__ volatile("local.get %0\n" + "global.set thread_done" ::"r"(done)); +} +int wasm_get_thread_done(void) +{ + int done; + __asm__ volatile("global.get thread_done\n" + "local.set %0" + : "=r"(done)); + return done; +} diff --git a/arch/wasm/kernel/process.c b/arch/wasm/kernel/process.c index 903a0cd8f56ead..d4c6e0ada1f12c 100644 --- a/arch/wasm/kernel/process.c +++ b/arch/wasm/kernel/process.c @@ -43,6 +43,10 @@ struct task_struct *__switch_to(struct task_struct *from, // pr_info("waiting cpu=%i task=%p in switch\n", cpu, from); + // this is set to true in do_task_dead: + if (wasm_get_thread_done()) + wasm_kernel_halt_worker(); + // sleep this worker: /* memory.atomic.wait32 returns: * 0 -> the thread blocked and was woken diff --git a/arch/wasm/kernel/setup.c b/arch/wasm/kernel/setup.c index 7f89aaaa003735..86493d8f71ea27 100644 --- a/arch/wasm/kernel/setup.c +++ b/arch/wasm/kernel/setup.c @@ -93,7 +93,7 @@ void __init setup_arch(char **cmdline_p) void machine_restart(char *cmd) { pr_info("restart %s\n", cmd); - wasm_kernel_restart(); + BUG(); } void machine_halt(void) diff --git a/arch/wasm/kernel/signal.c b/arch/wasm/kernel/signal.c index 3d5e57da22b2f8..1ac1d96f43c133 100644 --- a/arch/wasm/kernel/signal.c +++ b/arch/wasm/kernel/signal.c @@ -1,10 +1,14 @@ +#include #include -SYSCALL_DEFINE0(rt_sigreturn) -{ - current->restart_block.fn = do_no_restart_syscall; +void arch_do_signal_or_restart(struct pt_regs *regs) { + struct ksignal ksig; - // this will likely require sjlj or some other exception based control flow + if (get_signal(&ksig)) { + struct sigaction* sa = &ksig.ka.sa; + if (sa->sa_flags&SA_SIGINFO) + pr_warn("TODO: SA_SIGINFO in signal handler\n"); + wasm_user_call_signal_handler((uintptr_t)sa->sa_handler, ksig.sig); + } +} - BUG(); -} \ No newline at end of file diff --git a/arch/wasm/kernel/smp.c b/arch/wasm/kernel/smp.c index b50b9ada40479f..56959a45373907 100644 --- a/arch/wasm/kernel/smp.c +++ b/arch/wasm/kernel/smp.c @@ -187,7 +187,7 @@ static irqreturn_t handle_ipi(int irq, void *dev) if (ops & (1 << IPI_CPU_STOP)) { stats[IPI_CPU_STOP]++; - wasm_kernel_halt(); + wasm_kernel_halt_worker(); } if (ops & (1 << IPI_CALL_FUNC)) { diff --git a/arch/wasm/kernel/syscall.c b/arch/wasm/kernel/syscall.c index 593865763c1087..c402bda442b926 100644 --- a/arch/wasm/kernel/syscall.c +++ b/arch/wasm/kernel/syscall.c @@ -28,8 +28,6 @@ wasm_syscall(long nr, unsigned long arg0, unsigned long arg1, if (nr < 0 || nr >= ARRAY_SIZE(syscall_table)) return -ENOSYS; - // TODO: something something check there's a pending signal - regs->syscall_nr = nr; regs->syscall_args[0] = arg0; regs->syscall_args[1] = arg1; diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index f7768b5f58ab59..c3e22c29e68951 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -439,8 +439,8 @@ __SC_COMP_3264(__NR_rt_sigtimedwait, sys_rt_sigtimedwait_time32, \ #define __NR_rt_sigqueueinfo 138 __SC_COMP(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo, \ compat_sys_rt_sigqueueinfo) -#define __NR_rt_sigreturn 139 -__SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn) +// #define __NR_rt_sigreturn 139 +// __SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn) /* kernel/sys.c */ #define __NR_setpriority 140 @@ -623,10 +623,10 @@ __SC_COMP(__NR_readahead, sys_readahead, compat_sys_readahead) /* mm/nommu.c, also with MMU */ // #define __NR_brk 214 // __SYSCALL(__NR_brk, sys_brk) -#define __NR_munmap 215 -__SYSCALL(__NR_munmap, sys_munmap) -#define __NR_mremap 216 -__SYSCALL(__NR_mremap, sys_mremap) +// #define __NR_munmap 215 +// __SYSCALL(__NR_munmap, sys_munmap) +// #define __NR_mremap 216 +// __SYSCALL(__NR_mremap, sys_mremap) /* security/keys/keyctl.c */ #define __NR_add_key 217 diff --git a/kernel/panic.c b/kernel/panic.c index c5be27b261cb35..b8c947ff0f2ab5 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -453,7 +453,7 @@ void panic(const char *fmt, ...) #ifdef CONFIG_WASM wasm_kernel_breakpoint(); - wasm_kernel_halt(); + wasm_kernel_halt_worker(); #endif for (i = 0; ; i += PANIC_TIMER_STEP) { diff --git a/kernel/sched/core.c b/kernel/sched/core.c index df7d663c42e98e..d4632d53fa658e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6578,6 +6578,9 @@ void __noreturn do_task_dead(void) /* Tell freezer to ignore us: */ current->flags |= PF_NOFREEZE; +#ifdef CONFIG_WASM + wasm_set_thread_done(true); +#endif __schedule(SM_NONE); BUG(); diff --git a/tools/wasm/public/index.html b/tools/wasm/public/index.html index 4e36786e293e58..9ea15a428c49ca 100644 --- a/tools/wasm/public/index.html +++ b/tools/wasm/public/index.html @@ -184,18 +184,6 @@ machine.bootConsole.pipeTo(stdout2); - machine.on("halt", () => { - term.write("halting..."); - }); - - machine.on("restart", () => { - location.reload(); - }); - - machine.on("error", ({ error, threadName }) => { - term.write(`${error.name} in ${threadName}: ${error.message}\n`); - }); - machine.boot(); diff --git a/tools/wasm/run.js b/tools/wasm/run.js index 50e19e2347198b..8e44a616e23a6c 100755 --- a/tools/wasm/run.js +++ b/tools/wasm/run.js @@ -54,18 +54,4 @@ const machine = new Machine({ machine.bootConsole.pipeTo(Deno.stderr.writable, { preventClose: true }); -machine.on("halt", () => { - console.log("halting..."); - Deno.exit(1); -}); - -machine.on("restart", () => { - console.log("reboot requested. halting..."); - Deno.exit(0); -}); - -machine.on("error", ({ error, threadName }) => { - console.log(`Error in ${threadName}:`, error); -}); - machine.boot(); diff --git a/tools/wasm/src/index.ts b/tools/wasm/src/index.ts index 5fb13171921500..160f91f391021c 100644 --- a/tools/wasm/src/index.ts +++ b/tools/wasm/src/index.ts @@ -2,7 +2,7 @@ import initramfs from "./build/initramfs_data.cpio"; import sections from "./build/sections.json" with { type: "json" }; import vmlinuxUrl from "./build/vmlinux.wasm"; import { type DeviceTreeNode, generate_devicetree } from "./devicetree.ts"; -import { assert, EventEmitter, get_script_path, unreachable } from "./util.ts"; +import { assert, get_script_path, unreachable } from "./util.ts"; import { virtio_imports, VirtioDevice } from "./virtio.ts"; import { type Imports, type Instance, kernel_imports } from "./wasm.ts"; import type { InitMessage, WorkerMessage } from "./worker.ts"; @@ -18,11 +18,7 @@ const vmlinux_promise = "compileStreaming" in WebAssembly const INITCPIO_ADDR = 0x200000; -export class Machine extends EventEmitter<{ - halt: void; - restart: void; - error: { error: Error; threadName: string }; -}> { +export class Machine { #boot_console: TransformStream; #boot_console_writer: WritableStreamDefaultWriter; #workers: Worker[] = []; @@ -44,7 +40,6 @@ export class Machine extends EventEmitter<{ devices: VirtioDevice[]; initcpio?: ArrayBufferView; }) { - super(); this.#boot_console = new TransformStream(); this.#boot_console_writer = this.#boot_console.writable.getWriter(); this.#devices = options.devices; @@ -210,6 +205,7 @@ export class Machine extends EventEmitter<{ instantiate: unavailable, call: unavailable, switch_entry: unavailable, + call_signal_handler: unavailable, read: unavailable, write: unavailable, write_zeroes: unavailable, diff --git a/tools/wasm/src/util.ts b/tools/wasm/src/util.ts index f68de60c4a38c6..4e85a07390baee 100644 --- a/tools/wasm/src/util.ts +++ b/tools/wasm/src/util.ts @@ -15,15 +15,15 @@ export function get_script_path(fn: () => void, import_meta: ImportMeta) { return new URL(match, import_meta.url); } -export class EventEmitter { - #subscribers: { [K in keyof Events]?: Set<(data: Events[K]) => void> } = {}; - on(event: K, handler: (data: Events[K]) => void) { - (this.#subscribers[event] ??= new Set()).add(handler); - } - off(event: K, handler: (data: Events[K]) => void) { - this.#subscribers[event]?.delete(handler); - } - protected emit(event: K, data: Events[K]) { - this.#subscribers[event]?.forEach((handler) => handler(data)); - } -} +// export class EventEmitter { +// #subscribers: { [K in keyof Events]?: Set<(data: Events[K]) => void> } = {}; +// on(event: K, handler: (data: Events[K]) => void) { +// (this.#subscribers[event] ??= new Set()).add(handler); +// } +// off(event: K, handler: (data: Events[K]) => void) { +// this.#subscribers[event]?.delete(handler); +// } +// protected emit(event: K, data: Events[K]) { +// this.#subscribers[event]?.forEach((handler) => handler(data)); +// } +// } diff --git a/tools/wasm/src/wasm.ts b/tools/wasm/src/wasm.ts index 4fd9a6f8cabd5f..19bd039f4321c3 100644 --- a/tools/wasm/src/wasm.ts +++ b/tools/wasm/src/wasm.ts @@ -26,8 +26,7 @@ export interface Imports { }; kernel: { breakpoint(): void; - halt(): void; - restart(): void; + halt_worker(): void; boot_console_write(msg: number, len: number): void; boot_console_close(): void; return_address(_level: number): number; @@ -47,6 +46,7 @@ export interface Imports { instantiate(): void; call(): void; switch_entry(fn: number, arg: number): void; + call_signal_handler(fn: number, sig: number): void; read(to: number, from: number, n: number): number; write(to: number, from: number, n: number): number; write_zeroes(to: number, n: number): number; @@ -108,14 +108,10 @@ export function kernel_imports( // deno-lint-ignore no-debugger debugger; }, - halt: () => { + halt_worker: () => { if (!is_worker) throw new Error("Halt called in main thread"); self.close(); }, - restart: () => { - // TODO: plumb this to the main thread, emit an event - throw new Error("Restart not implemented"); - }, boot_console_write: (msg, len) => { boot_console_write(memory.buffer.slice(msg, msg + len)); diff --git a/tools/wasm/src/worker.ts b/tools/wasm/src/worker.ts index 003c49d35457b7..cfc0188a6517f7 100644 --- a/tools/wasm/src/worker.ts +++ b/tools/wasm/src/worker.ts @@ -43,7 +43,7 @@ function user_imports({ memory: WebAssembly.Memory | null; imports: Imports["user"]; } { - const HALT_USER = Symbol("halt"); + const HALT_USER = Symbol("halt user"); const kernel_memory_buffer = new Uint8Array(kernel_memory.buffer); let module: WebAssembly.Module | null = null; @@ -180,9 +180,29 @@ function user_imports({ f(arg); // throw new Error("thread entrypoint reached the end without exiting"); + console.warn("thread entrypoint reached the end without exiting"); }; }, + // signal handling: + call_signal_handler(fn, sig) { + assert(instance); + + const { __indirect_function_table } = instance.exports; + assert( + __indirect_function_table instanceof WebAssembly.Table, + "Invalid function table", + ); + + const f = __indirect_function_table.get(fn); + assert( + typeof f === "function" && f.length === 1, + "Invalid function signature", + ); + + f(sig); // TODO: the siginfo overload + }, + // memory: read(to, from, n) { assert(memory); @@ -210,12 +230,12 @@ self.onmessage = (event: MessageEvent) => { const { fn, arg, vmlinux, memory, parent_user_module, parent_user_memory } = event.data; - const user = user_imports({ - kernel_memory: memory, - get_kernel_instance: () => instance, - parent_user_module, - parent_user_memory, - }); + const user = user_imports({ + kernel_memory: memory, + get_kernel_instance: () => instance, + parent_user_module, + parent_user_memory, + }); const imports = { env: { memory },