1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 8 * See "LICENSE_GPLv2.txt" for details. 9 * 10 * @TAG(DATA61_GPL) 11 */ 12 13#include <mode/machine.h> 14#include <arch/machine/fpu.h> 15#include <mode/model/statedata.h> 16#include <config.h> 17#include <util.h> 18 19/* We cache the following value to avoid reading the coprocessor when isFpuEnable() 20 * is called. enableFpu() and disableFpu(), the value is set to cache/reflect the 21 * actual HW FPU enable/disable state. 22 */ 23bool_t isFPUEnabledCached[CONFIG_MAX_NUM_NODES]; 24 25/* 26 * The following function checks if the subarchitecture support asynchronous exceptions 27 */ 28BOOT_CODE static inline bool_t supportsAsyncExceptions(void) 29{ 30 word_t fpexc; 31 32 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { 33 enableFpuInstInHyp(); 34 } 35 /* Set FPEXC.EX=1 */ 36 MRC(FPEXC, fpexc); 37 fpexc |= BIT(FPEXC_EX_BIT); 38 MCR(FPEXC, fpexc); 39 40 /* Read back the FPEXC register*/ 41 MRC(FPEXC, fpexc); 42 43 return !!(fpexc & BIT(FPEXC_EX_BIT)); 44} 45 46#ifdef CONFIG_HAVE_FPU 47/* This variable is set at boot/init time to true if the FPU supports 32 registers (d0-d31). 48 * otherwise it only supports 16 registers (d0-d15). 49 * We cache this value in the following variable to avoid reading the coprocessor 50 * on every FPU context switch, since it shouldn't change for one platform on run-time. 51 */ 52bool_t isFPUD32SupportedCached; 53 54BOOT_CODE static inline bool_t isFPUD32Supported(void) 55{ 56 word_t mvfr0; 57 asm volatile (".word 0xeef73a10 \n" /* vmrs r3, mvfr0 */ 58 "mov %0, r3 \n" 59 : "=r" (mvfr0) 60 : 61 : "r3"); 62 return ((mvfr0 & 0xf) == 2); 63} 64 65/* Initialise the FP/SIMD for this machine. */ 66BOOT_CODE bool_t 67fpsimd_init(void) 68{ 69 word_t cpacr; 70 71 MRC(CPACR, cpacr); 72 cpacr |= (CPACR_CP_ACCESS_PLX << CPACR_CP_10_SHIFT_POS | 73 CPACR_CP_ACCESS_PLX << CPACR_CP_11_SHIFT_POS); 74 MCR(CPACR, cpacr); 75 76 isb(); 77 78 if (supportsAsyncExceptions()) { 79 /* In the future, when we've targets that support asynchronous FPU exceptions, we've to support them */ 80 printf("Error: seL4 doesn't support FPU subarchitectures that support asynchronous exceptions\n"); 81 return false; 82 } 83 84 isFPUD32SupportedCached = isFPUD32Supported(); 85 /* Set the FPU to lazy switch mode */ 86 disableFpu(); 87 88 return true; 89} 90#endif /* CONFIG_HAVE_FPU */ 91 92BOOT_CODE bool_t 93fpsimd_HWCapTest(void) 94{ 95 word_t cpacr, fpsid; 96 97 /* Change permissions of CP10 and CP11 to read control/status registers */ 98 MRC(CPACR, cpacr); 99 cpacr |= (CPACR_CP_ACCESS_PLX << CPACR_CP_10_SHIFT_POS | 100 CPACR_CP_ACCESS_PLX << CPACR_CP_11_SHIFT_POS); 101 MCR(CPACR, cpacr); 102 103 isb(); 104 105 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { 106 enableFpuInstInHyp(); 107 } 108 109 /* Check of this platform supports HW FP instructions */ 110 asm volatile (".word 0xeef00a10 \n" /* vmrs r0, fpsid */ 111 "mov %0, r0 \n" 112 : "=r" (fpsid) : 113 : "r0"); 114 if (fpsid & BIT(FPSID_SW_BIT)) { 115 return false; 116 } 117 118 word_t fpsid_subarch; 119 120 if (supportsAsyncExceptions()) { 121 /* In the future, when we've targets that support asynchronous FPU exceptions, we've to support them */ 122 if (config_set(CONFIG_HAVE_FPU)) { 123 printf("Error: seL4 doesn't support FPU subarchitectures that support asynchronous exceptions\n"); 124 return false; 125 } else { 126 // if we aren't using the fpu then we have detected an fpu that we cannot use, but that is fine 127 return true; 128 } 129 } 130 /* Check for subarchitectures we support */ 131 fpsid_subarch = (fpsid >> FPSID_SUBARCH_SHIFT_POS) & 0x7f; 132 133 switch (fpsid_subarch) { 134 /* We only support the following subarch values */ 135 case 0x2: 136 case 0x3: 137 case 0x4: 138 break; 139 default: { 140 if (config_set(CONFIG_HAVE_FPU)) { 141 printf("Error: seL4 doesn't support this VFP subarchitecture\n"); 142 return false; 143 } else { 144 // if we aren't using the fpu then we have detected an fpu that we cannot use, but that is fine 145 return true; 146 } 147 } 148 149 } 150 151 if (!config_set(CONFIG_HAVE_FPU)) { 152 printf("Info: Not using supported FPU as FPU is disabled in the build configuration\n"); 153 } 154 return true; 155} 156