armv8_deprecated.c revision f2e97ae6b98e61fa4f1539a47661baef41992b04
1ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal/* 2ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * Copyright (C) 2014 ARM Limited 3ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 4ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * This program is free software; you can redistribute it and/or modify 5ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * it under the terms of the GNU General Public License version 2 as 6ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * published by the Free Software Foundation. 7ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal */ 8ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 9ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/init.h> 10ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/list.h> 11f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <linux/perf_event.h> 12f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <linux/sched.h> 13ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/slab.h> 14ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/sysctl.h> 15ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 16f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/insn.h> 17f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/opcodes.h> 18f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/system_misc.h> 19ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <asm/traps.h> 20f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/uaccess.h> 21ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 22ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal/* 23ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * The runtime support for deprecated instruction support can be in one of 24ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * following three states - 25ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 26ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 0 = undef 27ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 1 = emulate (software emulation) 28ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 2 = hw (supported in hardware) 29ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal */ 30ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalenum insn_emulation_mode { 31ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_UNDEF, 32ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_EMULATE, 33ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_HW, 34ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 35ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 36ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalenum legacy_insn_status { 37ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_DEPRECATED, 38ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_OBSOLETE, 39ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 40ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 41ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstruct insn_emulation_ops { 42ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal const char *name; 43ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal enum legacy_insn_status status; 44ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct undef_hook *hooks; 45ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int (*set_hw_mode)(bool enable); 46ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 47ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 48ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstruct insn_emulation { 49ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct list_head node; 50ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation_ops *ops; 51ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int current_mode; 52ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int min; 53ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int max; 54ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 55ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 56ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic LIST_HEAD(insn_emulation); 57ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int nr_insn_emulated; 58ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic DEFINE_RAW_SPINLOCK(insn_emulation_lock); 59ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 60ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void register_emulation_hooks(struct insn_emulation_ops *ops) 61ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 62ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct undef_hook *hook; 63ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 64ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal BUG_ON(!ops->hooks); 65ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 66ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal for (hook = ops->hooks; hook->instr_mask; hook++) 67ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_undef_hook(hook); 68ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 69ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Registered %s emulation handler\n", ops->name); 70ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 71ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 72ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void remove_emulation_hooks(struct insn_emulation_ops *ops) 73ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 74ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct undef_hook *hook; 75ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 76ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal BUG_ON(!ops->hooks); 77ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 78ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal for (hook = ops->hooks; hook->instr_mask; hook++) 79ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal unregister_undef_hook(hook); 80ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 81ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Removed %s emulation handler\n", ops->name); 82ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 83ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 84ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int update_insn_emulation_mode(struct insn_emulation *insn, 85ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal enum insn_emulation_mode prev) 86ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 87ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int ret = 0; 88ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 89ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal switch (prev) { 90ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_UNDEF: /* Nothing to be done */ 91ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 92ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_EMULATE: 93ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal remove_emulation_hooks(insn->ops); 94ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 95ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_HW: 96ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (insn->ops->set_hw_mode) { 97ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->ops->set_hw_mode(false); 98ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Disabled %s support\n", insn->ops->name); 99ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 100ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 101ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 102ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 103ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal switch (insn->current_mode) { 104ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_UNDEF: 105ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 106ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_EMULATE: 107ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_emulation_hooks(insn->ops); 108ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 109ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_HW: 110ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) 111ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Enabled %s support\n", insn->ops->name); 112ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal else 113ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal ret = -EINVAL; 114ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 115ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 116ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 117ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal return ret; 118ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 119ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 120ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void register_insn_emulation(struct insn_emulation_ops *ops) 121ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 122ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal unsigned long flags; 123ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation *insn; 124ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 125ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn = kzalloc(sizeof(*insn), GFP_KERNEL); 126ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->ops = ops; 127ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->min = INSN_UNDEF; 128ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 129ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal switch (ops->status) { 130ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_DEPRECATED: 131ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->current_mode = INSN_EMULATE; 132ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->max = INSN_HW; 133ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 134ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_OBSOLETE: 135ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->current_mode = INSN_UNDEF; 136ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->max = INSN_EMULATE; 137ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 138ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 139ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 140ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_lock_irqsave(&insn_emulation_lock, flags); 141ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal list_add(&insn->node, &insn_emulation); 142ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal nr_insn_emulated++; 143ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); 144ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 145ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal /* Register any handlers if required */ 146ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal update_insn_emulation_mode(insn, INSN_UNDEF); 147ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 148ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 149ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int emulation_proc_handler(struct ctl_table *table, int write, 150ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal void __user *buffer, size_t *lenp, 151ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal loff_t *ppos) 152ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 153ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int ret = 0; 154ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation *insn = (struct insn_emulation *) table->data; 155ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal enum insn_emulation_mode prev_mode = insn->current_mode; 156ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 157ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal table->data = &insn->current_mode; 158ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); 159ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 160ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (ret || !write || prev_mode == insn->current_mode) 161ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal goto ret; 162ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 163ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal ret = update_insn_emulation_mode(insn, prev_mode); 164ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (!ret) { 165ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal /* Mode change failed, revert to previous mode. */ 166ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->current_mode = prev_mode; 167ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal update_insn_emulation_mode(insn, INSN_UNDEF); 168ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 169ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalret: 170ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal table->data = insn; 171ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal return ret; 172ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 173ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 174ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic struct ctl_table ctl_abi[] = { 175ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal { 176ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal .procname = "abi", 177ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal .mode = 0555, 178ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal }, 179ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal { } 180ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 181ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 182ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void register_insn_emulation_sysctl(struct ctl_table *table) 183ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 184ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal unsigned long flags; 185ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int i = 0; 186ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation *insn; 187ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct ctl_table *insns_sysctl, *sysctl; 188ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 189ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1), 190ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal GFP_KERNEL); 191ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 192ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_lock_irqsave(&insn_emulation_lock, flags); 193ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal list_for_each_entry(insn, &insn_emulation, node) { 194ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl = &insns_sysctl[i]; 195ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 196ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->mode = 0644; 197ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->maxlen = sizeof(int); 198ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 199ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->procname = insn->ops->name; 200ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->data = insn; 201ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->extra1 = &insn->min; 202ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->extra2 = &insn->max; 203ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->proc_handler = emulation_proc_handler; 204ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal i++; 205ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 206ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); 207ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 208ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal table->child = insns_sysctl; 209ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_sysctl_table(table); 210ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 211ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 212ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal/* 213f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Implement emulation of the SWP/SWPB instructions using load-exclusive and 214f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * store-exclusive. 215f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * 216f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>] 217f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Where: Rt = destination 218f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Rt2 = source 219f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Rn = address 220f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 221f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 222f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 223f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Error-checking SWP macros implemented using ldxr{b}/stxr{b} 224f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 225f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define __user_swpX_asm(data, addr, res, temp, B) \ 226f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __asm__ __volatile__( \ 227f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " mov %w2, %w1\n" \ 228f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "0: ldxr"B" %w1, [%3]\n" \ 229f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "1: stxr"B" %w0, %w2, [%3]\n" \ 230f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " cbz %w0, 2f\n" \ 231f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " mov %w0, %w4\n" \ 232f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "2:\n" \ 233f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .pushsection .fixup,\"ax\"\n" \ 234f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .align 2\n" \ 235f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "3: mov %w0, %w5\n" \ 236f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " b 2b\n" \ 237f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .popsection" \ 238f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .pushsection __ex_table,\"a\"\n" \ 239f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .align 3\n" \ 240f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .quad 0b, 3b\n" \ 241f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .quad 1b, 3b\n" \ 242f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .popsection" \ 243f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal : "=&r" (res), "+r" (data), "=&r" (temp) \ 244f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ 245f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal : "memory") 246f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 247f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define __user_swp_asm(data, addr, res, temp) \ 248f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swpX_asm(data, addr, res, temp, "") 249f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define __user_swpb_asm(data, addr, res, temp) \ 250f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swpX_asm(data, addr, res, temp, "b") 251f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 252f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 253f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Bit 22 of the instruction encoding distinguishes between 254f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * the SWP and SWPB variants (bit set means SWPB). 255f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 256f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define TYPE_SWPB (1 << 22) 257f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 258f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 259f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Set up process info to signal segmentation fault - called on access error. 260f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 261f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic void set_segfault(struct pt_regs *regs, unsigned long addr) 262f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal{ 263f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal siginfo_t info; 264f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 265f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal down_read(¤t->mm->mmap_sem); 266f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (find_vma(current->mm, addr) == NULL) 267f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_code = SEGV_MAPERR; 268f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal else 269f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_code = SEGV_ACCERR; 270f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal up_read(¤t->mm->mmap_sem); 271f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 272f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_signo = SIGSEGV; 273f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_errno = 0; 274f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_addr = (void *) instruction_pointer(regs); 275f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 276f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("SWP{B} emulation: access caused memory abort!\n"); 277f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal arm64_notify_die("Illegal memory access", regs, &info, 0); 278f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal} 279f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 280f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic int emulate_swpX(unsigned int address, unsigned int *data, 281f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal unsigned int type) 282f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal{ 283f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal unsigned int res = 0; 284f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 285f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if ((type != TYPE_SWPB) && (address & 0x3)) { 286f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* SWP to unaligned address not permitted */ 287f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("SWP instruction on unaligned pointer!\n"); 288f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return -EFAULT; 289f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 290f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 291f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal while (1) { 292f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal unsigned long temp; 293f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 294f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (type == TYPE_SWPB) 295f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swpb_asm(*data, address, res, temp); 296f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal else 297f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swp_asm(*data, address, res, temp); 298f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 299f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (likely(res != -EAGAIN) || signal_pending(current)) 300f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal break; 301f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 302f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal cond_resched(); 303f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 304f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 305f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return res; 306f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal} 307f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 308f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 309f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * swp_handler logs the id of calling process, dissects the instruction, sanity 310f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * checks the memory location, calls emulate_swpX for the actual operation and 311f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * deals with fixup/error handling before returning 312f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 313f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic int swp_handler(struct pt_regs *regs, u32 instr) 314f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal{ 315f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal u32 destreg, data, type, address = 0; 316f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal int rn, rt2, res = 0; 317f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 318f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); 319f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 320f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal type = instr & TYPE_SWPB; 321f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 322f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal switch (arm_check_condition(instr, regs->pstate)) { 323f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal case ARM_OPCODE_CONDTEST_PASS: 324f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal break; 325f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal case ARM_OPCODE_CONDTEST_FAIL: 326f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* Condition failed - return to next instruction */ 327f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal goto ret; 328f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal case ARM_OPCODE_CONDTEST_UNCOND: 329f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* If unconditional encoding - not a SWP, undef */ 330f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return -EFAULT; 331f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal default: 332f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return -EINVAL; 333f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 334f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 335f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET); 336f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET); 337f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 338f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal address = (u32)regs->user_regs.regs[rn]; 339f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal data = (u32)regs->user_regs.regs[rt2]; 340f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET); 341f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 342f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", 343f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal rn, address, destreg, 344f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data); 345f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 346f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* Check access in reasonable access range for both SWP and SWPB */ 347f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { 348f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", 349f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal address); 350f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal goto fault; 351f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 352f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 353f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal res = emulate_swpX(address, &data, type); 354f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (res == -EFAULT) 355f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal goto fault; 356f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal else if (res == 0) 357f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal regs->user_regs.regs[destreg] = data; 358f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 359f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalret: 360f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n", 361f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal current->comm, (unsigned long)current->pid, regs->pc); 362f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 363f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal regs->pc += 4; 364f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return 0; 365f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 366f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalfault: 367f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal set_segfault(regs, address); 368f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 369f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return 0; 370f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal} 371f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 372f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 373f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Only emulate SWP/SWPB executed in ARM state/User mode. 374f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * The kernel must be SWP free and SWP{B} does not exist in Thumb. 375f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 376f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic struct undef_hook swp_hooks[] = { 377f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal { 378f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .instr_mask = 0x0fb00ff0, 379f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .instr_val = 0x01000090, 380f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .pstate_mask = COMPAT_PSR_MODE_MASK, 381f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .pstate_val = COMPAT_PSR_MODE_USR, 382f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .fn = swp_handler 383f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal }, 384f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal { } 385f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal}; 386f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 387f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic struct insn_emulation_ops swp_ops = { 388f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .name = "swp", 389f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .status = INSN_OBSOLETE, 390f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .hooks = swp_hooks, 391f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .set_hw_mode = NULL, 392f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal}; 393f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 394f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 395ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * Invoked as late_initcall, since not needed before init spawned. 396ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal */ 397ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int __init armv8_deprecated_init(void) 398ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 399f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (IS_ENABLED(CONFIG_SWP_EMULATION)) 400f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal register_insn_emulation(&swp_ops); 401f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 402ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_insn_emulation_sysctl(ctl_abi); 403ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 404ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal return 0; 405ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 406ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 407ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawallate_initcall(armv8_deprecated_init); 408