Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/wasm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions arch/wasm/configs/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
4 changes: 4 additions & 0 deletions arch/wasm/include/asm/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ static inline void *get_stack_pointer(void)
return ptr;
}


void set_current_cpu(int cpu);
int get_current_cpu(void);

Expand All @@ -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
5 changes: 3 additions & 2 deletions arch/wasm/include/asm/wasm_imports.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
17 changes: 16 additions & 1 deletion arch/wasm/kernel/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions arch/wasm/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/wasm/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 10 additions & 6 deletions arch/wasm/kernel/signal.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#include <asm/wasm_imports.h>
#include <linux/syscalls.h>

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();
}
2 changes: 1 addition & 1 deletion arch/wasm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
2 changes: 0 additions & 2 deletions arch/wasm/kernel/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions include/uapi/asm-generic/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion kernel/panic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions kernel/sched/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
12 changes: 0 additions & 12 deletions tools/wasm/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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();
</script>
</body>
Expand Down
14 changes: 0 additions & 14 deletions tools/wasm/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
10 changes: 3 additions & 7 deletions tools/wasm/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<Uint8Array, Uint8Array>;
#boot_console_writer: WritableStreamDefaultWriter<Uint8Array>;
#workers: Worker[] = [];
Expand All @@ -44,7 +40,6 @@ export class Machine extends EventEmitter<{
devices: VirtioDevice[];
initcpio?: ArrayBufferView;
}) {
super();
this.#boot_console = new TransformStream<Uint8Array, Uint8Array>();
this.#boot_console_writer = this.#boot_console.writable.getWriter();
this.#devices = options.devices;
Expand Down Expand Up @@ -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,
Expand Down
24 changes: 12 additions & 12 deletions tools/wasm/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ export function get_script_path(fn: () => void, import_meta: ImportMeta) {
return new URL(match, import_meta.url);
}

export class EventEmitter<Events> {
#subscribers: { [K in keyof Events]?: Set<(data: Events[K]) => void> } = {};
on<K extends keyof Events>(event: K, handler: (data: Events[K]) => void) {
(this.#subscribers[event] ??= new Set()).add(handler);
}
off<K extends keyof Events>(event: K, handler: (data: Events[K]) => void) {
this.#subscribers[event]?.delete(handler);
}
protected emit<K extends keyof Events>(event: K, data: Events[K]) {
this.#subscribers[event]?.forEach((handler) => handler(data));
}
}
// export class EventEmitter<Events> {
// #subscribers: { [K in keyof Events]?: Set<(data: Events[K]) => void> } = {};
// on<K extends keyof Events>(event: K, handler: (data: Events[K]) => void) {
// (this.#subscribers[event] ??= new Set()).add(handler);
// }
// off<K extends keyof Events>(event: K, handler: (data: Events[K]) => void) {
// this.#subscribers[event]?.delete(handler);
// }
// protected emit<K extends keyof Events>(event: K, data: Events[K]) {
// this.#subscribers[event]?.forEach((handler) => handler(data));
// }
// }
10 changes: 3 additions & 7 deletions tools/wasm/src/wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
34 changes: 27 additions & 7 deletions tools/wasm/src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -210,12 +230,12 @@ self.onmessage = (event: MessageEvent<InitMessage>) => {
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 },
Expand Down
Loading