diff options
Diffstat (limited to 'arch/mips/kernel/process.c')
-rw-r--r-- | arch/mips/kernel/process.c | 166 |
1 files changed, 112 insertions, 54 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 44a6f25e902e..8c26ecac930d 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/cpu.h> | 32 | #include <asm/cpu.h> |
33 | #include <asm/dsp.h> | 33 | #include <asm/dsp.h> |
34 | #include <asm/fpu.h> | 34 | #include <asm/fpu.h> |
35 | #include <asm/irq.h> | ||
35 | #include <asm/msa.h> | 36 | #include <asm/msa.h> |
36 | #include <asm/pgtable.h> | 37 | #include <asm/pgtable.h> |
37 | #include <asm/mipsregs.h> | 38 | #include <asm/mipsregs.h> |
@@ -191,11 +192,9 @@ struct mips_frame_info { | |||
191 | #define J_TARGET(pc,target) \ | 192 | #define J_TARGET(pc,target) \ |
192 | (((unsigned long)(pc) & 0xf0000000) | ((target) << 2)) | 193 | (((unsigned long)(pc) & 0xf0000000) | ((target) << 2)) |
193 | 194 | ||
194 | static inline int is_ra_save_ins(union mips_instruction *ip) | 195 | static inline int is_ra_save_ins(union mips_instruction *ip, int *poff) |
195 | { | 196 | { |
196 | #ifdef CONFIG_CPU_MICROMIPS | 197 | #ifdef CONFIG_CPU_MICROMIPS |
197 | union mips_instruction mmi; | ||
198 | |||
199 | /* | 198 | /* |
200 | * swsp ra,offset | 199 | * swsp ra,offset |
201 | * swm16 reglist,offset(sp) | 200 | * swm16 reglist,offset(sp) |
@@ -205,29 +204,71 @@ static inline int is_ra_save_ins(union mips_instruction *ip) | |||
205 | * | 204 | * |
206 | * microMIPS is way more fun... | 205 | * microMIPS is way more fun... |
207 | */ | 206 | */ |
208 | if (mm_insn_16bit(ip->halfword[0])) { | 207 | if (mm_insn_16bit(ip->halfword[1])) { |
209 | mmi.word = (ip->halfword[0] << 16); | 208 | switch (ip->mm16_r5_format.opcode) { |
210 | return (mmi.mm16_r5_format.opcode == mm_swsp16_op && | 209 | case mm_swsp16_op: |
211 | mmi.mm16_r5_format.rt == 31) || | 210 | if (ip->mm16_r5_format.rt != 31) |
212 | (mmi.mm16_m_format.opcode == mm_pool16c_op && | 211 | return 0; |
213 | mmi.mm16_m_format.func == mm_swm16_op); | 212 | |
213 | *poff = ip->mm16_r5_format.simmediate; | ||
214 | *poff = (*poff << 2) / sizeof(ulong); | ||
215 | return 1; | ||
216 | |||
217 | case mm_pool16c_op: | ||
218 | switch (ip->mm16_m_format.func) { | ||
219 | case mm_swm16_op: | ||
220 | *poff = ip->mm16_m_format.imm; | ||
221 | *poff += 1 + ip->mm16_m_format.rlist; | ||
222 | *poff = (*poff << 2) / sizeof(ulong); | ||
223 | return 1; | ||
224 | |||
225 | default: | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | default: | ||
230 | return 0; | ||
231 | } | ||
214 | } | 232 | } |
215 | else { | 233 | |
216 | mmi.halfword[0] = ip->halfword[1]; | 234 | switch (ip->i_format.opcode) { |
217 | mmi.halfword[1] = ip->halfword[0]; | 235 | case mm_sw32_op: |
218 | return (mmi.mm_m_format.opcode == mm_pool32b_op && | 236 | if (ip->i_format.rs != 29) |
219 | mmi.mm_m_format.rd > 9 && | 237 | return 0; |
220 | mmi.mm_m_format.base == 29 && | 238 | if (ip->i_format.rt != 31) |
221 | mmi.mm_m_format.func == mm_swm32_func) || | 239 | return 0; |
222 | (mmi.i_format.opcode == mm_sw32_op && | 240 | |
223 | mmi.i_format.rs == 29 && | 241 | *poff = ip->i_format.simmediate / sizeof(ulong); |
224 | mmi.i_format.rt == 31); | 242 | return 1; |
243 | |||
244 | case mm_pool32b_op: | ||
245 | switch (ip->mm_m_format.func) { | ||
246 | case mm_swm32_func: | ||
247 | if (ip->mm_m_format.rd < 0x10) | ||
248 | return 0; | ||
249 | if (ip->mm_m_format.base != 29) | ||
250 | return 0; | ||
251 | |||
252 | *poff = ip->mm_m_format.simmediate; | ||
253 | *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32); | ||
254 | *poff /= sizeof(ulong); | ||
255 | return 1; | ||
256 | default: | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | default: | ||
261 | return 0; | ||
225 | } | 262 | } |
226 | #else | 263 | #else |
227 | /* sw / sd $ra, offset($sp) */ | 264 | /* sw / sd $ra, offset($sp) */ |
228 | return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && | 265 | if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && |
229 | ip->i_format.rs == 29 && | 266 | ip->i_format.rs == 29 && ip->i_format.rt == 31) { |
230 | ip->i_format.rt == 31; | 267 | *poff = ip->i_format.simmediate / sizeof(ulong); |
268 | return 1; | ||
269 | } | ||
270 | |||
271 | return 0; | ||
231 | #endif | 272 | #endif |
232 | } | 273 | } |
233 | 274 | ||
@@ -242,13 +283,16 @@ static inline int is_jump_ins(union mips_instruction *ip) | |||
242 | * | 283 | * |
243 | * microMIPS is kind of more fun... | 284 | * microMIPS is kind of more fun... |
244 | */ | 285 | */ |
245 | union mips_instruction mmi; | 286 | if (mm_insn_16bit(ip->halfword[1])) { |
246 | 287 | if ((ip->mm16_r5_format.opcode == mm_pool16c_op && | |
247 | mmi.word = (ip->halfword[0] << 16); | 288 | (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op)) |
289 | return 1; | ||
290 | return 0; | ||
291 | } | ||
248 | 292 | ||
249 | if ((mmi.mm16_r5_format.opcode == mm_pool16c_op && | 293 | if (ip->j_format.opcode == mm_j32_op) |
250 | (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) || | 294 | return 1; |
251 | ip->j_format.opcode == mm_jal32_op) | 295 | if (ip->j_format.opcode == mm_jal32_op) |
252 | return 1; | 296 | return 1; |
253 | if (ip->r_format.opcode != mm_pool32a_op || | 297 | if (ip->r_format.opcode != mm_pool32a_op || |
254 | ip->r_format.func != mm_pool32axf_op) | 298 | ip->r_format.func != mm_pool32axf_op) |
@@ -276,15 +320,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip) | |||
276 | * | 320 | * |
277 | * microMIPS is not more fun... | 321 | * microMIPS is not more fun... |
278 | */ | 322 | */ |
279 | if (mm_insn_16bit(ip->halfword[0])) { | 323 | if (mm_insn_16bit(ip->halfword[1])) { |
280 | union mips_instruction mmi; | 324 | return (ip->mm16_r3_format.opcode == mm_pool16d_op && |
281 | 325 | ip->mm16_r3_format.simmediate && mm_addiusp_func) || | |
282 | mmi.word = (ip->halfword[0] << 16); | 326 | (ip->mm16_r5_format.opcode == mm_pool16d_op && |
283 | return (mmi.mm16_r3_format.opcode == mm_pool16d_op && | 327 | ip->mm16_r5_format.rt == 29); |
284 | mmi.mm16_r3_format.simmediate && mm_addiusp_func) || | ||
285 | (mmi.mm16_r5_format.opcode == mm_pool16d_op && | ||
286 | mmi.mm16_r5_format.rt == 29); | ||
287 | } | 328 | } |
329 | |||
288 | return ip->mm_i_format.opcode == mm_addiu32_op && | 330 | return ip->mm_i_format.opcode == mm_addiu32_op && |
289 | ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29; | 331 | ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29; |
290 | #else | 332 | #else |
@@ -299,30 +341,36 @@ static inline int is_sp_move_ins(union mips_instruction *ip) | |||
299 | 341 | ||
300 | static int get_frame_info(struct mips_frame_info *info) | 342 | static int get_frame_info(struct mips_frame_info *info) |
301 | { | 343 | { |
302 | #ifdef CONFIG_CPU_MICROMIPS | 344 | bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS); |
303 | union mips_instruction *ip = (void *) (((char *) info->func) - 1); | 345 | union mips_instruction insn, *ip, *ip_end; |
304 | #else | 346 | const unsigned int max_insns = 128; |
305 | union mips_instruction *ip = info->func; | 347 | unsigned int i; |
306 | #endif | ||
307 | unsigned max_insns = info->func_size / sizeof(union mips_instruction); | ||
308 | unsigned i; | ||
309 | 348 | ||
310 | info->pc_offset = -1; | 349 | info->pc_offset = -1; |
311 | info->frame_size = 0; | 350 | info->frame_size = 0; |
312 | 351 | ||
352 | ip = (void *)msk_isa16_mode((ulong)info->func); | ||
313 | if (!ip) | 353 | if (!ip) |
314 | goto err; | 354 | goto err; |
315 | 355 | ||
316 | if (max_insns == 0) | 356 | ip_end = (void *)ip + info->func_size; |
317 | max_insns = 128U; /* unknown function size */ | ||
318 | max_insns = min(128U, max_insns); | ||
319 | 357 | ||
320 | for (i = 0; i < max_insns; i++, ip++) { | 358 | for (i = 0; i < max_insns && ip < ip_end; i++, ip++) { |
359 | if (is_mmips && mm_insn_16bit(ip->halfword[0])) { | ||
360 | insn.halfword[0] = 0; | ||
361 | insn.halfword[1] = ip->halfword[0]; | ||
362 | } else if (is_mmips) { | ||
363 | insn.halfword[0] = ip->halfword[1]; | ||
364 | insn.halfword[1] = ip->halfword[0]; | ||
365 | } else { | ||
366 | insn.word = ip->word; | ||
367 | } | ||
321 | 368 | ||
322 | if (is_jump_ins(ip)) | 369 | if (is_jump_ins(&insn)) |
323 | break; | 370 | break; |
371 | |||
324 | if (!info->frame_size) { | 372 | if (!info->frame_size) { |
325 | if (is_sp_move_ins(ip)) | 373 | if (is_sp_move_ins(&insn)) |
326 | { | 374 | { |
327 | #ifdef CONFIG_CPU_MICROMIPS | 375 | #ifdef CONFIG_CPU_MICROMIPS |
328 | if (mm_insn_16bit(ip->halfword[0])) | 376 | if (mm_insn_16bit(ip->halfword[0])) |
@@ -345,11 +393,9 @@ static int get_frame_info(struct mips_frame_info *info) | |||
345 | } | 393 | } |
346 | continue; | 394 | continue; |
347 | } | 395 | } |
348 | if (info->pc_offset == -1 && is_ra_save_ins(ip)) { | 396 | if (info->pc_offset == -1 && |
349 | info->pc_offset = | 397 | is_ra_save_ins(&insn, &info->pc_offset)) |
350 | ip->i_format.simmediate / sizeof(long); | ||
351 | break; | 398 | break; |
352 | } | ||
353 | } | 399 | } |
354 | if (info->frame_size && info->pc_offset >= 0) /* nested */ | 400 | if (info->frame_size && info->pc_offset >= 0) /* nested */ |
355 | return 0; | 401 | return 0; |
@@ -507,7 +553,19 @@ EXPORT_SYMBOL(unwind_stack_by_address); | |||
507 | unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | 553 | unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, |
508 | unsigned long pc, unsigned long *ra) | 554 | unsigned long pc, unsigned long *ra) |
509 | { | 555 | { |
510 | unsigned long stack_page = (unsigned long)task_stack_page(task); | 556 | unsigned long stack_page = 0; |
557 | int cpu; | ||
558 | |||
559 | for_each_possible_cpu(cpu) { | ||
560 | if (on_irq_stack(cpu, *sp)) { | ||
561 | stack_page = (unsigned long)irq_stack[cpu]; | ||
562 | break; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | if (!stack_page) | ||
567 | stack_page = (unsigned long)task_stack_page(task); | ||
568 | |||
511 | return unwind_stack_by_address(stack_page, sp, pc, ra); | 569 | return unwind_stack_by_address(stack_page, sp, pc, ra); |
512 | } | 570 | } |
513 | #endif | 571 | #endif |