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