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 BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12#pragma once 13 14#include <sel4bench/types.h> 15#include <sel4bench/cpu/private.h> 16#include <assert.h> 17#include <sel4/sel4.h> 18 19//begin system-mode stubs for sel4bench_* api functions 20static KERNELFN void sel4bench_private_init(void* data) 21{ 22 sel4bench_arm1136_pmnc_t init_pmnc = { 23 { 24 .C = 1, //reset CCNT 25 .P = 1, //reset performance counters 26 .Flag = 0x7, //reset overflow flags 27 .E = 1, //start all counters 28 } 29 }; 30 31 //reset and enable all counters 32 sel4bench_private_set_pmnc(init_pmnc); 33} 34 35static KERNELFN void sel4bench_private_destroy(void* data) 36{ 37 sel4bench_arm1136_pmnc_t kill_pmnc = { 38 { 39 .C = 1, //reset CCNT 40 .P = 1, //reset performance counters 41 .Flag = 0x7, //reset overflow flags 42 .E = 0, //stop all counters 43 } 44 }; 45 46 //disable and reset all counters 47 sel4bench_private_set_pmnc(kill_pmnc); 48} 49 50static KERNELFN void sel4bench_private_reset_gp_counters(void* data) 51{ 52 sel4bench_arm1136_pmnc_t reset_pmnc = sel4bench_private_get_pmnc(); 53 reset_pmnc.P = 1; //reset performance counters 54 reset_pmnc.Flag = 0x3; //clear overflow flags on C0 and C1 55 reset_pmnc.C = 0; //don't touch CCNT 56 reset_pmnc.SBZ1 = 0; //per spec 57 reset_pmnc.SBZ2 = 0; //per spec 58 59 //reset and enable all counters 60 sel4bench_private_set_pmnc(reset_pmnc); 61} 62 63static KERNELFN void sel4bench_private_get_cycle_count(void* data) 64{ 65 //get contents of PMNC 66 sel4bench_arm1136_pmnc_t pmnc_contents = sel4bench_private_get_pmnc(); 67 pmnc_contents.Flag = 0; //don't reset anything 68 pmnc_contents.SBZ1 = 0; //per spec 69 pmnc_contents.SBZ2 = 0; //per spec 70 71 //store current state 72 sel4bench_arm1136_pmnc_t pmnc_contents_restore = pmnc_contents; 73 74 //disable counters 75 pmnc_contents.E = 0; 76 sel4bench_private_set_pmnc(pmnc_contents); 77 78 //read value of specified counter 79 *(uint32_t*)data = sel4bench_private_get_ccnt(); 80 81 //restore previous state 82 sel4bench_private_set_pmnc(pmnc_contents_restore); 83} 84 85static KERNELFN void sel4bench_private_get_counter(void* data) 86{ 87 //get contents of PMNC 88 sel4bench_arm1136_pmnc_t pmnc_contents = sel4bench_private_get_pmnc(); 89 pmnc_contents.Flag = 0; //don't reset anything 90 pmnc_contents.SBZ1 = 0; //per spec 91 pmnc_contents.SBZ2 = 0; //per spec 92 93 //store current state 94 sel4bench_arm1136_pmnc_t pmnc_contents_restore = pmnc_contents; 95 96 //disable counters 97 pmnc_contents.E = 0; 98 sel4bench_private_set_pmnc(pmnc_contents); 99 100 //read value of specified counter 101 *(uint32_t*)data = *(uint32_t*)data ? sel4bench_private_get_pmn1() : sel4bench_private_get_pmn0(); 102 103 //restore previous state 104 sel4bench_private_set_pmnc(pmnc_contents_restore); 105} 106 107static KERNELFN void sel4bench_private_get_counters(void* data) 108{ 109 //get contents of PMNC 110 sel4bench_arm1136_pmnc_t pmnc_contents = sel4bench_private_get_pmnc(); 111 pmnc_contents.Flag = 0; //don't reset anything 112 pmnc_contents.SBZ1 = 0; //per spec 113 pmnc_contents.SBZ2 = 0; //per spec 114 115 //store current state 116 sel4bench_arm1136_pmnc_t pmnc_contents_restore = pmnc_contents; 117 118 //disable counters 119 pmnc_contents.E = 0; 120 sel4bench_private_set_pmnc(pmnc_contents); 121 122 uint32_t* args = (uint32_t*)data; 123 uint32_t mask = args[0]; 124 ccnt_t* values = (ccnt_t*)args[1]; 125 126 //read value of specified counters 127 if (mask & 1) { 128 values[0] = sel4bench_private_get_pmn0(); 129 } 130 if (mask & 2) { 131 values[1] = sel4bench_private_get_pmn1(); 132 } 133 134 //read CCNT 135 args[0] = sel4bench_private_get_ccnt(); 136 137 //restore previous state 138 sel4bench_private_set_pmnc(pmnc_contents_restore); 139} 140 141static KERNELFN void sel4bench_private_set_count_event(void* data) 142{ 143 //bring in arguments 144 uint32_t counter = ((uint32_t)data) >> 31; 145 uint32_t event = ((uint32_t)data) & ~(1U << 31); 146 147 //get contents of PMNC 148 sel4bench_arm1136_pmnc_t pmnc_contents = sel4bench_private_get_pmnc(); 149 pmnc_contents.Flag = 0; //don't reset anything 150 pmnc_contents.SBZ1 = 0; //per spec 151 pmnc_contents.SBZ2 = 0; //per spec 152 153 //store current state 154 sel4bench_arm1136_pmnc_t pmnc_contents_restore = pmnc_contents; 155 156 //stop counters 157 pmnc_contents.E = 0; 158 sel4bench_private_set_pmnc(pmnc_contents); 159 160 //setup specified counter 161 if (counter) { 162 //setting counter 1 163 pmnc_contents_restore.EvtCount2 = event; 164 sel4bench_private_set_pmn1(0); 165 } else { 166 //setting counter 0 167 pmnc_contents_restore.EvtCount1 = event; 168 sel4bench_private_set_pmn0(0); 169 170 } 171 172 //restore previous state 173 sel4bench_private_set_pmnc(pmnc_contents_restore); 174} 175 176/* Silence warnings about including the following functions when seL4_DebugRun 177 * is not enabled when we are not calling them. If we actually call these 178 * functions without seL4_DebugRun enabled, we'll get a link failure, so this 179 * should be OK. 180 */ 181void seL4_DebugRun(void (* userfn) (void *), void* userarg); 182 183//begin actual sel4bench_* api functions 184 185static FASTFN void sel4bench_init() 186{ 187 seL4_DebugRun(&sel4bench_private_init, NULL); 188} 189 190static FASTFN void sel4bench_destroy() 191{ 192 seL4_DebugRun(&sel4bench_private_destroy, NULL); 193} 194 195static FASTFN seL4_Word sel4bench_get_num_counters() 196{ 197 return SEL4BENCH_ARM1136_NUM_COUNTERS; 198} 199 200static FASTFN ccnt_t sel4bench_get_cycle_count() 201{ 202 uint32_t val = 0; 203 seL4_DebugRun(&sel4bench_private_get_cycle_count, &val); 204 return val; 205} 206 207static FASTFN ccnt_t sel4bench_get_counter(counter_t counter) 208{ 209 assert(counter < sel4bench_get_num_counters()); //range check 210 211 uint32_t val = counter; 212 seL4_DebugRun(&sel4bench_private_get_counter, &val); 213 return val; 214} 215 216static FASTFN ccnt_t sel4bench_get_counters(counter_bitfield_t mask, ccnt_t* values) 217{ 218 assert(mask & (sel4bench_get_num_counters() - 1)); //there are only two counters, so there should be no other 1 bits 219 assert(values); //NULL guard -- because otherwise we'll get a kernel fault 220 221 uint32_t args[2] = {mask, (uint32_t)values}; 222 //entry 0: in = mask, out = ccnt 223 //entry 1: in = values 224 seL4_DebugRun(&sel4bench_private_get_counters, args); 225 return args[0]; 226} 227 228static FASTFN void sel4bench_set_count_event(counter_t counter, event_id_t event) 229{ 230 assert(counter < sel4bench_get_num_counters()); //range check 231 232 seL4_DebugRun(&sel4bench_private_set_count_event, (void*)(event | ((counter & 1U) << 31))); 233} 234 235static FASTFN void sel4bench_stop_counters(counter_bitfield_t mask) 236{ 237 /* all three ARM1136 counters have to start at the same time... 238 * so we just start them all at init time and make this a no-op 239 */ 240} 241 242static FASTFN void sel4bench_reset_counters(void) 243{ 244 seL4_DebugRun(&sel4bench_private_reset_gp_counters, NULL); 245} 246 247static FASTFN void sel4bench_start_counters(counter_bitfield_t mask) 248{ 249 /* all three ARM1136 counters have to start at the same time... 250 * so we just start them all at init time and make this reset them 251 */ 252 sel4bench_reset_counters(); 253} 254