linux/arch/arm64/kernel/armv8_deprecated.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2014 ARM Limited
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/cpu.h>
  10#include <linux/init.h>
  11#include <linux/list.h>
  12#include <linux/perf_event.h>
  13#include <linux/sched.h>
  14#include <linux/slab.h>
  15#include <linux/sysctl.h>
  16
  17#include <asm/alternative.h>
  18#include <asm/cpufeature.h>
  19#include <asm/insn.h>
  20#include <asm/opcodes.h>
  21#include <asm/sysreg.h>
  22#include <asm/system_misc.h>
  23#include <asm/traps.h>
  24#include <asm/uaccess.h>
  25#include <asm/cpufeature.h>
  26
  27#define CREATE_TRACE_POINTS
  28#include "trace-events-emulation.h"
  29
  30/*
  31 * The runtime support for deprecated instruction support can be in one of
  32 * following three states -
  33 *
  34 * 0 = undef
  35 * 1 = emulate (software emulation)
  36 * 2 = hw (supported in hardware)
  37 */
  38enum insn_emulation_mode {
  39        INSN_UNDEF,
  40        INSN_EMULATE,
  41        INSN_HW,
  42};
  43
  44enum legacy_insn_status {
  45        INSN_DEPRECATED,
  46        INSN_OBSOLETE,
  47};
  48
  49struct insn_emulation_ops {
  50        const char              *name;
  51        enum legacy_insn_status status;
  52        struct undef_hook       *hooks;
  53        int                     (*set_hw_mode)(bool enable);
  54};
  55
  56struct insn_emulation {
  57        struct list_head node;
  58        struct insn_emulation_ops *ops;
  59        int current_mode;
  60        int min;
  61        int max;
  62};
  63
  64static LIST_HEAD(insn_emulation);
  65static int nr_insn_emulated __initdata;
  66static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
  67
  68static void register_emulation_hooks(struct insn_emulation_ops *ops)
  69{
  70        struct undef_hook *hook;
  71
  72        BUG_ON(!ops->hooks);
  73
  74        for (hook = ops->hooks; hook->instr_mask; hook++)
  75                register_undef_hook(hook);
  76
  77        pr_notice("Registered %s emulation handler\n", ops->name);
  78}
  79
  80static void remove_emulation_hooks(struct insn_emulation_ops *ops)
  81{
  82        struct undef_hook *hook;
  83
  84        BUG_ON(!ops->hooks);
  85
  86        for (hook = ops->hooks; hook->instr_mask; hook++)
  87                unregister_undef_hook(hook);
  88
  89        pr_notice("Removed %s emulation handler\n", ops->name);
  90}
  91
  92static void enable_insn_hw_mode(void *data)
  93{
  94        struct insn_emulation *insn = (struct insn_emulation *)data;
  95        if (insn->ops->set_hw_mode)
  96                insn->ops->set_hw_mode(true);
  97}
  98
  99static void disable_insn_hw_mode(void *data)
 100{
 101        struct insn_emulation *insn = (struct insn_emulation *)data;
 102        if (insn->ops->set_hw_mode)
 103                insn->ops->set_hw_mode(false);
 104}
 105
 106/* Run set_hw_mode(mode) on all active CPUs */
 107static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable)
 108{
 109        if (!insn->ops->set_hw_mode)
 110                return -EINVAL;
 111        if (enable)
 112                on_each_cpu(enable_insn_hw_mode, (void *)insn, true);
 113        else
 114                on_each_cpu(disable_insn_hw_mode, (void *)insn, true);
 115        return 0;
 116}
 117
 118/*
 119 * Run set_hw_mode for all insns on a starting CPU.
 120 * Returns:
 121 *  0           - If all the hooks ran successfully.
 122 * -EINVAL      - At least one hook is not supported by the CPU.
 123 */
 124static int run_all_insn_set_hw_mode(unsigned long cpu)
 125{
 126        int rc = 0;
 127        unsigned long flags;
 128        struct insn_emulation *insn;
 129
 130        raw_spin_lock_irqsave(&insn_emulation_lock, flags);
 131        list_for_each_entry(insn, &insn_emulation, node) {
 132                bool enable = (insn->current_mode == INSN_HW);
 133                if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(enable)) {
 134                        pr_warn("CPU[%ld] cannot support the emulation of %s",
 135                                cpu, insn->ops->name);
 136                        rc = -EINVAL;
 137                }
 138        }
 139        raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
 140        return rc;
 141}
 142
 143static int update_insn_emulation_mode(struct insn_emulation *insn,
 144                                       enum insn_emulation_mode prev)
 145{
 146        int ret = 0;
 147
 148        switch (prev) {
 149        case INSN_UNDEF: /* Nothing to be done */
 150                break;
 151        case INSN_EMULATE:
 152                remove_emulation_hooks(insn->ops);
 153                break;
 154        case INSN_HW:
 155                if (!run_all_cpu_set_hw_mode(insn, false))
 156                        pr_notice("Disabled %s support\n", insn->ops->name);
 157                break;
 158        }
 159
 160        switch (insn->current_mode) {
 161        case INSN_UNDEF:
 162                break;
 163        case INSN_EMULATE:
 164                register_emulation_hooks(insn->ops);
 165                break;
 166        case INSN_HW:
 167                ret = run_all_cpu_set_hw_mode(insn, true);
 168                if (!ret)
 169                        pr_notice("Enabled %s support\n", insn->ops->name);
 170                break;
 171        }
 172
 173        return ret;
 174}
 175
 176static void __init register_insn_emulation(struct insn_emulation_ops *ops)
 177{
 178        unsigned long flags;
 179        struct insn_emulation *insn;
 180
 181        insn = kzalloc(sizeof(*insn), GFP_KERNEL);
 182        insn->ops = ops;
 183        insn->min = INSN_UNDEF;
 184
 185        switch (ops->status) {
 186        case INSN_DEPRECATED:
 187                insn->current_mode = INSN_EMULATE;
 188                /* Disable the HW mode if it was turned on at early boot time */
 189                run_all_cpu_set_hw_mode(insn, false);
 190                insn->max = INSN_HW;
 191                break;
 192        case INSN_OBSOLETE:
 193                insn->current_mode = INSN_UNDEF;
 194                insn->max = INSN_EMULATE;
 195                break;
 196        }
 197
 198        raw_spin_lock_irqsave(&insn_emulation_lock, flags);
 199        list_add(&insn->node, &insn_emulation);
 200        nr_insn_emulated++;
 201        raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
 202
 203        /* Register any handlers if required */
 204        update_insn_emulation_mode(insn, INSN_UNDEF);
 205}
 206
 207static int emulation_proc_handler(struct ctl_table *table, int write,
 208                                  void __user *buffer, size_t *lenp,
 209                                  loff_t *ppos)
 210{
 211        int ret = 0;
 212        struct insn_emulation *insn = (struct insn_emulation *) table->data;
 213        enum insn_emulation_mode prev_mode = insn->current_mode;
 214
 215        table->data = &insn->current_mode;
 216        ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 217
 218        if (ret || !write || prev_mode == insn->current_mode)
 219                goto ret;
 220
 221        ret = update_insn_emulation_mode(insn, prev_mode);
 222        if (ret) {
 223                /* Mode change failed, revert to previous mode. */
 224                insn->current_mode = prev_mode;
 225                update_insn_emulation_mode(insn, INSN_UNDEF);
 226        }
 227ret:
 228        table->data = insn;
 229        return ret;
 230}
 231
 232static struct ctl_table ctl_abi[] = {
 233        {
 234                .procname = "abi",
 235                .mode = 0555,
 236        },
 237        { }
 238};
 239
 240static void __init register_insn_emulation_sysctl(struct ctl_table *table)
 241{
 242        unsigned long flags;
 243        int i = 0;
 244        struct insn_emulation *insn;
 245        struct ctl_table *insns_sysctl, *sysctl;
 246
 247        insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1),
 248                              GFP_KERNEL);
 249
 250        raw_spin_lock_irqsave(&insn_emulation_lock, flags);
 251        list_for_each_entry(insn, &insn_emulation, node) {
 252                sysctl = &insns_sysctl[i];
 253
 254                sysctl->mode = 0644;
 255                sysctl->maxlen = sizeof(int);
 256
 257                sysctl->procname = insn->ops->name;
 258                sysctl->data = insn;
 259                sysctl->extra1 = &insn->min;
 260                sysctl->extra2 = &insn->max;
 261                sysctl->proc_handler = emulation_proc_handler;
 262                i++;
 263        }
 264        raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
 265
 266        table->child = insns_sysctl;
 267        register_sysctl_table(table);
 268}
 269
 270/*
 271 *  Implement emulation of the SWP/SWPB instructions using load-exclusive and
 272 *  store-exclusive.
 273 *
 274 *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
 275 *  Where: Rt  = destination
 276 *         Rt2 = source
 277 *         Rn  = address
 278 */
 279
 280/*
 281 * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
 282 */
 283#define __user_swpX_asm(data, addr, res, temp, B)               \
 284        __asm__ __volatile__(                                   \
 285        ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN,    \
 286                    CONFIG_ARM64_PAN)                           \
 287        "0:     ldxr"B"         %w2, [%3]\n"                    \
 288        "1:     stxr"B"         %w0, %w1, [%3]\n"               \
 289        "       cbz             %w0, 2f\n"                      \
 290        "       mov             %w0, %w4\n"                     \
 291        "       b               3f\n"                           \
 292        "2:\n"                                                  \
 293        "       mov             %w1, %w2\n"                     \
 294        "3:\n"                                                  \
 295        "       .pushsection     .fixup,\"ax\"\n"               \
 296        "       .align          2\n"                            \
 297        "4:     mov             %w0, %w5\n"                     \
 298        "       b               3b\n"                           \
 299        "       .popsection"                                    \
 300        _ASM_EXTABLE(0b, 4b)                                    \
 301        _ASM_EXTABLE(1b, 4b)                                    \
 302        ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,    \
 303                CONFIG_ARM64_PAN)                               \
 304        : "=&r" (res), "+r" (data), "=&r" (temp)                \
 305        : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)              \
 306        : "memory")
 307
 308#define __user_swp_asm(data, addr, res, temp) \
 309        __user_swpX_asm(data, addr, res, temp, "")
 310#define __user_swpb_asm(data, addr, res, temp) \
 311        __user_swpX_asm(data, addr, res, temp, "b")
 312
 313/*
 314 * Bit 22 of the instruction encoding distinguishes between
 315 * the SWP and SWPB variants (bit set means SWPB).
 316 */
 317#define TYPE_SWPB (1 << 22)
 318
 319/*
 320 * Set up process info to signal segmentation fault - called on access error.
 321 */
 322static void set_segfault(struct pt_regs *regs, unsigned long addr)
 323{
 324        siginfo_t info;
 325
 326        down_read(&current->mm->mmap_sem);
 327        if (find_vma(current->mm, addr) == NULL)
 328                info.si_code = SEGV_MAPERR;
 329        else
 330                info.si_code = SEGV_ACCERR;
 331        up_read(&current->mm->mmap_sem);
 332
 333        info.si_signo = SIGSEGV;
 334        info.si_errno = 0;
 335        info.si_addr  = (void *) instruction_pointer(regs);
 336
 337        pr_debug("SWP{B} emulation: access caused memory abort!\n");
 338        arm64_notify_die("Illegal memory access", regs, &info, 0);
 339}
 340
 341static int emulate_swpX(unsigned int address, unsigned int *data,
 342                        unsigned int type)
 343{
 344        unsigned int res = 0;
 345
 346        if ((type != TYPE_SWPB) && (address & 0x3)) {
 347                /* SWP to unaligned address not permitted */
 348                pr_debug("SWP instruction on unaligned pointer!\n");
 349                return -EFAULT;
 350        }
 351
 352        while (1) {
 353                unsigned long temp;
 354
 355                if (type == TYPE_SWPB)
 356                        __user_swpb_asm(*data, address, res, temp);
 357                else
 358                        __user_swp_asm(*data, address, res, temp);
 359
 360                if (likely(res != -EAGAIN) || signal_pending(current))
 361                        break;
 362
 363                cond_resched();
 364        }
 365
 366        return res;
 367}
 368
 369/*
 370 * swp_handler logs the id of calling process, dissects the instruction, sanity
 371 * checks the memory location, calls emulate_swpX for the actual operation and
 372 * deals with fixup/error handling before returning
 373 */
 374static int swp_handler(struct pt_regs *regs, u32 instr)
 375{
 376        u32 destreg, data, type, address = 0;
 377        int rn, rt2, res = 0;
 378
 379        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
 380
 381        type = instr & TYPE_SWPB;
 382
 383        switch (arm_check_condition(instr, regs->pstate)) {
 384        case ARM_OPCODE_CONDTEST_PASS:
 385                break;
 386        case ARM_OPCODE_CONDTEST_FAIL:
 387                /* Condition failed - return to next instruction */
 388                goto ret;
 389        case ARM_OPCODE_CONDTEST_UNCOND:
 390                /* If unconditional encoding - not a SWP, undef */
 391                return -EFAULT;
 392        default:
 393                return -EINVAL;
 394        }
 395
 396        rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET);
 397        rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET);
 398
 399        address = (u32)regs->user_regs.regs[rn];
 400        data    = (u32)regs->user_regs.regs[rt2];
 401        destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET);
 402
 403        pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
 404                rn, address, destreg,
 405                aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data);
 406
 407        /* Check access in reasonable access range for both SWP and SWPB */
 408        if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
 409                pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n",
 410                        address);
 411                goto fault;
 412        }
 413
 414        res = emulate_swpX(address, &data, type);
 415        if (res == -EFAULT)
 416                goto fault;
 417        else if (res == 0)
 418                regs->user_regs.regs[destreg] = data;
 419
 420ret:
 421        if (type == TYPE_SWPB)
 422                trace_instruction_emulation("swpb", regs->pc);
 423        else
 424                trace_instruction_emulation("swp", regs->pc);
 425
 426        pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
 427                        current->comm, (unsigned long)current->pid, regs->pc);
 428
 429        regs->pc += 4;
 430        return 0;
 431
 432fault:
 433        set_segfault(regs, address);
 434
 435        return 0;
 436}
 437
 438/*
 439 * Only emulate SWP/SWPB executed in ARM state/User mode.
 440 * The kernel must be SWP free and SWP{B} does not exist in Thumb.
 441 */
 442static struct undef_hook swp_hooks[] = {
 443        {
 444                .instr_mask     = 0x0fb00ff0,
 445                .instr_val      = 0x01000090,
 446                .pstate_mask    = COMPAT_PSR_MODE_MASK,
 447                .pstate_val     = COMPAT_PSR_MODE_USR,
 448                .fn             = swp_handler
 449        },
 450        { }
 451};
 452
 453static struct insn_emulation_ops swp_ops = {
 454        .name = "swp",
 455        .status = INSN_OBSOLETE,
 456        .hooks = swp_hooks,
 457        .set_hw_mode = NULL,
 458};
 459
 460static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
 461{
 462        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
 463
 464        switch (arm_check_condition(instr, regs->pstate)) {
 465        case ARM_OPCODE_CONDTEST_PASS:
 466                break;
 467        case ARM_OPCODE_CONDTEST_FAIL:
 468                /* Condition failed - return to next instruction */
 469                goto ret;
 470        case ARM_OPCODE_CONDTEST_UNCOND:
 471                /* If unconditional encoding - not a barrier instruction */
 472                return -EFAULT;
 473        default:
 474                return -EINVAL;
 475        }
 476
 477        switch (aarch32_insn_mcr_extract_crm(instr)) {
 478        case 10:
 479                /*
 480                 * dmb - mcr p15, 0, Rt, c7, c10, 5
 481                 * dsb - mcr p15, 0, Rt, c7, c10, 4
 482                 */
 483                if (aarch32_insn_mcr_extract_opc2(instr) == 5) {
 484                        dmb(sy);
 485                        trace_instruction_emulation(
 486                                "mcr p15, 0, Rt, c7, c10, 5 ; dmb", regs->pc);
 487                } else {
 488                        dsb(sy);
 489                        trace_instruction_emulation(
 490                                "mcr p15, 0, Rt, c7, c10, 4 ; dsb", regs->pc);
 491                }
 492                break;
 493        case 5:
 494                /*
 495                 * isb - mcr p15, 0, Rt, c7, c5, 4
 496                 *
 497                 * Taking an exception or returning from one acts as an
 498                 * instruction barrier. So no explicit barrier needed here.
 499                 */
 500                trace_instruction_emulation(
 501                        "mcr p15, 0, Rt, c7, c5, 4 ; isb", regs->pc);
 502                break;
 503        }
 504
 505ret:
 506        pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n",
 507                        current->comm, (unsigned long)current->pid, regs->pc);
 508
 509        regs->pc += 4;
 510        return 0;
 511}
 512
 513static int cp15_barrier_set_hw_mode(bool enable)
 514{
 515        if (enable)
 516                config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
 517        else
 518                config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
 519        return 0;
 520}
 521
 522static struct undef_hook cp15_barrier_hooks[] = {
 523        {
 524                .instr_mask     = 0x0fff0fdf,
 525                .instr_val      = 0x0e070f9a,
 526                .pstate_mask    = COMPAT_PSR_MODE_MASK,
 527                .pstate_val     = COMPAT_PSR_MODE_USR,
 528                .fn             = cp15barrier_handler,
 529        },
 530        {
 531                .instr_mask     = 0x0fff0fff,
 532                .instr_val      = 0x0e070f95,
 533                .pstate_mask    = COMPAT_PSR_MODE_MASK,
 534                .pstate_val     = COMPAT_PSR_MODE_USR,
 535                .fn             = cp15barrier_handler,
 536        },
 537        { }
 538};
 539
 540static struct insn_emulation_ops cp15_barrier_ops = {
 541        .name = "cp15_barrier",
 542        .status = INSN_DEPRECATED,
 543        .hooks = cp15_barrier_hooks,
 544        .set_hw_mode = cp15_barrier_set_hw_mode,
 545};
 546
 547static int setend_set_hw_mode(bool enable)
 548{
 549        if (!cpu_supports_mixed_endian_el0())
 550                return -EINVAL;
 551
 552        if (enable)
 553                config_sctlr_el1(SCTLR_EL1_SED, 0);
 554        else
 555                config_sctlr_el1(0, SCTLR_EL1_SED);
 556        return 0;
 557}
 558
 559static int compat_setend_handler(struct pt_regs *regs, u32 big_endian)
 560{
 561        char *insn;
 562
 563        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
 564
 565        if (big_endian) {
 566                insn = "setend be";
 567                regs->pstate |= COMPAT_PSR_E_BIT;
 568        } else {
 569                insn = "setend le";
 570                regs->pstate &= ~COMPAT_PSR_E_BIT;
 571        }
 572
 573        trace_instruction_emulation(insn, regs->pc);
 574        pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n",
 575                        current->comm, (unsigned long)current->pid, regs->pc);
 576
 577        return 0;
 578}
 579
 580static int a32_setend_handler(struct pt_regs *regs, u32 instr)
 581{
 582        int rc = compat_setend_handler(regs, (instr >> 9) & 1);
 583        regs->pc += 4;
 584        return rc;
 585}
 586
 587static int t16_setend_handler(struct pt_regs *regs, u32 instr)
 588{
 589        int rc = compat_setend_handler(regs, (instr >> 3) & 1);
 590        regs->pc += 2;
 591        return rc;
 592}
 593
 594static struct undef_hook setend_hooks[] = {
 595        {
 596                .instr_mask     = 0xfffffdff,
 597                .instr_val      = 0xf1010000,
 598                .pstate_mask    = COMPAT_PSR_MODE_MASK,
 599                .pstate_val     = COMPAT_PSR_MODE_USR,
 600                .fn             = a32_setend_handler,
 601        },
 602        {
 603                /* Thumb mode */
 604                .instr_mask     = 0x0000fff7,
 605                .instr_val      = 0x0000b650,
 606                .pstate_mask    = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK),
 607                .pstate_val     = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR),
 608                .fn             = t16_setend_handler,
 609        },
 610        {}
 611};
 612
 613static struct insn_emulation_ops setend_ops = {
 614        .name = "setend",
 615        .status = INSN_DEPRECATED,
 616        .hooks = setend_hooks,
 617        .set_hw_mode = setend_set_hw_mode,
 618};
 619
 620static int insn_cpu_hotplug_notify(struct notifier_block *b,
 621                              unsigned long action, void *hcpu)
 622{
 623        int rc = 0;
 624        if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
 625                rc = run_all_insn_set_hw_mode((unsigned long)hcpu);
 626
 627        return notifier_from_errno(rc);
 628}
 629
 630static struct notifier_block insn_cpu_hotplug_notifier = {
 631        .notifier_call = insn_cpu_hotplug_notify,
 632};
 633
 634/*
 635 * Invoked as late_initcall, since not needed before init spawned.
 636 */
 637static int __init armv8_deprecated_init(void)
 638{
 639        if (IS_ENABLED(CONFIG_SWP_EMULATION))
 640                register_insn_emulation(&swp_ops);
 641
 642        if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
 643                register_insn_emulation(&cp15_barrier_ops);
 644
 645        if (IS_ENABLED(CONFIG_SETEND_EMULATION)) {
 646                if(system_supports_mixed_endian_el0())
 647                        register_insn_emulation(&setend_ops);
 648                else
 649                        pr_info("setend instruction emulation is not supported on the system");
 650        }
 651
 652        register_cpu_notifier(&insn_cpu_hotplug_notifier);
 653        register_insn_emulation_sysctl(ctl_abi);
 654
 655        return 0;
 656}
 657
 658late_initcall(armv8_deprecated_init);
 659