Commit 27fb9eee authored by Dorel Coman's avatar Dorel Coman Committed by Oliver Horst
Browse files

memguard: improved idention, comments, solved issue with user access to PMU

parent e60d9f1c
......@@ -102,7 +102,8 @@ synchronize all the MemGuard instances */
/* Minimum Guaranteed bandwidth for the main memory in BUS_ACCESS per ms,
eg. 78.000 BUS_ACCESS/ms for 1200 MB/S*/
#define MIN_GUARANTEED_BUDGET (uint32_t) (MIN_GUARANTEED_BW_IN_MB_PER_S * ACCESSES_PER_MB * WINDOW_TIME)
#define MIN_GUARANTEED_BUDGET (uint32_t) \
(MIN_GUARANTEED_BW_IN_MB_PER_S * ACCESSES_PER_MB * WINDOW_TIME)
/* Minimum assigned budget to be given when the static assigned quota of a task
finished called Qmin in memguard - generally should be small - in this case
......@@ -113,10 +114,11 @@ finished called Qmin in memguard - generally should be small - in this case
the task, this doesn't influence the bandwidth cause the task is deleted
before memguard starts monitoring */
#define BANDWIDTH_ASS_MEMGUARD_TASK_IN_MB_PER_S 1000U
#define MEMGUARD_TASK_BUDGET (BANDWIDTH_ASS_MEMGUARD_TASK_IN_MB_PER_S * ACCESSES_PER_MB * WINDOW_TIME)
#define MEMGUARD_TASK_BUDGET \
(BANDWIDTH_ASS_MEMGUARD_TASK_IN_MB_PER_S * ACCESSES_PER_MB * WINDOW_TIME)
/* Base address of the On-Chip Memory where we store the variables shared
among the cores */
among the cores */
#define OCM_ADDRESS 0xFFFC0000
/* Weight used for the ema() function */
......@@ -335,7 +337,6 @@ void memguard_notify_new_task_created(TaskHandle_t task_handle, uint32_t bandwid
/* Converting the bandwidth into the statically assigned budget and
storing it */
new_task_info->ass_budget = convert_mb_to_events(bandwidth);
new_task_info->budget_finished = 0;
/* The average budget is initializes with teh ass_budget in order to
......@@ -363,8 +364,11 @@ void memguard_notify_task_suspended(TaskHandle_t task_handle)
start_memguard_trace();
#endif
memguard_task_info *task_info = (memguard_task_info *) pvTaskGetMemguardTaskInfo(task_handle);
task_info->tsk_susp_by_user = pdTRUE;
memguard_task_info *task_info = (memguard_task_info *)
pvTaskGetMemguardTaskInfo(task_handle);
if(task_info != NULL)
task_info->tsk_susp_by_user = pdTRUE;
#if (INCLUDE_memguard_benchmark)
stop_memguard_trace();
......@@ -377,7 +381,8 @@ void memguard_notify_task_resumed(TaskHandle_t task_handle)
start_memguard_trace();
#endif
memguard_task_info *task_info = (memguard_task_info *) pvTaskGetMemguardTaskInfo(task_handle);
memguard_task_info *task_info = (memguard_task_info *)
pvTaskGetMemguardTaskInfo(task_handle);
task_info->tsk_susp_by_user = pdFALSE;
#if (INCLUDE_memguard_benchmark)
......@@ -394,7 +399,7 @@ void memguard_notify_task_deleted(TaskHandle_t task_handle)
vPortFree(task_info);
}
BaseType_t memguard_is_task_susp_by_memguard(TaskHandle_t xTask)
BaseType_t memguard_can_task_resume(TaskHandle_t xTask)
{
#if (INCLUDE_memguard_benchmark)
start_memguard_trace();
......@@ -408,7 +413,7 @@ BaseType_t memguard_is_task_susp_by_memguard(TaskHandle_t xTask)
/* If the task was suspended and the tsk_susp_by_user flag is false means
that memguard suspended it, otherwise the flag would be pdTRUE */
return task_info->tsk_susp_by_memguard;
return can_task_resume;
}
void memguard_task_reset_window(TaskHandle_t task_handle)
......@@ -421,7 +426,8 @@ void memguard_task_reset_window(TaskHandle_t task_handle)
TaskStatus_t status;
vTaskGetInfo(task_handle, &status, pdFALSE, eInvalid);
memguard_task_info *task_info = pvTaskGetMemguardTaskInfo(task_handle);
memguard_task_info *task_info = (memguard_task_info *)
pvTaskGetMemguardTaskInfo(task_handle);
/* Checking if the task was unable to use all the statically assigned
memory in the last window - in this case we compensate the difference
......@@ -432,7 +438,8 @@ void memguard_task_reset_window(TaskHandle_t task_handle)
/* The substraction represents how much quota the task wasn't able
to use in the last time window */
if(task_info->ass_budget > task_info->curr_used_budget)
new_quota = task_info->ass_budget + (task_info->ass_budget - task_info->curr_used_budget);
new_quota = task_info->ass_budget +
(task_info->ass_budget - task_info->curr_used_budget);
else
new_quota = task_info->ass_budget;
......@@ -442,20 +449,23 @@ void memguard_task_reset_window(TaskHandle_t task_handle)
quota, but checking first if there wasn't an overflow meanwhile,
in order to don't add the wrong value to curr_used_budget */
if(task_info->counter_val > mask_value(task_info->cur_ass_budget))
task_info->curr_used_budget += task_info->counter_val - mask_value(task_info->cur_ass_budget);
task_info->curr_used_budget +=
task_info->counter_val - mask_value(task_info->cur_ass_budget);
else
task_info->curr_used_budget += task_info->cur_ass_budget;
/* Computing the average of bandwidth usage in order to reduce the
allocated quota if not used */
task_info->average_used_budget = ema(task_info->curr_used_budget, task_info->average_used_budget, ALPHA_EMA);
task_info->average_used_budget = ema(task_info->curr_used_budget,
task_info->average_used_budget, ALPHA_EMA);
if(task_info->average_used_budget > task_info->ass_budget){
new_quota = task_info->ass_budget;
} else {
new_quota = task_info->average_used_budget;
atomic_fetch_add(&(memguard_info.global_budget), (task_info->ass_budget - new_quota));
atomic_fetch_add(&(memguard_info.global_budget),
(task_info->ass_budget - new_quota));
}
......@@ -502,7 +512,8 @@ void memguard_switch_in()
#endif
TaskHandle_t taskHandle = xTaskGetCurrentTaskHandle();
memguard_task_info *task_info = (memguard_task_info *) pvTaskGetMemguardTaskInfo(taskHandle);
memguard_task_info *task_info = (memguard_task_info *)
pvTaskGetMemguardTaskInfo(taskHandle);
if(task_info != NULL){
/* From here we are monitoring what the task is doing until it is
......@@ -532,7 +543,8 @@ void memguard_switch_out()
pmu_disable_intr(MEMGUARD_CNTR_ID);
TaskHandle_t taskHandle = xTaskGetCurrentTaskHandle();
memguard_task_info *task_info = (memguard_task_info *) pvTaskGetMemguardTaskInfo(taskHandle);
memguard_task_info *task_info = (memguard_task_info *)
pvTaskGetMemguardTaskInfo(taskHandle);
if(task_info != NULL){
task_info->counter_val = pmu_read_counter(MEMGUARD_CNTR_ID);
......@@ -595,14 +607,17 @@ int setup_inter_core_interrupts()
if(XScuGic_GetCpuID() == MASTER_CORE_ID){
status = XScuGic_Connect(int_controller_ptr, MASTER_MEMGUARD_ICI_INT_ID,
(Xil_ExceptionHandler)periodic_timer_handler_master, (void *)&int_controller_ptr);
(Xil_ExceptionHandler)periodic_timer_handler_master,
(void *)&int_controller_ptr);
if (status != XST_SUCCESS) {
xil_printf("Failed to XScuGic_connect");
return XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(int_controller_ptr, MASTER_MEMGUARD_ICI_INT_ID, ICI_INT_PRIORITY, 0b01);
XScuGic_SetPriorityTriggerType(int_controller_ptr,
MASTER_MEMGUARD_ICI_INT_ID,
ICI_INT_PRIORITY, 0b01);
XScuGic_Enable(int_controller_ptr, MASTER_MEMGUARD_ICI_INT_ID);
}
......@@ -619,7 +634,8 @@ int setup_inter_core_interrupts()
}
/* Enable the interrupt for inter-core communication */
XScuGic_SetPriorityTriggerType(int_controller_ptr, MEMGUARD_ICI_INT_ID, ICI_INT_PRIORITY, 0b01);
XScuGic_SetPriorityTriggerType(int_controller_ptr, MEMGUARD_ICI_INT_ID,
ICI_INT_PRIORITY, 0b01);
XScuGic_Enable(int_controller_ptr, MEMGUARD_ICI_INT_ID);
return XST_SUCCESS;
......@@ -652,9 +668,11 @@ int setup_pmu_overflow_interrupt()
/* Setting the priority of the PMU interrupts to low value, in order to
make the PMU interrupts preemtable by the timer or ICI interrupts.
Trigger type: 0b01 => Active HIGH level sensitive */
XScuGic_SetPriorityTriggerType(int_controller_ptr, PMU_INT_ID, (u8)PMU_OVERFLOW_INT_PRIORITY, 0b01);
XScuGic_SetPriorityTriggerType(int_controller_ptr, PMU_INT_ID,
(u8)PMU_OVERFLOW_INT_PRIORITY, 0b01);
XScuGic_InterruptMaptoCpu(int_controller_ptr, (u8) (XScuGic_GetCpuID()), PMU_INT_ID);
XScuGic_InterruptMaptoCpu(int_controller_ptr, (u8) (XScuGic_GetCpuID()),
PMU_INT_ID);
XScuGic_Enable(int_controller_ptr, PMU_INT_ID);
return XST_SUCCESS;
......@@ -704,7 +722,8 @@ void check_if_cores_are_ready()
on all cores calling the master core to start the framework because
everybody is ready setting the value of cores_ready to 0 so we are
sure that only one core is triggering the master to start */
status = XScuGic_SoftwareIntr(int_controller_ptr, MASTER_MEMGUARD_ICI_INT_ID, MASTER_CORE_ICI_MASK);
status = XScuGic_SoftwareIntr(int_controller_ptr,
MASTER_MEMGUARD_ICI_INT_ID, MASTER_CORE_ICI_MASK);
configASSERT(status == XST_SUCCESS);
}
}
......@@ -738,7 +757,8 @@ void memguard_timer_setup()
/* The following call will map the frequency to the interval and
prescaler values. */
XTtcPs_CalcIntervalFromFreq(&memguard_timer, TIMER_FREQ_MEMGUARD, &INTERVAL, &PRESCALER);
XTtcPs_CalcIntervalFromFreq(&memguard_timer, TIMER_FREQ_MEMGUARD,
&INTERVAL, &PRESCALER);
/* Set the interval and pre-scale */
XTtcPs_SetInterval(&memguard_timer, INTERVAL);
......@@ -746,7 +766,8 @@ void memguard_timer_setup()
/* Connect to the interrupt controller */
status = XScuGic_Connect(int_controller_ptr, TTC_TIMER_INTR_ID,
(Xil_ExceptionHandler) periodic_timer_handler_master, (void *) (&memguard_timer));
(Xil_ExceptionHandler) periodic_timer_handler_master,
(void *) (&memguard_timer));
configASSERT(status == XST_SUCCESS);
/* Enable the GIC for the window timer */
......@@ -791,7 +812,8 @@ static void periodic_timer_handler_master(void *callback_ref)
#endif
/* Calling periodic_timer_handler_slave() on each core through ICI */
int32_t status = XScuGic_SoftwareIntr(int_controller_ptr, MEMGUARD_ICI_INT_ID, CORES_ICI_MASK);
int32_t status = XScuGic_SoftwareIntr(int_controller_ptr,
MEMGUARD_ICI_INT_ID, CORES_ICI_MASK);
/* We need to check if this Software Interrupt is triggered properly,
otherwise we risk that some tasks finish their bandwidth and remain
......@@ -831,7 +853,8 @@ static void periodic_timer_handler_slave(void *callback_ref)
atomic_fetch_sub(&(memguard_info.cores_ready), 1);
}
xTimerPendFunctionCallFromISR(reset_window_routine, NULL, 0, &xHigherPriorityTaskWoken);
xTimerPendFunctionCallFromISR(reset_window_routine, NULL, 0,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#if (INCLUDE_memguard_benchmark)
......@@ -901,7 +924,8 @@ void overflow_interrupt_handler(void *callback_ref)
pmu_clear_interrupt(MEMGUARD_CNTR_ID);
TaskHandle_t curr_task = xTaskGetCurrentTaskHandle();
memguard_task_info *task_info = (memguard_task_info *) pvTaskGetMemguardTaskInfo(curr_task);
memguard_task_info *task_info = (memguard_task_info *)
pvTaskGetMemguardTaskInfo(curr_task);
if(task_info == NULL)
return;
......@@ -949,7 +973,8 @@ void overflow_interrupt_handler(void *callback_ref)
/* Incrementing the budget_used_in_window with the budget used by the
current task */
atomic_fetch_add(&(memguard_info.budget_used_in_window), task_info->curr_used_budget);
atomic_fetch_add(&(memguard_info.budget_used_in_window),
task_info->curr_used_budget);
atomic_uint sum_of_quota_used = atomic_load(&(memguard_info.budget_used_in_window));
#if( PROPORTIONAL_SHARE == 1)
{
......@@ -1011,13 +1036,15 @@ BaseType_t find_new_budget(memguard_task_info *task_info)
} else {
#if(INCLUDE_memguard_benchmark)
trace_reclaim_tries();
trace_reclaim_tries();
#endif
reclaimed = min(global_budget_read, reclaimed);
atomic_store(&new_global_budget, (global_budget_read - reclaimed));
if(atomic_compare_exchange_strong(&(memguard_info.global_budget), &(global_budget_read), new_global_budget)){
if(atomic_compare_exchange_strong(&(memguard_info.global_budget),
&(global_budget_read),
new_global_budget)){
task_info->counter_val = mask_value(reclaimed);
task_info->cur_ass_budget = reclaimed;
......@@ -1027,7 +1054,6 @@ BaseType_t find_new_budget(memguard_task_info *task_info)
}
#endif
return pdTRUE;
}
}
}
......
......@@ -7,6 +7,7 @@
#include "memguard/perfmon.h"
#include <xil/xpseudo_asm.h>
#include "freertos/FreeRTOSConfig.h"
/* Macros used for accessing the register in read and write mode */
#define read_register(REG, VAL) __asm__ __volatile__("mrs %0, "#REG : "=r" (VAL))
......@@ -73,17 +74,19 @@
* Function definitions
******************************************************************************/
/**
* It enables user-mode access to counters. It is important in order to be able
* to use the counters in FreeRTOS
*/
static inline void enable_user_access_to_counters()
{
uint32_t reg_val;
read_register(PMUSERENR_EL0, reg_val);
reg_val = reg_val | PMUSERENR_ENABLE_ALL;
write_register(PMUSERENR_EL0, reg_val);
}
#if(configUSE_PMU_IN_USER_MODE == 1)
/**
* It enables user-mode access to counters. It is important in order to
* be able to use the counters in FreeRTOS
*/
static inline void enable_user_access_to_counters()
{
uint32_t reg_val;
read_register(PMUSERENR_EL0, reg_val);
reg_val = reg_val | PMUSERENR_ENABLE_ALL;
write_register(PMUSERENR_EL0, reg_val);
}
#endif
/**
* This function enables the selected counter in order to make it count. If
......@@ -93,7 +96,7 @@ static inline void enable_user_access_to_counters()
*/
static inline void pmu_enable_counter(uint32_t idx)
{
write_register(PMCNTENSET_EL0, (1 << idx));
write_register(PMCNTENSET_EL0, (1 << idx));
}
/**
......@@ -102,7 +105,7 @@ static inline void pmu_enable_counter(uint32_t idx)
*/
static inline void pmu_disable_counter(uint32_t idx)
{
write_register(PMCNTENSET_EL0, (0 << idx));
write_register(PMCNTENSET_EL0, (0 << idx));
}
/**
......@@ -111,9 +114,9 @@ static inline void pmu_disable_counter(uint32_t idx)
*/
static inline void pmu_control_write(uint32_t val)
{
val &= PMCR_MASK;
isb();
write_register(PMCR_EL0, val);
val &= PMCR_MASK;
isb();
write_register(PMCR_EL0, val);
}
/**
......@@ -122,9 +125,9 @@ static inline void pmu_control_write(uint32_t val)
*/
static inline uint32_t pmu_control_read(void)
{
unsigned int val;
read_register(PMCR_EL0, val);
return val;
unsigned int val;
read_register(PMCR_EL0, val);
return val;
}
/**
......@@ -134,8 +137,8 @@ static inline uint32_t pmu_control_read(void)
*/
static inline void set_pmcr_el0()
{
uint32_t val = pmu_control_read();
pmu_control_write(val | PMCR_E);
uint32_t val = pmu_control_read();
pmu_control_write(val | PMCR_E);
}
......@@ -146,8 +149,8 @@ static inline void set_pmcr_el0()
*/
static inline void pmu_counter_select(uint32_t idx)
{
write_register(PMSELR_EL0, idx);
isb();
write_register(PMSELR_EL0, idx);
isb();
}
/**
......@@ -159,123 +162,127 @@ static inline void pmu_counter_select(uint32_t idx)
*/
static inline void pmu_type_select(uint32_t idx, uint32_t type)
{
pmu_counter_select(idx);
write_register(PMXEVTYPER_EL0, type);
pmu_counter_select(idx);
write_register(PMXEVTYPER_EL0, type);
}
void pmu_init_counters()
{
enable_user_access_to_counters();
set_pmcr_el0();
uint32_t number_of_counters = pmu_get_number_counters();
for (uint32_t i = 0; i < number_of_counters; ++i) {
pmu_clear_interrupt(i);
#if(configUSE_PMU_IN_USER_MODE == 1)
{
enable_user_access_to_counters();
}
#endif
set_pmcr_el0();
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)
{
pmu_disable_counter(idx);
pmu_type_select(idx, event_type);
pmu_enable_counter(idx);
pmu_disable_counter(idx);
pmu_type_select(idx, event_type);
pmu_enable_counter(idx);
}
uint32_t pmu_get_core_id()
{
uint32_t value;
read_register(MPIDR_EL1, value);
value = value & CPU_ID_MASK;
uint32_t value;
read_register(MPIDR_EL1, value);
value = value & CPU_ID_MASK;
return value;
return value;
}
uint32_t pmu_counter_has_overflowed(uint32_t idx)
{
uint32_t value;
read_register(PMOVSSET_EL0, value);
uint32_t value;
read_register(PMOVSSET_EL0, value);
return ((value) & (1 << idx));
return ((value) & (1 << idx));
}
void pmu_enable_intr(uint32_t idx)
{
write_register(PMINTENSET_EL1, (1 << idx));
write_register(PMINTENSET_EL1, (1 << idx));
}
void pmu_disable_intr(uint32_t idx)
{
/* Disabling the interrupt for the selected counter */
write_register(PMINTENCLR_EL1, (1 << idx));
isb();
/* Disabling the interrupt for the selected counter */
write_register(PMINTENCLR_EL1, (1 << idx));
isb();
/* Clearing the interrupt line */
write_register(PMOVSCLR_EL0, (1 << idx));
isb();
/* Clearing the interrupt line */
write_register(PMOVSCLR_EL0, (1 << idx));
isb();
}
void pmu_clear_interrupt(uint32_t idx)
{
write_register(PMOVSCLR_EL0, (1 << idx));
write_register(PMOVSCLR_EL0, (1 << idx));
isb();
}
void pmu_start_counter(uint32_t idx, uint32_t count_val)
{
/* Writing the value on the selected counter */
pmu_write_counter(idx, count_val);
/* Writing the value on the selected counter */
pmu_write_counter(idx, count_val);
/* Clear the interrupt register before enabling it again to be sure it
wasn't already triggered */
pmu_clear_interrupt(idx);
pmu_enable_intr(idx);
/* Clear the interrupt register before enabling it again to be sure it
wasn't already triggered */
pmu_clear_interrupt(idx);
pmu_enable_intr(idx);
}
uint32_t mask_value(uint32_t value)
{
uint32_t MAX = 0xFFFFFFFF;
uint32_t val = MAX - value;
uint32_t MAX = 0xFFFFFFFF;
uint32_t val = MAX - value;
return val;
return val;
}
uint32_t pmu_read_counter(uint32_t idx)
{
uint32_t value;
if (idx == CYLCE_CNTR_ID) {
read_register(PMCCNTR_EL0, value);
uint32_t value;
} else {
pmu_counter_select(idx);
read_register(PMXEVCNTR_EL0, value);
}
return value;
if (idx < pmu_get_number_counters()) {
pmu_counter_select(idx);
read_register(PMXEVCNTR_EL0, value);
return value;
} else {
return 0;
}
}
void pmu_write_counter(uint32_t idx, uint32_t value)
{
if (idx == CYLCE_CNTR_ID) {
write_register(PMCCNTR_EL0, value);
} else {
pmu_counter_select(idx);
write_register(PMXEVCNTR_EL0, value);
}
if (idx < pmu_get_number_counters()) {
pmu_counter_select(idx);
write_register(PMXEVCNTR_EL0, value);
}
}
uint64_t pmu_read_cyclecount(void)
uint64_t pmu_read_cycle_counter(void)
{
uint64_t value;
read_register(PMCCNTR_EL0, value);
return value;
uint64_t value;
read_register(PMCCNTR_EL0, value);
return value;
}
uint32_t pmu_get_number_counters(void)
{
uint32_t count = pmu_control_read();
/* Extracting the bits[15:11] - These bits store the number of counters
available for the respective CPU. The description of the register can be
found in the A53 CPU Technical Reference Manual at the chapter 12.4.1
Performance Monitors Control Register */
count = ((count >> PMCR_N_SHIFT) & PMCR_N_MASK);
return count;
uint32_t count = pmu_control_read();
/* Extracting the bits[15:11] - These bits store the number of counters
available for the respective CPU. The description of the register can be
found in the A53 CPU Technical Reference Manual at the chapter 12.4.1
Performance Monitors Control Register */
count = ((count >> PMCR_N_SHIFT) & PMCR_N_MASK);
return count;
}
\ No newline at end of file
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