-
rahix authored
Disable all maskable interrupts on core 1 during API calls. This brings two main advantages: 1. It means API calls are now always ISR-safe and can be used everywhere in core 1 code. This is mostly interesting to l0dables as Pycardium should not need to do this. 2. It allows Epicardium to halt the clock for core 1 without fear as we have observed problems with doing this when core 1 is currently executing instructions that touch memory. Now a synchronous call from core 1 will guarantee that it is currently waiting in a WFE and no other ISRs could be potentially running.
rahix authoredDisable all maskable interrupts on core 1 during API calls. This brings two main advantages: 1. It means API calls are now always ISR-safe and can be used everywhere in core 1 code. This is mostly interesting to l0dables as Pycardium should not need to do this. 2. It allows Epicardium to halt the clock for core 1 without fear as we have observed problems with doing this when core 1 is currently executing instructions that touch memory. Now a synchronous call from core 1 will guarantee that it is currently waiting in a WFE and no other ISRs could be potentially running.
caller.c 2.52 KiB
#include <stdlib.h>
#include "sema.h"
#include "api/caller.h"
#define MXC_ASSERT_ENABLE
#include "mxc_assert.h"
static uint32_t irq_save = 0;
void *_api_call_start(api_id_t id, uintptr_t size)
{
/*
* Disable all maskable interrupts here, to be turned on again at the
* end of _api_call_transact().
*/
irq_save = __get_PRIMASK();
__set_PRIMASK(1);
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {
}
if (API_CALL_MEM->call_flag != _API_FLAG_IDLE) {
/*
* The only way this can happen is if a call was issued from an
* interrupt hander while another call is still happening. This
* has to be prevented at all cost!
*/
mxc_assert(
"API recalled during ongoing call!",
__FILE__,
__LINE__
);
}
API_CALL_MEM->id = id;
return API_CALL_MEM->buffer;
}
void *_api_call_transact(void *buffer)
{
API_CALL_MEM->call_flag = _API_FLAG_CALLING;
SEMA_FreeSema(_API_SEMAPHORE);
/* Notify the dispather of the new call */
__SEV();
__WFE();
while (1) {
/* Wait for the dispather to return */
__WFE();
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {
}
if (API_CALL_MEM->call_flag == _API_FLAG_RETURNED) {
break;
}
SEMA_FreeSema(_API_SEMAPHORE);
}
API_CALL_MEM->call_flag = _API_FLAG_IDLE;
SEMA_FreeSema(_API_SEMAPHORE);
/*
* Re-enable interrupts (if previously enabled) after completing the API
* call.
*/
__set_PRIMASK(irq_save);
return API_CALL_MEM->buffer;
}
__attribute__((noreturn)) void epic_exit(int ret)
{
/*
* Call __epic_exit() and then jump to the reset routine/
*/
void *buffer;
buffer = _api_call_start(API_SYSTEM_EXIT, sizeof(int));
*(int *)buffer = ret;
_api_call_transact(buffer);
API_CALL_MEM->reset_stub();
/* unreachable */
while (1)
;
}
int epic_exec(char *name)
{
/*
* Call __epic_exec(). If it succeeds, jump to the reset routine.
* Otherwise, return the error code.
*/
void *buffer;
buffer = _api_call_start(API_SYSTEM_EXEC, sizeof(char *));
*(char **)buffer = name;
int ret = *(int *)_api_call_transact(buffer);
if (ret < 0) {
return ret;
}
API_CALL_MEM->reset_stub();
/* unreachable */
while (1)
;
}
int api_fetch_args(char *buf, size_t cnt)
{
if (API_CALL_MEM->id != 0) {
/*
* When any call happened before the args are fetched, they are
* overwritten and no longer accessible.
*/
return (-1);
}
if (API_CALL_MEM->buffer[0x20] == '\0') {
return 0;
}
size_t i;
for (i = 0; i < cnt && API_CALL_MEM->buffer[i + 0x20] != '\0'; i++) {
buf[i] = API_CALL_MEM->buffer[i + 0x20];
}
return i - 1;
}