From b3bd4436366e86c0adbcadb74dadf1c83b2116d0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 6 Apr 2021 23:07:58 -0700 Subject: [PATCH] svc: sanitize booleans in autogenerated abi stubs --- .../impl/svc_codegen_impl_code_generator.hpp | 5 +++ .../svc_codegen_impl_kernel_svc_wrapper.hpp | 35 +++++++++++++++++++ .../codegen/impl/svc_codegen_impl_layout.hpp | 25 ++++++------- .../impl/svc_codegen_impl_meta_code.hpp | 9 +++++ .../impl/svc_codegen_impl_parameter.hpp | 12 +++++-- 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_code_generator.hpp b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_code_generator.hpp index 88866a051..d0233ef7d 100644 --- a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_code_generator.hpp +++ b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_code_generator.hpp @@ -189,6 +189,11 @@ namespace ams::svc::codegen::impl { __asm__ __volatile__("mov x%c[dst], x%c[src]" :: [dst]"i"(Dst), [src]"i"(Src) : "memory"); } + template + static ALWAYS_INLINE void ConvertToBoolean() { + __asm__ __volatile__("and x%c[reg], x%c[reg], #1" :: [reg]"i"(Reg) : "memory"); + } + template static ALWAYS_INLINE void LoadFromStack() { if constexpr (Size == 4) { diff --git a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp index e553ae080..49af7dc43 100644 --- a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp +++ b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp @@ -317,6 +317,38 @@ namespace ams::svc::codegen::impl { return true; } + template + static constexpr void SanitizeInputBooleans(MetaCodeGenerator &mcg) { + /* Get the input layout. */ + constexpr auto InputLayout = Conversion::LayoutForSvc.GetInputLayout(); + + /* Check if we're done. */ + if constexpr (ParameterIndex < InputLayout.GetNumParameters()) { + /* Get the relevant parameter. */ + constexpr auto Param = InputLayout.GetParameter(ParameterIndex); + + /* Handle the case where the parameter is a boolean. */ + if constexpr (Param.IsBoolean()) { + /* Boolean parameters should have one location. */ + static_assert(Param.GetNumLocations() == 1); + + /* Get the location. */ + constexpr auto Loc = Param.GetLocation(0); + + /* TODO: Support boolean parameters passed-by-stack. */ + static_assert(Loc.GetStorage() == Storage::Register); + + /* Convert the input to boolean. */ + mcg.template ConvertToBoolean(); + } + + /* Handle the next parameter. */ + if constexpr (ParameterIndex + 1 < InputLayout.GetNumParameters()) { + SanitizeInputBooleans(mcg); + } + } + } + template struct TypeIndexFilter { @@ -436,6 +468,9 @@ namespace ams::svc::codegen::impl { mcg.template AllocateStackSpace(); } + /* Sanitize all input booleans. */ + SanitizeInputBooleans(mcg); + /* Generate code for before operations. */ if constexpr (Conversion::NumBeforeOperations > 0) { allocator = GenerateBeforeOperations(mcg, typename Conversion::BeforeOperations{}); diff --git a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_layout.hpp b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_layout.hpp index 4a6adadd8..ad8d5748c 100644 --- a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_layout.hpp +++ b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_layout.hpp @@ -36,21 +36,21 @@ namespace ams::svc::codegen::impl { : abi(a), num_parameters(0), parameters() { /* ... */ } - constexpr void AddSingle(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, Storage s, size_t idx) { + constexpr void AddSingle(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, bool b, Storage s, size_t idx) { for (size_t i = 0; i < this->num_parameters; i++) { if (this->parameters[i].Is(id)) { this->parameters[i].AddLocation(Location(s, idx)); return; } } - this->parameters[this->num_parameters++] = Parameter(id, type, ts, ps, p, Location(s, idx)); + this->parameters[this->num_parameters++] = Parameter(id, type, ts, ps, p, b, Location(s, idx)); } - constexpr size_t Add(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, Storage s, size_t i) { + constexpr size_t Add(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, bool b, Storage s, size_t i) { size_t required_registers = 0; while (required_registers * this->abi.register_size < ps) { - this->AddSingle(id, type, ts, ps, p, s, i++); + this->AddSingle(id, type, ts, ps, p, b, s, i++); required_registers++; } @@ -115,6 +115,7 @@ namespace ams::svc::codegen::impl { constexpr size_t ArgumentTypeSize = AbiType::template Size; constexpr bool PassedByPointer = IsPassedByPointer; + constexpr bool IsBoolean = std::same_as; constexpr size_t ArgumentPassSize = PassedByPointer ? AbiType::PointerSize : ArgumentTypeSize; /* TODO: Is there ever a case where this is not the correct alignment? */ @@ -135,19 +136,19 @@ namespace ams::svc::codegen::impl { const size_t registers_available = AbiType::RegisterCount - NGRN; if constexpr (!PassedByPointer && IsIntegralOrUserPointer && ArgumentTypeSize > AbiType::RegisterSize) { if (registers_available >= 2) { - this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Register, NGRN); + this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Register, NGRN); NGRN += 2; } else { /* Argument went on stack, so stop allocating arguments in registers. */ NGRN = AbiType::RegisterCount; NSAA += (NSAA & 1); - this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Stack, NSAA); + this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Stack, NSAA); NSAA += 2; } } else { if (ArgumentPassSize <= AbiType::RegisterSize * registers_available) { - NGRN += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Register, NGRN); + NGRN += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Register, NGRN); } else { /* Argument went on stack, so stop allocating arguments in registers. */ NGRN = AbiType::RegisterCount; @@ -155,7 +156,7 @@ namespace ams::svc::codegen::impl { /* TODO: Stack pointer alignment is only ensured for aapcs64. */ /* What should we do here? */ - NSAA += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Stack, NSAA); + NSAA += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Stack, NSAA); } } } @@ -176,7 +177,7 @@ namespace ams::svc::codegen::impl { /* TODO: It's unclear how to handle the non-integral and too-large case. */ if constexpr (!std::is_same::value) { constexpr size_t ReturnTypeSize = AbiType::template Size; - layout.output.Add(Parameter::Identifier("ReturnType"), ArgumentType::Invalid, ReturnTypeSize, ReturnTypeSize, false, Storage::Register, 0); + layout.output.Add(Parameter::Identifier("ReturnType"), ArgumentType::Invalid, ReturnTypeSize, ReturnTypeSize, false, false /* TODO */, Storage::Register, 0); static_assert(IsIntegral || ReturnTypeSize <= AbiType::RegisterSize); } @@ -270,7 +271,7 @@ namespace ams::svc::codegen::impl { const auto location = param.GetLocation(i); if (location.GetStorage() == Storage::Register) { reg_allocator.Allocate(location.GetIndex()); - dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), Storage::Register, location.GetIndex()); + dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), param.IsBoolean(), Storage::Register, location.GetIndex()); } } } @@ -281,7 +282,7 @@ namespace ams::svc::codegen::impl { const auto location = param.GetLocation(i); if (location.GetStorage() == Storage::Stack) { const size_t free_reg = reg_allocator.AllocateFirstFree(); - dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), Storage::Register, free_reg); + dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), param.IsBoolean(), Storage::Register, free_reg); } } } @@ -291,7 +292,7 @@ namespace ams::svc::codegen::impl { const size_t type_size = param.GetTypeSize(); for (size_t sz = 0; sz < type_size; sz += AbiType::RegisterSize) { const size_t free_reg = reg_allocator.AllocateFirstFree(); - dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), type_size, type_size, false, Storage::Register, free_reg); + dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), type_size, type_size, false, param.IsBoolean(), Storage::Register, free_reg); } } public: diff --git a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_meta_code.hpp b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_meta_code.hpp index 8d84a6182..5b5d0bc8f 100644 --- a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_meta_code.hpp +++ b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_meta_code.hpp @@ -29,6 +29,7 @@ namespace ams::svc::codegen::impl { AllocateStackSpace, FreeStackSpace, MoveRegister, + ConvertToBoolean, LoadFromStack, LoadPairFromStack, StoreToStack, @@ -47,6 +48,7 @@ namespace ams::svc::codegen::impl { META_CODE_OPERATION_KIND_ENUM_CASE(AllocateStackSpace); META_CODE_OPERATION_KIND_ENUM_CASE(FreeStackSpace); META_CODE_OPERATION_KIND_ENUM_CASE(MoveRegister); + META_CODE_OPERATION_KIND_ENUM_CASE(ConvertToBoolean); META_CODE_OPERATION_KIND_ENUM_CASE(LoadFromStack); META_CODE_OPERATION_KIND_ENUM_CASE(LoadPairFromStack); META_CODE_OPERATION_KIND_ENUM_CASE(StoreToStack); @@ -117,6 +119,7 @@ namespace ams::svc::codegen::impl { META_CODE_OPERATION_KIND_GENERATE_CODE(AllocateStackSpace) META_CODE_OPERATION_KIND_GENERATE_CODE(FreeStackSpace) META_CODE_OPERATION_KIND_GENERATE_CODE(MoveRegister) + META_CODE_OPERATION_KIND_GENERATE_CODE(ConvertToBoolean) META_CODE_OPERATION_KIND_GENERATE_CODE(LoadFromStack) META_CODE_OPERATION_KIND_GENERATE_CODE(LoadPairFromStack) META_CODE_OPERATION_KIND_GENERATE_CODE(StoreToStack) @@ -185,6 +188,12 @@ namespace ams::svc::codegen::impl { this->meta_code.AddOperation(op); } + template + constexpr void ConvertToBoolean() { + constexpr auto op = MetaCode::MakeOperation(); + this->meta_code.AddOperation(op); + } + template constexpr void LoadFromStack() { constexpr auto op = MetaCode::MakeOperation(); diff --git a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_parameter.hpp b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_parameter.hpp index f077e30ba..e7b502720 100644 --- a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_parameter.hpp +++ b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_parameter.hpp @@ -105,15 +105,16 @@ namespace ams::svc::codegen::impl { size_t type_size; size_t passed_size; bool passed_by_pointer; + bool is_boolean; size_t num_locations; Location locations[MaxLocations]; public: constexpr explicit Parameter() - : identifier(), type(ArgumentType::Invalid), type_size(0), passed_size(0), passed_by_pointer(0), num_locations(0), locations() + : identifier(), type(ArgumentType::Invalid), type_size(0), passed_size(0), passed_by_pointer(0), is_boolean(0), num_locations(0), locations() { /* ... */ } - constexpr explicit Parameter(Identifier id, ArgumentType t, size_t ts, size_t ps, bool p, Location l) - : identifier(id), type(t), type_size(ts), passed_size(ps), passed_by_pointer(p), num_locations(1), locations() + constexpr explicit Parameter(Identifier id, ArgumentType t, size_t ts, size_t ps, bool p, bool b, Location l) + : identifier(id), type(t), type_size(ts), passed_size(ps), passed_by_pointer(p), is_boolean(b), num_locations(1), locations() { this->locations[0] = l; } @@ -142,6 +143,10 @@ namespace ams::svc::codegen::impl { return this->passed_by_pointer; } + constexpr bool IsBoolean() const { + return this->is_boolean; + } + constexpr size_t GetNumLocations() const { return this->num_locations; } @@ -169,6 +174,7 @@ namespace ams::svc::codegen::impl { this->type_size == rhs.type_size && this->passed_size == rhs.passed_size && this->passed_by_pointer == rhs.passed_by_pointer && + this->is_boolean == rhs.is_boolean && this->num_locations == rhs.num_locations)) { return false;