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);*/