From ff022115ca82e7442c742e45e338c385502faef6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 13 Jul 2020 18:50:37 -0700 Subject: [PATCH] kern: Support older SVC ABIs --- .../source/arch/arm64/svc/kern_svc_tables.cpp | 48 ++++++++++++++++++- .../libmesosphere/source/kern_kernel.cpp | 4 +- .../svc/kern_svc_address_translation.cpp | 16 ++++++- .../source/svc/kern_svc_debug.cpp | 8 ++++ .../include/vapours/svc/svc_definitions.hpp | 20 +++++++- mesosphere/build_mesosphere.py | 17 ++----- .../kernel_ldr/source/kern_init_loader.cpp | 2 + 7 files changed, 94 insertions(+), 21 deletions(-) diff --git a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp index efec21e63..e2a1684fa 100644 --- a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp +++ b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp @@ -55,7 +55,7 @@ namespace ams::kern::svc { std::array table = {}; #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ - table[ID] = NAME::Call64From32; + if (table[ID] == nullptr) { table[ID] = NAME::Call64From32; } AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) #undef AMS_KERN_SVC_SET_TABLE_ENTRY @@ -66,7 +66,7 @@ namespace ams::kern::svc { std::array table = {}; #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ - table[ID] = NAME::Call64; + if (table[ID] == nullptr) { table[ID] = NAME::Call64; } AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) #undef AMS_KERN_SVC_SET_TABLE_ENTRY @@ -92,4 +92,48 @@ namespace ams::kern::svc { constinit const std::array SvcTable64From32 = SvcTable64From32Impl; + namespace { + + /* NOTE: Although the SVC tables are constants, our global constructor will run before .rodata is protected R--. */ + class SvcTablePatcher { + private: + using SvcTable = std::array; + private: + static SvcTablePatcher s_instance; + private: + ALWAYS_INLINE volatile SvcTableEntry *GetEditableTable(const SvcTable *table) { + if (table != nullptr) { + return const_cast(table->data()); + } else { + return nullptr; + } + } + + /* TODO: This should perhaps be implemented in assembly. */ + NOINLINE void PatchTables(volatile SvcTableEntry *table_64, volatile SvcTableEntry *table_64_from_32) { + /* Get the target firmware. */ + const auto target_fw = kern::GetTargetFirmware(); + + /* 10.0.0 broke the ABI for QueryIoMapping. */ + if (target_fw < TargetFirmware_10_0_0) { + if (table_64) { table_64[ svc::SvcId_QueryIoMapping] = LegacyQueryIoMapping::Call64; } + if (table_64_from_32) { table_64_from_32[svc::SvcId_QueryIoMapping] = LegacyQueryIoMapping::Call64From32; } + } + + /* 3.0.0 broke the ABI for ContinueDebugEvent. */ + if (target_fw < TargetFirmware_3_0_0) { + if (table_64) { table_64[ svc::SvcId_ContinueDebugEvent] = LegacyContinueDebugEvent::Call64; } + if (table_64_from_32) { table_64_from_32[svc::SvcId_ContinueDebugEvent] = LegacyContinueDebugEvent::Call64From32; } + } + } + public: + SvcTablePatcher(const SvcTable *table_64, const SvcTable *table_64_from_32) { + PatchTables(GetEditableTable(table_64), GetEditableTable(table_64_from_32)); + } + }; + + SvcTablePatcher SvcTablePatcher::s_instance(std::addressof(SvcTable64), std::addressof(SvcTable64From32)); + + } + } diff --git a/libraries/libmesosphere/source/kern_kernel.cpp b/libraries/libmesosphere/source/kern_kernel.cpp index 5c1c5a676..f9aa6f747 100644 --- a/libraries/libmesosphere/source/kern_kernel.cpp +++ b/libraries/libmesosphere/source/kern_kernel.cpp @@ -116,11 +116,13 @@ namespace ams::kern { } void Kernel::PrintLayout() { + const auto target_fw = kern::GetTargetFirmware(); + /* Print out the kernel version. */ - /* TODO: target firmware, if we support that? */ MESOSPHERE_LOG("Horizon Kernel (Mesosphere)\n"); MESOSPHERE_LOG("Built: %s %s\n", __DATE__, __TIME__); MESOSPHERE_LOG("Atmosphere version: %d.%d.%d-%s\n", ATMOSPHERE_RELEASE_VERSION, ATMOSPHERE_GIT_REVISION); + MESOSPHERE_LOG("Target Firmware: %d.%d.%d\n", (target_fw >> 24) & 0xFF, (target_fw >> 16) & 0xFF, (target_fw >> 8) & 0xFF); MESOSPHERE_LOG("Supported OS version: %d.%d.%d\n", ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR, ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR, ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO); MESOSPHERE_LOG("\n"); diff --git a/libraries/libmesosphere/source/svc/kern_svc_address_translation.cpp b/libraries/libmesosphere/source/svc/kern_svc_address_translation.cpp index c68eaa39b..588d8a9bc 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_address_translation.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_address_translation.cpp @@ -93,7 +93,13 @@ namespace ams::kern::svc { MESOSPHERE_PANIC("Stubbed SvcQueryPhysicalAddress64 was called."); } - Result QueryIoMapping64(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { + Result QueryIoMapping64(ams::svc::Address *out_address, ams::svc::Size *out_size, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { + static_assert(sizeof(*out_address) == sizeof(uintptr_t)); + static_assert(sizeof(*out_size) == sizeof(size_t)); + return QueryIoMapping(reinterpret_cast(out_address), reinterpret_cast(out_size), physical_address, size); + } + + Result LegacyQueryIoMapping64(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); return QueryIoMapping(reinterpret_cast(out_address), nullptr, physical_address, size); } @@ -104,7 +110,13 @@ namespace ams::kern::svc { MESOSPHERE_PANIC("Stubbed SvcQueryPhysicalAddress64From32 was called."); } - Result QueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { + Result QueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::Size *out_size, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { + static_assert(sizeof(*out_address) == sizeof(uintptr_t)); + static_assert(sizeof(*out_size) == sizeof(size_t)); + return QueryIoMapping(reinterpret_cast(out_address), reinterpret_cast(out_size), physical_address, size); + } + + Result LegacyQueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); return QueryIoMapping(reinterpret_cast(out_address), nullptr, physical_address, size); } diff --git a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp index c995bd015..3aee4aeed 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp @@ -47,6 +47,10 @@ namespace ams::kern::svc { MESOSPHERE_PANIC("Stubbed SvcContinueDebugEvent64 was called."); } + Result LegacyContinueDebugEvent64(ams::svc::Handle debug_handle, uint32_t flags, uint64_t thread_id) { + MESOSPHERE_PANIC("Stubbed SvcLegacyContinueDebugEvent64 was called."); + } + Result GetDebugThreadContext64(KUserPointer out_context, ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) { MESOSPHERE_PANIC("Stubbed SvcGetDebugThreadContext64 was called."); } @@ -97,6 +101,10 @@ namespace ams::kern::svc { MESOSPHERE_PANIC("Stubbed SvcContinueDebugEvent64From32 was called."); } + Result LegacyContinueDebugEvent64From32(ams::svc::Handle debug_handle, uint32_t flags, uint64_t thread_id) { + MESOSPHERE_PANIC("Stubbed SvcLegacyContinueDebugEvent64From32 was called."); + } + Result GetDebugThreadContext64From32(KUserPointer out_context, ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) { MESOSPHERE_PANIC("Stubbed SvcGetDebugThreadContext64From32 was called."); } diff --git a/libraries/libvapours/include/vapours/svc/svc_definitions.hpp b/libraries/libvapours/include/vapours/svc/svc_definitions.hpp index f44eda35f..558051a49 100644 --- a/libraries/libvapours/include/vapours/svc/svc_definitions.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_definitions.hpp @@ -107,7 +107,7 @@ HANDLER(0x52, Result, UnmapTransferMemory, INPUT(::ams::svc::Handle, trmem_handle), INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \ HANDLER(0x53, Result, CreateInterruptEvent, OUTPUT(::ams::svc::Handle, out_read_handle), INPUT(int32_t, interrupt_id), INPUT(::ams::svc::InterruptType, interrupt_type)) \ HANDLER(0x54, Result, QueryPhysicalAddress, OUTPUT(::ams::svc::NAMESPACE::PhysicalMemoryInfo, out_info), INPUT(::ams::svc::Address, address)) \ - HANDLER(0x55, Result, QueryIoMapping, OUTPUT(::ams::svc::Address, out_address), INPUT(::ams::svc::PhysicalAddress, physical_address), INPUT(::ams::svc::Size, size)) \ + HANDLER(0x55, Result, QueryIoMapping, OUTPUT(::ams::svc::Address, out_address), OUTPUT(::ams::svc::Size, out_size), INPUT(::ams::svc::PhysicalAddress, physical_address), INPUT(::ams::svc::Size, size)) \ HANDLER(0x56, Result, CreateDeviceAddressSpace, OUTPUT(::ams::svc::Handle, out_handle), INPUT(uint64_t, das_address), INPUT(uint64_t, das_size)) \ HANDLER(0x57, Result, AttachDeviceAddressSpace, INPUT(::ams::svc::DeviceName, device_name), INPUT(::ams::svc::Handle, das_handle)) \ HANDLER(0x58, Result, DetachDeviceAddressSpace, INPUT(::ams::svc::DeviceName, device_name), INPUT(::ams::svc::Handle, das_handle)) \ @@ -149,7 +149,10 @@ HANDLER(0x7C, Result, GetProcessInfo, OUTPUT(int64_t, out_info), INPUT(::ams::svc::Handle, process_handle), INPUT(::ams::svc::ProcessInfoType, info_type)) \ HANDLER(0x7D, Result, CreateResourceLimit, OUTPUT(::ams::svc::Handle, out_handle)) \ HANDLER(0x7E, Result, SetResourceLimitLimitValue, INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which), INPUT(int64_t, limit_value)) \ - HANDLER(0x7F, void, CallSecureMonitor, OUTPUT(::ams::svc::NAMESPACE::SecureMonitorArguments, args)) + HANDLER(0x7F, void, CallSecureMonitor, OUTPUT(::ams::svc::NAMESPACE::SecureMonitorArguments, args)) \ + \ + HANDLER(0x55, Result, LegacyQueryIoMapping, OUTPUT(::ams::svc::Address, out_address), INPUT(::ams::svc::PhysicalAddress, physical_address), INPUT(::ams::svc::Size, size)) \ + HANDLER(0x64, Result, LegacyContinueDebugEvent, INPUT(::ams::svc::Handle, debug_handle), INPUT(uint32_t, flags), INPUT(uint64_t, thread_id)) #define AMS_SVC_FOREACH_USER_DEFINITION(HANDLER, NAMESPACE) AMS_SVC_FOREACH_DEFINITION_IMPL(HANDLER, NAMESPACE, AMS_SVC_USER_INPUT_HANDLER, AMS_SVC_USER_OUTPUT_HANDLER, AMS_SVC_USER_INPTR_HANDLER, AMS_SVC_USER_OUTPTR_HANDLER) #define AMS_SVC_FOREACH_KERN_DEFINITION(HANDLER, NAMESPACE) AMS_SVC_FOREACH_DEFINITION_IMPL(HANDLER, NAMESPACE, AMS_SVC_KERN_INPUT_HANDLER, AMS_SVC_KERN_OUTPUT_HANDLER, AMS_SVC_KERN_INPTR_HANDLER, AMS_SVC_KERN_OUTPTR_HANDLER) @@ -157,6 +160,19 @@ #define AMS_SVC_DECLARE_FUNCTION_PROTOTYPE(ID, RETURN_TYPE, NAME, ...) \ RETURN_TYPE NAME(__VA_ARGS__); +namespace ams::svc { + + #define AMS_SVC_DEFINE_ID_ENUM_MEMBER(ID, RETURN_TYPE, NAME, ...) \ + SvcId_##NAME = ID, + + enum SvcId : u32 { + AMS_SVC_FOREACH_KERN_DEFINITION(AMS_SVC_DEFINE_ID_ENUM_MEMBER, _) + }; + + #undef AMS_SVC_DEFINE_ID_ENUM_MEMBER + +} + #ifdef ATMOSPHERE_IS_STRATOSPHERE namespace ams::svc { diff --git a/mesosphere/build_mesosphere.py b/mesosphere/build_mesosphere.py index 9bc8fe511..bbd06b62c 100644 --- a/mesosphere/build_mesosphere.py +++ b/mesosphere/build_mesosphere.py @@ -2,19 +2,8 @@ import sys, os from struct import pack as pk, unpack as up -ATMOSPHERE_TARGET_FIRMWARE_100 = 1 -ATMOSPHERE_TARGET_FIRMWARE_200 = 2 -ATMOSPHERE_TARGET_FIRMWARE_300 = 3 -ATMOSPHERE_TARGET_FIRMWARE_400 = 4 -ATMOSPHERE_TARGET_FIRMWARE_500 = 5 -ATMOSPHERE_TARGET_FIRMWARE_600 = 6 -ATMOSPHERE_TARGET_FIRMWARE_620 = 7 -ATMOSPHERE_TARGET_FIRMWARE_700 = 8 -ATMOSPHERE_TARGET_FIRMWARE_800 = 9 -ATMOSPHERE_TARGET_FIRMWARE_810 = 10 -ATMOSPHERE_TARGET_FIRMWARE_900 = 11 -ATMOSPHERE_TARGET_FIRMWARE_910 = 12 -ATMOSPHERE_TARGET_FIRMWARE_1000 = 13 +def atmosphere_target_firmware(major, minor, micro, rev = 0): + return (major << 24) | (minor << 16) | (micro << 8) | rev def align_up(val, algn): val += algn - 1 @@ -50,7 +39,7 @@ def main(argc, argv): with open('mesosphere.bin', 'wb') as f: f.write(kernel[:kernel_metadata_offset + 4]) - f.write(pk('