arm: Implement native code execution backend

This commit is contained in:
Liam 2023-11-17 23:44:53 +02:00 committed by t895
parent 4838837620
commit 9f91ba1f73
31 changed files with 1803 additions and 51 deletions

View file

@ -22,6 +22,10 @@
#include "core/loader/nso.h"
#include "core/memory.h"
#ifdef ARCHITECTURE_arm64
#include "core/arm/nce/patch.h"
#endif
namespace Loader {
struct NroSegmentHeader {
@ -139,7 +143,8 @@ static constexpr u32 PageAlignSize(u32 size) {
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
}
static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) {
static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
const std::vector<u8>& data) {
if (data.size() < sizeof(NroHeader)) {
return {};
}
@ -195,14 +200,60 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
codeset.DataSegment().size += bss_size;
program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
#ifdef ARCHITECTURE_arm64
const auto& code = codeset.CodeSegment();
// NROs are always 64-bit programs.
Settings::SetNceEnabled(true);
// Create NCE patcher
Core::NCE::Patcher patch{};
size_t image_size = program_image.size();
if (Settings::IsNceEnabled()) {
// Patch SVCs and MRS calls in the guest code
patch.PatchText(program_image, code);
// We only support PostData patching for NROs.
ASSERT(patch.Mode() == Core::NCE::PatchMode::PostData);
// Update patch section.
auto& patch_segment = codeset.PatchSegment();
patch_segment.addr = image_size;
patch_segment.size = static_cast<u32>(patch.SectionSize());
// Add patch section size to the module size.
image_size += patch_segment.size;
}
#endif
// Enable direct memory mapping in case of NCE.
const u64 fastmem_base = [&]() -> size_t {
if (Settings::IsNceEnabled()) {
auto& buffer = system.DeviceMemory().buffer;
buffer.EnableDirectMappedAddress();
return reinterpret_cast<u64>(buffer.VirtualBasePointer());
}
return 0;
}();
// Setup the process code layout
if (process
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), 0,
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), image_size, fastmem_base,
false)
.IsError()) {
return false;
}
// Relocate code patch and copy to the program_image if running under NCE.
// This needs to be after LoadFromMetadata so we can use the process entry point.
#ifdef ARCHITECTURE_arm64
if (Settings::IsNceEnabled()) {
patch.RelocateAndCopy(process.GetEntryPoint(), code, program_image,
&process.GetPostHandlers());
}
#endif
// Load codeset for current process
codeset.memory = std::move(program_image);
process.LoadModule(std::move(codeset), process.GetEntryPoint());
@ -210,8 +261,9 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
return true;
}
bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) {
return LoadNroImpl(process, nro_file.ReadAllBytes());
bool AppLoader_NRO::LoadNro(Core::System& system, Kernel::KProcess& process,
const FileSys::VfsFile& nro_file) {
return LoadNroImpl(system, process, nro_file.ReadAllBytes());
}
AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) {
@ -219,7 +271,7 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::S
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
if (!LoadNro(process, *file)) {
if (!LoadNro(system, process, *file)) {
return {ResultStatus::ErrorLoadingNRO, {}};
}