armv8_deprecated.c revision cbefb97b6d7961359f2af89d77b8d5ab77f45528
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 9cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal#include <linux/cpu.h> 10ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/init.h> 11ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/list.h> 12f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <linux/perf_event.h> 13f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <linux/sched.h> 14ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/slab.h> 15ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <linux/sysctl.h> 16ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 17f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/insn.h> 18f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/opcodes.h> 19f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/system_misc.h> 20ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal#include <asm/traps.h> 21f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#include <asm/uaccess.h> 22ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 23ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal/* 24ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * The runtime support for deprecated instruction support can be in one of 25ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * following three states - 26ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 27ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 0 = undef 28ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 1 = emulate (software emulation) 29ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * 2 = hw (supported in hardware) 30ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal */ 31ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalenum insn_emulation_mode { 32ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_UNDEF, 33ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_EMULATE, 34ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_HW, 35ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 36ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 37ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalenum legacy_insn_status { 38ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_DEPRECATED, 39ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal INSN_OBSOLETE, 40ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 41ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 42ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstruct insn_emulation_ops { 43ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal const char *name; 44ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal enum legacy_insn_status status; 45ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct undef_hook *hooks; 46ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int (*set_hw_mode)(bool enable); 47ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 48ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 49ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstruct insn_emulation { 50ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct list_head node; 51ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation_ops *ops; 52ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int current_mode; 53ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int min; 54ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int max; 55ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 56ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 57ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic LIST_HEAD(insn_emulation); 58ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int nr_insn_emulated; 59ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic DEFINE_RAW_SPINLOCK(insn_emulation_lock); 60ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 61ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void register_emulation_hooks(struct insn_emulation_ops *ops) 62ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 63ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct undef_hook *hook; 64ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 65ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal BUG_ON(!ops->hooks); 66ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 67ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal for (hook = ops->hooks; hook->instr_mask; hook++) 68ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_undef_hook(hook); 69ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 70ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Registered %s emulation handler\n", ops->name); 71ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 72ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 73ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void remove_emulation_hooks(struct insn_emulation_ops *ops) 74ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 75ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct undef_hook *hook; 76ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 77ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal BUG_ON(!ops->hooks); 78ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 79ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal for (hook = ops->hooks; hook->instr_mask; hook++) 80ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal unregister_undef_hook(hook); 81ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 82ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Removed %s emulation handler\n", ops->name); 83ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 84ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 85ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int update_insn_emulation_mode(struct insn_emulation *insn, 86ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal enum insn_emulation_mode prev) 87ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 88ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int ret = 0; 89ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 90ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal switch (prev) { 91ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_UNDEF: /* Nothing to be done */ 92ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 93ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_EMULATE: 94ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal remove_emulation_hooks(insn->ops); 95ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 96ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_HW: 97ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (insn->ops->set_hw_mode) { 98ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->ops->set_hw_mode(false); 99ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Disabled %s support\n", insn->ops->name); 100ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 101ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 102ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 103ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 104ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal switch (insn->current_mode) { 105ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_UNDEF: 106ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 107ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_EMULATE: 108ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_emulation_hooks(insn->ops); 109ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 110ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_HW: 111ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) 112ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal pr_notice("Enabled %s support\n", insn->ops->name); 113ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal else 114ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal ret = -EINVAL; 115ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 116ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 117ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 118ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal return ret; 119ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 120ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 121ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void register_insn_emulation(struct insn_emulation_ops *ops) 122ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 123ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal unsigned long flags; 124ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation *insn; 125ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 126ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn = kzalloc(sizeof(*insn), GFP_KERNEL); 127ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->ops = ops; 128ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->min = INSN_UNDEF; 129ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 130ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal switch (ops->status) { 131ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_DEPRECATED: 132ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->current_mode = INSN_EMULATE; 133ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->max = INSN_HW; 134ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 135ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal case INSN_OBSOLETE: 136ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->current_mode = INSN_UNDEF; 137ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->max = INSN_EMULATE; 138ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal break; 139ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 140ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 141ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_lock_irqsave(&insn_emulation_lock, flags); 142ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal list_add(&insn->node, &insn_emulation); 143ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal nr_insn_emulated++; 144ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); 145ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 146ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal /* Register any handlers if required */ 147ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal update_insn_emulation_mode(insn, INSN_UNDEF); 148ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 149ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 150ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int emulation_proc_handler(struct ctl_table *table, int write, 151ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal void __user *buffer, size_t *lenp, 152ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal loff_t *ppos) 153ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 154ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int ret = 0; 155ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation *insn = (struct insn_emulation *) table->data; 156ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal enum insn_emulation_mode prev_mode = insn->current_mode; 157ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 158ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal table->data = &insn->current_mode; 159ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); 160ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 161ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (ret || !write || prev_mode == insn->current_mode) 162ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal goto ret; 163ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 164ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal ret = update_insn_emulation_mode(insn, prev_mode); 165ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal if (!ret) { 166ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal /* Mode change failed, revert to previous mode. */ 167ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insn->current_mode = prev_mode; 168ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal update_insn_emulation_mode(insn, INSN_UNDEF); 169ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 170ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalret: 171ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal table->data = insn; 172ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal return ret; 173ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 174ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 175ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic struct ctl_table ctl_abi[] = { 176ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal { 177ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal .procname = "abi", 178ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal .mode = 0555, 179ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal }, 180ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal { } 181ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal}; 182ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 183ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic void register_insn_emulation_sysctl(struct ctl_table *table) 184ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 185ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal unsigned long flags; 186ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal int i = 0; 187ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct insn_emulation *insn; 188ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal struct ctl_table *insns_sysctl, *sysctl; 189ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 190ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1), 191ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal GFP_KERNEL); 192ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 193ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_lock_irqsave(&insn_emulation_lock, flags); 194ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal list_for_each_entry(insn, &insn_emulation, node) { 195ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl = &insns_sysctl[i]; 196ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 197ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->mode = 0644; 198ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->maxlen = sizeof(int); 199ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 200ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->procname = insn->ops->name; 201ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->data = insn; 202ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->extra1 = &insn->min; 203ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->extra2 = &insn->max; 204ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal sysctl->proc_handler = emulation_proc_handler; 205ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal i++; 206ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal } 207ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); 208ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 209ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal table->child = insns_sysctl; 210ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_sysctl_table(table); 211ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 212ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 213ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal/* 214f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Implement emulation of the SWP/SWPB instructions using load-exclusive and 215f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * store-exclusive. 216f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * 217f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>] 218f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Where: Rt = destination 219f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Rt2 = source 220f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Rn = address 221f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 222f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 223f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 224f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Error-checking SWP macros implemented using ldxr{b}/stxr{b} 225f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 226f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define __user_swpX_asm(data, addr, res, temp, B) \ 227f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __asm__ __volatile__( \ 228f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " mov %w2, %w1\n" \ 229f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "0: ldxr"B" %w1, [%3]\n" \ 230f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "1: stxr"B" %w0, %w2, [%3]\n" \ 231f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " cbz %w0, 2f\n" \ 232f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " mov %w0, %w4\n" \ 233f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "2:\n" \ 234f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .pushsection .fixup,\"ax\"\n" \ 235f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .align 2\n" \ 236f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal "3: mov %w0, %w5\n" \ 237f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " b 2b\n" \ 238f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .popsection" \ 239f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .pushsection __ex_table,\"a\"\n" \ 240f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .align 3\n" \ 241f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .quad 0b, 3b\n" \ 242f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .quad 1b, 3b\n" \ 243f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal " .popsection" \ 244f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal : "=&r" (res), "+r" (data), "=&r" (temp) \ 245f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ 246f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal : "memory") 247f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 248f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define __user_swp_asm(data, addr, res, temp) \ 249f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swpX_asm(data, addr, res, temp, "") 250f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define __user_swpb_asm(data, addr, res, temp) \ 251f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swpX_asm(data, addr, res, temp, "b") 252f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 253f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 254f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Bit 22 of the instruction encoding distinguishes between 255f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * the SWP and SWPB variants (bit set means SWPB). 256f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 257f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal#define TYPE_SWPB (1 << 22) 258f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 259f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 260f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Set up process info to signal segmentation fault - called on access error. 261f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 262f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic void set_segfault(struct pt_regs *regs, unsigned long addr) 263f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal{ 264f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal siginfo_t info; 265f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 266f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal down_read(¤t->mm->mmap_sem); 267f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (find_vma(current->mm, addr) == NULL) 268f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_code = SEGV_MAPERR; 269f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal else 270f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_code = SEGV_ACCERR; 271f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal up_read(¤t->mm->mmap_sem); 272f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 273f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_signo = SIGSEGV; 274f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_errno = 0; 275f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal info.si_addr = (void *) instruction_pointer(regs); 276f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 277f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("SWP{B} emulation: access caused memory abort!\n"); 278f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal arm64_notify_die("Illegal memory access", regs, &info, 0); 279f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal} 280f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 281f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic int emulate_swpX(unsigned int address, unsigned int *data, 282f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal unsigned int type) 283f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal{ 284f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal unsigned int res = 0; 285f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 286f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if ((type != TYPE_SWPB) && (address & 0x3)) { 287f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* SWP to unaligned address not permitted */ 288f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("SWP instruction on unaligned pointer!\n"); 289f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return -EFAULT; 290f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 291f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 292f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal while (1) { 293f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal unsigned long temp; 294f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 295f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (type == TYPE_SWPB) 296f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swpb_asm(*data, address, res, temp); 297f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal else 298f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal __user_swp_asm(*data, address, res, temp); 299f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 300f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (likely(res != -EAGAIN) || signal_pending(current)) 301f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal break; 302f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 303f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal cond_resched(); 304f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 305f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 306f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return res; 307f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal} 308f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 309f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 310f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * swp_handler logs the id of calling process, dissects the instruction, sanity 311f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * checks the memory location, calls emulate_swpX for the actual operation and 312f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * deals with fixup/error handling before returning 313f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 314f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic int swp_handler(struct pt_regs *regs, u32 instr) 315f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal{ 316f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal u32 destreg, data, type, address = 0; 317f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal int rn, rt2, res = 0; 318f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 319f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); 320f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 321f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal type = instr & TYPE_SWPB; 322f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 323f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal switch (arm_check_condition(instr, regs->pstate)) { 324f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal case ARM_OPCODE_CONDTEST_PASS: 325f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal break; 326f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal case ARM_OPCODE_CONDTEST_FAIL: 327f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* Condition failed - return to next instruction */ 328f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal goto ret; 329f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal case ARM_OPCODE_CONDTEST_UNCOND: 330f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* If unconditional encoding - not a SWP, undef */ 331f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return -EFAULT; 332f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal default: 333f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return -EINVAL; 334f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 335f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 336f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET); 337f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET); 338f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 339f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal address = (u32)regs->user_regs.regs[rn]; 340f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal data = (u32)regs->user_regs.regs[rt2]; 341f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET); 342f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 343f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", 344f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal rn, address, destreg, 345f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data); 346f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 347f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal /* Check access in reasonable access range for both SWP and SWPB */ 348f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { 349f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", 350f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal address); 351f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal goto fault; 352f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal } 353f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 354f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal res = emulate_swpX(address, &data, type); 355f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (res == -EFAULT) 356f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal goto fault; 357f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal else if (res == 0) 358f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal regs->user_regs.regs[destreg] = data; 359f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 360f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalret: 361f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n", 362f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal current->comm, (unsigned long)current->pid, regs->pc); 363f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 364f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal regs->pc += 4; 365f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return 0; 366f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 367f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalfault: 368f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal set_segfault(regs, address); 369f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 370f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal return 0; 371f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal} 372f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 373f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 374f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * Only emulate SWP/SWPB executed in ARM state/User mode. 375f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal * The kernel must be SWP free and SWP{B} does not exist in Thumb. 376f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal */ 377f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic struct undef_hook swp_hooks[] = { 378f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal { 379f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .instr_mask = 0x0fb00ff0, 380f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .instr_val = 0x01000090, 381f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .pstate_mask = COMPAT_PSR_MODE_MASK, 382f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .pstate_val = COMPAT_PSR_MODE_USR, 383f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .fn = swp_handler 384f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal }, 385f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal { } 386f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal}; 387f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 388f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawalstatic struct insn_emulation_ops swp_ops = { 389f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .name = "swp", 390f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .status = INSN_OBSOLETE, 391f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .hooks = swp_hooks, 392f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal .set_hw_mode = NULL, 393f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal}; 394f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 395cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic int cp15barrier_handler(struct pt_regs *regs, u32 instr) 396cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal{ 397cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); 398cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 399cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal switch (arm_check_condition(instr, regs->pstate)) { 400cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case ARM_OPCODE_CONDTEST_PASS: 401cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal break; 402cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case ARM_OPCODE_CONDTEST_FAIL: 403cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal /* Condition failed - return to next instruction */ 404cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal goto ret; 405cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case ARM_OPCODE_CONDTEST_UNCOND: 406cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal /* If unconditional encoding - not a barrier instruction */ 407cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal return -EFAULT; 408cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal default: 409cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal return -EINVAL; 410cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal } 411cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 412cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal switch (aarch32_insn_mcr_extract_crm(instr)) { 413cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case 10: 414cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal /* 415cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal * dmb - mcr p15, 0, Rt, c7, c10, 5 416cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal * dsb - mcr p15, 0, Rt, c7, c10, 4 417cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal */ 418cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal if (aarch32_insn_mcr_extract_opc2(instr) == 5) 419cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal dmb(sy); 420cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal else 421cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal dsb(sy); 422cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal break; 423cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case 5: 424cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal /* 425cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal * isb - mcr p15, 0, Rt, c7, c5, 4 426cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal * 427cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal * Taking an exception or returning from one acts as an 428cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal * instruction barrier. So no explicit barrier needed here. 429cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal */ 430cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal break; 431cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal } 432cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 433cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalret: 434cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n", 435cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal current->comm, (unsigned long)current->pid, regs->pc); 436cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 437cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal regs->pc += 4; 438cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal return 0; 439cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal} 440cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 441cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal#define SCTLR_EL1_CP15BEN (1 << 5) 442cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 443cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic inline void config_sctlr_el1(u32 clear, u32 set) 444cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal{ 445cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal u32 val; 446cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 447cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal asm volatile("mrs %0, sctlr_el1" : "=r" (val)); 448cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal val &= ~clear; 449cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal val |= set; 450cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal asm volatile("msr sctlr_el1, %0" : : "r" (val)); 451cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal} 452cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 453cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic void enable_cp15_ben(void *info) 454cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal{ 455cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal config_sctlr_el1(0, SCTLR_EL1_CP15BEN); 456cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal} 457cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 458cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic void disable_cp15_ben(void *info) 459cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal{ 460cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); 461cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal} 462cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 463cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic int cpu_hotplug_notify(struct notifier_block *b, 464cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal unsigned long action, void *hcpu) 465cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal{ 466cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal switch (action) { 467cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case CPU_STARTING: 468cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case CPU_STARTING_FROZEN: 469cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal enable_cp15_ben(NULL); 470cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal return NOTIFY_DONE; 471cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case CPU_DYING: 472cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal case CPU_DYING_FROZEN: 473cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal disable_cp15_ben(NULL); 474cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal return NOTIFY_DONE; 475cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal } 476cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 477cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal return NOTIFY_OK; 478cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal} 479cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 480cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic struct notifier_block cpu_hotplug_notifier = { 481cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .notifier_call = cpu_hotplug_notify, 482cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal}; 483cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 484cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic int cp15_barrier_set_hw_mode(bool enable) 485cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal{ 486cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal if (enable) { 487cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal register_cpu_notifier(&cpu_hotplug_notifier); 488cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal on_each_cpu(enable_cp15_ben, NULL, true); 489cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal } else { 490cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal unregister_cpu_notifier(&cpu_hotplug_notifier); 491cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal on_each_cpu(disable_cp15_ben, NULL, true); 492cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal } 493cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 494cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal return true; 495cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal} 496cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 497cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic struct undef_hook cp15_barrier_hooks[] = { 498cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal { 499cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .instr_mask = 0x0fff0fdf, 500cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .instr_val = 0x0e070f9a, 501cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .pstate_mask = COMPAT_PSR_MODE_MASK, 502cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .pstate_val = COMPAT_PSR_MODE_USR, 503cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .fn = cp15barrier_handler, 504cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal }, 505cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal { 506cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .instr_mask = 0x0fff0fff, 507cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .instr_val = 0x0e070f95, 508cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .pstate_mask = COMPAT_PSR_MODE_MASK, 509cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .pstate_val = COMPAT_PSR_MODE_USR, 510cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .fn = cp15barrier_handler, 511cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal }, 512cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal { } 513cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal}; 514cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 515cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawalstatic struct insn_emulation_ops cp15_barrier_ops = { 516cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .name = "cp15_barrier", 517cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .status = INSN_DEPRECATED, 518cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .hooks = cp15_barrier_hooks, 519cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal .set_hw_mode = cp15_barrier_set_hw_mode, 520cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal}; 521cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 522f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal/* 523ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal * Invoked as late_initcall, since not needed before init spawned. 524ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal */ 525ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawalstatic int __init armv8_deprecated_init(void) 526ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal{ 527f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal if (IS_ENABLED(CONFIG_SWP_EMULATION)) 528f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal register_insn_emulation(&swp_ops); 529f2e97ae6b98e61fa4f1539a47661baef41992b04Punit Agrawal 530cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) 531cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal register_insn_emulation(&cp15_barrier_ops); 532cbefb97b6d7961359f2af89d77b8d5ab77f45528Punit Agrawal 533ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal register_insn_emulation_sysctl(ctl_abi); 534ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 535ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal return 0; 536ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal} 537ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawal 538ab12a809254a343a42f7655e752a9d2eb65364dbPunit Agrawallate_initcall(armv8_deprecated_init); 539