diff options
| author | Steven Whitehouse <swhiteho@redhat.com> | 2006-09-28 08:29:59 -0400 |
|---|---|---|
| committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-09-28 08:29:59 -0400 |
| commit | 185a257f2f73bcd89050ad02da5bedbc28fc43fa (patch) | |
| tree | 5e32586114534ed3f2165614cba3d578f5d87307 /arch/mips/kernel | |
| parent | 3f1a9aaeffd8d1cbc5ab9776c45cbd66af1c9699 (diff) | |
| parent | a77c64c1a641950626181b4857abb701d8f38ccc (diff) | |
Merge branch 'master' into gfs2
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 | ||
