diff --git a/thermosphere/src/core_ctx.h b/thermosphere/src/core_ctx.h
index 8da5fac3a..5106f4163 100644
--- a/thermosphere/src/core_ctx.h
+++ b/thermosphere/src/core_ctx.h
@@ -17,20 +17,23 @@
#pragma once
#include "utils.h"
#include "barrier.h"
+#include "execute_function.h"
typedef struct CoreCtx {
- u64 kernelArgument; // @0x00
- uintptr_t kernelEntrypoint; // @0x08
- u8 *crashStack; // @0x10
- u64 scratch; // @0x18
- u32 coreId; // @0x20
- u8 gicInterfaceId; // @0x24
- bool isBootCore; // @0x25
- bool warmboot; // @0x26
+ u64 kernelArgument; // @0x00
+ uintptr_t kernelEntrypoint; // @0x08
+ u8 *crashStack; // @0x10
+ u64 scratch; // @0x18
+ u32 coreId; // @0x20
+ u8 gicInterfaceId; // @0x24
+ bool isBootCore; // @0x25
+ bool warmboot; // @0x26
// "Execute function"
- void *asyncFunctionArgs; // @0x28
- Barrier asyncFunctionBarrier; // @0x30
+ ExecutedFunction executedFunction; // @0x28
+ void *executedFunctionArgs; // @0x30
+ Barrier executedFunctionBarrier; // @0x38
+ bool executedFunctionSync; // @0x3C
} CoreCtx;
extern CoreCtx g_coreCtxs[4];
diff --git a/thermosphere/src/execute_function.c b/thermosphere/src/execute_function.c
new file mode 100644
index 000000000..dcf019ef5
--- /dev/null
+++ b/thermosphere/src/execute_function.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "execute_function.h"
+#include "utils.h"
+#include "core_ctx.h"
+#include "irq.h"
+
+void executeFunctionOnCores(ExecutedFunction fun, void *args, bool sync, u32 coreList)
+{
+ barrierInit(¤tCoreCtx->executedFunctionBarrier, coreList);
+ currentCoreCtx->executedFunction = fun;
+ currentCoreCtx->executedFunctionArgs = args;
+ currentCoreCtx->executedFunctionSync = sync;
+
+ generateSgiForList(ThermosphereSgi_ExecuteFunction, coreList);
+}
+
+void executeFunctionOnAllCores(ExecutedFunction fun, void *args, bool sync)
+{
+ executeFunctionOnCores(fun, args, sync, getActiveCoreMask());
+}
+
+void executeFunctionOnAllCoresButSelf(ExecutedFunction fun, void *args, bool sync)
+{
+ executeFunctionOnCores(fun, args, sync, getActiveCoreMask() & ~(BIT(currentCoreCtx->coreId)));
+}
+
+void executeFunctionInterruptHandler(u32 srcCore)
+{
+ CoreCtx *ctx = &g_coreCtxs[srcCore];
+ ctx->executedFunction(ctx->executedFunctionArgs);
+ if (ctx->executedFunctionSync) {
+ barrierWait(&ctx->executedFunctionBarrier);
+ }
+}
\ No newline at end of file
diff --git a/thermosphere/src/execute_function.h b/thermosphere/src/execute_function.h
new file mode 100644
index 000000000..202dc546c
--- /dev/null
+++ b/thermosphere/src/execute_function.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#pragma once
+
+#include "types.h"
+
+typedef void (*ExecutedFunction)(void *args);
+
+void executeFunctionOnCores(ExecutedFunction fun, void *args, bool sync, u32 coreList);
+void executeFunctionOnAllCores(ExecutedFunction fun, void *args, bool sync);
+void executeFunctionOnAllCoresButSelf(ExecutedFunction fun, void *args, bool sync);
+
+void executeFunctionInterruptHandler(u32 srcCore);
\ No newline at end of file
diff --git a/thermosphere/src/irq.c b/thermosphere/src/irq.c
index 48a09cd0f..1c207e55c 100644
--- a/thermosphere/src/irq.c
+++ b/thermosphere/src/irq.c
@@ -121,7 +121,10 @@ void initIrq(void)
initGic();
// Configure the interrupts we use here
- configureInterrupt(0, 0, false);
+ for (u32 i = 0; i < ThermosphereSgi_Max; i++) {
+ configureInterrupt(i, 0, false);
+ }
+
configureInterrupt(GIC_IRQID_MAINTENANCE, 0, true);
recursiveSpinlockUnlockRestoreIrq(&g_irqManager.lock, flags);
@@ -136,6 +139,7 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
// Acknowledge the interrupt. Interrupt goes from pending to active.
u32 iar = gicc->iar;
u32 irqId = iar & 0x3FF;
+ u32 srcCore = (iar >> 12) & 7;
DEBUG("Received irq %x\n", irqId);
@@ -146,7 +150,17 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
bool isGuestInterrupt = false;
- // TODO: handle the interrupt if it's a host interrupt
+ switch (irqId) {
+ case ThermosphereSgi_ExecuteFunction:
+ executeFunctionInterruptHandler(srcCore);
+ break;
+ case GIC_IRQID_MAINTENANCE:
+ /* TODO */
+ break;
+ default:
+ isGuestInterrupt = true;
+ break;
+ }
// Priority drop
gicc->eoir = iar;
diff --git a/thermosphere/src/main.c b/thermosphere/src/main.c
index 1db76a20a..5666d428b 100644
--- a/thermosphere/src/main.c
+++ b/thermosphere/src/main.c
@@ -16,6 +16,11 @@
extern const u8 __start__[];
+static void testf1(void *p)
+{
+ DEBUG("Hello from sgi 0, p=%016llx\n", p);
+}
+
static void loadKernelViaSemihosting(void)
{
size_t len = 1<<20; // max len
@@ -80,6 +85,9 @@ void main(ExceptionStackFrame *frame)
// Test
singleStepSetNextState(frame, SingleStepState_ActivePending);
+ // Test
+ executeFunctionOnAllCores(testf1, (void *)0x1234567, true);
+
/*// Test
unmaskIrq();
generateSgiForAll(0);*/