From 506b16db378f8a0e3114dfc97d0a313038814c88 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Wed, 22 Nov 2017 01:24:35 +0100 Subject: [PATCH] Fix watchpoints handling (huge thanks to @Nanquitas) --- k11_extension/include/debug.h | 39 +++++ k11_extension/source/debug.c | 147 +++++++++++++++++++ k11_extension/source/svc/KernelSetState.c | 37 ++++- sysmodules/rosalina/source/gdb/watchpoints.c | 96 +----------- 4 files changed, 227 insertions(+), 92 deletions(-) create mode 100644 k11_extension/include/debug.h create mode 100644 k11_extension/source/debug.c diff --git a/k11_extension/include/debug.h b/k11_extension/include/debug.h new file mode 100644 index 0000000..437208f --- /dev/null +++ b/k11_extension/include/debug.h @@ -0,0 +1,39 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016-2017 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that 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 . +* +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. +*/ + +#pragma once + +#include "types.h" +#include "globals.h" +#include "kernel.h" +#include "utils.h" + +extern KRecursiveLock dbgParamsLock; +extern u32 dbgParamWatchpointId, dbgParamDVA, dbgParamWCR, dbgParamContextId; + +KSchedulableInterruptEvent *enableMonitorModeDebugging(KBaseInterruptEvent *this, u32 interruptID); +KSchedulableInterruptEvent *disableWatchpoint(KBaseInterruptEvent *this, u32 interruptID); +KSchedulableInterruptEvent *setWatchpointWithContextId(KBaseInterruptEvent *this, u32 interruptID); diff --git a/k11_extension/source/debug.c b/k11_extension/source/debug.c new file mode 100644 index 0000000..9473aae --- /dev/null +++ b/k11_extension/source/debug.c @@ -0,0 +1,147 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016-2017 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that 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 . +* +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. +*/ + +#include "debug.h" +#include "memory.h" +#include "synchronization.h" + +KRecursiveLock dbgParamsLock = { NULL }; +u32 dbgParamWatchpointId, dbgParamDVA, dbgParamWCR, dbgParamContextId; + +KSchedulableInterruptEvent *enableMonitorModeDebugging(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED) +{ + coreBarrier(); + + u32 DSCR; + __asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 0" : [val] "=r" (DSCR)); + DSCR |= 0x8000; + __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 0" :: [val] "r" (DSCR)); + + __dsb(); + coreBarrier(); + + return NULL; +} + +static void disableWatchpoint0(void) +{ + u32 control; + + // WCR0 + __asm__ __volatile__("mrc p14, 0, %[val], c0, c0, 7" : [val] "=r" (control)); + control &= ~1; + __asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (control)); + + // BCR4 + __asm__ __volatile__("mrc p14, 0, %[val], c0, c4, 5" : [val] "=r" (control)); + control &= ~1; + __asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (control)); +} + +static void disableWatchpoint1(void) +{ + u32 control; + + // WCR1 + __asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 7" : [val] "=r" (control)); + control &= ~1; + __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (control)); + + // BCR5 + __asm__ __volatile__("mrc p14, 0, %[val], c0, c5, 5" : [val] "=r" (control)); + control &= ~1; + __asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (control)); +} + +KSchedulableInterruptEvent *disableWatchpoint(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED) +{ + coreBarrier(); + + if(dbgParamWatchpointId == 0) + disableWatchpoint0(); + else + disableWatchpoint1(); + + __dsb(); + coreBarrier(); + + return NULL; +} + +static void setWatchpoint0WithContextId(u32 DVA, u32 WCR, u32 contextId) +{ + // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html + u32 BCR = + (1 << 21) | /* compare with context ID */ + (1 << 20) | /* linked (with a WRP in our case) */ + (0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */ + (3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */ + (1 << 0) ; /* enabled */ + + disableWatchpoint0(); + + __asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 6" :: [val] "r" (DVA)); + __asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 4" :: [val] "r" (contextId)); + __asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (WCR)); + __asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (BCR)); + + __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB +} + +static void setWatchpoint1WithContextId(u32 DVA, u32 WCR, u32 contextId) +{ + // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html + u32 BCR = + (1 << 21) | /* compare with context ID */ + (1 << 20) | /* linked (with a WRP in our case) */ + (0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */ + (3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */ + (1 << 0) ; /* enabled */ + + disableWatchpoint1(); + + __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 6" :: [val] "r" (DVA)); + __asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 4" :: [val] "r" (contextId)); + __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (WCR)); + __asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (BCR)); + + __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB +} + +KSchedulableInterruptEvent *setWatchpointWithContextId(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED) +{ + coreBarrier(); + + if(dbgParamWatchpointId == 0) + setWatchpoint0WithContextId(dbgParamDVA, dbgParamWCR, dbgParamContextId); + else + setWatchpoint1WithContextId(dbgParamDVA, dbgParamWCR, dbgParamContextId); + + __dsb(); + coreBarrier(); + + return NULL; +} diff --git a/k11_extension/source/svc/KernelSetState.c b/k11_extension/source/svc/KernelSetState.c index 38a15ab..f5fd1f9 100644 --- a/k11_extension/source/svc/KernelSetState.c +++ b/k11_extension/source/svc/KernelSetState.c @@ -27,6 +27,7 @@ #include "svc/KernelSetState.h" #include "synchronization.h" #include "ipc.h" +#include "debug.h" #include "memory.h" #define MAX_DEBUG 3 @@ -142,7 +143,41 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3) res = SetSyscallDebugEventMask(varg1, (bool)varg2, (const u32 *)varg3); break; } - + case 0x10003: + { + executeFunctionOnCores(enableMonitorModeDebugging, 0xF, 0); + break; + } + case 0x10004: + { + KRecursiveLock__Lock(&dbgParamsLock); + dbgParamWatchpointId = varg1; + executeFunctionOnCores(disableWatchpoint, 0xF, 0); + KRecursiveLock__Unlock(&dbgParamsLock); + break; + } + case 0x10005: + { + KRecursiveLock__Lock(&dbgParamsLock); + dbgParamWatchpointId = 0; + dbgParamDVA = varg1; + dbgParamWCR = varg2; + dbgParamContextId = varg3; + executeFunctionOnCores(setWatchpointWithContextId, 0xF, 0); + KRecursiveLock__Unlock(&dbgParamsLock); + break; + } + case 0x10006: + { + KRecursiveLock__Lock(&dbgParamsLock); + dbgParamWatchpointId = 1; + dbgParamDVA = varg1; + dbgParamWCR = varg2; + dbgParamContextId = varg3; + executeFunctionOnCores(setWatchpointWithContextId, 0xF, 0); + KRecursiveLock__Unlock(&dbgParamsLock); + break; + } default: { res = KernelSetState(type, varg1, varg2, varg3); diff --git a/sysmodules/rosalina/source/gdb/watchpoints.c b/sysmodules/rosalina/source/gdb/watchpoints.c index e52a492..36a60dc 100644 --- a/sysmodules/rosalina/source/gdb/watchpoints.c +++ b/sysmodules/rosalina/source/gdb/watchpoints.c @@ -55,92 +55,6 @@ typedef struct WatchpointManager static WatchpointManager manager; -static void K_EnableMonitorModeDebugging(void) -{ - __asm__ __volatile__("cpsid aif"); - - u32 DSCR; - __asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 0" : [val] "=r" (DSCR)); - DSCR |= 0x8000; - __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 0" :: [val] "r" (DSCR)); -} - -static void K_DisableWatchpoint(u32 id) -{ - u32 control; - - __asm__ __volatile__("cpsid aif"); - - if(id == 0) - { - // WCR0 - __asm__ __volatile__("mrc p14, 0, %[val], c0, c0, 7" : [val] "=r" (control)); - control &= ~1; - __asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (control)); - - // BCR4 - __asm__ __volatile__("mrc p14, 0, %[val], c0, c4, 5" : [val] "=r" (control)); - control &= ~1; - __asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (control)); - } - else if(id == 1) - { - // WCR1 - __asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 7" : [val] "=r" (control)); - control &= ~1; - __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (control)); - - // BCR5 - __asm__ __volatile__("mrc p14, 0, %[val], c0, c5, 5" : [val] "=r" (control)); - control &= ~1; - __asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (control)); - } -} - -static void K_SetWatchpoint0WithContextId(u32 DVA, u32 WCR, u32 contextId) -{ - // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html - u32 BCR = - (1 << 21) | /* compare with context ID */ - (1 << 20) | /* linked (with a WRP in our case) */ - (0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */ - (3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */ - (1 << 0) ; /* enabled */ - - __asm__ __volatile__("cpsid aif"); - - K_DisableWatchpoint(0); - - __asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 6" :: [val] "r" (DVA)); - __asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 4" :: [val] "r" (contextId)); - __asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (WCR)); - __asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (BCR)); - - __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB -} - -static void K_SetWatchpoint1WithContextId(u32 DVA, u32 WCR, u32 contextId) -{ - // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html - u32 BCR = - (1 << 21) | /* compare with context ID */ - (1 << 20) | /* linked (with a WRP in our case) */ - (0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */ - (3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */ - (1 << 0) ; /* enabled */ - - __asm__ __volatile__("cpsid aif"); - - K_DisableWatchpoint(1); - - __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 6" :: [val] "r" (DVA)); - __asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 4" :: [val] "r" (contextId)); - __asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (WCR)); - __asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (BCR)); - - __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB -} - void GDB_ResetWatchpoints(void) { static bool lockInitialized = false; @@ -151,9 +65,9 @@ void GDB_ResetWatchpoints(void) } RecursiveLock_Lock(&watchpointManagerLock); - svcCustomBackdoor(K_EnableMonitorModeDebugging); - svcCustomBackdoor(K_DisableWatchpoint, 0); - svcCustomBackdoor(K_DisableWatchpoint, 1); + svcKernelSetState(0x10003); // enable monitor mode debugging + svcKernelSetState(0x10004, 0); // disable watchpoint 0 + svcKernelSetState(0x10004, 1); // disable watchpoint 1 memset(&manager, 0, sizeof(WatchpointManager)); @@ -192,7 +106,7 @@ int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kin if(R_SUCCEEDED(r)) { - svcCustomBackdoor(id == 0 ? K_SetWatchpoint0WithContextId : K_SetWatchpoint1WithContextId, address, WCR, (u32)out); + svcKernelSetState(id == 0 ? 0x10005 : 0x10006, address, WCR, (u32)out); // set watchpoint Watchpoint *watchpoint = &manager.watchpoints[id]; manager.total++; watchpoint->address = address; @@ -224,7 +138,7 @@ int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind) } else { - svcCustomBackdoor(K_DisableWatchpoint, id); + svcKernelSetState(0x10004, id); // disable watchpoint memset(&manager.watchpoints[id], 0, sizeof(Watchpoint)); manager.total--;