Skip to content
Snippets Groups Projects
  • rahix's avatar
    92741109
    feat(api-caller): Hard-disable all IRQs during API calls · 92741109
    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.
    92741109
    History
    feat(api-caller): Hard-disable all IRQs during API calls
    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.
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;
}