1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 Andrew Turner 5 * All rights reserved. 6 * 7 * This software was developed by SRI International and the University of 8 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 9 * ("CTSRD"), as part of the DARPA CRASH research programme. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include "opt_platform.h" 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/pcpu.h> 41 #include <sys/systm.h> 42 43 #include <machine/cpu.h> 44 45 #include <dev/psci/smccc.h> 46 47 typedef void (cpu_quirk_install)(void); 48 struct cpu_quirks { 49 cpu_quirk_install *quirk_install; 50 u_int midr_mask; 51 u_int midr_value; 52 }; 53 54 static enum { 55 SSBD_FORCE_ON, 56 SSBD_FORCE_OFF, 57 SSBD_KERNEL, 58 } ssbd_method = SSBD_KERNEL; 59 60 static cpu_quirk_install install_psci_bp_hardening; 61 static cpu_quirk_install install_ssbd_workaround; 62 static cpu_quirk_install install_thunderx_bcast_tlbi_workaround; 63 64 static struct cpu_quirks cpu_quirks[] = { 65 { 66 .midr_mask = CPU_IMPL_MASK | CPU_PART_MASK, 67 .midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A57,0,0), 68 .quirk_install = install_psci_bp_hardening, 69 }, 70 { 71 .midr_mask = CPU_IMPL_MASK | CPU_PART_MASK, 72 .midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A72,0,0), 73 .quirk_install = install_psci_bp_hardening, 74 }, 75 { 76 .midr_mask = CPU_IMPL_MASK | CPU_PART_MASK, 77 .midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A73,0,0), 78 .quirk_install = install_psci_bp_hardening, 79 }, 80 { 81 .midr_mask = CPU_IMPL_MASK | CPU_PART_MASK, 82 .midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A75,0,0), 83 .quirk_install = install_psci_bp_hardening, 84 }, 85 { 86 .midr_mask = CPU_IMPL_MASK | CPU_PART_MASK, 87 .midr_value = 88 CPU_ID_RAW(CPU_IMPL_CAVIUM, CPU_PART_THUNDERX2, 0,0), 89 .quirk_install = install_psci_bp_hardening, 90 }, 91 { 92 .midr_mask = 0, 93 .midr_value = 0, 94 .quirk_install = install_ssbd_workaround, 95 }, 96 { 97 .midr_mask = CPU_IMPL_MASK | CPU_PART_MASK, 98 .midr_value = 99 CPU_ID_RAW(CPU_IMPL_CAVIUM, CPU_PART_THUNDERX, 0, 0), 100 .quirk_install = install_thunderx_bcast_tlbi_workaround, 101 }, 102 { 103 .midr_mask = CPU_IMPL_MASK | CPU_PART_MASK, 104 .midr_value = 105 CPU_ID_RAW(CPU_IMPL_CAVIUM, CPU_PART_THUNDERX_81XX, 0, 0), 106 .quirk_install = install_thunderx_bcast_tlbi_workaround, 107 }, 108 }; 109 110 static void 111 install_psci_bp_hardening(void) 112 { 113 114 if (smccc_arch_features(SMCCC_ARCH_WORKAROUND_1) != SMCCC_RET_SUCCESS) 115 return; 116 117 PCPU_SET(bp_harden, smccc_arch_workaround_1); 118 } 119 120 static void 121 install_ssbd_workaround(void) 122 { 123 char *env; 124 125 if (PCPU_GET(cpuid) == 0) { 126 env = kern_getenv("kern.cfg.ssbd"); 127 if (env != NULL) { 128 if (strcmp(env, "force-on") == 0) { 129 ssbd_method = SSBD_FORCE_ON; 130 } else if (strcmp(env, "force-off") == 0) { 131 ssbd_method = SSBD_FORCE_OFF; 132 } 133 } 134 } 135 136 /* Enable the workaround on this CPU if it's enabled in the firmware */ 137 if (smccc_arch_features(SMCCC_ARCH_WORKAROUND_2) != SMCCC_RET_SUCCESS) 138 return; 139 140 switch(ssbd_method) { 141 case SSBD_FORCE_ON: 142 smccc_arch_workaround_2(1); 143 break; 144 case SSBD_FORCE_OFF: 145 smccc_arch_workaround_2(0); 146 break; 147 case SSBD_KERNEL: 148 default: 149 PCPU_SET(ssbd, smccc_arch_workaround_2); 150 break; 151 } 152 } 153 154 /* 155 * Workaround Cavium erratum 27456. 156 * 157 * Invalidate the local icache when changing address spaces. 158 */ 159 static void 160 install_thunderx_bcast_tlbi_workaround(void) 161 { 162 u_int midr; 163 164 midr = get_midr(); 165 if (CPU_PART(midr) == CPU_PART_THUNDERX_81XX) 166 PCPU_SET(bcast_tlbi_workaround, 1); 167 else if (CPU_PART(midr) == CPU_PART_THUNDERX) { 168 if (CPU_VAR(midr) == 0) { 169 /* ThunderX 1.x */ 170 PCPU_SET(bcast_tlbi_workaround, 1); 171 } else if (CPU_VAR(midr) == 1 && CPU_REV(midr) <= 1) { 172 /* ThunderX 2.0 - 2.1 */ 173 PCPU_SET(bcast_tlbi_workaround, 1); 174 } 175 } 176 } 177 178 void 179 install_cpu_errata(void) 180 { 181 u_int midr; 182 size_t i; 183 184 midr = get_midr(); 185 186 for (i = 0; i < nitems(cpu_quirks); i++) { 187 if ((midr & cpu_quirks[i].midr_mask) == 188 cpu_quirks[i].midr_value) { 189 cpu_quirks[i].quirk_install(); 190 } 191 } 192 } 193