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
3 changes: 2 additions & 1 deletion arch/wasm/configs/defconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
# CONFIG_CPU_ISOLATION is not set
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_BZIP2 is not set
Expand Down Expand Up @@ -46,7 +48,6 @@ CONFIG_HW_RANDOM_VIRTIO=y
# CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set
CONFIG_EXT2_FS=y
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
# CONFIG_DEBUG_MISC is not set
Expand Down
3 changes: 2 additions & 1 deletion arch/wasm/include/asm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#define _WASM_IRQ_H

#define IPI_IRQ 1
#define FIRST_EXT_IRQ 2
#define TIMER_IRQ 2
#define FIRST_EXT_IRQ 3
#define NR_IRQS 64

int wasm_alloc_irq(void);
Expand Down
1 change: 1 addition & 0 deletions arch/wasm/include/asm/sigcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
struct pt_regs {
long syscall_nr;
unsigned long syscall_args[6];
int user_mode;
};

struct sigcontext {
Expand Down
4 changes: 1 addition & 3 deletions arch/wasm/include/uapi/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@

struct task_struct;

#define user_mode(regs) (__builtin_trap(),0)
#define kernel_mode(regs) (__builtin_trap(),0)
#define profile_pc(regs) (__builtin_trap(),0)
#define user_mode(regs) (regs->user_mode)
#define instruction_pointer(regs) (-1)
#define user_stack_pointer(regs) (__builtin_trap(),0)

Expand Down
39 changes: 38 additions & 1 deletion arch/wasm/kernel/irq.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <asm/smp.h>
#include <asm/timex.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
#include <linux/hardirq.h>
Expand All @@ -10,11 +11,47 @@

static DEFINE_PER_CPU(unsigned long, irqflags);
static DEFINE_PER_CPU(atomic64_t, irq_pending);
static DEFINE_PER_CPU(u64, timer_deadline_ns);

void wasm_set_timer_deadline(u64 deadline_ns)
{
__this_cpu_write(timer_deadline_ns, deadline_ns);
}

u64 wasm_get_timer_deadline(void)
{
return __this_cpu_read(timer_deadline_ns);
}

void __cpuidle arch_cpu_idle(void)
{
atomic64_t *pending = this_cpu_ptr(&irq_pending);
__builtin_wasm_memory_atomic_wait64(&pending->counter, 0, -1);
u64 deadline = __this_cpu_read(timer_deadline_ns);
u64 now;
s64 timeout_ns;
int ret;

if (deadline == 0) {
timeout_ns = -1; // forever
} else {
now = wasm_kernel_get_now_nsec();
if ((s64)(deadline - now) <= 0) {
__this_cpu_write(timer_deadline_ns, 0);
atomic64_or(1 << TIMER_IRQ, pending);
raw_local_irq_enable();
return;
}
timeout_ns = deadline - now;
}

ret = __builtin_wasm_memory_atomic_wait64(&pending->counter, 0,
timeout_ns);

if (ret == 2 /* timeout reached */) {
__this_cpu_write(timer_deadline_ns, 0);
atomic64_or(1 << TIMER_IRQ, pending);
}

raw_local_irq_enable();
}

Expand Down
2 changes: 2 additions & 0 deletions arch/wasm/kernel/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ wasm_syscall(long nr, unsigned long arg0, unsigned long arg1,
struct pt_regs *regs = current_pt_regs();
long ret;

regs->user_mode = 0;
nr = syscall_enter_from_user_mode(regs, nr);

if (nr < 0 || nr >= ARRAY_SIZE(syscall_table))
Expand All @@ -39,6 +40,7 @@ wasm_syscall(long nr, unsigned long arg0, unsigned long arg1,
ret = syscall_table[nr](regs);

syscall_exit_to_user_mode(regs);
regs->user_mode = 1;

return ret;
}
Expand Down
80 changes: 78 additions & 2 deletions arch/wasm/kernel/time.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/cpuhotplug.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <asm/irq.h>
#include <asm/wasm_imports.h>
#include <asm/param.h>
#include <asm/timex.h>
#include <asm/processor.h>

extern unsigned long loops_per_jiffy;
extern void wasm_set_timer_deadline(u64 deadline_ns);
extern u64 wasm_get_timer_deadline(void);

static int timer_irq;
void calibrate_delay(void)
{
loops_per_jiffy = 1000000000 / HZ;
Expand All @@ -32,9 +42,11 @@ void __const_udelay(unsigned long xloops)
__delay(xloops / 0x10c7ul); /* 2**32 / 1000000 (rounded up) */
}

unsigned long long sched_clock(void) {
unsigned long long sched_clock(void)
{
static u64 origin = 0;
if (!origin) origin = wasm_kernel_get_now_nsec();
if (!origin)
origin = wasm_kernel_get_now_nsec();
return wasm_kernel_get_now_nsec() - origin;
}

Expand All @@ -51,8 +63,72 @@ static struct clocksource clocksource = {
.mask = CLOCKSOURCE_MASK(64),
};

static DEFINE_PER_CPU(struct clock_event_device, clockevent);

static irqreturn_t timer_interrupt(int irq, void *dev)
{
struct clock_event_device *evt = this_cpu_ptr(&clockevent);

if (evt->event_handler)
evt->event_handler(evt);

return IRQ_HANDLED;
}

static int timer_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
u64 now = wasm_kernel_get_now_nsec();
u64 deadline = now + delta;
wasm_set_timer_deadline(deadline);
return 0;
}

static int timer_set_oneshot(struct clock_event_device *evt)
{
return 0;
}

static int timer_shutdown(struct clock_event_device *evt)
{
wasm_set_timer_deadline(0);
return 0;
}

static int timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *evt = this_cpu_ptr(&clockevent);

evt->name = "wasm-timer";
evt->features = CLOCK_EVT_FEAT_ONESHOT;
evt->rating = 300;
evt->set_next_event = timer_set_next_event;
evt->set_state_oneshot = timer_set_oneshot;
evt->set_state_shutdown = timer_shutdown;
evt->cpumask = cpumask_of(cpu);
evt->irq = timer_irq;

clockevents_config_and_register(evt, NSEC_PER_SEC, 1000, LONG_MAX);

return 0;
}

void __init time_init(void)
{
int ret;

if (clocksource_register_khz(&clocksource, 1000 * 1000))
panic("unable to register clocksource\n");

timer_irq = irq_create_mapping(NULL, TIMER_IRQ);
if (!timer_irq)
panic("unable to create IRQ mapping for timer\n");

if (request_irq(timer_irq, timer_interrupt, IRQF_TIMER, "timer", NULL))
panic("unable to request timer IRQ\n");

ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "wasm/timer:online",
timer_starting_cpu, NULL);
if (ret < 0)
panic("unable to setup CPU hotplug state\n");
}
3 changes: 3 additions & 0 deletions tools/wasm/src/wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export interface Imports {
};
}

