From 920b0176777fb51c86e3357c1fc2defc69d62efd Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 31 Jul 2020 19:48:22 -0700 Subject: [PATCH] kern: implement svc trace --- libraries/config/templates/mesosphere.mk | 2 +- libraries/libmesosphere/Makefile | 2 +- .../include/mesosphere/kern_build_config.hpp | 31 +++++++++ .../include/mesosphere/kern_common.hpp | 19 +----- .../include/mesosphere/kern_k_trace.hpp | 29 +++++++++ .../arch/arm64/svc/kern_svc_handlers.cpp | 28 ++++++++ .../arch/arm64/svc/kern_svc_handlers_asm.s | 65 +++++++++++++++++++ .../libmesosphere/source/kern_k_trace.cpp | 46 +++++++++++++ 8 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 libraries/libmesosphere/include/mesosphere/kern_build_config.hpp create mode 100644 libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers.cpp diff --git a/libraries/config/templates/mesosphere.mk b/libraries/config/templates/mesosphere.mk index f3c84f5cc..6d66c65c0 100644 --- a/libraries/config/templates/mesosphere.mk +++ b/libraries/config/templates/mesosphere.mk @@ -10,7 +10,7 @@ export DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE export SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit -export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) +export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -nostdlib -nostartfiles -g $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now diff --git a/libraries/libmesosphere/Makefile b/libraries/libmesosphere/Makefile index 8bef7afec..5722de3f5 100644 --- a/libraries/libmesosphere/Makefile +++ b/libraries/libmesosphere/Makefile @@ -12,7 +12,7 @@ DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit -flto -ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) +ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source) diff --git a/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp b/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp new file mode 100644 index 000000000..84afc3e31 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018-2020 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 + +#if 1 || defined(AMS_BUILD_FOR_AUDITING) +#define MESOSPHERE_BUILD_FOR_AUDITING +#endif + +#if defined(MESOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) +#define MESOSPHERE_BUILD_FOR_DEBUGGING +#endif + +#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING +#define MESOSPHERE_ENABLE_ASSERTIONS +#define MESOSPHERE_ENABLE_DEBUG_PRINT +#endif + +#define MESOSPHERE_BUILD_FOR_TRACING diff --git a/libraries/libmesosphere/include/mesosphere/kern_common.hpp b/libraries/libmesosphere/include/mesosphere/kern_common.hpp index b1123b397..be7c94ab8 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_common.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_common.hpp @@ -15,6 +15,8 @@ */ #pragma once #include +#include +#include namespace ams::kern { @@ -23,20 +25,3 @@ namespace ams::kern { ams::TargetFirmware GetTargetFirmware(); } - -#if 1 || defined(AMS_BUILD_FOR_AUDITING) -#define MESOSPHERE_BUILD_FOR_AUDITING -#endif - -#if defined(MESOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) -#define MESOSPHERE_BUILD_FOR_DEBUGGING -#endif - -#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING -#define MESOSPHERE_ENABLE_ASSERTIONS -#define MESOSPHERE_ENABLE_DEBUG_PRINT -#endif - -#define MESOSPHERE_BUILD_FOR_TRACING - -#include diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_trace.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_trace.hpp index ae4bd65b3..6fe20ac99 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_trace.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_trace.hpp @@ -30,6 +30,13 @@ namespace ams::kern { static_assert(IsKTraceEnabled || !IsKTraceEnabled); class KTrace { + public: + enum Type { + Type_SvcEntry0 = 3, + Type_SvcEntry1 = 4, + Type_SvcExit0 = 5, + Type_SvcExit1 = 6, + }; private: static bool s_is_active; public: @@ -37,6 +44,8 @@ namespace ams::kern { static void Start(); static void Stop(); + static void PushRecord(u8 type, u64 param0 = 0, u64 param1 = 0, u64 param2 = 0, u64 param3 = 0, u64 param4 = 0, u64 param5 = 0); + static ALWAYS_INLINE bool IsActive() { return s_is_active; } }; @@ -55,3 +64,23 @@ namespace ams::kern { ::ams::kern::KTrace::Stop(); \ } \ }) + +#define MESOSPHERE_KTRACE_SVC_ENTRY(SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7) \ + ({ \ + if constexpr (::ams::kern::IsKTraceEnabled) { \ + if (::ams::kern::KTrace::IsActive()) { \ + ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcEntry0, SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4); \ + ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcEntry1, PARAM5, PARAM6, PARAM7); \ + } \ + } \ + }) + +#define MESOSPHERE_KTRACE_SVC_EXIT(SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7) \ + ({ \ + if constexpr (::ams::kern::IsKTraceEnabled) { \ + if (::ams::kern::KTrace::IsActive()) { \ + ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcExit0, SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4); \ + ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcExit1, PARAM5, PARAM6, PARAM7); \ + } \ + } \ + }) \ No newline at end of file diff --git a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers.cpp b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers.cpp new file mode 100644 index 000000000..72723557f --- /dev/null +++ b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2020 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 + +namespace ams::kern::svc { + + void TraceSvcEntry(const u64 *data) { + MESOSPHERE_KTRACE_SVC_ENTRY(GetCurrentThread().GetSvcId(), data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); + } + + void TraceSvcExit(const u64 *data) { + MESOSPHERE_KTRACE_SVC_EXIT(GetCurrentThread().GetSvcId(), data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); + } + +} diff --git a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers_asm.s b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers_asm.s index 39d8eda7e..fc8fb5058 100644 --- a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers_asm.s +++ b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers_asm.s @@ -13,6 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include /* ams::kern::arch::arm64::SvcHandler64() */ .section .text._ZN3ams4kern4arch5arm6412SvcHandler64Ev, "ax", %progbits @@ -83,6 +84,22 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev: strb w10, [sp, #(0x120 + 0x12)] strb w8, [sp, #(0x120 + 0x11)] + /* If we should, trace the svc entry. */ +#if defined(MESOSPHERE_BUILD_FOR_TRACING) + sub sp, sp, #0x40 + stp x0, x1, [sp, #(8 * 0)] + stp x2, x3, [sp, #(8 * 2)] + stp x4, x5, [sp, #(8 * 4)] + stp x6, x7, [sp, #(8 * 6)] + mov x0, sp + bl _ZN3ams4kern3svc13TraceSvcEntryEPKm + ldp x0, x1, [sp, #(8 * 0)] + ldp x2, x3, [sp, #(8 * 2)] + ldp x4, x5, [sp, #(8 * 4)] + ldp x6, x7, [sp, #(8 * 6)] + add sp, sp, #0x40 +#endif + /* Invoke the SVC handler. */ msr daifclr, #2 blr x11 @@ -163,6 +180,22 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev: /* Clear our in-SVC note. */ strb wzr, [sp, #(0x120 + 0x12)] + /* If we should, trace the svc exit. */ +#if defined(MESOSPHERE_BUILD_FOR_TRACING) + sub sp, sp, #0x40 + stp x0, x1, [sp, #(8 * 0)] + stp x2, x3, [sp, #(8 * 2)] + stp x4, x5, [sp, #(8 * 4)] + stp x6, x7, [sp, #(8 * 6)] + mov x0, sp + bl _ZN3ams4kern3svc12TraceSvcExitEPKm + ldp x0, x1, [sp, #(8 * 0)] + ldp x2, x3, [sp, #(8 * 2)] + ldp x4, x5, [sp, #(8 * 4)] + ldp x6, x7, [sp, #(8 * 6)] + add sp, sp, #0x40 +#endif + /* Restore registers. */ ldp x30, x8, [sp, #(8 * 30)] ldp x9, x10, [sp, #(8 * 32)] @@ -259,6 +292,22 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev: strb w15, [sp, #(0x120 + 0x12)] strb w16, [sp, #(0x120 + 0x11)] + /* If we should, trace the svc entry. */ +#if defined(MESOSPHERE_BUILD_FOR_TRACING) + sub sp, sp, #0x40 + stp x0, x1, [sp, #(8 * 0)] + stp x2, x3, [sp, #(8 * 2)] + stp x4, x5, [sp, #(8 * 4)] + stp x6, x7, [sp, #(8 * 6)] + mov x0, sp + bl _ZN3ams4kern3svc13TraceSvcEntryEPKm + ldp x0, x1, [sp, #(8 * 0)] + ldp x2, x3, [sp, #(8 * 2)] + ldp x4, x5, [sp, #(8 * 4)] + ldp x6, x7, [sp, #(8 * 6)] + add sp, sp, #0x40 +#endif + /* Invoke the SVC handler. */ msr daifclr, #2 blr x19 @@ -327,6 +376,22 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev: /* Clear our in-SVC note. */ strb wzr, [sp, #(0x120 + 0x12)] + /* If we should, trace the svc exit. */ +#if defined(MESOSPHERE_BUILD_FOR_TRACING) + sub sp, sp, #0x40 + stp x0, x1, [sp, #(8 * 0)] + stp x2, x3, [sp, #(8 * 2)] + stp x4, x5, [sp, #(8 * 4)] + stp x6, x7, [sp, #(8 * 6)] + mov x0, sp + bl _ZN3ams4kern3svc12TraceSvcExitEPKm + ldp x0, x1, [sp, #(8 * 0)] + ldp x2, x3, [sp, #(8 * 2)] + ldp x4, x5, [sp, #(8 * 4)] + ldp x6, x7, [sp, #(8 * 6)] + add sp, sp, #0x40 +#endif + /* Restore registers. */ ldp x8, x9, [sp, #(8 * 8)] ldp x10, x11, [sp, #(8 * 10)] diff --git a/libraries/libmesosphere/source/kern_k_trace.cpp b/libraries/libmesosphere/source/kern_k_trace.cpp index 15ab7f75a..5cba5d080 100644 --- a/libraries/libmesosphere/source/kern_k_trace.cpp +++ b/libraries/libmesosphere/source/kern_k_trace.cpp @@ -25,6 +25,7 @@ namespace ams::kern { constinit KSpinLock g_ktrace_lock; constinit KVirtualAddress g_ktrace_buffer_address = Null; constinit size_t g_ktrace_buffer_size = 0; + constinit u64 g_type_filter = 0; struct KTraceHeader { u32 magic; @@ -47,6 +48,10 @@ namespace ams::kern { static_assert(util::is_pod::value); static_assert(sizeof(KTraceRecord) == 0x40); + ALWAYS_INLINE bool IsTypeFiltered(u8 type) { + return (g_type_filter & (UINT64_C(1) << (type & (BITSIZEOF(u64) - 1)))) != 0; + } + } void KTrace::Initialize(KVirtualAddress address, size_t size) { @@ -67,6 +72,9 @@ namespace ams::kern { /* Set the global data. */ g_ktrace_buffer_address = address; g_ktrace_buffer_size = size; + + /* Set the filters to defaults. */ + g_type_filter = ~(UINT64_C(0)); } } } @@ -101,4 +109,42 @@ namespace ams::kern { } } + void KTrace::PushRecord(u8 type, u64 param0, u64 param1, u64 param2, u64 param3, u64 param4, u64 param5) { + /* Get exclusive access to the trace buffer. */ + KScopedInterruptDisable di; + KScopedSpinLock lk(g_ktrace_lock); + + /* Check whether we should push the record to the trace buffer. */ + if (s_is_active && IsTypeFiltered(type)) { + /* Get the current thread and process. */ + KThread &cur_thread = GetCurrentThread(); + KProcess *cur_process = GetCurrentProcessPointer(); + + /* Get the current record index from the header. */ + KTraceHeader *header = GetPointer(g_ktrace_buffer_address); + u32 index = header->index; + + /* Get the current record. */ + KTraceRecord *record = GetPointer(g_ktrace_buffer_address + header->offset + index * sizeof(KTraceRecord)); + + /* Set the record's data. */ + *record = { + .core_id = static_cast(GetCurrentCoreId()), + .type = type, + .process_id = static_cast(cur_process != nullptr ? cur_process->GetId() : ~0), + .thread_id = static_cast(cur_thread.GetId()), + .tick = static_cast(KHardwareTimer::GetTick()), + .data = { param0, param1, param2, param3, param4, param5 }, + }; + + /* Advance the current index. */ + if ((++index) >= header->count) { + index = 0; + } + + /* Set the next index. */ + header->index = index; + } + } + }