1 /*- 2 * Copyright (c) 2014 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Semihalf under 6 * the sponsorship of the FreeBSD Foundation. 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 34 #include <machine/armreg.h> 35 #include <machine/atomic.h> 36 37 #include <stand.h> 38 #include <efi.h> 39 40 #include "bootstrap.h" 41 #include "cache.h" 42 43 static long cache_flags; 44 #define CACHE_FLAG_DIC_OFF (1<<0) 45 #define CACHE_FLAG_IDC_OFF (1<<1) 46 47 static bool 48 get_cache_dic(uint64_t ctr) 49 { 50 if ((cache_flags & CACHE_FLAG_DIC_OFF) != 0) { 51 return (false); 52 } 53 54 return (CTR_DIC_VAL(ctr) != 0); 55 } 56 57 static bool 58 get_cache_idc(uint64_t ctr) 59 { 60 if ((cache_flags & CACHE_FLAG_IDC_OFF) != 0) { 61 return (false); 62 } 63 64 return (CTR_IDC_VAL(ctr) != 0); 65 } 66 67 static unsigned int 68 get_dcache_line_size(uint64_t ctr) 69 { 70 unsigned int dcl_size; 71 72 /* 73 * Relevant field [19:16] is LOG2 74 * of the number of words in DCache line 75 */ 76 dcl_size = CTR_DLINE_SIZE(ctr); 77 78 /* Size of word shifted by cache line size */ 79 return (sizeof(int) << dcl_size); 80 } 81 82 void 83 cpu_flush_dcache(const void *ptr, size_t len) 84 { 85 uint64_t cl_size, ctr; 86 vm_offset_t addr, end; 87 88 /* Accessible from all security levels */ 89 ctr = READ_SPECIALREG(ctr_el0); 90 91 if (get_cache_idc(ctr)) { 92 dsb(ishst); 93 } else { 94 cl_size = get_dcache_line_size(ctr); 95 96 /* Calculate end address to clean */ 97 end = (vm_offset_t)ptr + (vm_offset_t)len; 98 /* Align start address to cache line */ 99 addr = (vm_offset_t)ptr; 100 addr = rounddown2(addr, cl_size); 101 102 for (; addr < end; addr += cl_size) 103 __asm __volatile("dc civac, %0" : : "r" (addr) : 104 "memory"); 105 /* Full system DSB */ 106 dsb(ish); 107 } 108 } 109 110 void 111 cpu_inval_icache(void) 112 { 113 uint64_t ctr; 114 115 /* Accessible from all security levels */ 116 ctr = READ_SPECIALREG(ctr_el0); 117 118 if (get_cache_dic(ctr)) { 119 isb(); 120 } else { 121 __asm __volatile( 122 "ic ialluis \n" 123 "dsb ish \n" 124 "isb \n" 125 : : : "memory"); 126 } 127 } 128 129 static int 130 command_cache_flags(int argc, char *argv[]) 131 { 132 char *cp; 133 long new_flags; 134 135 if (argc == 3) { 136 if (strcmp(argv[1], "set") == 0) { 137 new_flags = strtol(argv[2], &cp, 0); 138 if (cp[0] != '\0') { 139 printf("Invalid flags\n"); 140 } else { 141 printf("Setting cache flags to %#lx\n", 142 new_flags); 143 cache_flags = new_flags; 144 return (CMD_OK); 145 } 146 } 147 } 148 149 printf("usage: cache_flags set <value>\n"); 150 return (CMD_ERROR); 151 } 152 COMMAND_SET(cache_flags, "cache_flags", "Set cache flags", command_cache_flags); 153