export const HALT_KERNEL = Symbol("halt kernel");

export function kernel_imports(
{
is_worker,
Expand Down Expand Up @@ -111,6 +113,7 @@ export function kernel_imports(
halt_worker: () => {
if (!is_worker) throw new Error("Halt called in main thread");
self.close();
throw HALT_KERNEL;
},

boot_console_write: (msg, len) => {
Expand Down
17 changes: 14 additions & 3 deletions tools/wasm/src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { assert } from "./util.ts";
import { type Imports, type Instance, kernel_imports } from "./wasm.ts";
import {
HALT_KERNEL,
type Imports,
type Instance,
kernel_imports,
} from "./wasm.ts";

export interface InitMessage {
fn: number;
Expand Down Expand Up @@ -151,6 +156,7 @@ function user_imports({
call_entry();
} catch (error) {
if (error === HALT_USER) continue;
if (error === HALT_KERNEL) throw error;
console.log("error running user module:", String(error));
return;
}
Expand Down Expand Up @@ -288,6 +294,11 @@ self.onmessage = (event: MessageEvent<InitMessage>) => {
},
} satisfies Imports;

const instance = (new WebAssembly.Instance(vmlinux, imports)) as Instance;
instance.exports.__indirect_function_table.get(fn)!(arg);
const instance = new WebAssembly.Instance(vmlinux, imports) as Instance;
try {
instance.exports.__indirect_function_table.get(fn)!(arg);
} catch (error) {
if (error === HALT_KERNEL) return;
throw error;
}
};
Loading