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/avr32/kernel | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'arch/avr32/kernel')
-rw-r--r-- | arch/avr32/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/avr32/kernel/cpu.c | 74 | ||||
-rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 18 | ||||
-rw-r--r-- | arch/avr32/kernel/irq.c | 2 | ||||
-rw-r--r-- | arch/avr32/kernel/process.c | 125 | ||||
-rw-r--r-- | arch/avr32/kernel/signal.c | 60 | ||||
-rw-r--r-- | arch/avr32/kernel/syscall-stubs.S | 24 | ||||
-rw-r--r-- | arch/avr32/kernel/syscall_table.S | 8 | ||||
-rw-r--r-- | arch/avr32/kernel/traps.c | 2 |
9 files changed, 219 insertions, 98 deletions
diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index 119a2e41def..18229d0d186 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile | |||
@@ -7,8 +7,8 @@ extra-y := head.o vmlinux.lds | |||
7 | obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o | 7 | obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o |
8 | obj-y += syscall_table.o syscall-stubs.o irq.o | 8 | obj-y += syscall_table.o syscall-stubs.o irq.o |
9 | obj-y += setup.o traps.o ocd.o ptrace.o | 9 | obj-y += setup.o traps.o ocd.o ptrace.o |
10 | obj-y += signal.o process.o time.o | 10 | obj-y += signal.o sys_avr32.o process.o time.o |
11 | obj-y += switch_to.o cpu.o | 11 | obj-y += init_task.o switch_to.o cpu.o |
12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o | 12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o |
13 | obj-$(CONFIG_KPROBES) += kprobes.o | 13 | obj-$(CONFIG_KPROBES) += kprobes.o |
14 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 14 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c index 2233be71e2e..e84faffbbec 100644 --- a/arch/avr32/kernel/cpu.c +++ b/arch/avr32/kernel/cpu.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/device.h> | 9 | #include <linux/sysdev.h> |
10 | #include <linux/seq_file.h> | 10 | #include <linux/seq_file.h> |
11 | #include <linux/cpu.h> | 11 | #include <linux/cpu.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
@@ -26,16 +26,16 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); | |||
26 | * XXX: If/when a SMP-capable implementation of AVR32 will ever be | 26 | * XXX: If/when a SMP-capable implementation of AVR32 will ever be |
27 | * made, we must make sure that the code executes on the correct CPU. | 27 | * made, we must make sure that the code executes on the correct CPU. |
28 | */ | 28 | */ |
29 | static ssize_t show_pc0event(struct device *dev, | 29 | static ssize_t show_pc0event(struct sys_device *dev, |
30 | struct device_attribute *attr, char *buf) | 30 | struct sysdev_attribute *attr, char *buf) |
31 | { | 31 | { |
32 | unsigned long pccr; | 32 | unsigned long pccr; |
33 | 33 | ||
34 | pccr = sysreg_read(PCCR); | 34 | pccr = sysreg_read(PCCR); |
35 | return sprintf(buf, "0x%lx\n", (pccr >> 12) & 0x3f); | 35 | return sprintf(buf, "0x%lx\n", (pccr >> 12) & 0x3f); |
36 | } | 36 | } |
37 | static ssize_t store_pc0event(struct device *dev, | 37 | static ssize_t store_pc0event(struct sys_device *dev, |
38 | struct device_attribute *attr, const char *buf, | 38 | struct sysdev_attribute *attr, const char *buf, |
39 | size_t count) | 39 | size_t count) |
40 | { | 40 | { |
41 | unsigned long val; | 41 | unsigned long val; |
@@ -48,16 +48,16 @@ static ssize_t store_pc0event(struct device *dev, | |||
48 | sysreg_write(PCCR, val); | 48 | sysreg_write(PCCR, val); |
49 | return count; | 49 | return count; |
50 | } | 50 | } |
51 | static ssize_t show_pc0count(struct device *dev, | 51 | static ssize_t show_pc0count(struct sys_device *dev, |
52 | struct device_attribute *attr, char *buf) | 52 | struct sysdev_attribute *attr, char *buf) |
53 | { | 53 | { |
54 | unsigned long pcnt0; | 54 | unsigned long pcnt0; |
55 | 55 | ||
56 | pcnt0 = sysreg_read(PCNT0); | 56 | pcnt0 = sysreg_read(PCNT0); |
57 | return sprintf(buf, "%lu\n", pcnt0); | 57 | return sprintf(buf, "%lu\n", pcnt0); |
58 | } | 58 | } |
59 | static ssize_t store_pc0count(struct device *dev, | 59 | static ssize_t store_pc0count(struct sys_device *dev, |
60 | struct device_attribute *attr, | 60 | struct sysdev_attribute *attr, |
61 | const char *buf, size_t count) | 61 | const char *buf, size_t count) |
62 | { | 62 | { |
63 | unsigned long val; | 63 | unsigned long val; |
@@ -71,16 +71,16 @@ static ssize_t store_pc0count(struct device *dev, | |||
71 | return count; | 71 | return count; |
72 | } | 72 | } |
73 | 73 | ||
74 | static ssize_t show_pc1event(struct device *dev, | 74 | static ssize_t show_pc1event(struct sys_device *dev, |
75 | struct device_attribute *attr, char *buf) | 75 | struct sysdev_attribute *attr, char *buf) |
76 | { | 76 | { |
77 | unsigned long pccr; | 77 | unsigned long pccr; |
78 | 78 | ||
79 | pccr = sysreg_read(PCCR); | 79 | pccr = sysreg_read(PCCR); |
80 | return sprintf(buf, "0x%lx\n", (pccr >> 18) & 0x3f); | 80 | return sprintf(buf, "0x%lx\n", (pccr >> 18) & 0x3f); |
81 | } | 81 | } |
82 | static ssize_t store_pc1event(struct device *dev, | 82 | static ssize_t store_pc1event(struct sys_device *dev, |
83 | struct device_attribute *attr, const char *buf, | 83 | struct sysdev_attribute *attr, const char *buf, |
84 | size_t count) | 84 | size_t count) |
85 | { | 85 | { |
86 | unsigned long val; | 86 | unsigned long val; |
@@ -93,16 +93,16 @@ static ssize_t store_pc1event(struct device *dev, | |||
93 | sysreg_write(PCCR, val); | 93 | sysreg_write(PCCR, val); |
94 | return count; | 94 | return count; |
95 | } | 95 | } |
96 | static ssize_t show_pc1count(struct device *dev, | 96 | static ssize_t show_pc1count(struct sys_device *dev, |
97 | struct device_attribute *attr, char *buf) | 97 | struct sysdev_attribute *attr, char *buf) |
98 | { | 98 | { |
99 | unsigned long pcnt1; | 99 | unsigned long pcnt1; |
100 | 100 | ||
101 | pcnt1 = sysreg_read(PCNT1); | 101 | pcnt1 = sysreg_read(PCNT1); |
102 | return sprintf(buf, "%lu\n", pcnt1); | 102 | return sprintf(buf, "%lu\n", pcnt1); |
103 | } | 103 | } |
104 | static ssize_t store_pc1count(struct device *dev, | 104 | static ssize_t store_pc1count(struct sys_device *dev, |
105 | struct device_attribute *attr, const char *buf, | 105 | struct sysdev_attribute *attr, const char *buf, |
106 | size_t count) | 106 | size_t count) |
107 | { | 107 | { |
108 | unsigned long val; | 108 | unsigned long val; |
@@ -116,16 +116,16 @@ static ssize_t store_pc1count(struct device *dev, | |||
116 | return count; | 116 | return count; |
117 | } | 117 | } |
118 | 118 | ||
119 | static ssize_t show_pccycles(struct device *dev, | 119 | static ssize_t show_pccycles(struct sys_device *dev, |
120 | struct device_attribute *attr, char *buf) | 120 | struct sysdev_attribute *attr, char *buf) |
121 | { | 121 | { |
122 | unsigned long pccnt; | 122 | unsigned long pccnt; |
123 | 123 | ||
124 | pccnt = sysreg_read(PCCNT); | 124 | pccnt = sysreg_read(PCCNT); |
125 | return sprintf(buf, "%lu\n", pccnt); | 125 | return sprintf(buf, "%lu\n", pccnt); |
126 | } | 126 | } |
127 | static ssize_t store_pccycles(struct device *dev, | 127 | static ssize_t store_pccycles(struct sys_device *dev, |
128 | struct device_attribute *attr, const char *buf, | 128 | struct sysdev_attribute *attr, const char *buf, |
129 | size_t count) | 129 | size_t count) |
130 | { | 130 | { |
131 | unsigned long val; | 131 | unsigned long val; |
@@ -139,16 +139,16 @@ static ssize_t store_pccycles(struct device *dev, | |||
139 | return count; | 139 | return count; |
140 | } | 140 | } |
141 | 141 | ||
142 | static ssize_t show_pcenable(struct device *dev, | 142 | static ssize_t show_pcenable(struct sys_device *dev, |
143 | struct device_attribute *attr, char *buf) | 143 | struct sysdev_attribute *attr, char *buf) |
144 | { | 144 | { |
145 | unsigned long pccr; | 145 | unsigned long pccr; |
146 | 146 | ||
147 | pccr = sysreg_read(PCCR); | 147 | pccr = sysreg_read(PCCR); |
148 | return sprintf(buf, "%c\n", (pccr & 1)?'1':'0'); | 148 | return sprintf(buf, "%c\n", (pccr & 1)?'1':'0'); |
149 | } | 149 | } |
150 | static ssize_t store_pcenable(struct device *dev, | 150 | static ssize_t store_pcenable(struct sys_device *dev, |
151 | struct device_attribute *attr, const char *buf, | 151 | struct sysdev_attribute *attr, const char *buf, |
152 | size_t count) | 152 | size_t count) |
153 | { | 153 | { |
154 | unsigned long pccr, val; | 154 | unsigned long pccr, val; |
@@ -167,12 +167,12 @@ static ssize_t store_pcenable(struct device *dev, | |||
167 | return count; | 167 | return count; |
168 | } | 168 | } |
169 | 169 | ||
170 | static DEVICE_ATTR(pc0event, 0600, show_pc0event, store_pc0event); | 170 | static SYSDEV_ATTR(pc0event, 0600, show_pc0event, store_pc0event); |
171 | static DEVICE_ATTR(pc0count, 0600, show_pc0count, store_pc0count); | 171 | static SYSDEV_ATTR(pc0count, 0600, show_pc0count, store_pc0count); |
172 | static DEVICE_ATTR(pc1event, 0600, show_pc1event, store_pc1event); | 172 | static SYSDEV_ATTR(pc1event, 0600, show_pc1event, store_pc1event); |
173 | static DEVICE_ATTR(pc1count, 0600, show_pc1count, store_pc1count); | 173 | static SYSDEV_ATTR(pc1count, 0600, show_pc1count, store_pc1count); |
174 | static DEVICE_ATTR(pccycles, 0600, show_pccycles, store_pccycles); | 174 | static SYSDEV_ATTR(pccycles, 0600, show_pccycles, store_pccycles); |
175 | static DEVICE_ATTR(pcenable, 0600, show_pcenable, store_pcenable); | 175 | static SYSDEV_ATTR(pcenable, 0600, show_pcenable, store_pcenable); |
176 | 176 | ||
177 | #endif /* CONFIG_PERFORMANCE_COUNTERS */ | 177 | #endif /* CONFIG_PERFORMANCE_COUNTERS */ |
178 | 178 | ||
@@ -186,12 +186,12 @@ static int __init topology_init(void) | |||
186 | register_cpu(c, cpu); | 186 | register_cpu(c, cpu); |
187 | 187 | ||
188 | #ifdef CONFIG_PERFORMANCE_COUNTERS | 188 | #ifdef CONFIG_PERFORMANCE_COUNTERS |
189 | device_create_file(&c->dev, &dev_attr_pc0event); | 189 | sysdev_create_file(&c->sysdev, &attr_pc0event); |
190 | device_create_file(&c->dev, &dev_attr_pc0count); | 190 | sysdev_create_file(&c->sysdev, &attr_pc0count); |
191 | device_create_file(&c->dev, &dev_attr_pc1event); | 191 | sysdev_create_file(&c->sysdev, &attr_pc1event); |
192 | device_create_file(&c->dev, &dev_attr_pc1count); | 192 | sysdev_create_file(&c->sysdev, &attr_pc1count); |
193 | device_create_file(&c->dev, &dev_attr_pccycles); | 193 | sysdev_create_file(&c->sysdev, &attr_pccycles); |
194 | device_create_file(&c->dev, &dev_attr_pcenable); | 194 | sysdev_create_file(&c->sysdev, &attr_pcenable); |
195 | #endif | 195 | #endif |
196 | } | 196 | } |
197 | 197 | ||
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 9899d3cc6f0..169268c40ae 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S | |||
@@ -251,15 +251,13 @@ syscall_badsys: | |||
251 | .global ret_from_fork | 251 | .global ret_from_fork |
252 | ret_from_fork: | 252 | ret_from_fork: |
253 | call schedule_tail | 253 | call schedule_tail |
254 | mov r12, 0 | ||
255 | rjmp syscall_return | ||
256 | 254 | ||
257 | .global ret_from_kernel_thread | 255 | /* check for syscall tracing */ |
258 | ret_from_kernel_thread: | 256 | get_thread_info r0 |
259 | call schedule_tail | 257 | ld.w r1, r0[TI_flags] |
260 | mov r12, r0 | 258 | andl r1, _TIF_ALLWORK_MASK, COH |
261 | mov lr, r2 /* syscall_return */ | 259 | brne syscall_exit_work |
262 | mov pc, r1 | 260 | rjmp syscall_exit_cont |
263 | 261 | ||
264 | syscall_trace_enter: | 262 | syscall_trace_enter: |
265 | pushm r8-r12 | 263 | pushm r8-r12 |
@@ -283,7 +281,7 @@ syscall_exit_work: | |||
283 | ld.w r1, r0[TI_flags] | 281 | ld.w r1, r0[TI_flags] |
284 | rjmp 1b | 282 | rjmp 1b |
285 | 283 | ||
286 | 2: mov r2, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME | 284 | 2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME |
287 | tst r1, r2 | 285 | tst r1, r2 |
288 | breq 3f | 286 | breq 3f |
289 | unmask_interrupts | 287 | unmask_interrupts |
@@ -589,7 +587,7 @@ fault_exit_work: | |||
589 | ld.w r1, r0[TI_flags] | 587 | ld.w r1, r0[TI_flags] |
590 | rjmp fault_exit_work | 588 | rjmp fault_exit_work |
591 | 589 | ||
592 | 1: mov r2, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME | 590 | 1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK |
593 | tst r1, r2 | 591 | tst r1, r2 |
594 | breq 2f | 592 | breq 2f |
595 | unmask_interrupts | 593 | unmask_interrupts |
diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c index 900e49b2258..bc3aa18293d 100644 --- a/arch/avr32/kernel/irq.c +++ b/arch/avr32/kernel/irq.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/kernel_stat.h> | 14 | #include <linux/kernel_stat.h> |
15 | #include <linux/proc_fs.h> | 15 | #include <linux/proc_fs.h> |
16 | #include <linux/seq_file.h> | 16 | #include <linux/seq_file.h> |
17 | #include <linux/device.h> | 17 | #include <linux/sysdev.h> |
18 | 18 | ||
19 | /* May be overridden by platform code */ | 19 | /* May be overridden by platform code */ |
20 | int __weak nmi_enable(void) | 20 | int __weak nmi_enable(void) |
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index fd78f58ea79..ef5a2a08fcc 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c | |||
@@ -34,13 +34,13 @@ void cpu_idle(void) | |||
34 | { | 34 | { |
35 | /* endless idle loop with no priority at all */ | 35 | /* endless idle loop with no priority at all */ |
36 | while (1) { | 36 | while (1) { |
37 | tick_nohz_idle_enter(); | 37 | tick_nohz_stop_sched_tick(1); |
38 | rcu_idle_enter(); | ||
39 | while (!need_resched()) | 38 | while (!need_resched()) |
40 | cpu_idle_sleep(); | 39 | cpu_idle_sleep(); |
41 | rcu_idle_exit(); | 40 | tick_nohz_restart_sched_tick(); |
42 | tick_nohz_idle_exit(); | 41 | preempt_enable_no_resched(); |
43 | schedule_preempt_disabled(); | 42 | schedule(); |
43 | preempt_disable(); | ||
44 | } | 44 | } |
45 | } | 45 | } |
46 | 46 | ||
@@ -69,6 +69,44 @@ void machine_restart(char *cmd) | |||
69 | } | 69 | } |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * PC is actually discarded when returning from a system call -- the | ||
73 | * return address must be stored in LR. This function will make sure | ||
74 | * LR points to do_exit before starting the thread. | ||
75 | * | ||
76 | * Also, when returning from fork(), r12 is 0, so we must copy the | ||
77 | * argument as well. | ||
78 | * | ||
79 | * r0 : The argument to the main thread function | ||
80 | * r1 : The address of do_exit | ||
81 | * r2 : The address of the main thread function | ||
82 | */ | ||
83 | asmlinkage extern void kernel_thread_helper(void); | ||
84 | __asm__(" .type kernel_thread_helper, @function\n" | ||
85 | "kernel_thread_helper:\n" | ||
86 | " mov r12, r0\n" | ||
87 | " mov lr, r2\n" | ||
88 | " mov pc, r1\n" | ||
89 | " .size kernel_thread_helper, . - kernel_thread_helper"); | ||
90 | |||
91 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
92 | { | ||
93 | struct pt_regs regs; | ||
94 | |||
95 | memset(®s, 0, sizeof(regs)); | ||
96 | |||
97 | regs.r0 = (unsigned long)arg; | ||
98 | regs.r1 = (unsigned long)fn; | ||
99 | regs.r2 = (unsigned long)do_exit; | ||
100 | regs.lr = (unsigned long)kernel_thread_helper; | ||
101 | regs.pc = (unsigned long)kernel_thread_helper; | ||
102 | regs.sr = MODE_SUPERVISOR; | ||
103 | |||
104 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, | ||
105 | 0, ®s, 0, NULL, NULL); | ||
106 | } | ||
107 | EXPORT_SYMBOL(kernel_thread); | ||
108 | |||
109 | /* | ||
72 | * Free current thread data structures etc | 110 | * Free current thread data structures etc |
73 | */ | 111 | */ |
74 | void exit_thread(void) | 112 | void exit_thread(void) |
@@ -294,32 +332,26 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
294 | } | 332 | } |
295 | 333 | ||
296 | asmlinkage void ret_from_fork(void); | 334 | asmlinkage void ret_from_fork(void); |
297 | asmlinkage void ret_from_kernel_thread(void); | ||
298 | asmlinkage void syscall_return(void); | ||
299 | 335 | ||
300 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 336 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
301 | unsigned long arg, | 337 | unsigned long unused, |
302 | struct task_struct *p) | 338 | struct task_struct *p, struct pt_regs *regs) |
303 | { | 339 | { |
304 | struct pt_regs *childregs = task_pt_regs(p); | 340 | struct pt_regs *childregs; |
305 | 341 | ||
306 | if (unlikely(p->flags & PF_KTHREAD)) { | 342 | childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1; |
307 | memset(childregs, 0, sizeof(struct pt_regs)); | 343 | *childregs = *regs; |
308 | p->thread.cpu_context.r0 = arg; | 344 | |
309 | p->thread.cpu_context.r1 = usp; /* fn */ | 345 | if (user_mode(regs)) |
310 | p->thread.cpu_context.r2 = syscall_return; | 346 | childregs->sp = usp; |
311 | p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread; | 347 | else |
312 | childregs->sr = MODE_SUPERVISOR; | 348 | childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; |
313 | } else { | 349 | |
314 | *childregs = *current_pt_regs(); | 350 | childregs->r12 = 0; /* Set return value for child */ |
315 | if (usp) | ||
316 | childregs->sp = usp; | ||
317 | childregs->r12 = 0; /* Set return value for child */ | ||
318 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; | ||
319 | } | ||
320 | 351 | ||
321 | p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; | 352 | p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; |
322 | p->thread.cpu_context.ksp = (unsigned long)childregs; | 353 | p->thread.cpu_context.ksp = (unsigned long)childregs; |
354 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; | ||
323 | 355 | ||
324 | clear_tsk_thread_flag(p, TIF_DEBUG); | 356 | clear_tsk_thread_flag(p, TIF_DEBUG); |
325 | if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) | 357 | if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) |
@@ -328,6 +360,49 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
328 | return 0; | 360 | return 0; |
329 | } | 361 | } |
330 | 362 | ||
363 | /* r12-r8 are dummy parameters to force the compiler to use the stack */ | ||
364 | asmlinkage int sys_fork(struct pt_regs *regs) | ||
365 | { | ||
366 | return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); | ||
367 | } | ||
368 | |||
369 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
370 | void __user *parent_tidptr, void __user *child_tidptr, | ||
371 | struct pt_regs *regs) | ||
372 | { | ||
373 | if (!newsp) | ||
374 | newsp = regs->sp; | ||
375 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, | ||
376 | child_tidptr); | ||
377 | } | ||
378 | |||
379 | asmlinkage int sys_vfork(struct pt_regs *regs) | ||
380 | { | ||
381 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, | ||
382 | 0, NULL, NULL); | ||
383 | } | ||
384 | |||
385 | asmlinkage int sys_execve(const char __user *ufilename, | ||
386 | const char __user *const __user *uargv, | ||
387 | const char __user *const __user *uenvp, | ||
388 | struct pt_regs *regs) | ||
389 | { | ||
390 | int error; | ||
391 | char *filename; | ||
392 | |||
393 | filename = getname(ufilename); | ||
394 | error = PTR_ERR(filename); | ||
395 | if (IS_ERR(filename)) | ||
396 | goto out; | ||
397 | |||
398 | error = do_execve(filename, uargv, uenvp, regs); | ||
399 | putname(filename); | ||
400 | |||
401 | out: | ||
402 | return error; | ||
403 | } | ||
404 | |||
405 | |||
331 | /* | 406 | /* |
332 | * This function is supposed to answer the question "who called | 407 | * This function is supposed to answer the question "who called |
333 | * schedule()?" | 408 | * schedule()?" |
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 5e01c3a40ce..64f886fac2e 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c | |||
@@ -15,12 +15,15 @@ | |||
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/ptrace.h> | 16 | #include <linux/ptrace.h> |
17 | #include <linux/unistd.h> | 17 | #include <linux/unistd.h> |
18 | #include <linux/freezer.h> | ||
18 | #include <linux/tracehook.h> | 19 | #include <linux/tracehook.h> |
19 | 20 | ||
20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
21 | #include <asm/ucontext.h> | 22 | #include <asm/ucontext.h> |
22 | #include <asm/syscalls.h> | 23 | #include <asm/syscalls.h> |
23 | 24 | ||
25 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
26 | |||
24 | asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 27 | asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
25 | struct pt_regs *regs) | 28 | struct pt_regs *regs) |
26 | { | 29 | { |
@@ -74,9 +77,6 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | |||
74 | struct rt_sigframe __user *frame; | 77 | struct rt_sigframe __user *frame; |
75 | sigset_t set; | 78 | sigset_t set; |
76 | 79 | ||
77 | /* Always make any pending restarted system calls return -EINTR */ | ||
78 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
79 | |||
80 | frame = (struct rt_sigframe __user *)regs->sp; | 80 | frame = (struct rt_sigframe __user *)regs->sp; |
81 | pr_debug("SIG return: frame = %p\n", frame); | 81 | pr_debug("SIG return: frame = %p\n", frame); |
82 | 82 | ||
@@ -86,7 +86,11 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | |||
86 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 86 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
87 | goto badframe; | 87 | goto badframe; |
88 | 88 | ||
89 | set_current_blocked(&set); | 89 | sigdelsetmask(&set, ~_BLOCKABLE); |
90 | spin_lock_irq(¤t->sighand->siglock); | ||
91 | current->blocked = set; | ||
92 | recalc_sigpending(); | ||
93 | spin_unlock_irq(¤t->sighand->siglock); | ||
90 | 94 | ||
91 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | 95 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
92 | goto badframe; | 96 | goto badframe; |
@@ -220,14 +224,14 @@ static inline void setup_syscall_restart(struct pt_regs *regs) | |||
220 | 224 | ||
221 | static inline void | 225 | static inline void |
222 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 226 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, |
223 | struct pt_regs *regs, int syscall) | 227 | sigset_t *oldset, struct pt_regs *regs, int syscall) |
224 | { | 228 | { |
225 | int ret; | 229 | int ret; |
226 | 230 | ||
227 | /* | 231 | /* |
228 | * Set up the stack frame | 232 | * Set up the stack frame |
229 | */ | 233 | */ |
230 | ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs); | 234 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
231 | 235 | ||
232 | /* | 236 | /* |
233 | * Check that the resulting registers are sane | 237 | * Check that the resulting registers are sane |
@@ -235,12 +239,21 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
235 | ret |= !valid_user_regs(regs); | 239 | ret |= !valid_user_regs(regs); |
236 | 240 | ||
237 | /* | 241 | /* |
238 | * Block the signal if we were successful. | 242 | * Block the signal if we were unsuccessful. |
239 | */ | 243 | */ |
240 | if (ret != 0) | 244 | if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) { |
241 | force_sigsegv(sig, current); | 245 | spin_lock_irq(¤t->sighand->siglock); |
242 | else | 246 | sigorsets(¤t->blocked, ¤t->blocked, |
243 | signal_delivered(sig, info, ka, regs, 0); | 247 | &ka->sa.sa_mask); |
248 | sigaddset(¤t->blocked, sig); | ||
249 | recalc_sigpending(); | ||
250 | spin_unlock_irq(¤t->sighand->siglock); | ||
251 | } | ||
252 | |||
253 | if (ret == 0) | ||
254 | return; | ||
255 | |||
256 | force_sigsegv(sig, current); | ||
244 | } | 257 | } |
245 | 258 | ||
246 | /* | 259 | /* |
@@ -248,7 +261,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
248 | * doesn't want to handle. Thus you cannot kill init even with a | 261 | * doesn't want to handle. Thus you cannot kill init even with a |
249 | * SIGKILL even by mistake. | 262 | * SIGKILL even by mistake. |
250 | */ | 263 | */ |
251 | static void do_signal(struct pt_regs *regs, int syscall) | 264 | int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall) |
252 | { | 265 | { |
253 | siginfo_t info; | 266 | siginfo_t info; |
254 | int signr; | 267 | int signr; |
@@ -260,7 +273,12 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
260 | * without doing anything if so. | 273 | * without doing anything if so. |
261 | */ | 274 | */ |
262 | if (!user_mode(regs)) | 275 | if (!user_mode(regs)) |
263 | return; | 276 | return 0; |
277 | |||
278 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
279 | oldset = ¤t->saved_sigmask; | ||
280 | else if (!oldset) | ||
281 | oldset = ¤t->blocked; | ||
264 | 282 | ||
265 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 283 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
266 | if (syscall) { | 284 | if (syscall) { |
@@ -285,11 +303,15 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
285 | 303 | ||
286 | if (signr == 0) { | 304 | if (signr == 0) { |
287 | /* No signal to deliver -- put the saved sigmask back */ | 305 | /* No signal to deliver -- put the saved sigmask back */ |
288 | restore_saved_sigmask(); | 306 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
289 | return; | 307 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
308 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
309 | } | ||
310 | return 0; | ||
290 | } | 311 | } |
291 | 312 | ||
292 | handle_signal(signr, &ka, &info, regs, syscall); | 313 | handle_signal(signr, &ka, &info, oldset, regs, syscall); |
314 | return 1; | ||
293 | } | 315 | } |
294 | 316 | ||
295 | asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) | 317 | asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) |
@@ -299,11 +321,13 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) | |||
299 | if ((sysreg_read(SR) & MODE_MASK) == MODE_SUPERVISOR) | 321 | if ((sysreg_read(SR) & MODE_MASK) == MODE_SUPERVISOR) |
300 | syscall = 1; | 322 | syscall = 1; |
301 | 323 | ||
302 | if (ti->flags & _TIF_SIGPENDING) | 324 | if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
303 | do_signal(regs, syscall); | 325 | do_signal(regs, ¤t->blocked, syscall); |
304 | 326 | ||
305 | if (ti->flags & _TIF_NOTIFY_RESUME) { | 327 | if (ti->flags & _TIF_NOTIFY_RESUME) { |
306 | clear_thread_flag(TIF_NOTIFY_RESUME); | 328 | clear_thread_flag(TIF_NOTIFY_RESUME); |
307 | tracehook_notify_resume(regs); | 329 | tracehook_notify_resume(regs); |
330 | if (current->replacement_session_keyring) | ||
331 | key_replace_session_keyring(); | ||
308 | } | 332 | } |
309 | } | 333 | } |
diff --git a/arch/avr32/kernel/syscall-stubs.S b/arch/avr32/kernel/syscall-stubs.S index 275aab9731f..0447a3e2ba6 100644 --- a/arch/avr32/kernel/syscall-stubs.S +++ b/arch/avr32/kernel/syscall-stubs.S | |||
@@ -32,6 +32,30 @@ __sys_rt_sigreturn: | |||
32 | mov r12, sp | 32 | mov r12, sp |
33 | rjmp sys_rt_sigreturn | 33 | rjmp sys_rt_sigreturn |
34 | 34 | ||
35 | .global __sys_fork | ||
36 | .type __sys_fork,@function | ||
37 | __sys_fork: | ||
38 | mov r12, sp | ||
39 | rjmp sys_fork | ||
40 | |||
41 | .global __sys_clone | ||
42 | .type __sys_clone,@function | ||
43 | __sys_clone: | ||
44 | mov r8, sp | ||
45 | rjmp sys_clone | ||
46 | |||
47 | .global __sys_vfork | ||
48 | .type __sys_vfork,@function | ||
49 | __sys_vfork: | ||
50 | mov r12, sp | ||
51 | rjmp sys_vfork | ||
52 | |||
53 | .global __sys_execve | ||
54 | .type __sys_execve,@function | ||
55 | __sys_execve: | ||
56 | mov r9, sp | ||
57 | rjmp sys_execve | ||
58 | |||
35 | .global __sys_mmap2 | 59 | .global __sys_mmap2 |
36 | .type __sys_mmap2,@function | 60 | .type __sys_mmap2,@function |
37 | __sys_mmap2: | 61 | __sys_mmap2: |
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S index f27bb878da6..6eba53530d1 100644 --- a/arch/avr32/kernel/syscall_table.S +++ b/arch/avr32/kernel/syscall_table.S | |||
@@ -15,7 +15,7 @@ | |||
15 | sys_call_table: | 15 | sys_call_table: |
16 | .long sys_restart_syscall | 16 | .long sys_restart_syscall |
17 | .long sys_exit | 17 | .long sys_exit |
18 | .long sys_fork | 18 | .long __sys_fork |
19 | .long sys_read | 19 | .long sys_read |
20 | .long sys_write | 20 | .long sys_write |
21 | .long sys_open /* 5 */ | 21 | .long sys_open /* 5 */ |
@@ -24,7 +24,7 @@ sys_call_table: | |||
24 | .long sys_creat | 24 | .long sys_creat |
25 | .long sys_link | 25 | .long sys_link |
26 | .long sys_unlink /* 10 */ | 26 | .long sys_unlink /* 10 */ |
27 | .long sys_execve | 27 | .long __sys_execve |
28 | .long sys_chdir | 28 | .long sys_chdir |
29 | .long sys_time | 29 | .long sys_time |
30 | .long sys_mknod | 30 | .long sys_mknod |
@@ -57,7 +57,7 @@ sys_call_table: | |||
57 | .long sys_dup | 57 | .long sys_dup |
58 | .long sys_pipe | 58 | .long sys_pipe |
59 | .long sys_times | 59 | .long sys_times |
60 | .long sys_clone | 60 | .long __sys_clone |
61 | .long sys_brk /* 45 */ | 61 | .long sys_brk /* 45 */ |
62 | .long sys_setgid | 62 | .long sys_setgid |
63 | .long sys_getgid | 63 | .long sys_getgid |
@@ -127,7 +127,7 @@ sys_call_table: | |||
127 | .long sys_newuname | 127 | .long sys_newuname |
128 | .long sys_adjtimex | 128 | .long sys_adjtimex |
129 | .long sys_mprotect | 129 | .long sys_mprotect |
130 | .long sys_vfork | 130 | .long __sys_vfork |
131 | .long sys_init_module /* 115 */ | 131 | .long sys_init_module /* 115 */ |
132 | .long sys_delete_module | 132 | .long sys_delete_module |
133 | .long sys_quotactl | 133 | .long sys_quotactl |
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c index 3d760c06f02..7aa25756412 100644 --- a/arch/avr32/kernel/traps.c +++ b/arch/avr32/kernel/traps.c | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | static DEFINE_SPINLOCK(die_lock); | 25 | static DEFINE_SPINLOCK(die_lock); |
26 | 26 | ||
27 | void die(const char *str, struct pt_regs *regs, long err) | 27 | void NORET_TYPE die(const char *str, struct pt_regs *regs, long err) |
28 | { | 28 | { |
29 | static int die_counter; | 29 | static int die_counter; |
30 | 30 | ||