Skip to content

Commit b32c91b

Browse files
authored
implement timers (#21)
1 parent 4211df7 commit b32c91b

File tree

9 files changed

+141
-11
lines changed

9 files changed

+141
-11
lines changed

arch/wasm/configs/defconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# CONFIG_LOCALVERSION_AUTO is not set
2+
CONFIG_NO_HZ_IDLE=y
3+
CONFIG_HIGH_RES_TIMERS=y
24
# CONFIG_CPU_ISOLATION is not set
35
CONFIG_BLK_DEV_INITRD=y
46
# CONFIG_RD_BZIP2 is not set
@@ -46,7 +48,6 @@ CONFIG_HW_RANDOM_VIRTIO=y
4648
# CONFIG_VIRTIO_MENU is not set
4749
# CONFIG_VHOST_MENU is not set
4850
CONFIG_EXT2_FS=y
49-
# CONFIG_FILE_LOCKING is not set
5051
# CONFIG_DNOTIFY is not set
5152
# CONFIG_INOTIFY_USER is not set
5253
# CONFIG_DEBUG_MISC is not set

arch/wasm/include/asm/irq.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
#define _WASM_IRQ_H
33

44
#define IPI_IRQ 1
5-
#define FIRST_EXT_IRQ 2
5+
#define TIMER_IRQ 2
6+
#define FIRST_EXT_IRQ 3
67
#define NR_IRQS 64
78

89
int wasm_alloc_irq(void);

arch/wasm/include/asm/sigcontext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
struct pt_regs {
55
long syscall_nr;
66
unsigned long syscall_args[6];
7+
int user_mode;
78
};
89

910
struct sigcontext {

arch/wasm/include/uapi/asm/ptrace.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66

77
struct task_struct;
88

9-
#define user_mode(regs) (__builtin_trap(),0)
10-
#define kernel_mode(regs) (__builtin_trap(),0)
11-
#define profile_pc(regs) (__builtin_trap(),0)
9+
#define user_mode(regs) (regs->user_mode)
1210
#define instruction_pointer(regs) (-1)
1311
#define user_stack_pointer(regs) (__builtin_trap(),0)
1412

arch/wasm/kernel/irq.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <asm/smp.h>
2+
#include <asm/timex.h>
23
#include <linux/cpu.h>
34
#include <linux/bitops.h>
45
#include <linux/hardirq.h>
@@ -10,11 +11,47 @@
1011

1112
static DEFINE_PER_CPU(unsigned long, irqflags);
1213
static DEFINE_PER_CPU(atomic64_t, irq_pending);
14+
static DEFINE_PER_CPU(u64, timer_deadline_ns);
15+
16+
void wasm_set_timer_deadline(u64 deadline_ns)
17+
{
18+
__this_cpu_write(timer_deadline_ns, deadline_ns);
19+
}
20+
21+
u64 wasm_get_timer_deadline(void)
22+
{
23+
return __this_cpu_read(timer_deadline_ns);
24+
}
1325

1426
void __cpuidle arch_cpu_idle(void)
1527
{
1628
atomic64_t *pending = this_cpu_ptr(&irq_pending);
17-
__builtin_wasm_memory_atomic_wait64(&pending->counter, 0, -1);
29+
u64 deadline = __this_cpu_read(timer_deadline_ns);
30+
u64 now;
31+
s64 timeout_ns;
32+
int ret;
33+
34+
if (deadline == 0) {
35+
timeout_ns = -1; // forever
36+
} else {
37+
now = wasm_kernel_get_now_nsec();
38+
if ((s64)(deadline - now) <= 0) {
39+
__this_cpu_write(timer_deadline_ns, 0);
40+
atomic64_or(1 << TIMER_IRQ, pending);
41+
raw_local_irq_enable();
42+
return;
43+
}
44+
timeout_ns = deadline - now;
45+
}
46+
47+
ret = __builtin_wasm_memory_atomic_wait64(&pending->counter, 0,
48+
timeout_ns);
49+
50+
if (ret == 2 /* timeout reached */) {
51+
__this_cpu_write(timer_deadline_ns, 0);
52+
atomic64_or(1 << TIMER_IRQ, pending);
53+
}
54+
1855
raw_local_irq_enable();
1956
}
2057

arch/wasm/kernel/syscall.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ wasm_syscall(long nr, unsigned long arg0, unsigned long arg1,
2323
struct pt_regs *regs = current_pt_regs();
2424
long ret;
2525

26+
regs->user_mode = 0;
2627
nr = syscall_enter_from_user_mode(regs, nr);
2728

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

4142
syscall_exit_to_user_mode(regs);
43+
regs->user_mode = 1;
4244

4345
return ret;
4446
}

arch/wasm/kernel/time.c

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1+
#include <linux/clockchips.h>
12
#include <linux/clocksource.h>
3+
#include <linux/cpuhotplug.h>
24
#include <linux/delay.h>
35
#include <linux/init.h>
6+
#include <linux/interrupt.h>
7+
#include <linux/irq.h>
8+
#include <linux/irqdomain.h>
9+
#include <asm/irq.h>
410
#include <asm/wasm_imports.h>
511
#include <asm/param.h>
612
#include <asm/timex.h>
713
#include <asm/processor.h>
814

915
extern unsigned long loops_per_jiffy;
16+
extern void wasm_set_timer_deadline(u64 deadline_ns);
17+
extern u64 wasm_get_timer_deadline(void);
18+
19+
static int timer_irq;
1020
void calibrate_delay(void)
1121
{
1222
loops_per_jiffy = 1000000000 / HZ;
@@ -32,9 +42,11 @@ void __const_udelay(unsigned long xloops)
3242
__delay(xloops / 0x10c7ul); /* 2**32 / 1000000 (rounded up) */
3343
}
3444

35-
unsigned long long sched_clock(void) {
45+
unsigned long long sched_clock(void)
46+
{
3647
static u64 origin = 0;
37-
if (!origin) origin = wasm_kernel_get_now_nsec();
48+
if (!origin)
49+
origin = wasm_kernel_get_now_nsec();
3850
return wasm_kernel_get_now_nsec() - origin;
3951
}
4052

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

66+
static DEFINE_PER_CPU(struct clock_event_device, clockevent);
67+
68+
static irqreturn_t timer_interrupt(int irq, void *dev)
69+
{
70+
struct clock_event_device *evt = this_cpu_ptr(&clockevent);
71+
72+
if (evt->event_handler)
73+
evt->event_handler(evt);
74+
75+
return IRQ_HANDLED;
76+
}
77+
78+
static int timer_set_next_event(unsigned long delta,
79+
struct clock_event_device *evt)
80+
{
81+
u64 now = wasm_kernel_get_now_nsec();
82+
u64 deadline = now + delta;
83+
wasm_set_timer_deadline(deadline);
84+
return 0;
85+
}
86+
87+
static int timer_set_oneshot(struct clock_event_device *evt)
88+
{
89+
return 0;
90+
}
91+
92+
static int timer_shutdown(struct clock_event_device *evt)
93+
{
94+
wasm_set_timer_deadline(0);
95+
return 0;
96+
}
97+
98+
static int timer_starting_cpu(unsigned int cpu)
99+
{
100+
struct clock_event_device *evt = this_cpu_ptr(&clockevent);
101+
102+
evt->name = "wasm-timer";
103+
evt->features = CLOCK_EVT_FEAT_ONESHOT;
104+
evt->rating = 300;
105+
evt->set_next_event = timer_set_next_event;
106+
evt->set_state_oneshot = timer_set_oneshot;
107+
evt->set_state_shutdown = timer_shutdown;
108+
evt->cpumask = cpumask_of(cpu);
109+
evt->irq = timer_irq;
110+
111+
clockevents_config_and_register(evt, NSEC_PER_SEC, 1000, LONG_MAX);
112+
113+
return 0;
114+
}
115+
54116
void __init time_init(void)
55117
{
118+
int ret;
119+
56120
if (clocksource_register_khz(&clocksource, 1000 * 1000))
57121
panic("unable to register clocksource\n");
122+
123+
timer_irq = irq_create_mapping(NULL, TIMER_IRQ);
124+
if (!timer_irq)
125+
panic("unable to create IRQ mapping for timer\n");
126+
127+
if (request_irq(timer_irq, timer_interrupt, IRQF_TIMER, "timer", NULL))
128+
panic("unable to request timer IRQ\n");
129+
130+
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "wasm/timer:online",
131+
timer_starting_cpu, NULL);
132+
if (ret < 0)
133+
panic("unable to setup CPU hotplug state\n");
58134
}

tools/wasm/src/wasm.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export interface Imports {
7575
};
7676
}
7777

78+
export const HALT_KERNEL = Symbol("halt kernel");
79+
7880
export function kernel_imports(
7981
{
8082
is_worker,
@@ -111,6 +113,7 @@ export function kernel_imports(
111113
halt_worker: () => {
112114
if (!is_worker) throw new Error("Halt called in main thread");
113115
self.close();
116+
throw HALT_KERNEL;
114117
},
115118

116119
boot_console_write: (msg, len) => {

tools/wasm/src/worker.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { assert } from "./util.ts";
2-
import { type Imports, type Instance, kernel_imports } from "./wasm.ts";
2+
import {
3+
HALT_KERNEL,
4+
type Imports,
5+
type Instance,
6+
kernel_imports,
7+
} from "./wasm.ts";
38

49
export interface InitMessage {
510
fn: number;
@@ -151,6 +156,7 @@ function user_imports({
151156
call_entry();
152157
} catch (error) {
153158
if (error === HALT_USER) continue;
159+
if (error === HALT_KERNEL) throw error;
154160
console.log("error running user module:", String(error));
155161
return;
156162
}
@@ -288,6 +294,11 @@ self.onmessage = (event: MessageEvent<InitMessage>) => {
288294
},
289295
} satisfies Imports;
290296

291-
const instance = (new WebAssembly.Instance(vmlinux, imports)) as Instance;
292-
instance.exports.__indirect_function_table.get(fn)!(arg);
297+
const instance = new WebAssembly.Instance(vmlinux, imports) as Instance;
298+
try {
299+
instance.exports.__indirect_function_table.get(fn)!(arg);
300+
} catch (error) {
301+
if (error === HALT_KERNEL) return;
302+
throw error;
303+
}
293304
};

0 commit comments

Comments
 (0)