diff options
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 62 | ||||
-rw-r--r-- | arch/mips/kernel/irixsig.c | 63 | ||||
-rw-r--r-- | arch/mips/kernel/linux32.c | 10 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 257 | ||||
-rw-r--r-- | arch/mips/kernel/scall32-o32.S | 2 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-64.S | 2 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-n32.S | 6 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-o32.S | 4 | ||||
-rw-r--r-- | arch/mips/kernel/setup.c | 439 | ||||
-rw-r--r-- | arch/mips/kernel/signal.c | 8 | ||||
-rw-r--r-- | arch/mips/kernel/signal32.c | 7 | ||||
-rw-r--r-- | arch/mips/kernel/smp-mt.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/smtc-asm.S | 2 | ||||
-rw-r--r-- | arch/mips/kernel/syscall.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 146 | ||||
-rw-r--r-- | arch/mips/kernel/vpe.c | 6 |
16 files changed, 561 insertions, 459 deletions
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index aa2caa67299a..9fbf8430c849 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
@@ -38,15 +38,40 @@ static void r3081_wait(void) | |||
38 | 38 | ||
39 | static void r39xx_wait(void) | 39 | static void r39xx_wait(void) |
40 | { | 40 | { |
41 | unsigned long cfg = read_c0_conf(); | 41 | local_irq_disable(); |
42 | write_c0_conf(cfg | TX39_CONF_HALT); | 42 | if (!need_resched()) |
43 | write_c0_conf(read_c0_conf() | TX39_CONF_HALT); | ||
44 | local_irq_enable(); | ||
43 | } | 45 | } |
44 | 46 | ||
47 | /* | ||
48 | * There is a race when WAIT instruction executed with interrupt | ||
49 | * enabled. | ||
50 | * But it is implementation-dependent wheter the pipelie restarts when | ||
51 | * a non-enabled interrupt is requested. | ||
52 | */ | ||
45 | static void r4k_wait(void) | 53 | static void r4k_wait(void) |
46 | { | 54 | { |
47 | __asm__(".set\tmips3\n\t" | 55 | __asm__(" .set mips3 \n" |
48 | "wait\n\t" | 56 | " wait \n" |
49 | ".set\tmips0"); | 57 | " .set mips0 \n"); |
58 | } | ||
59 | |||
60 | /* | ||
61 | * This variant is preferable as it allows testing need_resched and going to | ||
62 | * sleep depending on the outcome atomically. Unfortunately the "It is | ||
63 | * implementation-dependent whether the pipeline restarts when a non-enabled | ||
64 | * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes | ||
65 | * using this version a gamble. | ||
66 | */ | ||
67 | static void r4k_wait_irqoff(void) | ||
68 | { | ||
69 | local_irq_disable(); | ||
70 | if (!need_resched()) | ||
71 | __asm__(" .set mips3 \n" | ||
72 | " wait \n" | ||
73 | " .set mips0 \n"); | ||
74 | local_irq_enable(); | ||
50 | } | 75 | } |
51 | 76 | ||
52 | /* The Au1xxx wait is available only if using 32khz counter or | 77 | /* The Au1xxx wait is available only if using 32khz counter or |
@@ -56,17 +81,17 @@ int allow_au1k_wait; | |||
56 | static void au1k_wait(void) | 81 | static void au1k_wait(void) |
57 | { | 82 | { |
58 | /* using the wait instruction makes CP0 counter unusable */ | 83 | /* using the wait instruction makes CP0 counter unusable */ |
59 | __asm__(".set mips3\n\t" | 84 | __asm__(" .set mips3 \n" |
60 | "cache 0x14, 0(%0)\n\t" | 85 | " cache 0x14, 0(%0) \n" |
61 | "cache 0x14, 32(%0)\n\t" | 86 | " cache 0x14, 32(%0) \n" |
62 | "sync\n\t" | 87 | " sync \n" |
63 | "nop\n\t" | 88 | " nop \n" |
64 | "wait\n\t" | 89 | " wait \n" |
65 | "nop\n\t" | 90 | " nop \n" |
66 | "nop\n\t" | 91 | " nop \n" |
67 | "nop\n\t" | 92 | " nop \n" |
68 | "nop\n\t" | 93 | " nop \n" |
69 | ".set mips0\n\t" | 94 | " .set mips0 \n" |
70 | : : "r" (au1k_wait)); | 95 | : : "r" (au1k_wait)); |
71 | } | 96 | } |
72 | 97 | ||
@@ -111,7 +136,6 @@ static inline void check_wait(void) | |||
111 | case CPU_NEVADA: | 136 | case CPU_NEVADA: |
112 | case CPU_RM7000: | 137 | case CPU_RM7000: |
113 | case CPU_RM9000: | 138 | case CPU_RM9000: |
114 | case CPU_TX49XX: | ||
115 | case CPU_4KC: | 139 | case CPU_4KC: |
116 | case CPU_4KEC: | 140 | case CPU_4KEC: |
117 | case CPU_4KSC: | 141 | case CPU_4KSC: |
@@ -125,6 +149,10 @@ static inline void check_wait(void) | |||
125 | cpu_wait = r4k_wait; | 149 | cpu_wait = r4k_wait; |
126 | printk(" available.\n"); | 150 | printk(" available.\n"); |
127 | break; | 151 | break; |
152 | case CPU_TX49XX: | ||
153 | cpu_wait = r4k_wait_irqoff; | ||
154 | printk(" available.\n"); | ||
155 | break; | ||
128 | case CPU_AU1000: | 156 | case CPU_AU1000: |
129 | case CPU_AU1100: | 157 | case CPU_AU1100: |
130 | case CPU_AU1500: | 158 | case CPU_AU1500: |
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 676e868d26fb..2132485caa74 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
19 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
20 | #include <asm/unistd.h> | ||
20 | 21 | ||
21 | #undef DEBUG_SIG | 22 | #undef DEBUG_SIG |
22 | 23 | ||
@@ -172,11 +173,12 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info, | |||
172 | return ret; | 173 | return ret; |
173 | } | 174 | } |
174 | 175 | ||
175 | asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) | 176 | void do_irix_signal(struct pt_regs *regs) |
176 | { | 177 | { |
177 | struct k_sigaction ka; | 178 | struct k_sigaction ka; |
178 | siginfo_t info; | 179 | siginfo_t info; |
179 | int signr; | 180 | int signr; |
181 | sigset_t *oldset; | ||
180 | 182 | ||
181 | /* | 183 | /* |
182 | * We want the common case to go fast, which is why we may in certain | 184 | * We want the common case to go fast, which is why we may in certain |
@@ -184,19 +186,28 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) | |||
184 | * if so. | 186 | * if so. |
185 | */ | 187 | */ |
186 | if (!user_mode(regs)) | 188 | if (!user_mode(regs)) |
187 | return 1; | 189 | return; |
188 | 190 | ||
189 | if (try_to_freeze()) | 191 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
190 | goto no_signal; | 192 | oldset = ¤t->saved_sigmask; |
191 | 193 | else | |
192 | if (!oldset) | ||
193 | oldset = ¤t->blocked; | 194 | oldset = ¤t->blocked; |
194 | 195 | ||
195 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 196 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
196 | if (signr > 0) | 197 | if (signr > 0) { |
197 | return handle_signal(signr, &info, &ka, oldset, regs); | 198 | /* Whee! Actually deliver the signal. */ |
199 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | ||
200 | /* a signal was successfully delivered; the saved | ||
201 | * sigmask will have been stored in the signal frame, | ||
202 | * and will be restored by sigreturn, so we can simply | ||
203 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
204 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
205 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
206 | } | ||
207 | |||
208 | return; | ||
209 | } | ||
198 | 210 | ||
199 | no_signal: | ||
200 | /* | 211 | /* |
201 | * Who's code doesn't conform to the restartable syscall convention | 212 | * Who's code doesn't conform to the restartable syscall convention |
202 | * dies here!!! The li instruction, a single machine instruction, | 213 | * dies here!!! The li instruction, a single machine instruction, |
@@ -208,8 +219,22 @@ no_signal: | |||
208 | regs->regs[2] == ERESTARTNOINTR) { | 219 | regs->regs[2] == ERESTARTNOINTR) { |
209 | regs->cp0_epc -= 8; | 220 | regs->cp0_epc -= 8; |
210 | } | 221 | } |
222 | if (regs->regs[2] == ERESTART_RESTARTBLOCK) { | ||
223 | regs->regs[2] = __NR_restart_syscall; | ||
224 | regs->regs[7] = regs->regs[26]; | ||
225 | regs->cp0_epc -= 4; | ||
226 | } | ||
227 | regs->regs[0] = 0; /* Don't deal with this again. */ | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * If there's no signal to deliver, we just put the saved sigmask | ||
232 | * back | ||
233 | */ | ||
234 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
235 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
236 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
211 | } | 237 | } |
212 | return 0; | ||
213 | } | 238 | } |
214 | 239 | ||
215 | asmlinkage void | 240 | asmlinkage void |
@@ -298,6 +323,9 @@ struct sigact_irix5 { | |||
298 | int _unused0[2]; | 323 | int _unused0[2]; |
299 | }; | 324 | }; |
300 | 325 | ||
326 | #define SIG_SETMASK32 256 /* Goodie from SGI for BSD compatibility: | ||
327 | set only the low 32 bit of the sigset. */ | ||
328 | |||
301 | #ifdef DEBUG_SIG | 329 | #ifdef DEBUG_SIG |
302 | static inline void dump_sigact_irix5(struct sigact_irix5 *p) | 330 | static inline void dump_sigact_irix5(struct sigact_irix5 *p) |
303 | { | 331 | { |
@@ -413,7 +441,7 @@ asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new, | |||
413 | 441 | ||
414 | asmlinkage int irix_sigsuspend(struct pt_regs *regs) | 442 | asmlinkage int irix_sigsuspend(struct pt_regs *regs) |
415 | { | 443 | { |
416 | sigset_t saveset, newset; | 444 | sigset_t newset; |
417 | sigset_t __user *uset; | 445 | sigset_t __user *uset; |
418 | 446 | ||
419 | uset = (sigset_t __user *) regs->regs[4]; | 447 | uset = (sigset_t __user *) regs->regs[4]; |
@@ -422,18 +450,15 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs) | |||
422 | sigdelsetmask(&newset, ~_BLOCKABLE); | 450 | sigdelsetmask(&newset, ~_BLOCKABLE); |
423 | 451 | ||
424 | spin_lock_irq(¤t->sighand->siglock); | 452 | spin_lock_irq(¤t->sighand->siglock); |
425 | saveset = current->blocked; | 453 | current->saved_sigmask = current->blocked; |
426 | current->blocked = newset; | 454 | current->blocked = newset; |
427 | recalc_sigpending(); | 455 | recalc_sigpending(); |
428 | spin_unlock_irq(¤t->sighand->siglock); | 456 | spin_unlock_irq(¤t->sighand->siglock); |
429 | 457 | ||
430 | regs->regs[2] = -EINTR; | 458 | current->state = TASK_INTERRUPTIBLE; |
431 | while (1) { | 459 | schedule(); |
432 | current->state = TASK_INTERRUPTIBLE; | 460 | set_thread_flag(TIF_RESTORE_SIGMASK); |
433 | schedule(); | 461 | return -ERESTARTNOHAND; |
434 | if (do_irix_signal(&saveset, regs)) | ||
435 | return -EINTR; | ||
436 | } | ||
437 | } | 462 | } |
438 | 463 | ||
439 | /* hate hate hate... */ | 464 | /* hate hate hate... */ |
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 450ac592da57..43b1162d714f 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c | |||
@@ -991,7 +991,7 @@ struct sysctl_args32 | |||
991 | unsigned int __unused[4]; | 991 | unsigned int __unused[4]; |
992 | }; | 992 | }; |
993 | 993 | ||
994 | #ifdef CONFIG_SYSCTL | 994 | #ifdef CONFIG_SYSCTL_SYSCALL |
995 | 995 | ||
996 | asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args) | 996 | asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args) |
997 | { | 997 | { |
@@ -1032,7 +1032,7 @@ asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args) | |||
1032 | return error; | 1032 | return error; |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | #endif /* CONFIG_SYSCTL */ | 1035 | #endif /* CONFIG_SYSCTL_SYSCALL */ |
1036 | 1036 | ||
1037 | asmlinkage long sys32_newuname(struct new_utsname __user * name) | 1037 | asmlinkage long sys32_newuname(struct new_utsname __user * name) |
1038 | { | 1038 | { |
@@ -1296,9 +1296,3 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs) | |||
1296 | return do_fork(clone_flags, newsp, ®s, 0, | 1296 | return do_fork(clone_flags, newsp, ®s, 0, |
1297 | parent_tidptr, child_tidptr); | 1297 | parent_tidptr, child_tidptr); |
1298 | } | 1298 | } |
1299 | |||
1300 | extern asmlinkage void sys_set_thread_area(u32 addr); | ||
1301 | asmlinkage void sys32_set_thread_area(u32 addr) | ||
1302 | { | ||
1303 | sys_set_thread_area(AA(addr)); | ||
1304 | } | ||
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 7ab67f786bfe..2613a0dd4b82 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -273,104 +273,107 @@ long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | |||
273 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | 273 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); |
274 | } | 274 | } |
275 | 275 | ||
276 | static struct mips_frame_info { | 276 | /* |
277 | void *func; | 277 | * |
278 | unsigned long func_size; | 278 | */ |
279 | int frame_size; | 279 | struct mips_frame_info { |
280 | int pc_offset; | 280 | void *func; |
281 | } *schedule_frame, mfinfo[64]; | 281 | unsigned long func_size; |
282 | static int mfinfo_num; | 282 | int frame_size; |
283 | 283 | int pc_offset; | |
284 | static int __init get_frame_info(struct mips_frame_info *info) | 284 | }; |
285 | |||
286 | static inline int is_ra_save_ins(union mips_instruction *ip) | ||
285 | { | 287 | { |
286 | int i; | 288 | /* sw / sd $ra, offset($sp) */ |
287 | void *func = info->func; | 289 | return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && |
288 | union mips_instruction *ip = (union mips_instruction *)func; | 290 | ip->i_format.rs == 29 && |
291 | ip->i_format.rt == 31; | ||
292 | } | ||
293 | |||
294 | static inline int is_jal_jalr_jr_ins(union mips_instruction *ip) | ||
295 | { | ||
296 | if (ip->j_format.opcode == jal_op) | ||
297 | return 1; | ||
298 | if (ip->r_format.opcode != spec_op) | ||
299 | return 0; | ||
300 | return ip->r_format.func == jalr_op || ip->r_format.func == jr_op; | ||
301 | } | ||
302 | |||
303 | static inline int is_sp_move_ins(union mips_instruction *ip) | ||
304 | { | ||
305 | /* addiu/daddiu sp,sp,-imm */ | ||
306 | if (ip->i_format.rs != 29 || ip->i_format.rt != 29) | ||
307 | return 0; | ||
308 | if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) | ||
309 | return 1; | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int get_frame_info(struct mips_frame_info *info) | ||
314 | { | ||
315 | union mips_instruction *ip = info->func; | ||
316 | unsigned max_insns = info->func_size / sizeof(union mips_instruction); | ||
317 | unsigned i; | ||
318 | |||
289 | info->pc_offset = -1; | 319 | info->pc_offset = -1; |
290 | info->frame_size = 0; | 320 | info->frame_size = 0; |
291 | for (i = 0; i < 128; i++, ip++) { | ||
292 | /* if jal, jalr, jr, stop. */ | ||
293 | if (ip->j_format.opcode == jal_op || | ||
294 | (ip->r_format.opcode == spec_op && | ||
295 | (ip->r_format.func == jalr_op || | ||
296 | ip->r_format.func == jr_op))) | ||
297 | break; | ||
298 | 321 | ||
299 | if (info->func_size && i >= info->func_size / 4) | 322 | if (!ip) |
323 | goto err; | ||
324 | |||
325 | if (max_insns == 0) | ||
326 | max_insns = 128U; /* unknown function size */ | ||
327 | max_insns = min(128U, max_insns); | ||
328 | |||
329 | for (i = 0; i < max_insns; i++, ip++) { | ||
330 | |||
331 | if (is_jal_jalr_jr_ins(ip)) | ||
300 | break; | 332 | break; |
301 | if ( | 333 | if (!info->frame_size) { |
302 | #ifdef CONFIG_32BIT | 334 | if (is_sp_move_ins(ip)) |
303 | ip->i_format.opcode == addiu_op && | 335 | info->frame_size = - ip->i_format.simmediate; |
304 | #endif | 336 | continue; |
305 | #ifdef CONFIG_64BIT | ||
306 | ip->i_format.opcode == daddiu_op && | ||
307 | #endif | ||
308 | ip->i_format.rs == 29 && | ||
309 | ip->i_format.rt == 29) { | ||
310 | /* addiu/daddiu sp,sp,-imm */ | ||
311 | if (info->frame_size) | ||
312 | continue; | ||
313 | info->frame_size = - ip->i_format.simmediate; | ||
314 | } | 337 | } |
315 | 338 | if (info->pc_offset == -1 && is_ra_save_ins(ip)) { | |
316 | if ( | ||
317 | #ifdef CONFIG_32BIT | ||
318 | ip->i_format.opcode == sw_op && | ||
319 | #endif | ||
320 | #ifdef CONFIG_64BIT | ||
321 | ip->i_format.opcode == sd_op && | ||
322 | #endif | ||
323 | ip->i_format.rs == 29 && | ||
324 | ip->i_format.rt == 31) { | ||
325 | /* sw / sd $ra, offset($sp) */ | ||
326 | if (info->pc_offset != -1) | ||
327 | continue; | ||
328 | info->pc_offset = | 339 | info->pc_offset = |
329 | ip->i_format.simmediate / sizeof(long); | 340 | ip->i_format.simmediate / sizeof(long); |
341 | break; | ||
330 | } | 342 | } |
331 | } | 343 | } |
332 | if (info->pc_offset == -1 || info->frame_size == 0) { | 344 | if (info->frame_size && info->pc_offset >= 0) /* nested */ |
333 | if (func == schedule) | 345 | return 0; |
334 | printk("Can't analyze prologue code at %p\n", func); | 346 | if (info->pc_offset < 0) /* leaf */ |
335 | info->pc_offset = -1; | 347 | return 1; |
336 | info->frame_size = 0; | 348 | /* prologue seems boggus... */ |
337 | } | 349 | err: |
338 | 350 | return -1; | |
339 | return 0; | ||
340 | } | 351 | } |
341 | 352 | ||
353 | static struct mips_frame_info schedule_mfi __read_mostly; | ||
354 | |||
342 | static int __init frame_info_init(void) | 355 | static int __init frame_info_init(void) |
343 | { | 356 | { |
344 | int i; | 357 | unsigned long size = 0; |
345 | #ifdef CONFIG_KALLSYMS | 358 | #ifdef CONFIG_KALLSYMS |
359 | unsigned long ofs; | ||
346 | char *modname; | 360 | char *modname; |
347 | char namebuf[KSYM_NAME_LEN + 1]; | 361 | char namebuf[KSYM_NAME_LEN + 1]; |
348 | unsigned long start, size, ofs; | 362 | |
349 | extern char __sched_text_start[], __sched_text_end[]; | 363 | kallsyms_lookup((unsigned long)schedule, &size, &ofs, &modname, namebuf); |
350 | extern char __lock_text_start[], __lock_text_end[]; | ||
351 | |||
352 | start = (unsigned long)__sched_text_start; | ||
353 | for (i = 0; i < ARRAY_SIZE(mfinfo); i++) { | ||
354 | if (start == (unsigned long)schedule) | ||
355 | schedule_frame = &mfinfo[i]; | ||
356 | if (!kallsyms_lookup(start, &size, &ofs, &modname, namebuf)) | ||
357 | break; | ||
358 | mfinfo[i].func = (void *)(start + ofs); | ||
359 | mfinfo[i].func_size = size; | ||
360 | start += size - ofs; | ||
361 | if (start >= (unsigned long)__lock_text_end) | ||
362 | break; | ||
363 | if (start == (unsigned long)__sched_text_end) | ||
364 | start = (unsigned long)__lock_text_start; | ||
365 | } | ||
366 | #else | ||
367 | mfinfo[0].func = schedule; | ||
368 | schedule_frame = &mfinfo[0]; | ||
369 | #endif | 364 | #endif |
370 | for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) | 365 | schedule_mfi.func = schedule; |
371 | get_frame_info(&mfinfo[i]); | 366 | schedule_mfi.func_size = size; |
367 | |||
368 | get_frame_info(&schedule_mfi); | ||
369 | |||
370 | /* | ||
371 | * Without schedule() frame info, result given by | ||
372 | * thread_saved_pc() and get_wchan() are not reliable. | ||
373 | */ | ||
374 | if (schedule_mfi.pc_offset < 0) | ||
375 | printk("Can't analyze schedule() prologue at %p\n", schedule); | ||
372 | 376 | ||
373 | mfinfo_num = i; | ||
374 | return 0; | 377 | return 0; |
375 | } | 378 | } |
376 | 379 | ||
@@ -386,54 +389,86 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
386 | /* New born processes are a special case */ | 389 | /* New born processes are a special case */ |
387 | if (t->reg31 == (unsigned long) ret_from_fork) | 390 | if (t->reg31 == (unsigned long) ret_from_fork) |
388 | return t->reg31; | 391 | return t->reg31; |
389 | 392 | if (schedule_mfi.pc_offset < 0) | |
390 | if (!schedule_frame || schedule_frame->pc_offset < 0) | ||
391 | return 0; | 393 | return 0; |
392 | return ((unsigned long *)t->reg29)[schedule_frame->pc_offset]; | 394 | return ((unsigned long *)t->reg29)[schedule_mfi.pc_offset]; |
393 | } | 395 | } |
394 | 396 | ||
395 | /* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */ | 397 | |
396 | unsigned long get_wchan(struct task_struct *p) | 398 | #ifdef CONFIG_KALLSYMS |
399 | /* used by show_backtrace() */ | ||
400 | unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | ||
401 | unsigned long pc, unsigned long ra) | ||
397 | { | 402 | { |
398 | unsigned long stack_page; | 403 | unsigned long stack_page; |
399 | unsigned long pc; | 404 | struct mips_frame_info info; |
400 | #ifdef CONFIG_KALLSYMS | 405 | char *modname; |
401 | unsigned long frame; | 406 | char namebuf[KSYM_NAME_LEN + 1]; |
402 | #endif | 407 | unsigned long size, ofs; |
408 | int leaf; | ||
403 | 409 | ||
404 | if (!p || p == current || p->state == TASK_RUNNING) | 410 | stack_page = (unsigned long)task_stack_page(task); |
411 | if (!stack_page) | ||
405 | return 0; | 412 | return 0; |
406 | 413 | ||
407 | stack_page = (unsigned long)task_stack_page(p); | 414 | if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) |
408 | if (!stack_page || !mfinfo_num) | 415 | return 0; |
416 | /* | ||
417 | * Return ra if an exception occured at the first instruction | ||
418 | */ | ||
419 | if (unlikely(ofs == 0)) | ||
420 | return ra; | ||
421 | |||
422 | info.func = (void *)(pc - ofs); | ||
423 | info.func_size = ofs; /* analyze from start to ofs */ | ||
424 | leaf = get_frame_info(&info); | ||
425 | if (leaf < 0) | ||
426 | return 0; | ||
427 | |||
428 | if (*sp < stack_page || | ||
429 | *sp + info.frame_size > stack_page + THREAD_SIZE - 32) | ||
409 | return 0; | 430 | return 0; |
410 | 431 | ||
411 | pc = thread_saved_pc(p); | 432 | if (leaf) |
433 | /* | ||
434 | * For some extreme cases, get_frame_info() can | ||
435 | * consider wrongly a nested function as a leaf | ||
436 | * one. In that cases avoid to return always the | ||
437 | * same value. | ||
438 | */ | ||
439 | pc = pc != ra ? ra : 0; | ||
440 | else | ||
441 | pc = ((unsigned long *)(*sp))[info.pc_offset]; | ||
442 | |||
443 | *sp += info.frame_size; | ||
444 | return __kernel_text_address(pc) ? pc : 0; | ||
445 | } | ||
446 | #endif | ||
447 | |||
448 | /* | ||
449 | * get_wchan - a maintenance nightmare^W^Wpain in the ass ... | ||
450 | */ | ||
451 | unsigned long get_wchan(struct task_struct *task) | ||
452 | { | ||
453 | unsigned long pc = 0; | ||
412 | #ifdef CONFIG_KALLSYMS | 454 | #ifdef CONFIG_KALLSYMS |
413 | if (!in_sched_functions(pc)) | 455 | unsigned long sp; |
414 | return pc; | 456 | #endif |
415 | 457 | ||
416 | frame = p->thread.reg29 + schedule_frame->frame_size; | 458 | if (!task || task == current || task->state == TASK_RUNNING) |
417 | do { | 459 | goto out; |
418 | int i; | 460 | if (!task_stack_page(task)) |
461 | goto out; | ||
419 | 462 | ||
420 | if (frame < stack_page || frame > stack_page + THREAD_SIZE - 32) | 463 | pc = thread_saved_pc(task); |
421 | return 0; | ||
422 | 464 | ||
423 | for (i = mfinfo_num - 1; i >= 0; i--) { | 465 | #ifdef CONFIG_KALLSYMS |
424 | if (pc >= (unsigned long) mfinfo[i].func) | 466 | sp = task->thread.reg29 + schedule_mfi.frame_size; |
425 | break; | ||
426 | } | ||
427 | if (i < 0) | ||
428 | break; | ||
429 | 467 | ||
430 | pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; | 468 | while (in_sched_functions(pc)) |
431 | if (!mfinfo[i].frame_size) | 469 | pc = unwind_stack(task, &sp, pc, 0); |
432 | break; | ||
433 | frame += mfinfo[i].frame_size; | ||
434 | } while (in_sched_functions(pc)); | ||
435 | #endif | 470 | #endif |
436 | 471 | ||
472 | out: | ||
437 | return pc; | 473 | return pc; |
438 | } | 474 | } |
439 | |||
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index ba1bcd83c7d3..e71785102206 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S | |||
@@ -662,6 +662,8 @@ einval: li v0, -EINVAL | |||
662 | sys sys_tee 4 | 662 | sys sys_tee 4 |
663 | sys sys_vmsplice 4 | 663 | sys sys_vmsplice 4 |
664 | sys sys_move_pages 6 | 664 | sys sys_move_pages 6 |
665 | sys sys_set_robust_list 2 | ||
666 | sys sys_get_robust_list 3 | ||
665 | .endm | 667 | .endm |
666 | 668 | ||
667 | /* We pre-compute the number of _instruction_ bytes needed to | 669 | /* We pre-compute the number of _instruction_ bytes needed to |
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 939e172db953..4c22d0b4825d 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S | |||
@@ -466,3 +466,5 @@ sys_call_table: | |||
466 | PTR sys_tee /* 5265 */ | 466 | PTR sys_tee /* 5265 */ |
467 | PTR sys_vmsplice | 467 | PTR sys_vmsplice |
468 | PTR sys_move_pages | 468 | PTR sys_move_pages |
469 | PTR sys_set_robust_list | ||
470 | PTR sys_get_robust_list | ||
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 98abbc5a9f13..f25c2a2f1038 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S | |||
@@ -247,7 +247,7 @@ EXPORT(sysn32_call_table) | |||
247 | PTR sys_capset | 247 | PTR sys_capset |
248 | PTR sys32_rt_sigpending /* 6125 */ | 248 | PTR sys32_rt_sigpending /* 6125 */ |
249 | PTR compat_sys_rt_sigtimedwait | 249 | PTR compat_sys_rt_sigtimedwait |
250 | PTR sys_rt_sigqueueinfo | 250 | PTR sys32_rt_sigqueueinfo |
251 | PTR sysn32_rt_sigsuspend | 251 | PTR sysn32_rt_sigsuspend |
252 | PTR sys32_sigaltstack | 252 | PTR sys32_sigaltstack |
253 | PTR compat_sys_utime /* 6130 */ | 253 | PTR compat_sys_utime /* 6130 */ |
@@ -390,5 +390,7 @@ EXPORT(sysn32_call_table) | |||
390 | PTR sys_splice | 390 | PTR sys_splice |
391 | PTR sys_sync_file_range | 391 | PTR sys_sync_file_range |
392 | PTR sys_tee | 392 | PTR sys_tee |
393 | PTR sys_vmsplice /* 6271 */ | 393 | PTR sys_vmsplice /* 6270 */ |
394 | PTR sys_move_pages | 394 | PTR sys_move_pages |
395 | PTR compat_sys_set_robust_list | ||
396 | PTR compat_sys_get_robust_list | ||
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 505c9ee54009..288ee4ac4dbb 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S | |||
@@ -498,7 +498,7 @@ sys_call_table: | |||
498 | PTR sys_mknodat /* 4290 */ | 498 | PTR sys_mknodat /* 4290 */ |
499 | PTR sys_fchownat | 499 | PTR sys_fchownat |
500 | PTR compat_sys_futimesat | 500 | PTR compat_sys_futimesat |
501 | PTR compat_sys_newfstatat | 501 | PTR sys_newfstatat |
502 | PTR sys_unlinkat | 502 | PTR sys_unlinkat |
503 | PTR sys_renameat /* 4295 */ | 503 | PTR sys_renameat /* 4295 */ |
504 | PTR sys_linkat | 504 | PTR sys_linkat |
@@ -514,4 +514,6 @@ sys_call_table: | |||
514 | PTR sys_tee | 514 | PTR sys_tee |
515 | PTR sys_vmsplice | 515 | PTR sys_vmsplice |
516 | PTR compat_sys_move_pages | 516 | PTR compat_sys_move_pages |
517 | PTR compat_sys_set_robust_list | ||
518 | PTR compat_sys_get_robust_list /* 4310 */ | ||
517 | .size sys_call_table,.-sys_call_table | 519 | .size sys_call_table,.-sys_call_table |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 8c2b596a136f..fdbb508661c5 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
@@ -10,29 +10,15 @@ | |||
10 | * Copyright (C) 1999 Silicon Graphics, Inc. | 10 | * Copyright (C) 1999 Silicon Graphics, Inc. |
11 | * Copyright (C) 2000 2001, 2002 Maciej W. Rozycki | 11 | * Copyright (C) 2000 2001, 2002 Maciej W. Rozycki |
12 | */ | 12 | */ |
13 | #include <linux/errno.h> | ||
14 | #include <linux/init.h> | 13 | #include <linux/init.h> |
15 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/module.h> | 15 | #include <linux/module.h> |
20 | #include <linux/stddef.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/user.h> | ||
25 | #include <linux/utsname.h> | ||
26 | #include <linux/a.out.h> | ||
27 | #include <linux/screen_info.h> | 16 | #include <linux/screen_info.h> |
28 | #include <linux/bootmem.h> | 17 | #include <linux/bootmem.h> |
29 | #include <linux/initrd.h> | 18 | #include <linux/initrd.h> |
30 | #include <linux/major.h> | ||
31 | #include <linux/kdev_t.h> | ||
32 | #include <linux/root_dev.h> | 19 | #include <linux/root_dev.h> |
33 | #include <linux/highmem.h> | 20 | #include <linux/highmem.h> |
34 | #include <linux/console.h> | 21 | #include <linux/console.h> |
35 | #include <linux/mmzone.h> | ||
36 | #include <linux/pfn.h> | 22 | #include <linux/pfn.h> |
37 | 23 | ||
38 | #include <asm/addrspace.h> | 24 | #include <asm/addrspace.h> |
@@ -96,6 +82,12 @@ void __init add_memory_region(phys_t start, phys_t size, long type) | |||
96 | int x = boot_mem_map.nr_map; | 82 | int x = boot_mem_map.nr_map; |
97 | struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1; | 83 | struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1; |
98 | 84 | ||
85 | /* Sanity check */ | ||
86 | if (start + size < start) { | ||
87 | printk("Trying to add an invalid memory region, skipped\n"); | ||
88 | return; | ||
89 | } | ||
90 | |||
99 | /* | 91 | /* |
100 | * Try to merge with previous entry if any. This is far less than | 92 | * Try to merge with previous entry if any. This is far less than |
101 | * perfect but is sufficient for most real world cases. | 93 | * perfect but is sufficient for most real world cases. |
@@ -143,167 +135,132 @@ static void __init print_memory_map(void) | |||
143 | } | 135 | } |
144 | } | 136 | } |
145 | 137 | ||
146 | static inline void parse_cmdline_early(void) | 138 | /* |
139 | * Manage initrd | ||
140 | */ | ||
141 | #ifdef CONFIG_BLK_DEV_INITRD | ||
142 | |||
143 | static int __init rd_start_early(char *p) | ||
147 | { | 144 | { |
148 | char c = ' ', *to = command_line, *from = saved_command_line; | 145 | unsigned long start = memparse(p, &p); |
149 | unsigned long start_at, mem_size; | ||
150 | int len = 0; | ||
151 | int usermem = 0; | ||
152 | 146 | ||
153 | printk("Determined physical RAM map:\n"); | 147 | #ifdef CONFIG_64BIT |
154 | print_memory_map(); | 148 | /* HACK: Guess if the sign extension was forgotten */ |
149 | if (start > 0x0000000080000000 && start < 0x00000000ffffffff) | ||
150 | start |= 0xffffffff00000000UL; | ||
151 | #endif | ||
152 | initrd_start = start; | ||
153 | initrd_end += start; | ||
155 | 154 | ||
156 | for (;;) { | 155 | return 0; |
157 | /* | 156 | } |
158 | * "mem=XXX[kKmM]" defines a memory region from | 157 | early_param("rd_start", rd_start_early); |
159 | * 0 to <XXX>, overriding the determined size. | ||
160 | * "mem=XXX[KkmM]@YYY[KkmM]" defines a memory region from | ||
161 | * <YYY> to <YYY>+<XXX>, overriding the determined size. | ||
162 | */ | ||
163 | if (c == ' ' && !memcmp(from, "mem=", 4)) { | ||
164 | if (to != command_line) | ||
165 | to--; | ||
166 | /* | ||
167 | * If a user specifies memory size, we | ||
168 | * blow away any automatically generated | ||
169 | * size. | ||
170 | */ | ||
171 | if (usermem == 0) { | ||
172 | boot_mem_map.nr_map = 0; | ||
173 | usermem = 1; | ||
174 | } | ||
175 | mem_size = memparse(from + 4, &from); | ||
176 | if (*from == '@') | ||
177 | start_at = memparse(from + 1, &from); | ||
178 | else | ||
179 | start_at = 0; | ||
180 | add_memory_region(start_at, mem_size, BOOT_MEM_RAM); | ||
181 | } | ||
182 | c = *(from++); | ||
183 | if (!c) | ||
184 | break; | ||
185 | if (CL_SIZE <= ++len) | ||
186 | break; | ||
187 | *(to++) = c; | ||
188 | } | ||
189 | *to = '\0'; | ||
190 | 158 | ||
191 | if (usermem) { | 159 | static int __init rd_size_early(char *p) |
192 | printk("User-defined physical RAM map:\n"); | 160 | { |
193 | print_memory_map(); | 161 | initrd_end += memparse(p, &p); |
194 | } | 162 | |
163 | return 0; | ||
195 | } | 164 | } |
165 | early_param("rd_size", rd_size_early); | ||
196 | 166 | ||
197 | static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_end) | 167 | static unsigned long __init init_initrd(void) |
198 | { | 168 | { |
169 | unsigned long tmp, end, size; | ||
170 | u32 *initrd_header; | ||
171 | |||
172 | ROOT_DEV = Root_RAM0; | ||
173 | |||
199 | /* | 174 | /* |
200 | * "rd_start=0xNNNNNNNN" defines the memory address of an initrd | 175 | * Board specific code or command line parser should have |
201 | * "rd_size=0xNN" it's size | 176 | * already set up initrd_start and initrd_end. In these cases |
177 | * perfom sanity checks and use them if all looks good. | ||
202 | */ | 178 | */ |
203 | unsigned long start = 0; | 179 | size = initrd_end - initrd_start; |
204 | unsigned long size = 0; | 180 | if (initrd_end == 0 || size == 0) { |
205 | unsigned long end; | 181 | initrd_start = 0; |
206 | char cmd_line[CL_SIZE]; | 182 | initrd_end = 0; |
207 | char *start_str; | 183 | } else |
208 | char *size_str; | 184 | return initrd_end; |
209 | char *tmp; | 185 | |
210 | 186 | end = (unsigned long)&_end; | |
211 | strcpy(cmd_line, command_line); | 187 | tmp = PAGE_ALIGN(end) - sizeof(u32) * 2; |
212 | *command_line = 0; | 188 | if (tmp < end) |
213 | tmp = cmd_line; | 189 | tmp += PAGE_SIZE; |
214 | /* Ignore "rd_start=" strings in other parameters. */ | 190 | |
215 | start_str = strstr(cmd_line, "rd_start="); | 191 | initrd_header = (u32 *)tmp; |
216 | if (start_str && start_str != cmd_line && *(start_str - 1) != ' ') | 192 | if (initrd_header[0] == 0x494E5244) { |
217 | start_str = strstr(start_str, " rd_start="); | 193 | initrd_start = (unsigned long)&initrd_header[2]; |
218 | while (start_str) { | 194 | initrd_end = initrd_start + initrd_header[1]; |
219 | if (start_str != cmd_line) | ||
220 | strncat(command_line, tmp, start_str - tmp); | ||
221 | start = memparse(start_str + 9, &start_str); | ||
222 | tmp = start_str + 1; | ||
223 | start_str = strstr(start_str, " rd_start="); | ||
224 | } | 195 | } |
225 | if (*tmp) | 196 | return initrd_end; |
226 | strcat(command_line, tmp); | 197 | } |
227 | 198 | ||
228 | strcpy(cmd_line, command_line); | 199 | static void __init finalize_initrd(void) |
229 | *command_line = 0; | 200 | { |
230 | tmp = cmd_line; | 201 | unsigned long size = initrd_end - initrd_start; |
231 | /* Ignore "rd_size" strings in other parameters. */ | 202 | |
232 | size_str = strstr(cmd_line, "rd_size="); | 203 | if (size == 0) { |
233 | if (size_str && size_str != cmd_line && *(size_str - 1) != ' ') | 204 | printk(KERN_INFO "Initrd not found or empty"); |
234 | size_str = strstr(size_str, " rd_size="); | 205 | goto disable; |
235 | while (size_str) { | 206 | } |
236 | if (size_str != cmd_line) | 207 | if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) { |
237 | strncat(command_line, tmp, size_str - tmp); | 208 | printk("Initrd extends beyond end of memory"); |
238 | size = memparse(size_str + 8, &size_str); | 209 | goto disable; |
239 | tmp = size_str + 1; | ||
240 | size_str = strstr(size_str, " rd_size="); | ||
241 | } | 210 | } |
242 | if (*tmp) | ||
243 | strcat(command_line, tmp); | ||
244 | 211 | ||
245 | #ifdef CONFIG_64BIT | 212 | reserve_bootmem(CPHYSADDR(initrd_start), size); |
246 | /* HACK: Guess if the sign extension was forgotten */ | 213 | initrd_below_start_ok = 1; |
247 | if (start > 0x0000000080000000 && start < 0x00000000ffffffff) | 214 | |
248 | start |= 0xffffffff00000000UL; | 215 | printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n", |
216 | initrd_start, size); | ||
217 | return; | ||
218 | disable: | ||
219 | printk(" - disabling initrd\n"); | ||
220 | initrd_start = 0; | ||
221 | initrd_end = 0; | ||
222 | } | ||
223 | |||
224 | #else /* !CONFIG_BLK_DEV_INITRD */ | ||
225 | |||
226 | #define init_initrd() 0 | ||
227 | #define finalize_initrd() do {} while (0) | ||
228 | |||
249 | #endif | 229 | #endif |
250 | 230 | ||
251 | end = start + size; | 231 | /* |
252 | if (start && end) { | 232 | * Initialize the bootmem allocator. It also setup initrd related data |
253 | *rd_start = start; | 233 | * if needed. |
254 | *rd_end = end; | 234 | */ |
255 | return 1; | 235 | #ifdef CONFIG_SGI_IP27 |
256 | } | 236 | |
257 | return 0; | 237 | static void __init bootmem_init(void) |
238 | { | ||
239 | init_initrd(); | ||
240 | finalize_initrd(); | ||
258 | } | 241 | } |
259 | 242 | ||
260 | #define MAXMEM HIGHMEM_START | 243 | #else /* !CONFIG_SGI_IP27 */ |
261 | #define MAXMEM_PFN PFN_DOWN(MAXMEM) | ||
262 | 244 | ||
263 | static inline void bootmem_init(void) | 245 | static void __init bootmem_init(void) |
264 | { | 246 | { |
265 | unsigned long start_pfn; | 247 | unsigned long reserved_end; |
266 | unsigned long reserved_end = (unsigned long)&_end; | 248 | unsigned long highest = 0; |
267 | #ifndef CONFIG_SGI_IP27 | 249 | unsigned long mapstart = -1UL; |
268 | unsigned long first_usable_pfn; | ||
269 | unsigned long bootmap_size; | 250 | unsigned long bootmap_size; |
270 | int i; | 251 | int i; |
271 | #endif | ||
272 | #ifdef CONFIG_BLK_DEV_INITRD | ||
273 | int initrd_reserve_bootmem = 0; | ||
274 | |||
275 | /* Board specific code should have set up initrd_start and initrd_end */ | ||
276 | ROOT_DEV = Root_RAM0; | ||
277 | if (parse_rd_cmdline(&initrd_start, &initrd_end)) { | ||
278 | reserved_end = max(reserved_end, initrd_end); | ||
279 | initrd_reserve_bootmem = 1; | ||
280 | } else { | ||
281 | unsigned long tmp; | ||
282 | u32 *initrd_header; | ||
283 | |||
284 | tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - sizeof(u32) * 2; | ||
285 | if (tmp < reserved_end) | ||
286 | tmp += PAGE_SIZE; | ||
287 | initrd_header = (u32 *)tmp; | ||
288 | if (initrd_header[0] == 0x494E5244) { | ||
289 | initrd_start = (unsigned long)&initrd_header[2]; | ||
290 | initrd_end = initrd_start + initrd_header[1]; | ||
291 | reserved_end = max(reserved_end, initrd_end); | ||
292 | initrd_reserve_bootmem = 1; | ||
293 | } | ||
294 | } | ||
295 | #endif /* CONFIG_BLK_DEV_INITRD */ | ||
296 | 252 | ||
297 | /* | 253 | /* |
298 | * Partially used pages are not usable - thus | 254 | * Init any data related to initrd. It's a nop if INITRD is |
299 | * we are rounding upwards. | 255 | * not selected. Once that done we can determine the low bound |
256 | * of usable memory. | ||
300 | */ | 257 | */ |
301 | start_pfn = PFN_UP(CPHYSADDR(reserved_end)); | 258 | reserved_end = init_initrd(); |
259 | reserved_end = PFN_UP(CPHYSADDR(max(reserved_end, (unsigned long)&_end))); | ||
302 | 260 | ||
303 | #ifndef CONFIG_SGI_IP27 | 261 | /* |
304 | /* Find the highest page frame number we have available. */ | 262 | * Find the highest page frame number we have available. |
305 | max_pfn = 0; | 263 | */ |
306 | first_usable_pfn = -1UL; | ||
307 | for (i = 0; i < boot_mem_map.nr_map; i++) { | 264 | for (i = 0; i < boot_mem_map.nr_map; i++) { |
308 | unsigned long start, end; | 265 | unsigned long start, end; |
309 | 266 | ||
@@ -312,56 +269,38 @@ static inline void bootmem_init(void) | |||
312 | 269 | ||
313 | start = PFN_UP(boot_mem_map.map[i].addr); | 270 | start = PFN_UP(boot_mem_map.map[i].addr); |
314 | end = PFN_DOWN(boot_mem_map.map[i].addr | 271 | end = PFN_DOWN(boot_mem_map.map[i].addr |
315 | + boot_mem_map.map[i].size); | 272 | + boot_mem_map.map[i].size); |
316 | 273 | ||
317 | if (start >= end) | 274 | if (end > highest) |
275 | highest = end; | ||
276 | if (end <= reserved_end) | ||
318 | continue; | 277 | continue; |
319 | if (end > max_pfn) | 278 | if (start >= mapstart) |
320 | max_pfn = end; | 279 | continue; |
321 | if (start < first_usable_pfn) { | 280 | mapstart = max(reserved_end, start); |
322 | if (start > start_pfn) { | ||
323 | first_usable_pfn = start; | ||
324 | } else if (end > start_pfn) { | ||
325 | first_usable_pfn = start_pfn; | ||
326 | } | ||
327 | } | ||
328 | } | 281 | } |
329 | 282 | ||
330 | /* | 283 | /* |
331 | * Determine low and high memory ranges | 284 | * Determine low and high memory ranges |
332 | */ | 285 | */ |
333 | max_low_pfn = max_pfn; | 286 | if (highest > PFN_DOWN(HIGHMEM_START)) { |
334 | if (max_low_pfn > MAXMEM_PFN) { | 287 | #ifdef CONFIG_HIGHMEM |
335 | max_low_pfn = MAXMEM_PFN; | 288 | highstart_pfn = PFN_DOWN(HIGHMEM_START); |
336 | #ifndef CONFIG_HIGHMEM | 289 | highend_pfn = highest; |
337 | /* Maximum memory usable is what is directly addressable */ | ||
338 | printk(KERN_WARNING "Warning only %ldMB will be used.\n", | ||
339 | MAXMEM >> 20); | ||
340 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); | ||
341 | #endif | 290 | #endif |
291 | highest = PFN_DOWN(HIGHMEM_START); | ||
342 | } | 292 | } |
343 | 293 | ||
344 | #ifdef CONFIG_HIGHMEM | ||
345 | /* | 294 | /* |
346 | * Crude, we really should make a better attempt at detecting | 295 | * Initialize the boot-time allocator with low memory only. |
347 | * highstart_pfn | ||
348 | */ | 296 | */ |
349 | highstart_pfn = highend_pfn = max_pfn; | 297 | bootmap_size = init_bootmem(mapstart, highest); |
350 | if (max_pfn > MAXMEM_PFN) { | ||
351 | highstart_pfn = MAXMEM_PFN; | ||
352 | printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", | ||
353 | (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT)); | ||
354 | } | ||
355 | #endif | ||
356 | |||
357 | /* Initialize the boot-time allocator with low memory only. */ | ||
358 | bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn); | ||
359 | 298 | ||
360 | /* | 299 | /* |
361 | * Register fully available low RAM pages with the bootmem allocator. | 300 | * Register fully available low RAM pages with the bootmem allocator. |
362 | */ | 301 | */ |
363 | for (i = 0; i < boot_mem_map.nr_map; i++) { | 302 | for (i = 0; i < boot_mem_map.nr_map; i++) { |
364 | unsigned long curr_pfn, last_pfn, size; | 303 | unsigned long start, end, size; |
365 | 304 | ||
366 | /* | 305 | /* |
367 | * Reserve usable memory. | 306 | * Reserve usable memory. |
@@ -369,85 +308,50 @@ static inline void bootmem_init(void) | |||
369 | if (boot_mem_map.map[i].type != BOOT_MEM_RAM) | 308 | if (boot_mem_map.map[i].type != BOOT_MEM_RAM) |
370 | continue; | 309 | continue; |
371 | 310 | ||
372 | /* | 311 | start = PFN_UP(boot_mem_map.map[i].addr); |
373 | * We are rounding up the start address of usable memory: | 312 | end = PFN_DOWN(boot_mem_map.map[i].addr |
374 | */ | ||
375 | curr_pfn = PFN_UP(boot_mem_map.map[i].addr); | ||
376 | if (curr_pfn >= max_low_pfn) | ||
377 | continue; | ||
378 | if (curr_pfn < start_pfn) | ||
379 | curr_pfn = start_pfn; | ||
380 | |||
381 | /* | ||
382 | * ... and at the end of the usable range downwards: | ||
383 | */ | ||
384 | last_pfn = PFN_DOWN(boot_mem_map.map[i].addr | ||
385 | + boot_mem_map.map[i].size); | 313 | + boot_mem_map.map[i].size); |
386 | |||
387 | if (last_pfn > max_low_pfn) | ||
388 | last_pfn = max_low_pfn; | ||
389 | |||
390 | /* | 314 | /* |
391 | * Only register lowmem part of lowmem segment with bootmem. | 315 | * We are rounding up the start address of usable memory |
316 | * and at the end of the usable range downwards. | ||
392 | */ | 317 | */ |
393 | size = last_pfn - curr_pfn; | 318 | if (start >= max_low_pfn) |
394 | if (curr_pfn > PFN_DOWN(HIGHMEM_START)) | ||
395 | continue; | ||
396 | if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START)) | ||
397 | size = PFN_DOWN(HIGHMEM_START) - curr_pfn; | ||
398 | if (!size) | ||
399 | continue; | 319 | continue; |
320 | if (start < reserved_end) | ||
321 | start = reserved_end; | ||
322 | if (end > max_low_pfn) | ||
323 | end = max_low_pfn; | ||
400 | 324 | ||
401 | /* | 325 | /* |
402 | * ... finally, did all the rounding and playing | 326 | * ... finally, is the area going away? |
403 | * around just make the area go away? | ||
404 | */ | 327 | */ |
405 | if (last_pfn <= curr_pfn) | 328 | if (end <= start) |
406 | continue; | 329 | continue; |
330 | size = end - start; | ||
407 | 331 | ||
408 | /* Register lowmem ranges */ | 332 | /* Register lowmem ranges */ |
409 | free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); | 333 | free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT); |
410 | memory_present(0, curr_pfn, curr_pfn + size - 1); | 334 | memory_present(0, start, end); |
411 | } | 335 | } |
412 | 336 | ||
413 | /* Reserve the bootmap memory. */ | 337 | /* |
414 | reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size); | 338 | * Reserve the bootmap memory. |
415 | #endif /* CONFIG_SGI_IP27 */ | 339 | */ |
416 | 340 | reserve_bootmem(PFN_PHYS(mapstart), bootmap_size); | |
417 | #ifdef CONFIG_BLK_DEV_INITRD | ||
418 | initrd_below_start_ok = 1; | ||
419 | if (initrd_start) { | ||
420 | unsigned long initrd_size = ((unsigned char *)initrd_end) - | ||
421 | ((unsigned char *)initrd_start); | ||
422 | const int width = sizeof(long) * 2; | ||
423 | |||
424 | printk("Initial ramdisk at: 0x%p (%lu bytes)\n", | ||
425 | (void *)initrd_start, initrd_size); | ||
426 | |||
427 | if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) { | ||
428 | printk("initrd extends beyond end of memory " | ||
429 | "(0x%0*Lx > 0x%0*Lx)\ndisabling initrd\n", | ||
430 | width, | ||
431 | (unsigned long long) CPHYSADDR(initrd_end), | ||
432 | width, | ||
433 | (unsigned long long) PFN_PHYS(max_low_pfn)); | ||
434 | initrd_start = initrd_end = 0; | ||
435 | initrd_reserve_bootmem = 0; | ||
436 | } | ||
437 | 341 | ||
438 | if (initrd_reserve_bootmem) | 342 | /* |
439 | reserve_bootmem(CPHYSADDR(initrd_start), initrd_size); | 343 | * Reserve initrd memory if needed. |
440 | } | 344 | */ |
441 | #endif /* CONFIG_BLK_DEV_INITRD */ | 345 | finalize_initrd(); |
442 | } | 346 | } |
443 | 347 | ||
348 | #endif /* CONFIG_SGI_IP27 */ | ||
349 | |||
444 | /* | 350 | /* |
445 | * arch_mem_init - initialize memory managment subsystem | 351 | * arch_mem_init - initialize memory managment subsystem |
446 | * | 352 | * |
447 | * o plat_mem_setup() detects the memory configuration and will record detected | 353 | * o plat_mem_setup() detects the memory configuration and will record detected |
448 | * memory areas using add_memory_region. | 354 | * memory areas using add_memory_region. |
449 | * o parse_cmdline_early() parses the command line for mem= options which, | ||
450 | * iff detected, will override the results of the automatic detection. | ||
451 | * | 355 | * |
452 | * At this stage the memory configuration of the system is known to the | 356 | * At this stage the memory configuration of the system is known to the |
453 | * kernel but generic memory managment system is still entirely uninitialized. | 357 | * kernel but generic memory managment system is still entirely uninitialized. |
@@ -465,25 +369,59 @@ static inline void bootmem_init(void) | |||
465 | * initialization hook for anything else was introduced. | 369 | * initialization hook for anything else was introduced. |
466 | */ | 370 | */ |
467 | 371 | ||
468 | extern void plat_mem_setup(void); | 372 | static int usermem __initdata = 0; |
373 | |||
374 | static int __init early_parse_mem(char *p) | ||
375 | { | ||
376 | unsigned long start, size; | ||
377 | |||
378 | /* | ||
379 | * If a user specifies memory size, we | ||
380 | * blow away any automatically generated | ||
381 | * size. | ||
382 | */ | ||
383 | if (usermem == 0) { | ||
384 | boot_mem_map.nr_map = 0; | ||
385 | usermem = 1; | ||
386 | } | ||
387 | start = 0; | ||
388 | size = memparse(p, &p); | ||
389 | if (*p == '@') | ||
390 | start = memparse(p + 1, &p); | ||
391 | |||
392 | add_memory_region(start, size, BOOT_MEM_RAM); | ||
393 | return 0; | ||
394 | } | ||
395 | early_param("mem", early_parse_mem); | ||
469 | 396 | ||
470 | static void __init arch_mem_init(char **cmdline_p) | 397 | static void __init arch_mem_init(char **cmdline_p) |
471 | { | 398 | { |
399 | extern void plat_mem_setup(void); | ||
400 | |||
472 | /* call board setup routine */ | 401 | /* call board setup routine */ |
473 | plat_mem_setup(); | 402 | plat_mem_setup(); |
474 | 403 | ||
404 | printk("Determined physical RAM map:\n"); | ||
405 | print_memory_map(); | ||
406 | |||
475 | strlcpy(command_line, arcs_cmdline, sizeof(command_line)); | 407 | strlcpy(command_line, arcs_cmdline, sizeof(command_line)); |
476 | strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); | 408 | strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); |
477 | 409 | ||
478 | *cmdline_p = command_line; | 410 | *cmdline_p = command_line; |
479 | 411 | ||
480 | parse_cmdline_early(); | 412 | parse_early_param(); |
413 | |||
414 | if (usermem) { | ||
415 | printk("User-defined physical RAM map:\n"); | ||
416 | print_memory_map(); | ||
417 | } | ||
418 | |||
481 | bootmem_init(); | 419 | bootmem_init(); |
482 | sparse_init(); | 420 | sparse_init(); |
483 | paging_init(); | 421 | paging_init(); |
484 | } | 422 | } |
485 | 423 | ||
486 | static inline void resource_init(void) | 424 | static void __init resource_init(void) |
487 | { | 425 | { |
488 | int i; | 426 | int i; |
489 | 427 | ||
@@ -504,10 +442,10 @@ static inline void resource_init(void) | |||
504 | 442 | ||
505 | start = boot_mem_map.map[i].addr; | 443 | start = boot_mem_map.map[i].addr; |
506 | end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1; | 444 | end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1; |
507 | if (start >= MAXMEM) | 445 | if (start >= HIGHMEM_START) |
508 | continue; | 446 | continue; |
509 | if (end >= MAXMEM) | 447 | if (end >= HIGHMEM_START) |
510 | end = MAXMEM - 1; | 448 | end = HIGHMEM_START - 1; |
511 | 449 | ||
512 | res = alloc_bootmem(sizeof(struct resource)); | 450 | res = alloc_bootmem(sizeof(struct resource)); |
513 | switch (boot_mem_map.map[i].type) { | 451 | switch (boot_mem_map.map[i].type) { |
@@ -536,9 +474,6 @@ static inline void resource_init(void) | |||
536 | } | 474 | } |
537 | } | 475 | } |
538 | 476 | ||
539 | #undef MAXMEM | ||
540 | #undef MAXMEM_PFN | ||
541 | |||
542 | void __init setup_arch(char **cmdline_p) | 477 | void __init setup_arch(char **cmdline_p) |
543 | { | 478 | { |
544 | cpu_probe(); | 479 | cpu_probe(); |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 6b4d9be31615..b9d358e05214 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
@@ -424,15 +424,11 @@ void do_signal(struct pt_regs *regs) | |||
424 | if (!user_mode(regs)) | 424 | if (!user_mode(regs)) |
425 | return; | 425 | return; |
426 | 426 | ||
427 | if (try_to_freeze()) | ||
428 | goto no_signal; | ||
429 | |||
430 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 427 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
431 | oldset = ¤t->saved_sigmask; | 428 | oldset = ¤t->saved_sigmask; |
432 | else | 429 | else |
433 | oldset = ¤t->blocked; | 430 | oldset = ¤t->blocked; |
434 | 431 | ||
435 | |||
436 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 432 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
437 | if (signr > 0) { | 433 | if (signr > 0) { |
438 | /* Whee! Actually deliver the signal. */ | 434 | /* Whee! Actually deliver the signal. */ |
@@ -446,9 +442,10 @@ void do_signal(struct pt_regs *regs) | |||
446 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 442 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
447 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 443 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
448 | } | 444 | } |
445 | |||
446 | return; | ||
449 | } | 447 | } |
450 | 448 | ||
451 | no_signal: | ||
452 | /* | 449 | /* |
453 | * Who's code doesn't conform to the restartable syscall convention | 450 | * Who's code doesn't conform to the restartable syscall convention |
454 | * dies here!!! The li instruction, a single machine instruction, | 451 | * dies here!!! The li instruction, a single machine instruction, |
@@ -466,6 +463,7 @@ no_signal: | |||
466 | regs->regs[7] = regs->regs[26]; | 463 | regs->regs[7] = regs->regs[26]; |
467 | regs->cp0_epc -= 4; | 464 | regs->cp0_epc -= 4; |
468 | } | 465 | } |
466 | regs->regs[0] = 0; /* Don't deal with this again. */ | ||
469 | } | 467 | } |
470 | 468 | ||
471 | /* | 469 | /* |
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index f32a22997c3d..c86a5ddff050 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c | |||
@@ -815,9 +815,6 @@ void do_signal32(struct pt_regs *regs) | |||
815 | if (!user_mode(regs)) | 815 | if (!user_mode(regs)) |
816 | return; | 816 | return; |
817 | 817 | ||
818 | if (try_to_freeze()) | ||
819 | goto no_signal; | ||
820 | |||
821 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 818 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
822 | oldset = ¤t->saved_sigmask; | 819 | oldset = ¤t->saved_sigmask; |
823 | else | 820 | else |
@@ -836,9 +833,10 @@ void do_signal32(struct pt_regs *regs) | |||
836 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 833 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
837 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 834 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
838 | } | 835 | } |
836 | |||
837 | return; | ||
839 | } | 838 | } |
840 | 839 | ||
841 | no_signal: | ||
842 | /* | 840 | /* |
843 | * Who's code doesn't conform to the restartable syscall convention | 841 | * Who's code doesn't conform to the restartable syscall convention |
844 | * dies here!!! The li instruction, a single machine instruction, | 842 | * dies here!!! The li instruction, a single machine instruction, |
@@ -856,6 +854,7 @@ no_signal: | |||
856 | regs->regs[7] = regs->regs[26]; | 854 | regs->regs[7] = regs->regs[26]; |
857 | regs->cp0_epc -= 4; | 855 | regs->cp0_epc -= 4; |
858 | } | 856 | } |
857 | regs->regs[0] = 0; /* Don't deal with this again. */ | ||
859 | } | 858 | } |
860 | 859 | ||
861 | /* | 860 | /* |
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 93429a4d3012..766253c44f3f 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c | |||
@@ -203,7 +203,7 @@ void plat_smp_setup(void) | |||
203 | write_vpe_c0_config( read_c0_config()); | 203 | write_vpe_c0_config( read_c0_config()); |
204 | 204 | ||
205 | /* make sure there are no software interrupts pending */ | 205 | /* make sure there are no software interrupts pending */ |
206 | write_vpe_c0_cause(read_vpe_c0_cause() & ~(C_SW1|C_SW0)); | 206 | write_vpe_c0_cause(0); |
207 | 207 | ||
208 | /* Propagate Config7 */ | 208 | /* Propagate Config7 */ |
209 | write_vpe_c0_config7(read_c0_config7()); | 209 | write_vpe_c0_config7(read_c0_config7()); |
diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S index 4cc3dea36612..76cb31d57482 100644 --- a/arch/mips/kernel/smtc-asm.S +++ b/arch/mips/kernel/smtc-asm.S | |||
@@ -8,7 +8,7 @@ | |||
8 | #include <asm/regdef.h> | 8 | #include <asm/regdef.h> |
9 | #include <asm/asmmacro.h> | 9 | #include <asm/asmmacro.h> |
10 | #include <asm/stackframe.h> | 10 | #include <asm/stackframe.h> |
11 | #include <asm/stackframe.h> | 11 | #include <asm/irqflags.h> |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * "Software Interrupt" linkage. | 14 | * "Software Interrupt" linkage. |
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 0721314db657..9951240cc3fd 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c | |||
@@ -263,7 +263,7 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) | |||
263 | return error; | 263 | return error; |
264 | } | 264 | } |
265 | 265 | ||
266 | void sys_set_thread_area(unsigned long addr) | 266 | asmlinkage int sys_set_thread_area(unsigned long addr) |
267 | { | 267 | { |
268 | struct thread_info *ti = task_thread_info(current); | 268 | struct thread_info *ti = task_thread_info(current); |
269 | 269 | ||
@@ -271,6 +271,8 @@ void sys_set_thread_area(unsigned long addr) | |||
271 | 271 | ||
272 | /* If some future MIPS implementation has this register in hardware, | 272 | /* If some future MIPS implementation has this register in hardware, |
273 | * we will need to update it here (and in context switches). */ | 273 | * we will need to update it here (and in context switches). */ |
274 | |||
275 | return 0; | ||
274 | } | 276 | } |
275 | 277 | ||
276 | asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) | 278 | asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 954a198494ef..e51d8fd9a152 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/kallsyms.h> | 21 | #include <linux/kallsyms.h> |
22 | #include <linux/bootmem.h> | 22 | #include <linux/bootmem.h> |
23 | #include <linux/interrupt.h> | ||
23 | 24 | ||
24 | #include <asm/bootinfo.h> | 25 | #include <asm/bootinfo.h> |
25 | #include <asm/branch.h> | 26 | #include <asm/branch.h> |
@@ -72,28 +73,68 @@ void (*board_nmi_handler_setup)(void); | |||
72 | void (*board_ejtag_handler_setup)(void); | 73 | void (*board_ejtag_handler_setup)(void); |
73 | void (*board_bind_eic_interrupt)(int irq, int regset); | 74 | void (*board_bind_eic_interrupt)(int irq, int regset); |
74 | 75 | ||
75 | /* | 76 | |
76 | * These constant is for searching for possible module text segments. | 77 | static void show_raw_backtrace(unsigned long reg29) |
77 | * MODULE_RANGE is a guess of how much space is likely to be vmalloced. | 78 | { |
78 | */ | 79 | unsigned long *sp = (unsigned long *)reg29; |
79 | #define MODULE_RANGE (8*1024*1024) | 80 | unsigned long addr; |
81 | |||
82 | printk("Call Trace:"); | ||
83 | #ifdef CONFIG_KALLSYMS | ||
84 | printk("\n"); | ||
85 | #endif | ||
86 | while (!kstack_end(sp)) { | ||
87 | addr = *sp++; | ||
88 | if (__kernel_text_address(addr)) | ||
89 | print_ip_sym(addr); | ||
90 | } | ||
91 | printk("\n"); | ||
92 | } | ||
93 | |||
94 | #ifdef CONFIG_KALLSYMS | ||
95 | static int raw_show_trace; | ||
96 | static int __init set_raw_show_trace(char *str) | ||
97 | { | ||
98 | raw_show_trace = 1; | ||
99 | return 1; | ||
100 | } | ||
101 | __setup("raw_show_trace", set_raw_show_trace); | ||
102 | |||
103 | extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | ||
104 | unsigned long pc, unsigned long ra); | ||
105 | |||
106 | static void show_backtrace(struct task_struct *task, struct pt_regs *regs) | ||
107 | { | ||
108 | unsigned long sp = regs->regs[29]; | ||
109 | unsigned long ra = regs->regs[31]; | ||
110 | unsigned long pc = regs->cp0_epc; | ||
111 | |||
112 | if (raw_show_trace || !__kernel_text_address(pc)) { | ||
113 | show_raw_backtrace(sp); | ||
114 | return; | ||
115 | } | ||
116 | printk("Call Trace:\n"); | ||
117 | do { | ||
118 | print_ip_sym(pc); | ||
119 | pc = unwind_stack(task, &sp, pc, ra); | ||
120 | ra = 0; | ||
121 | } while (pc); | ||
122 | printk("\n"); | ||
123 | } | ||
124 | #else | ||
125 | #define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]); | ||
126 | #endif | ||
80 | 127 | ||
81 | /* | 128 | /* |
82 | * This routine abuses get_user()/put_user() to reference pointers | 129 | * This routine abuses get_user()/put_user() to reference pointers |
83 | * with at least a bit of error checking ... | 130 | * with at least a bit of error checking ... |
84 | */ | 131 | */ |
85 | void show_stack(struct task_struct *task, unsigned long *sp) | 132 | static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) |
86 | { | 133 | { |
87 | const int field = 2 * sizeof(unsigned long); | 134 | const int field = 2 * sizeof(unsigned long); |
88 | long stackdata; | 135 | long stackdata; |
89 | int i; | 136 | int i; |
90 | 137 | unsigned long *sp = (unsigned long *)regs->regs[29]; | |
91 | if (!sp) { | ||
92 | if (task && task != current) | ||
93 | sp = (unsigned long *) task->thread.reg29; | ||
94 | else | ||
95 | sp = (unsigned long *) &sp; | ||
96 | } | ||
97 | 138 | ||
98 | printk("Stack :"); | 139 | printk("Stack :"); |
99 | i = 0; | 140 | i = 0; |
@@ -114,32 +155,48 @@ void show_stack(struct task_struct *task, unsigned long *sp) | |||
114 | i++; | 155 | i++; |
115 | } | 156 | } |
116 | printk("\n"); | 157 | printk("\n"); |
158 | show_backtrace(task, regs); | ||
117 | } | 159 | } |
118 | 160 | ||
119 | void show_trace(struct task_struct *task, unsigned long *stack) | 161 | static __always_inline void prepare_frametrace(struct pt_regs *regs) |
120 | { | 162 | { |
121 | const int field = 2 * sizeof(unsigned long); | 163 | __asm__ __volatile__( |
122 | unsigned long addr; | 164 | ".set push\n\t" |
123 | 165 | ".set noat\n\t" | |
124 | if (!stack) { | 166 | #ifdef CONFIG_64BIT |
125 | if (task && task != current) | 167 | "1: dla $1, 1b\n\t" |
126 | stack = (unsigned long *) task->thread.reg29; | 168 | "sd $1, %0\n\t" |
127 | else | 169 | "sd $29, %1\n\t" |
128 | stack = (unsigned long *) &stack; | 170 | "sd $31, %2\n\t" |
129 | } | 171 | #else |
130 | 172 | "1: la $1, 1b\n\t" | |
131 | printk("Call Trace:"); | 173 | "sw $1, %0\n\t" |
132 | #ifdef CONFIG_KALLSYMS | 174 | "sw $29, %1\n\t" |
133 | printk("\n"); | 175 | "sw $31, %2\n\t" |
134 | #endif | 176 | #endif |
135 | while (!kstack_end(stack)) { | 177 | ".set pop\n\t" |
136 | addr = *stack++; | 178 | : "=m" (regs->cp0_epc), |
137 | if (__kernel_text_address(addr)) { | 179 | "=m" (regs->regs[29]), "=m" (regs->regs[31]) |
138 | printk(" [<%0*lx>] ", field, addr); | 180 | : : "memory"); |
139 | print_symbol("%s\n", addr); | 181 | } |
182 | |||
183 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
184 | { | ||
185 | struct pt_regs regs; | ||
186 | if (sp) { | ||
187 | regs.regs[29] = (unsigned long)sp; | ||
188 | regs.regs[31] = 0; | ||
189 | regs.cp0_epc = 0; | ||
190 | } else { | ||
191 | if (task && task != current) { | ||
192 | regs.regs[29] = task->thread.reg29; | ||
193 | regs.regs[31] = 0; | ||
194 | regs.cp0_epc = task->thread.reg31; | ||
195 | } else { | ||
196 | prepare_frametrace(®s); | ||
140 | } | 197 | } |
141 | } | 198 | } |
142 | printk("\n"); | 199 | show_stacktrace(task, ®s); |
143 | } | 200 | } |
144 | 201 | ||
145 | /* | 202 | /* |
@@ -147,9 +204,15 @@ void show_trace(struct task_struct *task, unsigned long *stack) | |||
147 | */ | 204 | */ |
148 | void dump_stack(void) | 205 | void dump_stack(void) |
149 | { | 206 | { |
150 | unsigned long stack; | 207 | struct pt_regs regs; |
151 | 208 | ||
152 | show_trace(current, &stack); | 209 | /* |
210 | * Remove any garbage that may be in regs (specially func | ||
211 | * addresses) to avoid show_raw_backtrace() to report them | ||
212 | */ | ||
213 | memset(®s, 0, sizeof(regs)); | ||
214 | prepare_frametrace(®s); | ||
215 | show_backtrace(current, ®s); | ||
153 | } | 216 | } |
154 | 217 | ||
155 | EXPORT_SYMBOL(dump_stack); | 218 | EXPORT_SYMBOL(dump_stack); |
@@ -268,8 +331,7 @@ void show_registers(struct pt_regs *regs) | |||
268 | print_modules(); | 331 | print_modules(); |
269 | printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", | 332 | printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", |
270 | current->comm, current->pid, current_thread_info(), current); | 333 | current->comm, current->pid, current_thread_info(), current); |
271 | show_stack(current, (long *) regs->regs[29]); | 334 | show_stacktrace(current, regs); |
272 | show_trace(current, (long *) regs->regs[29]); | ||
273 | show_code((unsigned int *) regs->cp0_epc); | 335 | show_code((unsigned int *) regs->cp0_epc); |
274 | printk("\n"); | 336 | printk("\n"); |
275 | } | 337 | } |
@@ -292,6 +354,16 @@ NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) | |||
292 | printk("%s[#%d]:\n", str, ++die_counter); | 354 | printk("%s[#%d]:\n", str, ++die_counter); |
293 | show_registers(regs); | 355 | show_registers(regs); |
294 | spin_unlock_irq(&die_lock); | 356 | spin_unlock_irq(&die_lock); |
357 | |||
358 | if (in_interrupt()) | ||
359 | panic("Fatal exception in interrupt"); | ||
360 | |||
361 | if (panic_on_oops) { | ||
362 | printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); | ||
363 | ssleep(5); | ||
364 | panic("Fatal exception"); | ||
365 | } | ||
366 | |||
295 | do_exit(SIGSEGV); | 367 | do_exit(SIGSEGV); |
296 | } | 368 | } |
297 | 369 | ||
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 9ee0ec2cd067..51ddd2166898 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c | |||
@@ -768,10 +768,16 @@ int vpe_run(struct vpe * v) | |||
768 | */ | 768 | */ |
769 | write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); | 769 | write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); |
770 | 770 | ||
771 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); | ||
772 | |||
773 | back_to_back_c0_hazard(); | ||
774 | |||
771 | /* Set up the XTC bit in vpeconf0 to point at our tc */ | 775 | /* Set up the XTC bit in vpeconf0 to point at our tc */ |
772 | write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) | 776 | write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) |
773 | | (t->index << VPECONF0_XTC_SHIFT)); | 777 | | (t->index << VPECONF0_XTC_SHIFT)); |
774 | 778 | ||
779 | back_to_back_c0_hazard(); | ||
780 | |||
775 | /* enable this VPE */ | 781 | /* enable this VPE */ |
776 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); | 782 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); |
777 | 783 | ||