| 442 | } |
| 443 | |
| 444 | void |
| 445 | do_el0_sync(struct thread *td, struct trapframe *frame) |
| 446 | { |
| 447 | pcpu_bp_harden bp_harden; |
| 448 | uint32_t exception; |
| 449 | uint64_t esr, far; |
| 450 | int dfsc; |
| 451 | |
| 452 | /* Check we have a sane environment when entering from userland */ |
| 453 | KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS, |
| 454 | ("Invalid pcpu address from userland: %p (tpidr %lx)", |
| 455 | get_pcpu(), READ_SPECIALREG(tpidr_el1))); |
| 456 | |
| 457 | esr = frame->tf_esr; |
| 458 | exception = ESR_ELx_EXCEPTION(esr); |
| 459 | switch (exception) { |
| 460 | case EXCP_INSN_ABORT_L: |
| 461 | far = READ_SPECIALREG(far_el1); |
| 462 | |
| 463 | /* |
| 464 | * Userspace may be trying to train the branch predictor to |
| 465 | * attack the kernel. If we are on a CPU affected by this |
| 466 | * call the handler to clear the branch predictor state. |
| 467 | */ |
| 468 | if (far > VM_MAXUSER_ADDRESS) { |
| 469 | bp_harden = PCPU_GET(bp_harden); |
| 470 | if (bp_harden != NULL) |
| 471 | bp_harden(); |
| 472 | } |
| 473 | break; |
| 474 | case EXCP_UNKNOWN: |
| 475 | case EXCP_DATA_ABORT_L: |
| 476 | case EXCP_DATA_ABORT: |
| 477 | case EXCP_WATCHPT_EL0: |
| 478 | far = READ_SPECIALREG(far_el1); |
| 479 | break; |
| 480 | } |
| 481 | intr_enable(); |
| 482 | |
| 483 | CTR4(KTR_TRAP, |
| 484 | "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td, esr, |
| 485 | frame->tf_elr, frame); |
| 486 | |
| 487 | switch (exception) { |
| 488 | case EXCP_FP_SIMD: |
| 489 | case EXCP_TRAP_FP: |
| 490 | #ifdef VFP |
| 491 | vfp_restore_state(); |
| 492 | #else |
| 493 | panic("VFP exception in userland"); |
| 494 | #endif |
| 495 | break; |
| 496 | case EXCP_SVC32: |
| 497 | case EXCP_SVC64: |
| 498 | svc_handler(td, frame); |
| 499 | break; |
| 500 | case EXCP_INSN_ABORT_L: |
| 501 | case EXCP_DATA_ABORT_L: |
nothing calls this directly
no test coverage detected