Commit 5b3009be authored by Dorel Coman's avatar Dorel Coman Committed by Oliver Horst
Browse files

memguard: restructured code for the perfon API

parent c4b422e1
/*
/******************************************************************************************************************
* Created by Dorel Coman on 23.10.17.
*
* This file contains all the events which can be monitored by Performance Monitor Unit (PMU) for each core
* The perfmon.c API provided can be used to monitor these events and trigger and interrupt when a certain
* event is occurring for a certain amount of times.
*
* With the function pmu_type_select() in perfmon.c one can choose which of the following events to monitor.
* With the function pmu_type_select() inside perfmon.c one can choose which of the following events to monitor.
*
* For a better description of the events check the paragraph "12.9 Events" in the technical reference manual of the
* ARM Cortex-A53
*
* Following list is taken from https://elixir.bootlin.com/linux/v4.0/source/arch/arm64/kernel/perf_event.c
*/
*******************************************************************************************************************/
#ifndef PROJECT_EVENTS_H
#define PROJECT_EVENTS_H
/* Required events. */
/* Required events. */
#define ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR 0x00
#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL 0x03
#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS 0x04
......@@ -24,11 +24,11 @@
#define ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES 0x11
#define ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED 0x12
/* At least one of the following is required. */
/* At least one of the following is required. */
#define ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED 0x08
#define ARMV8_PMUV3_PERFCTR_OP_SPEC 0x1B
/* Common architectural events. */
/* Common architectural events. */
#define ARMV8_PMUV3_PERFCTR_MEM_READ 0x06
#define ARMV8_PMUV3_PERFCTR_MEM_WRITE 0x07
#define ARMV8_PMUV3_PERFCTR_EXC_TAKEN 0x09
......@@ -42,7 +42,7 @@
#define ARMV8_PMUV3_PERFCTR_CHAIN 0x1E
#define ARMV8_PMUV3_PERFCTR_BR_RETIRED 0x21
/* Common microarchitectural events. */
/* Common microarchitectural events. */
#define ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL 0x01
#define ARMV8_PMUV3_PERFCTR_ITLB_REFILL 0x02
#define ARMV8_PMUV3_PERFCTR_DTLB_REFILL 0x05
......@@ -73,7 +73,7 @@
#define ARMV8_PMUV3_PERFCTR_L2D_TLB 0x2F
#define ARMV8_PMUV3_PERFCTR_L21_TLB 0x30
/* ARMv8 Cortex-A53 specific event types. */
/* ARMv8 Cortex-A53 specific event types. */
#define ARMV8_A53_PERFCTR_PREFETCH_LINEFILL 0xC2
#endif //PROJECT_EVENTS_H
\ No newline at end of file
/*
/****************************************************************************************
* Created by Dorel Coman on 23.10.17
*
* TODO:
*/
* This API provides functionalities for accessing the Performance Monitor Counters (PMU)
* registers of the ARM64 architectures
*
* Functions written in this file are freely inspired by the ARM64 implementation for Linux
* https://elixir.bootlin.com/linux/v4.0/source/arch/arm64/kernel/perf_event.c
*
****************************************************************************************/
#ifndef PROJECT_PERFMON_H
#define PROJECT_PERFMON_H
#include <xil/xil_smc.h>
#include <stdint-gcc.h>
#include "memguard/events.h"
/* counter used by MemGuard for counting BUS_ACCESS events*/
/* Id to be used on the functions below in case it is wanted to read/write the cycle counter PMCCNTR_EL0 */
#define CYLCE_CNTR_ID 31U
/***********************************************************************************
* Ids of used counters
**********************************************************************************/
/* Counter used by MemGuard for counting BUS_ACCESS events */
#define MEMGUARD_CNTR_ID 0
/* counters used by the benchmark */
/* Counters used by the MemgGuard benchmark functions */
#define BENCH_1_CNTR_ID_BUS_ACCESS 1
#define BENCH_2_CNTR_ID_INSTR_EX 2
#define BENCH_3_CNTR_ID_CLOCK_CYCLES 3
#define BENCH_4_CNTR_ID_CLOCK_CYCLES_OVER 4
#define CYLCE_CNTR_ID 31U
#define COUNTER_OVERFLOWED 1U
/***********************************************************************************
* Function declaration
**********************************************************************************/
/**
* This function sets up the Performance Monitor Unit (PMU) counters.
* It enables them and select the BUS ACCESS to be monitored by the counter 0
* We are using the counter 0 assuming that no other part of the program is using the counters
* This function initialize the Performance Monitor Unit (PMU) counters and
* should be executed before using the PMU.
*/
void pmu_init_counters();
/**
* This function sets up the Performance Monitor Unit (PMU) counters.
* It enables them and select the BUS ACCESS to be monitored by the counter 0
* We are using the counter 0 assuming that no other part of the program is using the counters
* This function enables the selected counter to monitor the selected event typ
*
* @param idx of the counter to be enabled
* @param event_type to monitored by the idx counter. The type of events, that can be
* monitored, can be found in events.h
*/
void pmu_enable_counter_for_event(uint32_t idx, uint32_t event_type);
/**
* This function returns the id of the core on which it is executed
* It returns the id of the core on which the program is executed
* retrieving it from the register MPIDR_EL1
* @return cpu_id
*
* @return cpu_id of the core running the program
*/
uint32_t pmu_get_core_id();
/**
* This function checks if one of the counters of the respective core has overflowed
* @return : 1 if the PMU counters have overflowed - 0 if they have not
*/
uint32_t pmu_counter_has_overflowed();
/**
* This function check if the selected counter has overflowed
* @param idx
* @return 1 if the counter idx has overflowed - 0 if it has not
*/
uint32_t pmu_counter_has_overflowed(uint32_t idx);
/**
* This function enable the interrupt line for the selected counter
* This function enable the interrupt in case of overflow for the selected counter
* @param idx of the counter
*/
void pmu_enable_intr(uint32_t idx);
/**
* This function disables the interrupts of a certain counter
* This function disables the interrupt in case of overflow for the selected counter
* @param idx
*/
void pmu_disable_intr(uint32_t idx);
......@@ -71,18 +81,18 @@ void pmu_disable_intr(uint32_t idx);
*/
void pmu_clear_interrupt(uint32_t idx);
/**
* This function enables the counter interrupt and sets the value of the counter COUNTER_ID
* to make it overflow when it reaches the value "mask_value(count_val)"
* Last it clears the overflow interrupt flag to be sure that it is not triggered already
*
* @param count_val value to be set on the counter - is should be masked before being set.
*/
void pmu_start_counter(uint32_t count_val);
/**
* This function enables interrupt and sets the value for the selected counter
*
* @param idx of the counter to be enabled and set
* @param count_val value to be set on the counter
*/
void pmu_start_counter(uint32_t idx, uint32_t count_val);
/**
* This function is needed for computing the value to set on the counter to make it overflow
* Setting the masked value to a counter, makes it overflow after this number of occurencies
* This function computes the masked value of the given input using the value 0xFFFFFFFF as base.
* This is used in order to make overflow a counter after the selected number of occurencies.
* The masked value has to be set on the counter.
*/
uint32_t mask_value(uint32_t value);
......@@ -94,22 +104,21 @@ uint32_t mask_value(uint32_t value);
uint32_t pmu_read_counter(uint32_t idx);
/**
*
* This function writes a value on a selected counter
* @param idx of the counter to write the value
* @param value value to be written in the PMU counter
*/
void pmu_write_counter(u32 idx, u32 value);
void pmu_write_counter(uint32_t idx, uint32_t value);
/**
* This functions returns the cycle count value
*
* @return
* This functions returns the cycle count which is kept inside the PMCCNTR_EL0 counter
* @return cycle count in 64 bits
*/
uint64_t pmu_read_cyclecount(void);
/**
* This function returns the number of counters implemented in the respective CPU
* @return # of counters available
* @return # of counters implemented
*/
uint32_t pmu_get_number_counters(void);
......
/*
* Created by Dorel Coman on 21.10.17.
*
* Functions written in this file are freely inspired by the ARM64 implementation for Linux
* https://elixir.bootlin.com/linux/v4.0/source/arch/arm64/kernel/perf_event.c
*/
#include "memguard/perfmon.h"
......@@ -15,7 +14,7 @@
/* Mask used for extracting the CPU_ID from the MPIDR_EL1 register */
#define CPU_ID_MASK (uint32_t) (0xFF)
/* Macros used for accessing the PMU registers and for their setup */
/* Macros used for accessing and setting up the PMU registers */
#define PMCR_MASK 0x3f
#define PMCR_E (1 << 0) /* Enable all counters */
#define PMCR_P (1 << 1) /* Reset all counters */
......@@ -29,9 +28,9 @@
#define PMUSERENR_ER (1 << 3) /* Event counter read enable */
#define PMUSERENR_ENABLE_ALL 0xD
/**
/*********************************************************
* Registers of the Performance Monitor Unit (PMU)
*/
*********************************************************/
/* Performance Monitors Event Counter Selection Register */
#define PMSELR_EL0 "PMSELR_EL0"
......@@ -71,11 +70,11 @@
void set_pmcr_el0();
void enable_user_access_to_counters();
void pmu_enable_counter(unsigned int idx);
void pmu_type_select(unsigned int idx, unsigned int type);
void pmu_enable_counter(uint32_t idx);
void pmu_type_select(uint32_t idx, uint32_t type);
uint32_t pmu_control_read(void);
void pmu_control_write(u32 val);
void pmu_counter_select(unsigned int idx);
void pmu_counter_select(uint32_t idx);
/***********************************************************************************
* Function definitions
......@@ -85,8 +84,11 @@ void pmu_init_counters()
{
enable_user_access_to_counters();
set_pmcr_el0();
// TODO: improve
pmu_clear_interrupt(MEMGUARD_CNTR_ID);
uint32_t number_of_counters = pmu_get_number_counters();
for (uint32_t i = 0; i < number_of_counters; ++i) {
pmu_clear_interrupt(i);
}
}
void pmu_enable_counter_for_event(uint32_t idx, uint32_t event_type)
......@@ -104,12 +106,12 @@ uint32_t pmu_get_core_id()
return value;
}
uint32_t pmu_counter_has_overflowed()
uint32_t pmu_counter_has_overflowed(uint32_t idx)
{
uint32_t value;
read_register(PMOVSSET_EL0, value);
return value;
return ((value) & (1 << idx));
}
void pmu_enable_intr(uint32_t idx)
......@@ -134,7 +136,7 @@ void pmu_clear_interrupt(uint32_t idx)
write_register(PMOVSCLR_EL0, (1 << idx));
}
void pmu_start_counter(uint32_t count_val)
void pmu_start_counter(uint32_t idx, uint32_t count_val)
{
/* writing the value on the selected counter */
pmu_write_counter(MEMGUARD_CNTR_ID, count_val);
......@@ -165,7 +167,7 @@ uint32_t pmu_read_counter(uint32_t idx)
return value;
}
void pmu_write_counter(u32 idx, u32 value)
void pmu_write_counter(uint32_t idx, uint32_t value)
{
if (idx == 31) {
write_register(PMCCNTR_EL0, value);
......@@ -185,14 +187,14 @@ uint64_t pmu_read_cyclecount(void)
uint32_t pmu_get_number_counters(void)
{
uint32_t count = pmu_control_read();
/* N, bits[15:11] */
/* extracting the bits[15:11] */
count = ((count >> PMCR_N_SHIFT) & PMCR_N_MASK);
return count;
}
/**
* Enable user-mode access to counters. It is fundamental to can use the counters
* in FreeRTOS
* It enables user-mode access to counters. It is important in order to be able
* to use the counters in FreeRTOS
*/
void enable_user_access_to_counters()
{
......@@ -203,7 +205,8 @@ void enable_user_access_to_counters()
}
/**
* pmu_enable_count - enable counter number n (idx)
* This function enables the selected counter in order to make it count. If the counter is not
* enabled, it will not count the occurencies of its selected event type
* @idx: The counter n index
*/
void pmu_enable_counter(uint32_t idx)
......@@ -212,7 +215,8 @@ void pmu_enable_counter(uint32_t idx)
}
/**
*
* This function reads the PMCR_EL0 register and writes it back with the value
* needed in order to activate the PMU counters. The PMCR_E mask enables all the counters
*/
void set_pmcr_el0()
{
......@@ -221,7 +225,8 @@ void set_pmcr_el0()
}
/**
* provides details of the Performance Monitors implementation
* This function returns the value of the PMCR_EL0 register
* @return PMCR_EL0 value
*/
uint32_t pmu_control_read(void)
{
......@@ -231,8 +236,8 @@ uint32_t pmu_control_read(void)
}
/**
* This function writes the PMCR register
* @param val
* This function writes the PMCR register of the PMU
* @param val to be written inside the PMCR register
*/
void pmu_control_write(uint32_t val)
{
......@@ -242,8 +247,8 @@ void pmu_control_write(uint32_t val)
}
/**
* This function selects the counter on which we want to execute some tasks
* @param idx
* This function selects the counter on which it is wanted to executed some PMU operations
* @param idx of the counter to be selecte
*/
void pmu_counter_select(uint32_t idx)
{
......@@ -252,11 +257,11 @@ void pmu_counter_select(uint32_t idx)
}
/**
* This function selects for a define counter, the type of event to be monitored and
* This function selects for the selected counter the type of event to be monitored and
* counted
* @param idx of the counter to be defined
* @param type of the event to be monitored. The events that can be monitored are contained
* in the file events.h
* @param idx of the counter of which it is being selected the event
* @param type of the event to be monitored. Events that can be monitored are contained
* in the file events.h
*/
void pmu_type_select(uint32_t idx, uint32_t type)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment