seperate function for getting the stack pointer. moving towards a platform-specific...
[cake.git] / arch / all-unix / kernel / host_intr.c
blobb419b667452a3171d8b6bca4f6f4ff82817ca680
1 #define DEBUG 1
3 #include <aros/system.h>
4 #include <exec/types.h>
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <ucontext.h>
10 #include <pthread.h>
11 #include <signal.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <limits.h>
16 #include <exec/lists.h>
17 #include <exec/execbase.h>
19 #include "etask.h"
21 #include "kernel_intern.h"
22 #include "syscall.h"
23 #include "host_debug.h"
25 #define IRQ_TIMER (1<<0)
26 #define IRQ_SYSCALL (1<<1)
28 struct ExecBase **SysBasePtr;
29 struct KernelBase **KernelBasePtr;
31 static int irq_enabled;
32 static int in_supervisor;
33 int sleep_state;
35 void core_intr_disable(void) {
36 //D(printf("[kernel] disabling interrupts\n"));
37 irq_enabled = 0;
40 void core_intr_enable(void) {
41 //D(printf("[kernel] enabling interrupts\n"));
42 irq_enabled = 1;
45 int core_is_super(void) {
46 return in_supervisor;
49 static pid_t pid;
51 static ucontext_t irq_ctx;
52 static void *irq_stack;
54 static unsigned long timer_period;
56 static ucontext_t idle_ctx;
58 void core_syscall(syscall_id_t type) {
59 sigqueue(pid, SIGUSR1, (const union sigval) (int) (IRQ_SYSCALL | ((type & 0xffff) << 16)));
62 static void *timer_entry(void *arg) {
63 sigset_t sigset;
64 struct timespec ts;
66 sigfillset(&sigset);
67 sigprocmask(SIG_BLOCK, &sigset, NULL);
69 while (1) {
70 D(printf("[kernel:timer] sleeping\n"));
72 clock_gettime(CLOCK_REALTIME, &ts);
73 ts.tv_nsec += 1000000000 / timer_period;
74 if (ts.tv_nsec > 999999999) {
75 ts.tv_nsec -= 1000000000;
76 ts.tv_sec++;
78 clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL);
80 D(printf("[kernel:timer] timer expiry, triggering timer interrupt\n"));
82 sigqueue(pid, SIGUSR1, (const union sigval) IRQ_TIMER);
86 static void irq_handler (int irq_bits) {
87 in_supervisor++;
89 if (irq_bits & IRQ_SYSCALL) {
90 switch ((irq_bits & 0xffff0000) >> 16) {
91 case sc_CAUSE:
92 core_Cause(*SysBasePtr);
93 break;
95 case sc_DISPATCH:
96 core_Dispatch();
97 break;
99 case sc_SWITCH:
100 core_Switch();
101 break;
103 case sc_SCHEDULE:
104 core_Schedule();
105 break;
109 if (irq_enabled)
110 core_ExitInterrupt();
112 in_supervisor--;
114 if (sleep_state != ss_RUNNING) {
115 sleep_state = ss_SLEEPING;
117 setcontext(&idle_ctx);
120 setcontext((ucontext_t *) GetIntETask((*SysBasePtr)->ThisTask)->iet_Context);
123 static void irq_trampoline (int signo, siginfo_t *si, void *vctx) {
124 if (!irq_enabled && !(si->si_value.sival_int & IRQ_SYSCALL)) return;
126 getcontext(&irq_ctx);
127 irq_ctx.uc_stack.ss_sp = irq_stack;
128 irq_ctx.uc_stack.ss_size = SIGSTKSZ;
129 irq_ctx.uc_stack.ss_flags = 0;
130 sigemptyset(&irq_ctx.uc_sigmask);
131 makecontext(&irq_ctx, (void (*)()) irq_handler, 1, si->si_value.sival_int);
133 swapcontext((ucontext_t *) GetIntETask((*SysBasePtr)->ThisTask)->iet_Context, &irq_ctx);
136 static void idle_handler (void) {
137 while (1) sleep(UINT_MAX);
140 int core_init (unsigned long TimerPeriod, struct ExecBase **SysBasePointer, struct KernelBase **KernelBasePointer) {
141 sigset_t sigset;
142 struct sigaction sa;
143 pthread_t thread;
144 pthread_attr_t thread_attrs;
146 D(printf("[kernel] initialising interrupts and task switching\n"));
148 SysBasePtr = SysBasePointer;
149 KernelBasePtr = KernelBasePointer;
151 irq_enabled = 0;
152 in_supervisor = 0;
153 sleep_state = 0;
155 timer_period = TimerPeriod;
157 irq_stack = malloc(SIGSTKSZ);
159 pid = getpid();
161 memset(&sa, 0, sizeof(sa));
162 sa.sa_flags = SA_SIGINFO;
163 sa.sa_sigaction = irq_trampoline;
164 sigaction(SIGUSR1, &sa, NULL);
166 getcontext(&idle_ctx);
167 idle_ctx.uc_stack.ss_sp = malloc(SIGSTKSZ);
168 idle_ctx.uc_stack.ss_size = SIGSTKSZ;
169 idle_ctx.uc_stack.ss_flags = 0;
170 makecontext(&idle_ctx, (void (*)()) idle_handler, 0);
172 pthread_attr_init(&thread_attrs);
173 pthread_attr_setdetachstate(&thread_attrs, PTHREAD_CREATE_DETACHED);
174 pthread_create(&thread, &thread_attrs, timer_entry, NULL);
176 D(printf("[kernel] timer started, frequency is %dhz\n", timer_period));
178 return 0;