diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /arch/score/kernel | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'arch/score/kernel')
-rw-r--r-- | arch/score/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/score/kernel/entry.S | 32 | ||||
-rw-r--r-- | arch/score/kernel/module.c | 10 | ||||
-rw-r--r-- | arch/score/kernel/process.c | 65 | ||||
-rw-r--r-- | arch/score/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/score/kernel/signal.c | 71 | ||||
-rw-r--r-- | arch/score/kernel/sys_score.c | 88 |
7 files changed, 220 insertions, 52 deletions
diff --git a/arch/score/kernel/Makefile b/arch/score/kernel/Makefile index fb1802b3f54..f218673b5d3 100644 --- a/arch/score/kernel/Makefile +++ b/arch/score/kernel/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | extra-y := head.o vmlinux.lds | 5 | extra-y := head.o vmlinux.lds |
6 | 6 | ||
7 | obj-y += entry.o irq.o process.o ptrace.o \ | 7 | obj-y += entry.o init_task.o irq.o process.o ptrace.o \ |
8 | setup.o signal.o sys_score.o time.o traps.o \ | 8 | setup.o signal.o sys_score.o time.o traps.o \ |
9 | sys_call_table.o | 9 | sys_call_table.o |
10 | 10 | ||
diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S index 1557ca1a295..577abba3fac 100644 --- a/arch/score/kernel/entry.S +++ b/arch/score/kernel/entry.S | |||
@@ -278,13 +278,6 @@ need_resched: | |||
278 | nop | 278 | nop |
279 | #endif | 279 | #endif |
280 | 280 | ||
281 | ENTRY(ret_from_kernel_thread) | ||
282 | bl schedule_tail # r4=struct task_struct *prev | ||
283 | nop | ||
284 | mv r4, r13 | ||
285 | brl r12 | ||
286 | j syscall_exit | ||
287 | |||
288 | ENTRY(ret_from_fork) | 281 | ENTRY(ret_from_fork) |
289 | bl schedule_tail # r4=struct task_struct *prev | 282 | bl schedule_tail # r4=struct task_struct *prev |
290 | 283 | ||
@@ -415,7 +408,7 @@ ENTRY(handle_sys) | |||
415 | sw r9, [r0, PT_EPC] | 408 | sw r9, [r0, PT_EPC] |
416 | 409 | ||
417 | cmpi.c r27, __NR_syscalls # check syscall number | 410 | cmpi.c r27, __NR_syscalls # check syscall number |
418 | bgeu illegal_syscall | 411 | bgtu illegal_syscall |
419 | 412 | ||
420 | slli r8, r27, 2 # get syscall routine | 413 | slli r8, r27, 2 # get syscall routine |
421 | la r11, sys_call_table | 414 | la r11, sys_call_table |
@@ -487,6 +480,16 @@ illegal_syscall: | |||
487 | sw r9, [r0, PT_R7] | 480 | sw r9, [r0, PT_R7] |
488 | j syscall_return | 481 | j syscall_return |
489 | 482 | ||
483 | ENTRY(sys_execve) | ||
484 | mv r4, r0 | ||
485 | la r8, score_execve | ||
486 | br r8 | ||
487 | |||
488 | ENTRY(sys_clone) | ||
489 | mv r4, r0 | ||
490 | la r8, score_clone | ||
491 | br r8 | ||
492 | |||
490 | ENTRY(sys_rt_sigreturn) | 493 | ENTRY(sys_rt_sigreturn) |
491 | mv r4, r0 | 494 | mv r4, r0 |
492 | la r8, score_rt_sigreturn | 495 | la r8, score_rt_sigreturn |
@@ -496,3 +499,16 @@ ENTRY(sys_sigaltstack) | |||
496 | mv r4, r0 | 499 | mv r4, r0 |
497 | la r8, score_sigaltstack | 500 | la r8, score_sigaltstack |
498 | br r8 | 501 | br r8 |
502 | |||
503 | #ifdef __ARCH_WANT_SYSCALL_DEPRECATED | ||
504 | ENTRY(sys_fork) | ||
505 | mv r4, r0 | ||
506 | la r8, score_fork | ||
507 | br r8 | ||
508 | |||
509 | ENTRY(sys_vfork) | ||
510 | mv r4, r0 | ||
511 | la r8, score_vfork | ||
512 | br r8 | ||
513 | #endif /* __ARCH_WANT_SYSCALL_DEPRECATED */ | ||
514 | |||
diff --git a/arch/score/kernel/module.c b/arch/score/kernel/module.c index 1378d99baa3..469e3b64e2f 100644 --- a/arch/score/kernel/module.c +++ b/arch/score/kernel/module.c | |||
@@ -125,6 +125,16 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, | |||
125 | return 0; | 125 | return 0; |
126 | } | 126 | } |
127 | 127 | ||
128 | int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, | ||
129 | unsigned int symindex, unsigned int relsec, | ||
130 | struct module *me) | ||
131 | { | ||
132 | /* Non-standard return value... most other arch's return -ENOEXEC | ||
133 | * for an unsupported relocation variant | ||
134 | */ | ||
135 | return 0; | ||
136 | } | ||
137 | |||
128 | /* Given an address, look for it in the module exception tables. */ | 138 | /* Given an address, look for it in the module exception tables. */ |
129 | const struct exception_table_entry *search_module_dbetables(unsigned long addr) | 139 | const struct exception_table_entry *search_module_dbetables(unsigned long addr) |
130 | { | 140 | { |
diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index 79568466b57..25d08030a88 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/reboot.h> | 27 | #include <linux/reboot.h> |
28 | #include <linux/elfcore.h> | 28 | #include <linux/elfcore.h> |
29 | #include <linux/pm.h> | 29 | #include <linux/pm.h> |
30 | #include <linux/rcupdate.h> | ||
31 | 30 | ||
32 | void (*pm_power_off)(void); | 31 | void (*pm_power_off)(void); |
33 | EXPORT_SYMBOL(pm_power_off); | 32 | EXPORT_SYMBOL(pm_power_off); |
@@ -51,16 +50,16 @@ void __noreturn cpu_idle(void) | |||
51 | { | 50 | { |
52 | /* endless idle loop with no priority at all */ | 51 | /* endless idle loop with no priority at all */ |
53 | while (1) { | 52 | while (1) { |
54 | rcu_idle_enter(); | ||
55 | while (!need_resched()) | 53 | while (!need_resched()) |
56 | barrier(); | 54 | barrier(); |
57 | rcu_idle_exit(); | 55 | |
58 | schedule_preempt_disabled(); | 56 | preempt_enable_no_resched(); |
57 | schedule(); | ||
58 | preempt_disable(); | ||
59 | } | 59 | } |
60 | } | 60 | } |
61 | 61 | ||
62 | void ret_from_fork(void); | 62 | void ret_from_fork(void); |
63 | void ret_from_kernel_thread(void); | ||
64 | 63 | ||
65 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) | 64 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) |
66 | { | 65 | { |
@@ -87,27 +86,29 @@ void flush_thread(void) {} | |||
87 | * set up the kernel stack and exception frames for a new process | 86 | * set up the kernel stack and exception frames for a new process |
88 | */ | 87 | */ |
89 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 88 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
90 | unsigned long arg, struct task_struct *p) | 89 | unsigned long unused, |
90 | struct task_struct *p, struct pt_regs *regs) | ||
91 | { | 91 | { |
92 | struct thread_info *ti = task_thread_info(p); | 92 | struct thread_info *ti = task_thread_info(p); |
93 | struct pt_regs *childregs = task_pt_regs(p); | 93 | struct pt_regs *childregs = task_pt_regs(p); |
94 | struct pt_regs *regs = current_pt_regs(); | ||
95 | 94 | ||
96 | p->thread.reg0 = (unsigned long) childregs; | 95 | p->set_child_tid = NULL; |
97 | if (unlikely(p->flags & PF_KTHREAD)) { | 96 | p->clear_child_tid = NULL; |
98 | memset(childregs, 0, sizeof(struct pt_regs)); | 97 | |
99 | p->thread->reg12 = usp; | 98 | *childregs = *regs; |
100 | p->thread->reg13 = arg; | 99 | childregs->regs[7] = 0; /* Clear error flag */ |
101 | p->thread.reg3 = (unsigned long) ret_from_kernel_thread; | 100 | childregs->regs[4] = 0; /* Child gets zero as return value */ |
101 | regs->regs[4] = p->pid; | ||
102 | |||
103 | if (childregs->cp0_psr & 0x8) { /* test kernel fork or user fork */ | ||
104 | childregs->regs[0] = usp; /* user fork */ | ||
102 | } else { | 105 | } else { |
103 | *childregs = *current_pt_regs(); | 106 | childregs->regs[28] = (unsigned long) ti; /* kernel fork */ |
104 | childregs->regs[7] = 0; /* Clear error flag */ | 107 | childregs->regs[0] = (unsigned long) childregs; |
105 | childregs->regs[4] = 0; /* Child gets zero as return value */ | ||
106 | if (usp) | ||
107 | childregs->regs[0] = usp; /* user fork */ | ||
108 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
109 | } | 108 | } |
110 | 109 | ||
110 | p->thread.reg0 = (unsigned long) childregs; | ||
111 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
111 | p->thread.cp0_psr = 0; | 112 | p->thread.cp0_psr = 0; |
112 | 113 | ||
113 | return 0; | 114 | return 0; |
@@ -119,6 +120,32 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) | |||
119 | return 1; | 120 | return 1; |
120 | } | 121 | } |
121 | 122 | ||
123 | static void __noreturn | ||
124 | kernel_thread_helper(void *unused0, int (*fn)(void *), | ||
125 | void *arg, void *unused1) | ||
126 | { | ||
127 | do_exit(fn(arg)); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Create a kernel thread. | ||
132 | */ | ||
133 | long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
134 | { | ||
135 | struct pt_regs regs; | ||
136 | |||
137 | memset(®s, 0, sizeof(regs)); | ||
138 | |||
139 | regs.regs[6] = (unsigned long) arg; | ||
140 | regs.regs[5] = (unsigned long) fn; | ||
141 | regs.cp0_epc = (unsigned long) kernel_thread_helper; | ||
142 | regs.cp0_psr = (regs.cp0_psr & ~(0x1|0x4|0x8)) | \ | ||
143 | ((regs.cp0_psr & 0x3) << 2); | ||
144 | |||
145 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, \ | ||
146 | 0, ®s, 0, NULL, NULL); | ||
147 | } | ||
148 | |||
122 | unsigned long thread_saved_pc(struct task_struct *tsk) | 149 | unsigned long thread_saved_pc(struct task_struct *tsk) |
123 | { | 150 | { |
124 | return task_pt_regs(tsk)->cp0_epc; | 151 | return task_pt_regs(tsk)->cp0_epc; |
diff --git a/arch/score/kernel/setup.c b/arch/score/kernel/setup.c index b48459afefd..6f898c05787 100644 --- a/arch/score/kernel/setup.c +++ b/arch/score/kernel/setup.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/bootmem.h> | 26 | #include <linux/bootmem.h> |
27 | #include <linux/initrd.h> | 27 | #include <linux/initrd.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/memblock.h> | ||
30 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
31 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
32 | #include <linux/screen_info.h> | 31 | #include <linux/screen_info.h> |
@@ -55,8 +54,7 @@ static void __init bootmem_init(void) | |||
55 | /* Initialize the boot-time allocator with low memory only. */ | 54 | /* Initialize the boot-time allocator with low memory only. */ |
56 | bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, | 55 | bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, |
57 | min_low_pfn, max_low_pfn); | 56 | min_low_pfn, max_low_pfn); |
58 | memblock_add_node(PFN_PHYS(min_low_pfn), | 57 | add_active_range(0, min_low_pfn, max_low_pfn); |
59 | PFN_PHYS(max_low_pfn - min_low_pfn), 0); | ||
60 | 58 | ||
61 | free_bootmem(PFN_PHYS(start_pfn), | 59 | free_bootmem(PFN_PHYS(start_pfn), |
62 | (max_low_pfn - start_pfn) << PAGE_SHIFT); | 60 | (max_low_pfn - start_pfn) << PAGE_SHIFT); |
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index 02353bde92d..aa57440e497 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c | |||
@@ -28,12 +28,13 @@ | |||
28 | #include <linux/ptrace.h> | 28 | #include <linux/ptrace.h> |
29 | #include <linux/unistd.h> | 29 | #include <linux/unistd.h> |
30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/tracehook.h> | ||
32 | 31 | ||
33 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
34 | #include <asm/syscalls.h> | 33 | #include <asm/syscalls.h> |
35 | #include <asm/ucontext.h> | 34 | #include <asm/ucontext.h> |
36 | 35 | ||
36 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
37 | |||
37 | struct rt_sigframe { | 38 | struct rt_sigframe { |
38 | u32 rs_ass[4]; /* argument save space */ | 39 | u32 rs_ass[4]; /* argument save space */ |
39 | u32 rs_code[2]; /* signal trampoline */ | 40 | u32 rs_code[2]; /* signal trampoline */ |
@@ -148,18 +149,20 @@ score_rt_sigreturn(struct pt_regs *regs) | |||
148 | { | 149 | { |
149 | struct rt_sigframe __user *frame; | 150 | struct rt_sigframe __user *frame; |
150 | sigset_t set; | 151 | sigset_t set; |
152 | stack_t st; | ||
151 | int sig; | 153 | int sig; |
152 | 154 | ||
153 | /* Always make any pending restarted system calls return -EINTR */ | ||
154 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
155 | |||
156 | frame = (struct rt_sigframe __user *) regs->regs[0]; | 155 | frame = (struct rt_sigframe __user *) regs->regs[0]; |
157 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 156 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
158 | goto badframe; | 157 | goto badframe; |
159 | if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) | 158 | if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) |
160 | goto badframe; | 159 | goto badframe; |
161 | 160 | ||
162 | set_current_blocked(&set); | 161 | sigdelsetmask(&set, ~_BLOCKABLE); |
162 | spin_lock_irq(¤t->sighand->siglock); | ||
163 | current->blocked = set; | ||
164 | recalc_sigpending(); | ||
165 | spin_unlock_irq(¤t->sighand->siglock); | ||
163 | 166 | ||
164 | sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); | 167 | sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); |
165 | if (sig < 0) | 168 | if (sig < 0) |
@@ -167,11 +170,12 @@ score_rt_sigreturn(struct pt_regs *regs) | |||
167 | else if (sig) | 170 | else if (sig) |
168 | force_sig(sig, current); | 171 | force_sig(sig, current); |
169 | 172 | ||
173 | if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) | ||
174 | goto badframe; | ||
175 | |||
170 | /* It is more difficult to avoid calling this function than to | 176 | /* It is more difficult to avoid calling this function than to |
171 | call it and ignore errors. */ | 177 | call it and ignore errors. */ |
172 | if (do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs->regs[0]) == -EFAULT) | 178 | do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]); |
173 | goto badframe; | ||
174 | regs->is_syscall = 0; | ||
175 | 179 | ||
176 | __asm__ __volatile__( | 180 | __asm__ __volatile__( |
177 | "mv\tr0, %0\n\t" | 181 | "mv\tr0, %0\n\t" |
@@ -232,13 +236,17 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
232 | return 0; | 236 | return 0; |
233 | 237 | ||
234 | give_sigsegv: | 238 | give_sigsegv: |
235 | force_sigsegv(signr, current); | 239 | if (signr == SIGSEGV) |
240 | ka->sa.sa_handler = SIG_DFL; | ||
241 | force_sig(SIGSEGV, current); | ||
236 | return -EFAULT; | 242 | return -EFAULT; |
237 | } | 243 | } |
238 | 244 | ||
239 | static void handle_signal(unsigned long sig, siginfo_t *info, | 245 | static int handle_signal(unsigned long sig, siginfo_t *info, |
240 | struct k_sigaction *ka, struct pt_regs *regs) | 246 | struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) |
241 | { | 247 | { |
248 | int ret; | ||
249 | |||
242 | if (regs->is_syscall) { | 250 | if (regs->is_syscall) { |
243 | switch (regs->regs[4]) { | 251 | switch (regs->regs[4]) { |
244 | case ERESTART_RESTARTBLOCK: | 252 | case ERESTART_RESTARTBLOCK: |
@@ -262,15 +270,22 @@ static void handle_signal(unsigned long sig, siginfo_t *info, | |||
262 | /* | 270 | /* |
263 | * Set up the stack frame | 271 | * Set up the stack frame |
264 | */ | 272 | */ |
265 | if (setup_rt_frame(ka, regs, sig, sigmask_to_save(), info) < 0) | 273 | ret = setup_rt_frame(ka, regs, sig, oldset, info); |
266 | return; | 274 | |
275 | spin_lock_irq(¤t->sighand->siglock); | ||
276 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | ||
277 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
278 | sigaddset(¤t->blocked, sig); | ||
279 | recalc_sigpending(); | ||
280 | spin_unlock_irq(¤t->sighand->siglock); | ||
267 | 281 | ||
268 | signal_delivered(sig, info, ka, regs, 0); | 282 | return ret; |
269 | } | 283 | } |
270 | 284 | ||
271 | static void do_signal(struct pt_regs *regs) | 285 | static void do_signal(struct pt_regs *regs) |
272 | { | 286 | { |
273 | struct k_sigaction ka; | 287 | struct k_sigaction ka; |
288 | sigset_t *oldset; | ||
274 | siginfo_t info; | 289 | siginfo_t info; |
275 | int signr; | 290 | int signr; |
276 | 291 | ||
@@ -282,10 +297,25 @@ static void do_signal(struct pt_regs *regs) | |||
282 | if (!user_mode(regs)) | 297 | if (!user_mode(regs)) |
283 | return; | 298 | return; |
284 | 299 | ||
300 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
301 | oldset = ¤t->saved_sigmask; | ||
302 | else | ||
303 | oldset = ¤t->blocked; | ||
304 | |||
285 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 305 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
286 | if (signr > 0) { | 306 | if (signr > 0) { |
287 | /* Actually deliver the signal. */ | 307 | /* Actually deliver the signal. */ |
288 | handle_signal(signr, &info, &ka, regs); | 308 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { |
309 | /* | ||
310 | * A signal was successfully delivered; the saved | ||
311 | * sigmask will have been stored in the signal frame, | ||
312 | * and will be restored by sigreturn, so we can simply | ||
313 | * clear the TIF_RESTORE_SIGMASK flag. | ||
314 | */ | ||
315 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
316 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
317 | } | ||
318 | |||
289 | return; | 319 | return; |
290 | } | 320 | } |
291 | 321 | ||
@@ -312,7 +342,10 @@ static void do_signal(struct pt_regs *regs) | |||
312 | * If there's no signal to deliver, we just put the saved sigmask | 342 | * If there's no signal to deliver, we just put the saved sigmask |
313 | * back | 343 | * back |
314 | */ | 344 | */ |
315 | restore_saved_sigmask(); | 345 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
346 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
347 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
348 | } | ||
316 | } | 349 | } |
317 | 350 | ||
318 | /* | 351 | /* |
@@ -323,10 +356,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, | |||
323 | __u32 thread_info_flags) | 356 | __u32 thread_info_flags) |
324 | { | 357 | { |
325 | /* deal with pending signal delivery */ | 358 | /* deal with pending signal delivery */ |
326 | if (thread_info_flags & _TIF_SIGPENDING) | 359 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
327 | do_signal(regs); | 360 | do_signal(regs); |
328 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
329 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
330 | tracehook_notify_resume(regs); | ||
331 | } | ||
332 | } | 361 | } |
diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c index 47c20ba4616..e478bf9a7e9 100644 --- a/arch/score/kernel/sys_score.c +++ b/arch/score/kernel/sys_score.c | |||
@@ -48,3 +48,91 @@ sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, | |||
48 | return -EINVAL; | 48 | return -EINVAL; |
49 | return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); | 49 | return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); |
50 | } | 50 | } |
51 | |||
52 | asmlinkage long | ||
53 | score_fork(struct pt_regs *regs) | ||
54 | { | ||
55 | return do_fork(SIGCHLD, regs->regs[0], regs, 0, NULL, NULL); | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * Clone a task - this clones the calling program thread. | ||
60 | * This is called indirectly via a small wrapper | ||
61 | */ | ||
62 | asmlinkage long | ||
63 | score_clone(struct pt_regs *regs) | ||
64 | { | ||
65 | unsigned long clone_flags; | ||
66 | unsigned long newsp; | ||
67 | int __user *parent_tidptr, *child_tidptr; | ||
68 | |||
69 | clone_flags = regs->regs[4]; | ||
70 | newsp = regs->regs[5]; | ||
71 | if (!newsp) | ||
72 | newsp = regs->regs[0]; | ||
73 | parent_tidptr = (int __user *)regs->regs[6]; | ||
74 | child_tidptr = (int __user *)regs->regs[8]; | ||
75 | |||
76 | return do_fork(clone_flags, newsp, regs, 0, | ||
77 | parent_tidptr, child_tidptr); | ||
78 | } | ||
79 | |||
80 | asmlinkage long | ||
81 | score_vfork(struct pt_regs *regs) | ||
82 | { | ||
83 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, | ||
84 | regs->regs[0], regs, 0, NULL, NULL); | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * sys_execve() executes a new program. | ||
89 | * This is called indirectly via a small wrapper | ||
90 | */ | ||
91 | asmlinkage long | ||
92 | score_execve(struct pt_regs *regs) | ||
93 | { | ||
94 | int error; | ||
95 | char *filename; | ||
96 | |||
97 | filename = getname((char __user*)regs->regs[4]); | ||
98 | error = PTR_ERR(filename); | ||
99 | if (IS_ERR(filename)) | ||
100 | return error; | ||
101 | |||
102 | error = do_execve(filename, | ||
103 | (const char __user *const __user *)regs->regs[5], | ||
104 | (const char __user *const __user *)regs->regs[6], | ||
105 | regs); | ||
106 | |||
107 | putname(filename); | ||
108 | return error; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Do a system call from kernel instead of calling sys_execve so we | ||
113 | * end up with proper pt_regs. | ||
114 | */ | ||
115 | int kernel_execve(const char *filename, | ||
116 | const char *const argv[], | ||
117 | const char *const envp[]) | ||
118 | { | ||
119 | register unsigned long __r4 asm("r4") = (unsigned long) filename; | ||
120 | register unsigned long __r5 asm("r5") = (unsigned long) argv; | ||
121 | register unsigned long __r6 asm("r6") = (unsigned long) envp; | ||
122 | register unsigned long __r7 asm("r7"); | ||
123 | |||
124 | __asm__ __volatile__ (" \n" | ||
125 | "ldi r27, %5 \n" | ||
126 | "syscall \n" | ||
127 | "mv %0, r4 \n" | ||
128 | "mv %1, r7 \n" | ||
129 | : "=&r" (__r4), "=r" (__r7) | ||
130 | : "r" (__r4), "r" (__r5), "r" (__r6), "i" (__NR_execve) | ||
131 | : "r8", "r9", "r10", "r11", "r22", "r23", "r24", "r25", | ||
132 | "r26", "r27", "memory"); | ||
133 | |||
134 | if (__r7 == 0) | ||
135 | return __r4; | ||
136 | |||
137 | return -__r4; | ||
138 | } | ||