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

memguard: improved some idention, comments and submodules

parent 0d334ba1
# TO BE FINISHED
The documentation of MemGuard can be found in the folder freertos/doc
under the name: MemGuard.pdf
TODO:
The function metal_start_slaves() from extra/multi_core needs the files
platform_info.c/.h and rsc_table.c/.h which can be found in runtimes/memguard
and runtimes/memguard/slave. There should be found a solution for the doubled
files and they should be moved inside open-amp submodule. also the
extra/multi_core folder and files should probably be moved inside the
open-amp submodule.
\ No newline at end of file
......@@ -250,6 +250,9 @@ void memguard_init()
uint32_t core_id = pmu_get_core_id();
XScuGic_SetCpuID(core_id);
/* TODO: the cache is disabled until all the cores are boot. It shouldd
be explored further wether we really need to disable the caches or not.
It is also signaled with a TODO where the cache is enabled */
Xil_DCacheDisable();
/* The global variables are initialized by the master core before the slave
......@@ -452,9 +455,7 @@ void memguard_task_reset_window(TaskHandle_t task_handle)
}
#if (INCLUDE_memguard_benchmark)
{
memguard_trace_bw_per_tick(task_info->curr_used_budget);
}
#endif
task_info->counter_val = mask_value(new_quota);
......@@ -475,9 +476,7 @@ void memguard_task_reset_window(TaskHandle_t task_handle)
void memguard_task_switch_in()
{
#if (INCLUDE_memguard_benchmark)
{
start_memguard_trace();
}
#endif
TaskHandle_t taskHandle = xTaskGetCurrentTaskHandle();
......@@ -490,25 +489,19 @@ void memguard_task_switch_in()
pmu_start_counter(MEMGUARD_CNTR_ID, task_info->counter_val);
#if(INCLUDE_memguard_benchmark)
{
start_benchmark_trace();
}
#endif
}
#if (INCLUDE_memguard_benchmark)
{
stop_memguard_trace();
}
#endif
}
void memguard_task_switch_out()
{
#if (INCLUDE_memguard_benchmark)
{
start_memguard_trace();
}
#endif
/* The PMU overflow interrupt is disabled because it is not wanted that
......@@ -523,16 +516,12 @@ void memguard_task_switch_out()
task_info->counter_val = pmu_read_counter(MEMGUARD_CNTR_ID);
#if(INCLUDE_memguard_benchmark)
{
stop_benchmark_trace();
}
#endif
}
#if (INCLUDE_memguard_benchmark)
{
stop_memguard_trace();
}
#endif
}
......@@ -550,30 +539,32 @@ static void memguard_init_task(void *arg)
int status;
int_controller_ptr = &xInterruptController;
/* */
/* We initialize the PMU counters and enable the MemGuard counter in
order to measure the BUS_ACCESS usage*/
pmu_init_counters();
pmu_enable_counter_for_event(MEMGUARD_CNTR_ID,
ARMV8_PMUV3_PERFCTR_BUS_ACCESS);
/* */
/* We initialize the inter core interrupts in order to enable
communication from the master core to the slave and vice versa */
status = setup_inter_core_interrupts();
configASSERT(status == XST_SUCCESS);
/* */
/* We setup the PMU overflow interrupt handler in order to catch the
MemGuard counter interrupt and handle it*/
status = setup_pmu_overflow_interrupt();
configASSERT(status == XST_SUCCESS);
/* */
/* The MemGuard timer is setup only on the master core. The timer is
meant to keep the time of the MemGuard windows, generally 1 ms*/
if(XScuGic_GetCpuID() == MASTER_CORE_ID){
memguard_timer_setup();
}
/**
* The last core to finish MemGuard initialization issues the first MemGuard
* ICI interrupt to the master core, to initiate the first window. The shared
* variable "cores_ready" is used for this synchronization purpose.
*/
/* The last core to finish MemGuard initialization issues the first MemGuard
ICI interrupt to the master core, to initiate the first window. The shared
variable "cores_ready" is used for this synchronization purpose. */
atomic_uint number_of_cores_ready;
atomic_init(&number_of_cores_ready, 0);
......@@ -581,7 +572,7 @@ static void memguard_init_task(void *arg)
atomic_fetch_add(&(memguard_info.cores_ready), 1);
number_of_cores_ready = atomic_load(&(memguard_info.cores_ready));
/* Checking how many cores are already initialized */
/* Checking how many cores are already initialized */
if(number_of_cores_ready == NUMBER_CORES){
/* The scheduler is suspended in order to wait for memguard to be ready
......@@ -593,7 +584,8 @@ static void memguard_init_task(void *arg)
configASSERT(status == XST_SUCCESS);
}
/* Delete MemGuard initialization task, as its job is done and it is not used anymore. */
/* Delete MemGuard initialization task, as its job is done and it is
not used anymore. */
vTaskDelete(NULL);
}
......@@ -641,7 +633,7 @@ static int setup_inter_core_interrupts()
return XST_FAILURE;
}
/* Enable the interrupt for inter-core communication */
/* Enable the interrupt for inter-core communication */
XScuGic_SetPriorityTriggerType(int_controller_ptr, MEMGUARD_ICI_INT_ID,
ICI_INT_PRIORITY, 0b01);
XScuGic_Enable(int_controller_ptr, MEMGUARD_ICI_INT_ID);
......@@ -705,31 +697,31 @@ static void memguard_timer_setup()
u8 PRESCALER = 0; // PreScaler value
u16 TIMER_OPTIONS = 0; // Option settings
/* Set up appropriate options for window timer: interval mode without
/* Set up appropriate options for window timer: interval mode without
waveform output */
TIMER_OPTIONS |= (XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE);
/* Look up the configuration based on the device identifier */
/* Look up the configuration based on the device identifier */
config = XTtcPs_LookupConfig(TTC_TIMER_DEVICE_ID);
configASSERT(config != NULL);
/* Initialize the TTC device */
/* Initialize the TTC device */
status = XTtcPs_CfgInitialize(&memguard_timer, config, config->BaseAddress);
configASSERT(status == XST_SUCCESS);
/* Set the options */
/* Set the options */
XTtcPs_SetOptions(&memguard_timer, TIMER_OPTIONS);
/* The following call will map the frequency to the interval and
/* The following call will map the frequency to the interval and
prescaler values. */
XTtcPs_CalcIntervalFromFreq(&memguard_timer, TIMER_FREQ_MEMGUARD,
&INTERVAL, &PRESCALER);
/* Set the interval and pre-scale */
/* Set the interval and pre-scale */
XTtcPs_SetInterval(&memguard_timer, INTERVAL);
XTtcPs_SetPrescaler(&memguard_timer, PRESCALER);
/* Connect to the interrupt controller */
/* Connect to the interrupt controller */
status = XScuGic_Connect(int_controller_ptr, TTC_TIMER_INTR_ID,
(Xil_ExceptionHandler) periodic_timer_handler_master,
(void *) (&memguard_timer));
......@@ -752,35 +744,35 @@ static void memguard_timer_setup()
*/
static void periodic_timer_handler_master(void *callback_ref)
{
/* Stop the timer because we need to start a new window */
/* Stop the timer because we need to start a new window */
XTtcPs_Stop(&memguard_timer);
#if (INCLUDE_memguard_benchmark)
start_memguard_trace();
#endif
/* Reaad the interrupt status, then write it back to clear the interrupt. */
/* Read the interrupt status, then write it back to clear the interrupt. */
u32 status_event = XTtcPs_GetInterruptStatus((XTtcPs *)callback_ref);
/* We clear the interrupt status only if it was triggered by a timer */
if ((XTTCPS_IXR_INTERVAL_MASK & status_event) != 0) {
XTtcPs_ClearInterruptStatus((XTtcPs *)callback_ref, status_event);
}
/* The global shared budget has to be reset to 0 */
/* The global shared budget has to be reset to 0 */
atomic_store(&(memguard_info.global_budget), 0);
/* Resetting the total budget used by the the cores */
/* Resetting the total budget used by the the cores */
atomic_store(&(memguard_info.budget_used_in_window), 0);
#if (INCLUDE_memguard_benchmark)
stop_memguard_trace();
#endif
/* Calling periodic_timer_handler_slave() on each core through ICI */
/* 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);
/* We need to check if this Software Interrupt is triggered properly,
/* We need to check if this Software Interrupt is triggered properly,
otherwise we risk that some tasks finish their bandwidth and remain
blocked in the suspended status */
configASSERT(status == XST_SUCCESS);
......@@ -802,11 +794,13 @@ static void periodic_timer_handler_slave(void *callback_ref)
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Re-enabling the Cache after it was disabled at start of the program.
/* Re-enabling the Cache after it was disabled at start of the program.
We disable the cache selectively only for the parts shared among the
cores */
if(atomic_load(&(memguard_info.cores_ready)) > 0){
/* TODO: the cache is enabled again, it should be checked wether
there is a need of enabling/disabling the cache during the boot. */
u64 attrib = (NORM_NONCACHE | INNER_SHAREABLE | OUTER_SHAREABLE);
Xil_SetTlbAttributes((UINTPTR) __ocm_ram_start, attrib);
Xil_DCacheEnable();
......@@ -840,9 +834,7 @@ static void memguard_reset_window_routine(void *pvParameter1,
uint32_t ulParameter2)
{
#if (INCLUDE_memguard_benchmark)
{
start_memguard_trace();
}
#endif
/* This routine should not be preempted by any task until it finishes
......@@ -885,8 +877,9 @@ static void memguard_overflow_interrupt_handler(void *callback_ref)
#endif
/* Checks if PMU has really really overflowed for the BUS_ACCESS counter.
It may happend that another counter has overflowed triggering the
interrupt handler, but our handler is not responsible for that counter. */
There is only one interrupt line for 6 counters. MemGuard uses only one
counter and therefore we have to check if MemGuard's counter has
overflowed or another counter of which we are not responsible of. */
if(!pmu_counter_has_overflowed(MEMGUARD_CNTR_ID)){
goto stop_trace;
}
......@@ -899,27 +892,24 @@ static void memguard_overflow_interrupt_handler(void *callback_ref)
/* CASE 1:
* An overflow occured while the TimerTask, IdleTask or MemGuard
was executing, hence, we simple return, as we are not monitoring
them. No other task will reach this point if its task_info is NULL.
*/
An overflow occured while the TimerTask, IdleTask or MemGuard was
executing, hence, we simple return, as we are not monitoring
them. No other task will reach this point if its task_info is NULL. */
if(task_info == NULL){
goto stop_trace;
}
/* CASE 2:
* Check whether there is still globally shared budget available (managed in
* variable global_budget). If yes, we can try to allocate parts of it and
* assign it to the current task.
*/
Check whether there is still globally shared budget available (managed in
variable global_budget). If yes, we can try to allocate parts of it and
assign it to the current task. */
uint32_t reclaimed = reclaim_budget(task_info);
if(reclaimed > 0){
/* We were able to reclaim additional budget and assign it to the
* current task.
*/
current task. */
task_info->counter_val = mask_value(reclaimed);
task_info->cur_ass_budget = reclaimed;
......@@ -932,18 +922,17 @@ static void memguard_overflow_interrupt_handler(void *callback_ref)
/* CASE 3:
* Even though our current task was interrupted by MemGuard, because we
* exceeded our assigned budget, we still might be below our statically
* assigned budget. This might happen, because we donated some budget
* at the beginning of the window, but we already finished the dynamically
* assigned bandwidth. As we were not able to reclaim additional bandwidth,
* we face the issue that our donated budget was already used by other
* tasks. The heuristic presented by the original paper suggests to let the
* task continue its execution anyhow. This might gives the current task
* the chance to still use its full statically assigned bandwidth. At the
* beginning of the next window the prediction for the dynamic memory
* budgeting will be adjusted accordingly.
*/
Even though our current task was interrupted by MemGuard, because we
exceeded our assigned budget, we still might be below our statically
assigned budget. This might happen, because we donated some budget
at the beginning of the window, but we already finished the dynamically
assigned bandwidth. As we were not able to reclaim additional bandwidth,
we face the issue that our donated budget was already used by other
tasks. The heuristic presented by the original paper suggests to let the
task continue its execution anyhow. This might gives the current task
the chance to still use its full statically assigned bandwidth. At the
beginning of the next window the prediction for the dynamic memory
budgeting will be adjusted accordingly. */
if (task_info->curr_used_budget < task_info->ass_budget){
/* The task is free to try to use some bandwidth until the end of
......@@ -964,17 +953,15 @@ static void memguard_overflow_interrupt_handler(void *callback_ref)
/* CASE 4:
* In case proportional sharing is enabled, we check whether the bandwidth
* consumed by all tasks on all cores during this window already exceeds
* the guaranteed minimal bandwidth. If yes, we issue a window reset to start
* freshly with a new budget share for all tasks/cores. We reach this situation
* if the tasks from all cores have finished their budget.
*/
In case proportional sharing is enabled, we check whether the bandwidth
consumed by all tasks on all cores during this window already exceeds
the guaranteed minimal bandwidth. If yes, we issue a window reset to start
freshly with a new budget share for all tasks/cores. We reach this situation
if the tasks from all cores have finished their budget. */
#if( PROPORTIONAL_SHARE == 1)
{
/* Incrementing the budget_used_in_window with the budget used by the
* current task
*/
current task */
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));
......@@ -984,7 +971,7 @@ static void memguard_overflow_interrupt_handler(void *callback_ref)
if (sum_of_quota_used >= MIN_GUARANTEED_BUDGET){
int status;
/* Calling the master core in order to start a new time window */
/* Calling the master core in order to start a new time window */
status = XScuGic_SoftwareIntr(int_controller_ptr,
MASTER_MEMGUARD_ICI_INT_ID, MASTER_CORE_ICI_MASK);
configASSERT(status == XST_SUCCESS);
......@@ -996,11 +983,10 @@ static void memguard_overflow_interrupt_handler(void *callback_ref)
/* CASE 5:
* The current task exceeded its currently assigned memory bandwidth, failed
* on reclaiming additional budget, even consumed all of its statically
* assigned budget. Thus, we have to suspend the task, as it has used all its
* budget.
*/
The current task exceeded its currently assigned memory bandwidth, failed
on reclaiming additional budget, even consumed all of its statically
assigned budget. Thus, we have to suspend the task, as it has used all its
budget. */
xTimerPendFunctionCallFromISR(suspend_task_routine, curr_task, 0, NULL);
portYIELD_FROM_ISR(pdTRUE);
......@@ -1024,15 +1010,15 @@ uint32_t reclaim_budget(memguard_task_info_t *task_info)
atomic_uint new_global_budget;
atomic_init(&new_global_budget, 0);
/* Adding the dynamic assigned quota, which was all used, to the
/* Adding the dynamic assigned quota, which was all used, to the
currently used quota to keep track of total quota used by the task in
the current window */
task_info->curr_used_budget += task_info->cur_ass_budget;
/* If the task has already used more than its ass_budget we are
assigning to it a small value called MIN_ASSIGNED_BUDGET of value
equivalent to 25 MB/s */
/* If the task has already used more than its ass_budget we are
assigning to it a small value called MIN_ASSIGNED_BUDGET of value
equivalent to 25 MB/s */
if(task_info->curr_used_budget < task_info->ass_budget){
reclaimed = task_info->ass_budget - task_info->curr_used_budget;
......@@ -1064,9 +1050,7 @@ uint32_t reclaim_budget(memguard_task_info_t *task_info)
task_info->cur_ass_budget = reclaimed;
#if (INCLUDE_memguard_benchmark)
{
trace_reclaim_exec(reclaimed);
}
#endif
break;
......
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