| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: trap.c,v 1.17.4.4 2021/01/01 12:58:35 martin Exp $ */ | | 1 | /* $NetBSD: trap.c,v 1.17.4.5 2021/01/01 13:14:29 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Matt Thomas of 3am Software Foundry. | | 8 | * by Matt Thomas of 3am Software Foundry. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -21,27 +21,27 @@ | | | @@ -21,27 +21,27 @@ |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | | | 33 | |
34 | __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.17.4.4 2021/01/01 12:58:35 martin Exp $"); | | 34 | __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.17.4.5 2021/01/01 13:14:29 martin Exp $"); |
35 | | | 35 | |
36 | #include "opt_arm_intr_impl.h" | | 36 | #include "opt_arm_intr_impl.h" |
37 | #include "opt_compat_netbsd32.h" | | 37 | #include "opt_compat_netbsd32.h" |
38 | #include "opt_dtrace.h" | | 38 | #include "opt_dtrace.h" |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/kauth.h> | | 41 | #include <sys/kauth.h> |
42 | #include <sys/types.h> | | 42 | #include <sys/types.h> |
43 | #include <sys/atomic.h> | | 43 | #include <sys/atomic.h> |
44 | #include <sys/cpu.h> | | 44 | #include <sys/cpu.h> |
45 | #ifdef KDB | | 45 | #ifdef KDB |
46 | #include <sys/kdb.h> | | 46 | #include <sys/kdb.h> |
47 | #endif | | 47 | #endif |
| @@ -78,26 +78,32 @@ __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.1 | | | @@ -78,26 +78,32 @@ __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.1 |
78 | #include <sys/dtrace_bsd.h> | | 78 | #include <sys/dtrace_bsd.h> |
79 | #endif | | 79 | #endif |
80 | | | 80 | |
81 | #ifdef DDB | | 81 | #ifdef DDB |
82 | int sigill_debug = 0; | | 82 | int sigill_debug = 0; |
83 | #endif | | 83 | #endif |
84 | | | 84 | |
85 | #ifdef KDTRACE_HOOKS | | 85 | #ifdef KDTRACE_HOOKS |
86 | dtrace_doubletrap_func_t dtrace_doubletrap_func = NULL; | | 86 | dtrace_doubletrap_func_t dtrace_doubletrap_func = NULL; |
87 | dtrace_trap_func_t dtrace_trap_func = NULL; | | 87 | dtrace_trap_func_t dtrace_trap_func = NULL; |
88 | int (*dtrace_invop_jump_addr)(struct trapframe *); | | 88 | int (*dtrace_invop_jump_addr)(struct trapframe *); |
89 | #endif | | 89 | #endif |
90 | | | 90 | |
| | | 91 | enum emul_arm_result { |
| | | 92 | EMUL_ARM_SUCCESS = 0, |
| | | 93 | EMUL_ARM_UNKNOWN, |
| | | 94 | EMUL_ARM_FAULT, |
| | | 95 | }; |
| | | 96 | |
91 | const char * const trap_names[] = { | | 97 | const char * const trap_names[] = { |
92 | [ESR_EC_UNKNOWN] = "Unknown Reason (Illegal Instruction)", | | 98 | [ESR_EC_UNKNOWN] = "Unknown Reason (Illegal Instruction)", |
93 | [ESR_EC_SERROR] = "SError Interrupt", | | 99 | [ESR_EC_SERROR] = "SError Interrupt", |
94 | [ESR_EC_WFX] = "WFI or WFE instruction execution", | | 100 | [ESR_EC_WFX] = "WFI or WFE instruction execution", |
95 | [ESR_EC_ILL_STATE] = "Illegal Execution State", | | 101 | [ESR_EC_ILL_STATE] = "Illegal Execution State", |
96 | | | 102 | |
97 | [ESR_EC_SYS_REG] = "MSR/MRS/SYS instruction", | | 103 | [ESR_EC_SYS_REG] = "MSR/MRS/SYS instruction", |
98 | [ESR_EC_SVC_A64] = "SVC Instruction Execution", | | 104 | [ESR_EC_SVC_A64] = "SVC Instruction Execution", |
99 | [ESR_EC_HVC_A64] = "HVC Instruction Execution", | | 105 | [ESR_EC_HVC_A64] = "HVC Instruction Execution", |
100 | [ESR_EC_SMC_A64] = "SMC Instruction Execution", | | 106 | [ESR_EC_SMC_A64] = "SMC Instruction Execution", |
101 | | | 107 | |
102 | [ESR_EC_INSN_ABT_EL0] = "Instruction Abort (EL0)", | | 108 | [ESR_EC_INSN_ABT_EL0] = "Instruction Abort (EL0)", |
103 | [ESR_EC_INSN_ABT_EL1] = "Instruction Abort (EL1)", | | 109 | [ESR_EC_INSN_ABT_EL1] = "Instruction Abort (EL1)", |
| @@ -346,131 +352,177 @@ interrupt(struct trapframe *tf) | | | @@ -346,131 +352,177 @@ interrupt(struct trapframe *tf) |
346 | ci->ci_intr_depth--; | | 352 | ci->ci_intr_depth--; |
347 | | | 353 | |
348 | cpu_dosoftints(); | | 354 | cpu_dosoftints(); |
349 | } | | 355 | } |
350 | | | 356 | |
351 | #ifdef COMPAT_NETBSD32 | | 357 | #ifdef COMPAT_NETBSD32 |
352 | | | 358 | |
353 | /* | | 359 | /* |
354 | * 32-bit length Thumb instruction. See ARMv7 DDI0406A A6.3. | | 360 | * 32-bit length Thumb instruction. See ARMv7 DDI0406A A6.3. |
355 | */ | | 361 | */ |
356 | #define THUMB_32BIT(hi) (((hi) & 0xe000) == 0xe000 && ((hi) & 0x1800)) | | 362 | #define THUMB_32BIT(hi) (((hi) & 0xe000) == 0xe000 && ((hi) & 0x1800)) |
357 | | | 363 | |
358 | static int | | 364 | static int |
359 | fetch_arm_insn(struct trapframe *tf, uint32_t *insn) | | 365 | fetch_arm_insn(uint64_t pc, uint64_t spsr, uint32_t *insn) |
360 | { | | 366 | { |
361 | | | 367 | |
362 | /* THUMB? */ | | 368 | /* THUMB? */ |
363 | if (tf->tf_spsr & SPSR_A32_T) { | | 369 | if (spsr & SPSR_A32_T) { |
364 | uint16_t *pc = (uint16_t *)(tf->tf_pc & ~1UL); /* XXX */ | | 370 | uint16_t *p = (uint16_t *)(pc & ~1UL); /* XXX */ |
365 | uint16_t hi, lo; | | 371 | uint16_t hi, lo; |
366 | | | 372 | |
367 | if (ufetch_16(pc, &hi)) | | 373 | if (ufetch_16(p, &hi)) |
368 | return -1; | | 374 | return -1; |
369 | | | 375 | |
370 | if (!THUMB_32BIT(hi)) { | | 376 | if (!THUMB_32BIT(hi)) { |
371 | /* 16-bit Thumb instruction */ | | 377 | /* 16-bit Thumb instruction */ |
372 | *insn = hi; | | 378 | *insn = hi; |
373 | return 2; | | 379 | return 2; |
374 | } | | 380 | } |
375 | | | 381 | |
376 | /* 32-bit Thumb instruction */ | | 382 | /* 32-bit Thumb instruction */ |
377 | if (ufetch_16(pc + 1, &lo)) | | 383 | if (ufetch_16(p + 1, &lo)) |
378 | return -1; | | 384 | return -1; |
379 | | | 385 | |
380 | *insn = ((uint32_t)hi << 16) | lo; | | 386 | *insn = ((uint32_t)hi << 16) | lo; |
381 | return 4; | | 387 | return 4; |
382 | } | | 388 | } |
383 | | | 389 | |
384 | if (ufetch_32((uint32_t *)tf->tf_pc, insn)) | | 390 | if (ufetch_32((uint32_t *)pc, insn)) |
385 | return -1; | | 391 | return -1; |
386 | | | 392 | |
387 | return 4; | | 393 | return 4; |
388 | } | | 394 | } |
389 | | | 395 | |
390 | enum emul_arm_result { | | 396 | static bool |
391 | EMUL_ARM_SUCCESS = 0, | | 397 | arm_cond_match(uint32_t insn, uint64_t spsr) |
392 | EMUL_ARM_UNKNOWN, | | 398 | { |
393 | EMUL_ARM_FAULT, | | 399 | bool invert = (insn >> 28) & 1; |
394 | }; | | 400 | bool match; |
| | | 401 | |
| | | 402 | switch (insn >> 29) { |
| | | 403 | case 0: /* EQ or NE */ |
| | | 404 | match = spsr & SPSR_Z; |
| | | 405 | break; |
| | | 406 | case 1: /* CS/HI or CC/LO */ |
| | | 407 | match = spsr & SPSR_C; |
| | | 408 | break; |
| | | 409 | case 2: /* MI or PL */ |
| | | 410 | match = spsr & SPSR_N; |
| | | 411 | break; |
| | | 412 | case 3: /* VS or VC */ |
| | | 413 | match = spsr & SPSR_V; |
| | | 414 | break; |
| | | 415 | case 4: /* HI or LS */ |
| | | 416 | match = ((spsr & (SPSR_C | SPSR_Z)) == SPSR_C); |
| | | 417 | break; |
| | | 418 | case 5: /* GE or LT */ |
| | | 419 | match = (!(spsr & SPSR_N) == !(spsr & SPSR_V)); |
| | | 420 | break; |
| | | 421 | case 6: /* GT or LE */ |
| | | 422 | match = !(spsr & SPSR_Z) && |
| | | 423 | (!(spsr & SPSR_N) == !(spsr & SPSR_V)); |
| | | 424 | break; |
| | | 425 | case 7: /* AL */ |
| | | 426 | match = true; |
| | | 427 | break; |
| | | 428 | } |
| | | 429 | return (!match != !invert); |
| | | 430 | } |
| | | 431 | |
| | | 432 | static enum emul_arm_result |
| | | 433 | emul_thumb_insn(struct trapframe *tf, uint32_t insn, int insn_size) |
| | | 434 | { |
| | | 435 | /* T32-16bit or 32bit instructions */ |
| | | 436 | switch (insn_size) { |
| | | 437 | case 2: |
| | | 438 | /* Breakpoint used by GDB */ |
| | | 439 | if (insn == 0xdefe) { |
| | | 440 | do_trapsignal(curlwp, SIGTRAP, TRAP_BRKPT, |
| | | 441 | (void *)tf->tf_pc, 0); |
| | | 442 | return EMUL_ARM_SUCCESS; |
| | | 443 | } |
| | | 444 | /* XXX: some T32 IT instruction deprecated should be emulated */ |
| | | 445 | break; |
| | | 446 | case 4: |
| | | 447 | break; |
| | | 448 | default: |
| | | 449 | return EMUL_ARM_FAULT; |
| | | 450 | } |
| | | 451 | return EMUL_ARM_UNKNOWN; |
| | | 452 | } |
395 | | | 453 | |
396 | static enum emul_arm_result | | 454 | static enum emul_arm_result |
397 | emul_arm_insn(struct trapframe *tf) | | 455 | emul_arm_insn(struct trapframe *tf) |
398 | { | | 456 | { |
399 | struct lwp * const l = curlwp; | | | |
400 | uint32_t insn; | | 457 | uint32_t insn; |
401 | int insn_size; | | 458 | int insn_size; |
402 | | | 459 | |
403 | insn_size = fetch_arm_insn(tf, &insn); | | 460 | insn_size = fetch_arm_insn(tf->tf_pc, tf->tf_spsr, &insn); |
| | | 461 | tf->tf_far = reg_far_el1_read(); |
404 | | | 462 | |
405 | switch (insn_size) { | | 463 | if (tf->tf_spsr & SPSR_A32_T) |
406 | case 2: | | 464 | return emul_thumb_insn(tf, insn, insn_size); |
407 | /* T32-16bit instruction */ | | 465 | if (insn_size != 4) |
408 | | | 466 | return EMUL_ARM_FAULT; |
409 | /* | | | |
410 | * Breakpoint used by GDB. | | | |
411 | */ | | | |
412 | if (insn == 0xdefe) | | | |
413 | goto trap; | | | |
414 | | | 467 | |
415 | /* XXX: some T32 IT instruction deprecated should be emulated */ | | 468 | /* Breakpoint used by GDB */ |
416 | break; | | 469 | if (insn == 0xe6000011 || insn == 0xe7ffdefe) { |
417 | case 4: | | 470 | do_trapsignal(curlwp, SIGTRAP, TRAP_BRKPT, |
418 | /* T32-32bit instruction, or A32 instruction */ | | 471 | (void *)tf->tf_pc, 0); |
| | | 472 | return EMUL_ARM_SUCCESS; |
| | | 473 | } |
419 | | | 474 | |
420 | /* | | 475 | /* Unconditional instruction extension space? */ |
421 | * Breakpoint used by GDB. | | 476 | if ((insn & 0xf0000000) == 0xf0000000) |
422 | */ | | 477 | goto unknown_insn; |
423 | if (insn == 0xe6000011 || insn == 0xe7ffdefe) { | | | |
424 | trap: | | | |
425 | do_trapsignal(l, SIGTRAP, TRAP_BRKPT, | | | |
426 | (void *)tf->tf_pc, 0); | | | |
427 | return 0; | | | |
428 | } | | | |
429 | | | 478 | |
430 | /* | | 479 | /* |
431 | * Emulate ARMv6 instructions with cache operations | | 480 | * Emulate ARMv6 instructions with cache operations |
432 | * register (c7), that can be used in user mode. | | 481 | * register (c7), that can be used in user mode. |
433 | */ | | 482 | */ |
434 | switch (insn & 0x0fff0fff) { | | 483 | switch (insn & 0x0fff0fff) { |
435 | case 0x0e070f95: | | 484 | case 0x0e070f95: |
| | | 485 | if (arm_cond_match(insn, tf->tf_spsr)) { |
436 | /* | | 486 | /* |
437 | * mcr p15, 0, <Rd>, c7, c5, 4 | | 487 | * mcr p15, 0, <Rd>, c7, c5, 4 |
438 | * (flush prefetch buffer) | | 488 | * (flush prefetch buffer) |
439 | */ | | 489 | */ |
440 | __asm __volatile("isb sy" ::: "memory"); | | 490 | __asm __volatile("isb sy" ::: "memory"); |
441 | goto emulated; | | 491 | } |
442 | case 0x0e070f9a: | | 492 | goto emulated; |
| | | 493 | case 0x0e070f9a: |
| | | 494 | if (arm_cond_match(insn, tf->tf_spsr)) { |
443 | /* | | 495 | /* |
444 | * mcr p15, 0, <Rd>, c7, c10, 4 | | 496 | * mcr p15, 0, <Rd>, c7, c10, 4 |
445 | * (data synchronization barrier) | | 497 | * (data synchronization barrier) |
446 | */ | | 498 | */ |
447 | __asm __volatile("dsb sy" ::: "memory"); | | 499 | __asm __volatile("dsb sy" ::: "memory"); |
448 | goto emulated; | | 500 | } |
449 | case 0x0e070fba: | | 501 | goto emulated; |
| | | 502 | case 0x0e070fba: |
| | | 503 | if (arm_cond_match(insn, tf->tf_spsr)) { |
450 | /* | | 504 | /* |
451 | * mcr p15, 0, <Rd>, c7, c10, 5 | | 505 | * mcr p15, 0, <Rd>, c7, c10, 5 |
452 | * (data memory barrier) | | 506 | * (data memory barrier) |
453 | */ | | 507 | */ |
454 | __asm __volatile("dmb sy" ::: "memory"); | | 508 | __asm __volatile("dmb sy" ::: "memory"); |
455 | goto emulated; | | | |
456 | default: | | | |
457 | break; | | | |
458 | } | | 509 | } |
459 | break; | | 510 | goto emulated; |
460 | default: | | 511 | default: |
461 | return EMUL_ARM_FAULT; | | 512 | break; |
462 | } | | 513 | } |
463 | | | 514 | |
| | | 515 | unknown_insn: |
464 | /* unknown, or unsupported instruction */ | | 516 | /* unknown, or unsupported instruction */ |
465 | return EMUL_ARM_UNKNOWN; | | 517 | return EMUL_ARM_UNKNOWN; |
466 | | | 518 | |
467 | emulated: | | 519 | emulated: |
468 | tf->tf_pc += insn_size; | | 520 | tf->tf_pc += insn_size; |
469 | return EMUL_ARM_SUCCESS; | | 521 | return EMUL_ARM_SUCCESS; |
470 | } | | 522 | } |
471 | #endif /* COMPAT_NETBSD32 */ | | 523 | #endif /* COMPAT_NETBSD32 */ |
472 | | | 524 | |
473 | void | | 525 | void |
474 | trap_el0_32sync(struct trapframe *tf) | | 526 | trap_el0_32sync(struct trapframe *tf) |
475 | { | | 527 | { |
476 | struct lwp * const l = curlwp; | | 528 | struct lwp * const l = curlwp; |
| @@ -515,27 +567,27 @@ trap_el0_32sync(struct trapframe *tf) | | | @@ -515,27 +567,27 @@ trap_el0_32sync(struct trapframe *tf) |
515 | case ESR_EC_BKPT_INSN_A32: | | 567 | case ESR_EC_BKPT_INSN_A32: |
516 | do_trapsignal(l, SIGTRAP, TRAP_BRKPT, (void *)tf->tf_pc, esr); | | 568 | do_trapsignal(l, SIGTRAP, TRAP_BRKPT, (void *)tf->tf_pc, esr); |
517 | userret(l); | | 569 | userret(l); |
518 | break; | | 570 | break; |
519 | | | 571 | |
520 | case ESR_EC_UNKNOWN: | | 572 | case ESR_EC_UNKNOWN: |
521 | switch (emul_arm_insn(tf)) { | | 573 | switch (emul_arm_insn(tf)) { |
522 | case EMUL_ARM_SUCCESS: | | 574 | case EMUL_ARM_SUCCESS: |
523 | break; | | 575 | break; |
524 | case EMUL_ARM_UNKNOWN: | | 576 | case EMUL_ARM_UNKNOWN: |
525 | goto unknown; | | 577 | goto unknown; |
526 | case EMUL_ARM_FAULT: | | 578 | case EMUL_ARM_FAULT: |
527 | do_trapsignal(l, SIGSEGV, SEGV_MAPERR, | | 579 | do_trapsignal(l, SIGSEGV, SEGV_MAPERR, |
528 | (void *)tf->tf_pc, esr); | | 580 | (void *)tf->tf_far, esr); |
529 | break; | | 581 | break; |
530 | } | | 582 | } |
531 | userret(l); | | 583 | userret(l); |
532 | break; | | 584 | break; |
533 | | | 585 | |
534 | case ESR_EC_CP15_RT: | | 586 | case ESR_EC_CP15_RT: |
535 | case ESR_EC_CP15_RRT: | | 587 | case ESR_EC_CP15_RRT: |
536 | case ESR_EC_CP14_RT: | | 588 | case ESR_EC_CP14_RT: |
537 | case ESR_EC_CP14_DT: | | 589 | case ESR_EC_CP14_DT: |
538 | case ESR_EC_CP14_RRT: | | 590 | case ESR_EC_CP14_RRT: |
539 | unknown: | | 591 | unknown: |
540 | #endif /* COMPAT_NETBSD32 */ | | 592 | #endif /* COMPAT_NETBSD32 */ |
541 | default: | | 593 | default: |