Fri Jan 1 13:14:29 2021 UTC ()
Pull up following revision(s) (requested by rin in ticket #1175):

	sys/arch/aarch64/aarch64/trap.c: revision 1.28,1.31,1.32 (patch)

- add support conditionally execution for A32 instruction emulation
- separated the processing of ARM and THUMB emul clearly. do not confuse the Thumb-32bit instruction with the ARM instruction.
- use far_el1 instead of tf_pc to return correct fault address when instruction emulation


(martin)
diff -r1.17.4.4 -r1.17.4.5 src/sys/arch/aarch64/aarch64/trap.c

cvs diff -r1.17.4.4 -r1.17.4.5 src/sys/arch/aarch64/aarch64/trap.c (expand / switch to unified diff)

--- src/sys/arch/aarch64/aarch64/trap.c 2021/01/01 12:58:35 1.17.4.4
+++ src/sys/arch/aarch64/aarch64/trap.c 2021/01/01 13:14:29 1.17.4.5
@@ -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
82int sigill_debug = 0; 82int sigill_debug = 0;
83#endif 83#endif
84 84
85#ifdef KDTRACE_HOOKS 85#ifdef KDTRACE_HOOKS
86dtrace_doubletrap_func_t dtrace_doubletrap_func = NULL; 86dtrace_doubletrap_func_t dtrace_doubletrap_func = NULL;
87dtrace_trap_func_t dtrace_trap_func = NULL; 87dtrace_trap_func_t dtrace_trap_func = NULL;
88int (*dtrace_invop_jump_addr)(struct trapframe *); 88int (*dtrace_invop_jump_addr)(struct trapframe *);
89#endif 89#endif
90 90
 91enum emul_arm_result {
 92 EMUL_ARM_SUCCESS = 0,
 93 EMUL_ARM_UNKNOWN,
 94 EMUL_ARM_FAULT,
 95};
 96
91const char * const trap_names[] = { 97const 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
358static int 364static int
359fetch_arm_insn(struct trapframe *tf, uint32_t *insn) 365fetch_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
390enum emul_arm_result { 396static bool
391 EMUL_ARM_SUCCESS = 0, 397arm_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
 432static enum emul_arm_result
 433emul_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
396static enum emul_arm_result 454static enum emul_arm_result
397emul_arm_insn(struct trapframe *tf) 455emul_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
473void 525void
474trap_el0_32sync(struct trapframe *tf) 526trap_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:
539unknown: 591unknown:
540#endif /* COMPAT_NETBSD32 */ 592#endif /* COMPAT_NETBSD32 */
541 default: 593 default: