1 |
2 |
drasko |
/*
|
2 |
|
|
* System Calls
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 2007 Bahadir Balban
|
5 |
|
|
*/
|
6 |
|
|
#include <l4/lib/mutex.h>
|
7 |
|
|
#include <l4/lib/printk.h>
|
8 |
|
|
#include <l4/generic/space.h>
|
9 |
|
|
#include <l4/generic/scheduler.h>
|
10 |
|
|
#include <l4/generic/debug.h>
|
11 |
|
|
#include <l4/generic/tcb.h>
|
12 |
|
|
#include <l4/api/errno.h>
|
13 |
|
|
#include INC_GLUE(memlayout.h)
|
14 |
|
|
#include INC_GLUE(syscall.h)
|
15 |
|
|
#include INC_GLUE(mapping.h)
|
16 |
|
|
#include INC_GLUE(debug.h)
|
17 |
|
|
#include INC_SUBARCH(mm.h)
|
18 |
|
|
#include INC_SUBARCH(perfmon.h)
|
19 |
|
|
#include INC_API(syscall.h)
|
20 |
|
|
#include INC_API(kip.h)
|
21 |
|
|
|
22 |
|
|
void kip_init_syscalls(void)
|
23 |
|
|
{
|
24 |
|
|
kip.irq_control = ARM_SYSCALL_PAGE + sys_irq_control_offset;
|
25 |
|
|
kip.thread_control = ARM_SYSCALL_PAGE + sys_thread_control_offset;
|
26 |
|
|
kip.ipc_control = ARM_SYSCALL_PAGE + sys_ipc_control_offset;
|
27 |
|
|
kip.map = ARM_SYSCALL_PAGE + sys_map_offset;
|
28 |
|
|
kip.ipc = ARM_SYSCALL_PAGE + sys_ipc_offset;
|
29 |
|
|
kip.capability_control = ARM_SYSCALL_PAGE + sys_capability_control_offset;
|
30 |
|
|
kip.unmap = ARM_SYSCALL_PAGE + sys_unmap_offset;
|
31 |
|
|
kip.exchange_registers = ARM_SYSCALL_PAGE + sys_exchange_registers_offset;
|
32 |
|
|
kip.thread_switch = ARM_SYSCALL_PAGE + sys_thread_switch_offset;
|
33 |
|
|
kip.schedule = ARM_SYSCALL_PAGE + sys_schedule_offset;
|
34 |
|
|
kip.getid = ARM_SYSCALL_PAGE + sys_getid_offset;
|
35 |
|
|
kip.container_control = ARM_SYSCALL_PAGE + sys_container_control_offset;
|
36 |
|
|
kip.time = ARM_SYSCALL_PAGE + sys_time_offset;
|
37 |
|
|
kip.mutex_control = ARM_SYSCALL_PAGE + sys_mutex_control_offset;
|
38 |
|
|
kip.cache_control = ARM_SYSCALL_PAGE + sys_cache_control_offset;
|
39 |
|
|
}
|
40 |
|
|
|
41 |
|
|
/* Jump table for all system calls. */
|
42 |
|
|
syscall_fn_t syscall_table[SYSCALLS_TOTAL];
|
43 |
|
|
|
44 |
|
|
|
45 |
|
|
int arch_sys_ipc(syscall_context_t *regs)
|
46 |
|
|
{
|
47 |
|
|
return sys_ipc((l4id_t)regs->r0, (l4id_t)regs->r1,
|
48 |
|
|
(unsigned int)regs->r2);
|
49 |
|
|
}
|
50 |
|
|
|
51 |
|
|
int arch_sys_thread_switch(syscall_context_t *regs)
|
52 |
|
|
{
|
53 |
|
|
return sys_thread_switch();
|
54 |
|
|
}
|
55 |
|
|
|
56 |
|
|
int arch_sys_thread_control(syscall_context_t *regs)
|
57 |
|
|
{
|
58 |
|
|
return sys_thread_control((unsigned int)regs->r0,
|
59 |
|
|
(struct task_ids *)regs->r1);
|
60 |
|
|
}
|
61 |
|
|
|
62 |
|
|
int arch_sys_exchange_registers(syscall_context_t *regs)
|
63 |
|
|
{
|
64 |
|
|
return sys_exchange_registers((struct exregs_data *)regs->r0,
|
65 |
|
|
(l4id_t)regs->r1);
|
66 |
|
|
}
|
67 |
|
|
|
68 |
|
|
int arch_sys_schedule(syscall_context_t *regs)
|
69 |
|
|
{
|
70 |
|
|
return sys_schedule();
|
71 |
|
|
}
|
72 |
|
|
|
73 |
|
|
int arch_sys_getid(syscall_context_t *regs)
|
74 |
|
|
{
|
75 |
|
|
return sys_getid((struct task_ids *)regs->r0);
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
int arch_sys_unmap(syscall_context_t *regs)
|
79 |
|
|
{
|
80 |
|
|
return sys_unmap((unsigned long)regs->r0, (unsigned long)regs->r1,
|
81 |
|
|
(unsigned int)regs->r2);
|
82 |
|
|
}
|
83 |
|
|
|
84 |
|
|
int arch_sys_irq_control(syscall_context_t *regs)
|
85 |
|
|
{
|
86 |
|
|
return sys_irq_control((unsigned int)regs->r0,
|
87 |
|
|
(unsigned int)regs->r1,
|
88 |
|
|
(l4id_t)regs->r2);
|
89 |
|
|
}
|
90 |
|
|
|
91 |
|
|
int arch_sys_ipc_control(syscall_context_t *regs)
|
92 |
|
|
{
|
93 |
|
|
return sys_ipc_control();
|
94 |
|
|
}
|
95 |
|
|
|
96 |
|
|
int arch_sys_map(syscall_context_t *regs)
|
97 |
|
|
{
|
98 |
|
|
return sys_map((unsigned long)regs->r0, (unsigned long)regs->r1,
|
99 |
|
|
(unsigned long)regs->r2, (unsigned long)regs->r3,
|
100 |
|
|
(l4id_t)regs->r4);
|
101 |
|
|
}
|
102 |
|
|
|
103 |
|
|
int arch_sys_capability_control(syscall_context_t *regs)
|
104 |
|
|
{
|
105 |
|
|
return sys_capability_control((unsigned int)regs->r0,
|
106 |
|
|
(unsigned int)regs->r1,
|
107 |
|
|
(void *)regs->r2);
|
108 |
|
|
}
|
109 |
|
|
|
110 |
|
|
int arch_sys_container_control(syscall_context_t *regs)
|
111 |
|
|
{
|
112 |
|
|
return sys_container_control((unsigned int)regs->r0,
|
113 |
|
|
(unsigned int)regs->r1,
|
114 |
|
|
(void *)regs->r2);
|
115 |
|
|
}
|
116 |
|
|
|
117 |
|
|
int arch_sys_time(syscall_context_t *regs)
|
118 |
|
|
{
|
119 |
|
|
return sys_time((struct timeval *)regs->r0, (int)regs->r1);
|
120 |
|
|
}
|
121 |
|
|
|
122 |
|
|
int arch_sys_mutex_control(syscall_context_t *regs)
|
123 |
|
|
{
|
124 |
|
|
return sys_mutex_control((unsigned long)regs->r0, (int)regs->r1);
|
125 |
|
|
}
|
126 |
|
|
|
127 |
|
|
int arch_sys_cache_control(syscall_context_t *regs)
|
128 |
|
|
{
|
129 |
|
|
return sys_cache_control((unsigned long)regs->r0,
|
130 |
|
|
(unsigned long)regs->r1,
|
131 |
|
|
(unsigned int)regs->r2);
|
132 |
|
|
}
|
133 |
|
|
|
134 |
|
|
/*
|
135 |
|
|
* Initialises the system call jump table, for kernel to use.
|
136 |
|
|
* Also maps the system call page into userspace.
|
137 |
|
|
*/
|
138 |
|
|
void syscall_init()
|
139 |
|
|
{
|
140 |
|
|
syscall_table[sys_ipc_offset >> 2] = (syscall_fn_t)arch_sys_ipc;
|
141 |
|
|
syscall_table[sys_thread_switch_offset >> 2] = (syscall_fn_t)arch_sys_thread_switch;
|
142 |
|
|
syscall_table[sys_thread_control_offset >> 2] = (syscall_fn_t)arch_sys_thread_control;
|
143 |
|
|
syscall_table[sys_exchange_registers_offset >> 2] = (syscall_fn_t)arch_sys_exchange_registers;
|
144 |
|
|
syscall_table[sys_schedule_offset >> 2] = (syscall_fn_t)arch_sys_schedule;
|
145 |
|
|
syscall_table[sys_getid_offset >> 2] = (syscall_fn_t)arch_sys_getid;
|
146 |
|
|
syscall_table[sys_unmap_offset >> 2] = (syscall_fn_t)arch_sys_unmap;
|
147 |
|
|
syscall_table[sys_irq_control_offset >> 2] = (syscall_fn_t)arch_sys_irq_control;
|
148 |
|
|
syscall_table[sys_ipc_control_offset >> 2] = (syscall_fn_t)arch_sys_ipc_control;
|
149 |
|
|
syscall_table[sys_map_offset >> 2] = (syscall_fn_t)arch_sys_map;
|
150 |
|
|
syscall_table[sys_capability_control_offset >> 2] = (syscall_fn_t)arch_sys_capability_control;
|
151 |
|
|
syscall_table[sys_container_control_offset >> 2] = (syscall_fn_t)arch_sys_container_control;
|
152 |
|
|
syscall_table[sys_time_offset >> 2] = (syscall_fn_t)arch_sys_time;
|
153 |
|
|
syscall_table[sys_mutex_control_offset >> 2] = (syscall_fn_t)arch_sys_mutex_control;
|
154 |
|
|
syscall_table[sys_cache_control_offset >> 2] = (syscall_fn_t)arch_sys_cache_control;
|
155 |
|
|
|
156 |
|
|
add_boot_mapping(virt_to_phys(&__syscall_page_start),
|
157 |
|
|
ARM_SYSCALL_PAGE, PAGE_SIZE, MAP_USR_RX);
|
158 |
|
|
}
|
159 |
|
|
|
160 |
|
|
/* Checks a syscall is legitimate and dispatches to appropriate handler. */
|
161 |
|
|
int syscall(syscall_context_t *regs, unsigned long swi_addr)
|
162 |
|
|
{
|
163 |
|
|
int ret = 0;
|
164 |
|
|
|
165 |
|
|
/* Check if genuine system call, coming from the syscall page */
|
166 |
|
|
if ((swi_addr & ARM_SYSCALL_PAGE) == ARM_SYSCALL_PAGE) {
|
167 |
|
|
/* Check within syscall offset boundary */
|
168 |
|
|
if (((swi_addr & syscall_offset_mask) >= 0) &&
|
169 |
|
|
((swi_addr & syscall_offset_mask) <= syscalls_end_offset)) {
|
170 |
|
|
|
171 |
|
|
/* Do system call accounting, if enabled */
|
172 |
|
|
system_account_syscall();
|
173 |
|
|
system_account_syscall_type(swi_addr);
|
174 |
|
|
|
175 |
|
|
/* Start measure syscall timing, if enabled */
|
176 |
|
|
system_measure_syscall_start();
|
177 |
|
|
|
178 |
|
|
/* Quick jump, rather than compare each */
|
179 |
|
|
ret = (*syscall_table[(swi_addr & 0xFF) >> 2])(regs);
|
180 |
|
|
|
181 |
|
|
/* End measure syscall timing, if enabled */
|
182 |
|
|
system_measure_syscall_end(swi_addr);
|
183 |
|
|
|
184 |
|
|
} else {
|
185 |
|
|
printk("System call received from call @ 0x%lx."
|
186 |
|
|
"Instruction: 0x%lx.\n", swi_addr,
|
187 |
|
|
*((unsigned long *)swi_addr));
|
188 |
|
|
return -ENOSYS;
|
189 |
|
|
}
|
190 |
|
|
} else {
|
191 |
|
|
printk("System call exception from unknown location 0x%lx."
|
192 |
|
|
"Discarding.\n", swi_addr);
|
193 |
|
|
return -ENOSYS;
|
194 |
|
|
}
|
195 |
|
|
|
196 |
|
|
if (current->flags & TASK_SUSPENDING) {
|
197 |
|
|
BUG_ON(current->nlocks);
|
198 |
|
|
sched_suspend_sync();
|
199 |
|
|
}
|
200 |
|
|
|
201 |
|
|
return ret;
|
202 |
|
|
}
|
203 |
|
|
|