aboutsummaryrefslogtreecommitdiffstats
path: root/arch/score/kernel
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /arch/score/kernel
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'arch/score/kernel')
-rw-r--r--arch/score/kernel/Makefile2
-rw-r--r--arch/score/kernel/entry.S32
-rw-r--r--arch/score/kernel/module.c10
-rw-r--r--arch/score/kernel/process.c65
-rw-r--r--arch/score/kernel/setup.c4
-rw-r--r--arch/score/kernel/signal.c71
-rw-r--r--arch/score/kernel/sys_score.c88
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
5extra-y := head.o vmlinux.lds 5extra-y := head.o vmlinux.lds
6 6
7obj-y += entry.o irq.o process.o ptrace.o \ 7obj-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
281ENTRY(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
288ENTRY(ret_from_fork) 281ENTRY(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
483ENTRY(sys_execve)
484 mv r4, r0
485 la r8, score_execve
486 br r8
487
488ENTRY(sys_clone)
489 mv r4, r0
490 la r8, score_clone
491 br r8
492
490ENTRY(sys_rt_sigreturn) 493ENTRY(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
504ENTRY(sys_fork)
505 mv r4, r0
506 la r8, score_fork
507 br r8
508
509ENTRY(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
128int 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. */
129const struct exception_table_entry *search_module_dbetables(unsigned long addr) 139const 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
32void (*pm_power_off)(void); 31void (*pm_power_off)(void);
33EXPORT_SYMBOL(pm_power_off); 32EXPORT_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
62void ret_from_fork(void); 62void ret_from_fork(void);
63void ret_from_kernel_thread(void);
64 63
65void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) 64void 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 */
89int copy_thread(unsigned long clone_flags, unsigned long usp, 88int 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
123static void __noreturn
124kernel_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 */
133long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
134{
135 struct pt_regs regs;
136
137 memset(&regs, 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, &regs, 0, NULL, NULL);
147}
148
122unsigned long thread_saved_pc(struct task_struct *tsk) 149unsigned 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
37struct rt_sigframe { 38struct 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(&current->sighand->siglock);
163 current->blocked = set;
164 recalc_sigpending();
165 spin_unlock_irq(&current->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
234give_sigsegv: 238give_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
239static void handle_signal(unsigned long sig, siginfo_t *info, 245static 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(&current->sighand->siglock);
276 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
277 if (!(ka->sa.sa_flags & SA_NODEFER))
278 sigaddset(&current->blocked, sig);
279 recalc_sigpending();
280 spin_unlock_irq(&current->sighand->siglock);
267 281
268 signal_delivered(sig, info, ka, regs, 0); 282 return ret;
269} 283}
270 284
271static void do_signal(struct pt_regs *regs) 285static 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 = &current->saved_sigmask;
302 else
303 oldset = &current->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, &current->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
52asmlinkage long
53score_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 */
62asmlinkage long
63score_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
80asmlinkage long
81score_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 */
91asmlinkage long
92score_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 */
115int 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}