summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes4
-rw-r--r--.travis.yml2
-rwxr-xr-x.travis/macos/build.sh2
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/audio_core/audio_renderer.cpp2
-rw-r--r--src/audio_core/audio_renderer.h2
-rw-r--r--src/audio_core/stream.cpp4
-rw-r--r--src/audio_core/stream.h14
-rw-r--r--src/core/arm/arm_interface.h10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp15
-rw-r--r--src/core/core.cpp4
-rw-r--r--src/core/core_cpu.cpp8
-rw-r--r--src/core/core_cpu.h2
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp62
-rw-r--r--src/core/file_sys/patch_manager.cpp56
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/program_metadata.h6
-rw-r--r--src/core/file_sys/registered_cache.cpp2
-rw-r--r--src/core/file_sys/romfs.cpp2
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/savedata_factory.cpp2
-rw-r--r--src/core/file_sys/vfs.cpp6
-rw-r--r--src/core/file_sys/vfs.h9
-rw-r--r--src/core/file_sys/vfs_concat.cpp45
-rw-r--r--src/core/file_sys/vfs_concat.h44
-rw-r--r--src/core/file_sys/vfs_layered.cpp15
-rw-r--r--src/core/file_sys/vfs_layered.h8
-rw-r--r--src/core/file_sys/vfs_static.h21
-rw-r--r--src/core/file_sys/vfs_vector.cpp6
-rw-r--r--src/core/file_sys/vfs_vector.h8
-rw-r--r--src/core/gdbstub/gdbstub.cpp17
-rw-r--r--src/core/hle/kernel/errors.h2
-rw-r--r--src/core/hle/kernel/object.h3
-rw-r--r--src/core/hle/kernel/process.cpp29
-rw-r--r--src/core/hle/kernel/process.h113
-rw-r--r--src/core/hle/kernel/scheduler.cpp16
-rw-r--r--src/core/hle/kernel/scheduler.h4
-rw-r--r--src/core/hle/kernel/shared_memory.cpp16
-rw-r--r--src/core/hle/kernel/svc.cpp95
-rw-r--r--src/core/hle/kernel/svc_wrap.h5
-rw-r--r--src/core/hle/kernel/thread.cpp5
-rw-r--r--src/core/hle/kernel/vm_manager.cpp180
-rw-r--r--src/core/hle/kernel/vm_manager.h100
-rw-r--r--src/core/hle/kernel/wait_object.h2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp3
-rw-r--r--src/core/hle/service/fatal/fatal.cpp4
-rw-r--r--src/core/hle/service/nfp/nfp.cpp1
-rw-r--r--src/core/hle/service/nim/nim.cpp1
-rw-r--r--src/core/hle/service/ns/pl_u.cpp6
-rw-r--r--src/core/hle/service/sm/controller.cpp3
-rw-r--r--src/core/hle/service/vi/vi.cpp20
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp21
-rw-r--r--src/core/loader/deconstructed_rom_directory.h3
-rw-r--r--src/core/loader/elf.cpp38
-rw-r--r--src/core/loader/elf.h5
-rw-r--r--src/core/loader/loader.h3
-rw-r--r--src/core/loader/nax.cpp2
-rw-r--r--src/core/loader/nax.h2
-rw-r--r--src/core/loader/nca.cpp2
-rw-r--r--src/core/loader/nca.h3
-rw-r--r--src/core/loader/nro.cpp14
-rw-r--r--src/core/loader/nro.h3
-rw-r--r--src/core/loader/nso.cpp16
-rw-r--r--src/core/loader/nso.h4
-rw-r--r--src/core/loader/nsp.cpp4
-rw-r--r--src/core/loader/nsp.h2
-rw-r--r--src/core/loader/xci.cpp4
-rw-r--r--src/core/loader/xci.h2
-rw-r--r--src/core/memory.cpp42
-rw-r--r--src/core/memory.h63
-rw-r--r--src/tests/core/arm/arm_test_common.cpp9
-rw-r--r--src/video_core/engines/maxwell_3d.h20
-rw-r--r--src/video_core/engines/maxwell_compute.cpp19
-rw-r--r--src/video_core/engines/maxwell_compute.h36
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp29
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h11
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h3
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp31
-rw-r--r--src/video_core/renderer_opengl/gl_state.h7
-rw-r--r--src/video_core/textures/decoders.cpp117
-rw-r--r--src/yuzu/game_list.cpp14
-rw-r--r--src/yuzu/game_list.h32
-rw-r--r--src/yuzu/game_list_p.h40
-rw-r--r--src/yuzu/main.cpp92
84 files changed, 1108 insertions, 579 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..ab861a396
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+dist/languages/* linguist-vendored
+dist/qt_themes/* linguist-vendored
+externals/* linguist-vendored
+*.h linguist-language=cpp
diff --git a/.travis.yml b/.travis.yml
index 4d363cbc9..b0fbe3c5f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -24,7 +24,7 @@ matrix:
- os: osx
env: NAME="macos build"
sudo: false
- osx_image: xcode9.3
+ osx_image: xcode10
install: "./.travis/macos/deps.sh"
script: "./.travis/macos/build.sh"
after_success: "./.travis/macos/upload.sh"
diff --git a/.travis/macos/build.sh b/.travis/macos/build.sh
index b881fa190..e68dc1400 100755
--- a/.travis/macos/build.sh
+++ b/.travis/macos/build.sh
@@ -2,7 +2,7 @@
set -o pipefail
-export MACOSX_DEPLOYMENT_TARGET=10.12
+export MACOSX_DEPLOYMENT_TARGET=10.13
export Qt5_DIR=$(brew --prefix)/opt/qt5
export UNICORNDIR=$(pwd)/externals/unicorn
export PATH="/usr/local/opt/ccache/libexec:$PATH"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 25c5cb112..cd990188e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -123,8 +123,6 @@ else()
# Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors.
add_definitions(/DWIN32_LEAN_AND_MEAN)
- # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms)
- set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE)
# Tweak optimization settings
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 521b19ff7..6f0ff953a 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -79,7 +79,7 @@ u32 AudioRenderer::GetMixBufferCount() const {
return worker_params.mix_buffer_count;
}
-u32 AudioRenderer::GetState() const {
+Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState();
}
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index be923ee65..dfef89e1d 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -170,7 +170,7 @@ public:
u32 GetSampleRate() const;
u32 GetSampleCount() const;
u32 GetMixBufferCount() const;
- u32 GetState() const;
+ Stream::State GetStreamState() const;
private:
class VoiceState;
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index ee4aa98af..742a5e0a0 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -53,8 +53,8 @@ void Stream::Stop() {
ASSERT_MSG(false, "Unimplemented");
}
-u32 Stream::GetState() const {
- return static_cast<u32>(state);
+Stream::State Stream::GetState() const {
+ return state;
}
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 43eca74e1..aebfeb51d 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -33,6 +33,12 @@ public:
Multi51Channel16,
};
+ /// Current state of the stream
+ enum class State {
+ Stopped,
+ Playing,
+ };
+
/// Callback function type, used to change guest state on a buffer being released
using ReleaseCallback = std::function<void()>;
@@ -73,15 +79,9 @@ public:
u32 GetNumChannels() const;
/// Get the state
- u32 GetState() const;
+ State GetState() const;
private:
- /// Current state of the stream
- enum class State {
- Stopped,
- Playing,
- };
-
/// Plays the next queued buffer in the audio stream, starting playback if necessary
void PlayNextBuffer();
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 16d528994..59da33f30 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -22,10 +22,16 @@ public:
std::array<u64, 31> cpu_registers;
u64 sp;
u64 pc;
- u64 pstate;
+ u32 pstate;
+ std::array<u8, 4> padding;
std::array<u128, 32> vector_registers;
- u64 fpcr;
+ u32 fpcr;
+ u32 fpsr;
+ u64 tpidr;
};
+ // Internally within the kernel, it expects the AArch64 version of the
+ // thread context to be 800 bytes in size.
+ static_assert(sizeof(ThreadContext) == 0x320);
/// Runs the CPU until an event happens
virtual void Run() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 7be5a38de..05cc84458 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -129,7 +129,8 @@ public:
};
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
- auto** const page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data();
+ auto& current_process = Core::CurrentProcess();
+ auto** const page_table = current_process->VMManager().page_table.pointers.data();
Dynarmic::A64::UserConfig config;
@@ -138,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
// Memory
config.page_table = reinterpret_cast<void**>(page_table);
- config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS;
+ config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth();
config.silently_mirror_page_table = false;
// Multi-process state
@@ -174,7 +175,7 @@ ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
std::size_t core_index)
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} {
- ThreadContext ctx;
+ ThreadContext ctx{};
inner_unicorn.SaveContext(ctx);
PageTableChanged();
LoadContext(ctx);
@@ -246,15 +247,19 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
ctx.pstate = jit->GetPstate();
ctx.vector_registers = jit->GetVectors();
ctx.fpcr = jit->GetFpcr();
+ ctx.fpsr = jit->GetFpsr();
+ ctx.tpidr = cb->tpidr_el0;
}
void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
- jit->SetPstate(static_cast<u32>(ctx.pstate));
+ jit->SetPstate(ctx.pstate);
jit->SetVectors(ctx.vector_registers);
- jit->SetFpcr(static_cast<u32>(ctx.fpcr));
+ jit->SetFpcr(ctx.fpcr);
+ jit->SetFpsr(ctx.fpsr);
+ SetTPIDR_EL0(ctx.tpidr);
}
void ARM_Dynarmic::PrepareReschedule() {
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 50f0a42fb..b6acfb3e4 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -64,7 +64,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
if (concat.empty())
return nullptr;
- return FileSys::ConcatenateFiles(concat, dir->GetName());
+ return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
}
return vfs->OpenFile(path, FileSys::Mode::Read);
@@ -202,7 +202,7 @@ struct System::Impl {
return init_result;
}
- const Loader::ResultStatus load_result{app_loader->Load(kernel.CurrentProcess())};
+ const Loader::ResultStatus load_result{app_loader->Load(*kernel.CurrentProcess())};
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
Shutdown();
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 21568ad50..265f8ed9c 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -55,16 +55,16 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
- arm_interface = std::make_shared<ARM_Dynarmic>(exclusive_monitor, core_index);
+ arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index);
#else
- arm_interface = std::make_shared<ARM_Unicorn>();
+ arm_interface = std::make_unique<ARM_Unicorn>();
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
- arm_interface = std::make_shared<ARM_Unicorn>();
+ arm_interface = std::make_unique<ARM_Unicorn>();
}
- scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
+ scheduler = std::make_shared<Kernel::Scheduler>(*arm_interface);
}
Cpu::~Cpu() = default;
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 685532965..ee7e04abc 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -76,7 +76,7 @@ public:
private:
void Reschedule();
- std::shared_ptr<ARM_Interface> arm_interface;
+ std::unique_ptr<ARM_Interface> arm_interface;
std::shared_ptr<CpuBarrier> cpu_barrier;
std::shared_ptr<Kernel::Scheduler> scheduler;
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 21fc3d796..2a913ce82 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -23,6 +23,7 @@
*/
#include <cstring>
+#include "common/alignment.h"
#include "common/assert.h"
#include "core/file_sys/fsmitm_romfsbuild.h"
#include "core/file_sys/vfs.h"
@@ -73,7 +74,7 @@ static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size
struct RomFSBuildFileContext;
struct RomFSBuildDirectoryContext {
- std::string path = "";
+ std::string path;
u32 cur_path_ofs = 0;
u32 path_len = 0;
u32 entry_offset = 0;
@@ -84,7 +85,7 @@ struct RomFSBuildDirectoryContext {
};
struct RomFSBuildFileContext {
- std::string path = "";
+ std::string path;
u32 cur_path_ofs = 0;
u32 path_len = 0;
u32 entry_offset = 0;
@@ -92,12 +93,10 @@ struct RomFSBuildFileContext {
u64 size = 0;
std::shared_ptr<RomFSBuildDirectoryContext> parent;
std::shared_ptr<RomFSBuildFileContext> sibling;
- VirtualFile source = nullptr;
-
- RomFSBuildFileContext() : path(""), cur_path_ofs(0), path_len(0) {}
+ VirtualFile source;
};
-static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t path_len) {
+static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) {
u32 hash = parent ^ 123456789;
for (u32 i = 0; i < path_len; i++) {
hash = (hash >> 5) | (hash << 27);
@@ -107,13 +106,16 @@ static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t
return hash;
}
-static u32 romfs_get_hash_table_count(u32 num_entries) {
+static u64 romfs_get_hash_table_count(u64 num_entries) {
if (num_entries < 3) {
return 3;
- } else if (num_entries < 19) {
+ }
+
+ if (num_entries < 19) {
return num_entries | 1;
}
- u32 count = num_entries;
+
+ u64 count = num_entries;
while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 ||
count % 11 == 0 || count % 13 == 0 || count % 17 == 0) {
count++;
@@ -139,7 +141,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs,
const auto child = std::make_shared<RomFSBuildDirectoryContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
- child->path_len = child->cur_path_ofs + kv.first.size();
+ child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
// Sanity check on path_len
@@ -152,7 +154,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs,
const auto child = std::make_shared<RomFSBuildFileContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
- child->path_len = child->cur_path_ofs + kv.first.size();
+ child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
// Sanity check on path_len
@@ -181,7 +183,7 @@ bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext>
// Add a new directory.
num_dirs++;
dir_table_size +=
- sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3);
+ sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4);
dir_ctx->parent = parent_dir_ctx;
directories.emplace(dir_ctx->path, dir_ctx);
@@ -199,7 +201,7 @@ bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> pare
// Add a new file.
num_files++;
file_table_size +=
- sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3);
+ sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4);
file_ctx->parent = parent_dir_ctx;
files.emplace(file_ctx->path, file_ctx);
@@ -219,8 +221,8 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_))
RomFSBuildContext::~RomFSBuildContext() = default;
std::map<u64, VirtualFile> RomFSBuildContext::Build() {
- const auto dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs);
- const auto file_hash_table_entry_count = romfs_get_hash_table_count(num_files);
+ const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs);
+ const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files);
dir_hash_table_size = 4 * dir_hash_table_entry_count;
file_hash_table_size = 4 * file_hash_table_entry_count;
@@ -233,12 +235,6 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
std::vector<u8> dir_table(dir_table_size);
std::vector<u8> file_table(file_table_size);
- // Clear out hash tables.
- for (u32 i = 0; i < dir_hash_table_entry_count; i++)
- dir_hash_table[i] = ROMFS_ENTRY_EMPTY;
- for (u32 i = 0; i < file_hash_table_entry_count; i++)
- file_hash_table[i] = ROMFS_ENTRY_EMPTY;
-
std::shared_ptr<RomFSBuildFileContext> cur_file;
// Determine file offsets.
@@ -246,12 +242,12 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr;
for (const auto& it : files) {
cur_file = it.second;
- file_partition_size = (file_partition_size + 0xFULL) & ~0xFULL;
+ file_partition_size = Common::AlignUp(file_partition_size, 16);
cur_file->offset = file_partition_size;
file_partition_size += cur_file->size;
cur_file->entry_offset = entry_offset;
- entry_offset +=
- sizeof(RomFSFileEntry) + ((cur_file->path_len - cur_file->cur_path_ofs + 3) & ~3);
+ entry_offset += sizeof(RomFSFileEntry) +
+ Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4);
prev_file = cur_file;
}
// Assign deferred parent/sibling ownership.
@@ -268,8 +264,8 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
for (const auto& it : directories) {
cur_dir = it.second;
cur_dir->entry_offset = entry_offset;
- entry_offset +=
- sizeof(RomFSDirectoryEntry) + ((cur_dir->path_len - cur_dir->cur_path_ofs + 3) & ~3);
+ entry_offset += sizeof(RomFSDirectoryEntry) +
+ Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4);
}
// Assign deferred parent/sibling ownership.
for (auto it = directories.rbegin(); it->second != root; ++it) {
@@ -302,7 +298,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source);
std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
- (cur_entry.name_size + 3) & ~3);
+ Common::AlignUp(cur_entry.name_size, 4));
std::memcpy(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry),
cur_file->path.data() + cur_file->cur_path_ofs, name_size);
}
@@ -329,10 +325,8 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry,
sizeof(RomFSDirectoryEntry));
- std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry,
- sizeof(RomFSDirectoryEntry));
std::memset(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 0,
- (cur_entry.name_size + 3) & ~3);
+ Common::AlignUp(cur_entry.name_size, 4));
std::memcpy(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry),
cur_dir->path.data() + cur_dir->cur_path_ofs, name_size);
}
@@ -344,18 +338,18 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
header.dir_hash_table_size = dir_hash_table_size;
header.dir_table_size = dir_table_size;
header.file_partition_ofs = ROMFS_FILEPARTITION_OFS;
- header.dir_hash_table_ofs = (header.file_partition_ofs + file_partition_size + 3ULL) & ~3ULL;
+ header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4);
header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size;
header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size;
header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size;
std::vector<u8> header_data(sizeof(RomFSHeader));
std::memcpy(header_data.data(), &header, header_data.size());
- out.emplace(0, std::make_shared<VectorVfsFile>(header_data));
+ out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data)));
std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size +
dir_table_size);
- auto index = 0;
+ std::size_t index = 0;
std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32));
index += dir_hash_table.size() * sizeof(u32);
std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size());
@@ -364,7 +358,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
file_hash_table.size() * sizeof(u32));
index += file_hash_table.size() * sizeof(u32);
std::memcpy(metadata.data() + index, file_table.data(), file_table.size());
- out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(metadata));
+ out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata)));
return out;
}
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index af3f9a78f..4b3b5e665 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -70,38 +70,40 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
- if (type == ContentRecordType::Program && load_dir != nullptr && load_dir->GetSize() > 0) {
- auto extracted = ExtractRomFS(romfs);
-
- if (extracted != nullptr) {
- auto patch_dirs = load_dir->GetSubdirectories();
- std::sort(patch_dirs.begin(), patch_dirs.end(),
- [](const VirtualDir& l, const VirtualDir& r) {
- return l->GetName() < r->GetName();
- });
-
- std::vector<VirtualDir> layers;
- layers.reserve(patch_dirs.size() + 1);
- for (const auto& subdir : patch_dirs) {
- auto romfs_dir = subdir->GetSubdirectory("romfs");
- if (romfs_dir != nullptr)
- layers.push_back(std::move(romfs_dir));
- }
+ if (type != ContentRecordType::Program || load_dir == nullptr || load_dir->GetSize() <= 0) {
+ return;
+ }
- layers.push_back(std::move(extracted));
+ auto extracted = ExtractRomFS(romfs);
+ if (extracted == nullptr) {
+ return;
+ }
- const auto layered = LayerDirectories(layers);
+ auto patch_dirs = load_dir->GetSubdirectories();
+ std::sort(patch_dirs.begin(), patch_dirs.end(),
+ [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
- if (layered != nullptr) {
- auto packed = CreateRomFS(layered);
+ std::vector<VirtualDir> layers;
+ layers.reserve(patch_dirs.size() + 1);
+ for (const auto& subdir : patch_dirs) {
+ auto romfs_dir = subdir->GetSubdirectory("romfs");
+ if (romfs_dir != nullptr)
+ layers.push_back(std::move(romfs_dir));
+ }
+ layers.push_back(std::move(extracted));
- if (packed != nullptr) {
- LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully");
- romfs = std::move(packed);
- }
- }
- }
+ auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
+ if (layered == nullptr) {
+ return;
+ }
+
+ auto packed = CreateRomFS(std::move(layered));
+ if (packed == nullptr) {
+ return;
}
+
+ LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully");
+ romfs = std::move(packed);
}
VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset,
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 02319ce0f..8903ed1d3 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -83,10 +83,12 @@ void ProgramMetadata::Print() const {
auto address_space = "Unknown";
switch (npdm_header.address_space_type) {
- case ProgramAddressSpaceType::Is64Bit:
+ case ProgramAddressSpaceType::Is36Bit:
+ case ProgramAddressSpaceType::Is39Bit:
address_space = "64-bit";
break;
case ProgramAddressSpaceType::Is32Bit:
+ case ProgramAddressSpaceType::Is32BitNoMap:
address_space = "32-bit";
break;
}
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 1143e36c4..e4470d6f0 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -17,8 +17,10 @@ enum class ResultStatus : u16;
namespace FileSys {
enum class ProgramAddressSpaceType : u8 {
- Is64Bit = 1,
- Is32Bit = 2,
+ Is32Bit = 0,
+ Is36Bit = 1,
+ Is32BitNoMap = 2,
+ Is39Bit = 3,
};
enum class ProgramFilePermission : u64 {
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 653ef2e7b..e9b040689 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -125,7 +125,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
if (concat.empty())
return nullptr;
- file = FileSys::ConcatenateFiles(concat, concat.front()->GetName());
+ file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
}
return file;
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index 205284a4d..5910f7046 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -134,7 +134,7 @@ VirtualFile CreateRomFS(VirtualDir dir) {
return nullptr;
RomFSBuildContext ctx{dir};
- return ConcatenateFiles<0>(ctx.Build(), dir->GetName());
+ return ConcatenatedVfsFile::MakeConcatenatedFile(0, ctx.Build(), dir->GetName());
}
} // namespace FileSys
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 3d1a3685e..d027a8d59 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -34,7 +34,7 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
if (!updatable)
return MakeResult<VirtualFile>(file);
- const PatchManager patch_manager(Core::CurrentProcess()->program_id);
+ const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID());
return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset));
}
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 9b2c51bbd..47f2ab9e0 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -81,7 +81,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData && title_id == 0)
- title_id = Core::CurrentProcess()->program_id;
+ title_id = Core::CurrentProcess()->GetTitleID();
std::string out;
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 5fbea1739..bfe50da73 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -463,14 +463,14 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t
return true;
}
-bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size) {
+bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size) {
if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
return false;
if (!dest->Resize(src->GetSize()))
return false;
std::vector<u8> temp(std::min(block_size, src->GetSize()));
- for (size_t i = 0; i < src->GetSize(); i += block_size) {
+ for (std::size_t i = 0; i < src->GetSize(); i += block_size) {
const auto read = std::min(block_size, src->GetSize() - i);
const auto block = src->Read(temp.data(), read, i);
@@ -481,7 +481,7 @@ bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_si
return true;
}
-bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size) {
+bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size) {
if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
return false;
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index cea4aa8b8..270291631 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -315,18 +315,19 @@ public:
bool Rename(std::string_view name) override;
};
-// Compare the two files, byte-for-byte, in increments specificed by block_size
-bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x1000);
+// Compare the two files, byte-for-byte, in increments specified by block_size
+bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2,
+ std::size_t block_size = 0x1000);
// A method that copies the raw data between two different implementations of VirtualFile. If you
// are using the same implementation, it is probably better to use the Copy method in the parent
// directory of src/dest.
-bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size = 0x1000);
+bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size = 0x1000);
// A method that performs a similar function to VfsRawCopy above, but instead copies entire
// directories. It suffers the same performance penalties as above and an implementation-specific
// Copy should always be preferred.
-bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size = 0x1000);
+bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size = 0x1000);
// Checks if the directory at path relative to rel exists. If it does, returns that. If it does not
// it attempts to create it and returns the new dir or nullptr on failure.
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index d9f9911da..16d801c0c 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -7,6 +7,7 @@
#include "common/assert.h"
#include "core/file_sys/vfs_concat.h"
+#include "core/file_sys/vfs_static.h"
namespace FileSys {
@@ -22,15 +23,6 @@ static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& m
return map.begin()->first == 0;
}
-VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) {
- if (files.empty())
- return nullptr;
- if (files.size() == 1)
- return files[0];
-
- return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
-}
-
ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name)
: name(std::move(name)) {
std::size_t next_offset = 0;
@@ -47,6 +39,41 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std:
ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
+VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> files,
+ std::string name) {
+ if (files.empty())
+ return nullptr;
+ if (files.size() == 1)
+ return files[0];
+
+ return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
+}
+
+VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
+ std::map<u64, VirtualFile> files,
+ std::string name) {
+ if (files.empty())
+ return nullptr;
+ if (files.size() == 1)
+ return files.begin()->second;
+
+ const auto last_valid = --files.end();
+ for (auto iter = files.begin(); iter != last_valid;) {
+ const auto old = iter++;
+ if (old->first + old->second->GetSize() != iter->first) {
+ files.emplace(old->first + old->second->GetSize(),
+ std::make_shared<StaticVfsFile>(filler_byte, iter->first - old->first -
+ old->second->GetSize()));
+ }
+ }
+
+ // Ensure the map starts at offset 0 (start of file), otherwise pad to fill.
+ if (files.begin()->first != 0)
+ files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first));
+
+ return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
+}
+
std::string ConcatenatedVfsFile::GetName() const {
if (files.empty())
return "";
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 76211d38a..c90f9d5d1 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -7,26 +7,27 @@
#include <map>
#include <memory>
#include <string_view>
-#include <boost/container/flat_map.hpp>
#include "core/file_sys/vfs.h"
-#include "core/file_sys/vfs_static.h"
namespace FileSys {
// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
// read-only.
class ConcatenatedVfsFile : public VfsFile {
- friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name);
-
- template <u8 filler_byte>
- friend VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name);
-
ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name);
public:
~ConcatenatedVfsFile() override;
+ /// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
+ static VirtualFile MakeConcatenatedFile(std::vector<VirtualFile> files, std::string name);
+
+ /// Convenience function that turns a map of offsets to files into a concatenated file, filling
+ /// gaps with a given filler byte.
+ static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::map<u64, VirtualFile> files,
+ std::string name);
+
std::string GetName() const override;
std::size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
@@ -43,33 +44,4 @@ private:
std::string name;
};
-// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
-VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name);
-
-// Convenience function that turns a map of offsets to files into a concatenated file, filling gaps
-// with template parameter.
-template <u8 filler_byte>
-VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name) {
- if (files.empty())
- return nullptr;
- if (files.size() == 1)
- return files.begin()->second;
-
- const auto last_valid = --files.end();
- for (auto iter = files.begin(); iter != last_valid;) {
- const auto old = iter++;
- if (old->first + old->second->GetSize() != iter->first) {
- files.emplace(old->first + old->second->GetSize(),
- std::make_shared<StaticVfsFile<filler_byte>>(iter->first - old->first -
- old->second->GetSize()));
- }
- }
-
- // Ensure the map starts at offset 0 (start of file), otherwise pad to fill.
- if (files.begin()->first != 0)
- files.emplace(0, std::make_shared<StaticVfsFile<filler_byte>>(files.begin()->first));
-
- return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
-}
-
} // namespace FileSys
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 45563d7ae..bfee01725 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -8,7 +8,13 @@
namespace FileSys {
-VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) {
+LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name)
+ : dirs(std::move(dirs)), name(std::move(name)) {}
+
+LayeredVfsDirectory::~LayeredVfsDirectory() = default;
+
+VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dirs,
+ std::string name) {
if (dirs.empty())
return nullptr;
if (dirs.size() == 1)
@@ -17,11 +23,6 @@ VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) {
return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name)));
}
-LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name)
- : dirs(std::move(dirs)), name(std::move(name)) {}
-
-LayeredVfsDirectory::~LayeredVfsDirectory() = default;
-
std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const {
for (const auto& layer : dirs) {
const auto file = layer->GetFileRelative(path);
@@ -41,7 +42,7 @@ std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative(
out.push_back(std::move(dir));
}
- return LayerDirectories(std::move(out));
+ return MakeLayeredDirectory(std::move(out));
}
std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const {
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h
index 4f6e341ab..d85310f57 100644
--- a/src/core/file_sys/vfs_layered.h
+++ b/src/core/file_sys/vfs_layered.h
@@ -9,20 +9,18 @@
namespace FileSys {
-// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases.
-VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name = "");
-
// Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first
// one and falling back to the one after. The highest priority directory (overwrites all others)
// should be element 0 in the dirs vector.
class LayeredVfsDirectory : public VfsDirectory {
- friend VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name);
-
LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name);
public:
~LayeredVfsDirectory() override;
+ /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases.
+ static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = "");
+
std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override;
std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override;
std::shared_ptr<VfsFile> GetFile(std::string_view name) const override;
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index 4dd47ffcc..44fab51d1 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -12,21 +12,21 @@
namespace FileSys {
-template <u8 value>
class StaticVfsFile : public VfsFile {
public:
- explicit StaticVfsFile(size_t size = 0, std::string name = "", VirtualDir parent = nullptr)
- : size(size), name(std::move(name)), parent(std::move(parent)) {}
+ explicit StaticVfsFile(u8 value, std::size_t size = 0, std::string name = "",
+ VirtualDir parent = nullptr)
+ : value{value}, size{size}, name{std::move(name)}, parent{std::move(parent)} {}
std::string GetName() const override {
return name;
}
- size_t GetSize() const override {
+ std::size_t GetSize() const override {
return size;
}
- bool Resize(size_t new_size) override {
+ bool Resize(std::size_t new_size) override {
size = new_size;
return true;
}
@@ -43,23 +43,23 @@ public:
return true;
}
- size_t Read(u8* data, size_t length, size_t offset) const override {
+ std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override {
const auto read = std::min(length, size - offset);
std::fill(data, data + read, value);
return read;
}
- size_t Write(const u8* data, size_t length, size_t offset) override {
+ std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
return 0;
}
- boost::optional<u8> ReadByte(size_t offset) const override {
+ boost::optional<u8> ReadByte(std::size_t offset) const override {
if (offset < size)
return value;
return boost::none;
}
- std::vector<u8> ReadBytes(size_t length, size_t offset) const override {
+ std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
const auto read = std::min(length, size - offset);
return std::vector<u8>(read, value);
}
@@ -70,7 +70,8 @@ public:
}
private:
- size_t size;
+ u8 value;
+ std::size_t size;
std::string name;
VirtualDir parent;
};
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 7033e2c88..389c7e003 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -9,7 +9,7 @@
namespace FileSys {
VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent)
- : data(std::move(initial_data)), name(std::move(name)), parent(std::move(parent)) {}
+ : data(std::move(initial_data)), parent(std::move(parent)), name(std::move(name)) {}
VectorVfsFile::~VectorVfsFile() = default;
@@ -38,13 +38,13 @@ bool VectorVfsFile::IsReadable() const {
return true;
}
-size_t VectorVfsFile::Read(u8* data_, size_t length, size_t offset) const {
+std::size_t VectorVfsFile::Read(u8* data_, std::size_t length, std::size_t offset) const {
const auto read = std::min(length, data.size() - offset);
std::memcpy(data_, data.data() + offset, read);
return read;
}
-size_t VectorVfsFile::Write(const u8* data_, size_t length, size_t offset) {
+std::size_t VectorVfsFile::Write(const u8* data_, std::size_t length, std::size_t offset) {
if (offset + length > data.size())
data.resize(offset + length);
const auto write = std::min(length, data.size() - offset);
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 115c3ae95..48a414c98 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -16,13 +16,13 @@ public:
~VectorVfsFile() override;
std::string GetName() const override;
- size_t GetSize() const override;
- bool Resize(size_t new_size) override;
+ std::size_t GetSize() const override;
+ bool Resize(std::size_t new_size) override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
- size_t Read(u8* data, size_t length, size_t offset) const override;
- size_t Write(const u8* data, size_t length, size_t offset) override;
+ std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
+ std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
bool Rename(std::string_view name) override;
virtual void Assign(std::vector<u8> new_data);
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 0ecdd9f82..5bc947010 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -37,7 +37,9 @@
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/loader.h"
#include "core/memory.h"
@@ -248,7 +250,7 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
} else if (id == PC_REGISTER) {
thread->context.pc = val;
} else if (id == PSTATE_REGISTER) {
- thread->context.pstate = val;
+ thread->context.pstate = static_cast<u32>(val);
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
}
@@ -585,7 +587,8 @@ static void HandleQuery() {
strlen("Xfer:features:read:target.xml:")) == 0) {
SendReply(target_xml);
} else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
- std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR);
+ const VAddr base_address = Core::CurrentProcess()->VMManager().GetCodeRegionBaseAddress();
+ std::string buffer = fmt::format("TextSeg={:0x}", base_address);
SendReply(buffer.c_str());
} else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
std::string val = "m";
@@ -893,11 +896,11 @@ static void ReadMemory() {
static u8 reply[GDB_BUFFER_SIZE - 4];
auto start_offset = command_buffer + 1;
- auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
- VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
+ const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
+ const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
start_offset = addr_pos + 1;
- u64 len =
+ const u64 len =
HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
@@ -906,7 +909,9 @@ static void ReadMemory() {
SendReply("E01");
}
- if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) {
+ const auto& vm_manager = Core::CurrentProcess()->VMManager();
+ if (addr < vm_manager.GetCodeRegionBaseAddress() ||
+ addr >= vm_manager.GetMapRegionEndAddress()) {
return SendReply("E00");
}
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 8c2be2681..e5fa67ae8 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -31,6 +31,7 @@ enum {
TooLarge = 119,
InvalidEnumValue = 120,
NoSuchEntry = 121,
+ AlreadyRegistered = 122,
InvalidState = 125,
ResourceLimitExceeded = 132,
};
@@ -58,6 +59,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
+constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered);
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
ErrCodes::InvalidThreadPriority);
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index b054cbf7d..9eb72315c 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -6,7 +6,6 @@
#include <atomic>
#include <string>
-#include <utility>
#include <boost/smart_ptr/intrusive_ptr.hpp>
@@ -97,7 +96,7 @@ using SharedPtr = boost::intrusive_ptr<T>;
template <typename T>
inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
- return boost::static_pointer_cast<T>(std::move(object));
+ return boost::static_pointer_cast<T>(object);
}
return nullptr;
}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 121f741fd..dc9fc8470 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -8,6 +8,7 @@
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "core/core.h"
+#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
@@ -34,14 +35,22 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
process->name = std::move(name);
process->flags.raw = 0;
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
+ process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION);
process->status = ProcessStatus::Created;
process->program_id = 0;
process->process_id = kernel.CreateNewProcessID();
+ process->svc_access_mask.set();
kernel.AppendNewProcess(process);
return process;
}
+void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
+ program_id = metadata.GetTitleID();
+ is_64bit_process = metadata.Is64BitProgram();
+ vm_manager.Reset(metadata.GetAddressSpaceType());
+}
+
void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
for (std::size_t i = 0; i < len; ++i) {
u32 descriptor = kernel_caps[i];
@@ -119,7 +128,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
// TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
// of the user address space.
vm_manager
- .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size,
+ .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
MemoryState::Mapped)
.Unwrap();
@@ -185,6 +194,7 @@ static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
+ const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress();
if (needs_allocation) {
tls_slots.emplace_back(0); // The page is completely available at the start
@@ -197,18 +207,17 @@ VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
- vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
- tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal);
+ vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0,
+ Memory::PAGE_SIZE, MemoryState::ThreadLocal);
}
tls_slots[available_page].set(available_slot);
- return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
- available_slot * Memory::TLS_ENTRY_SIZE;
+ return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
}
void Process::FreeTLSSlot(VAddr tls_address) {
- const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR;
+ const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress();
const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
@@ -232,8 +241,8 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
}
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
- if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
- target + size < target) {
+ if (target < vm_manager.GetHeapRegionBaseAddress() ||
+ target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
return ERR_INVALID_ADDRESS;
}
@@ -268,8 +277,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
}
ResultCode Process::HeapFree(VAddr target, u32 size) {
- if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
- target + size < target) {
+ if (target < vm_manager.GetHeapRegionBaseAddress() ||
+ target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
return ERR_INVALID_ADDRESS;
}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 04d74e572..590e0c73d 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -17,6 +17,10 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
+namespace FileSys {
+class ProgramMetadata;
+}
+
namespace Kernel {
class KernelCore;
@@ -131,6 +135,16 @@ public:
return HANDLE_TYPE;
}
+ /// Gets a reference to the process' memory manager.
+ Kernel::VMManager& VMManager() {
+ return vm_manager;
+ }
+
+ /// Gets a const reference to the process' memory manager.
+ const Kernel::VMManager& VMManager() const {
+ return vm_manager;
+ }
+
/// Gets the current status of the process
ProcessStatus GetStatus() const {
return status;
@@ -141,29 +155,52 @@ public:
return process_id;
}
- /// Title ID corresponding to the process
- u64 program_id;
+ /// Gets the title ID corresponding to this process.
+ u64 GetTitleID() const {
+ return program_id;
+ }
- /// Resource limit descriptor for this process
- SharedPtr<ResourceLimit> resource_limit;
+ /// Gets the resource limit descriptor for this process
+ ResourceLimit& GetResourceLimit() {
+ return *resource_limit;
+ }
- /// The process may only call SVCs which have the corresponding bit set.
- std::bitset<0x80> svc_access_mask;
- /// Maximum size of the handle table for the process.
- unsigned int handle_table_size = 0x200;
- /// Special memory ranges mapped into this processes address space. This is used to give
- /// processes access to specific I/O regions and device memory.
- boost::container::static_vector<AddressMapping, 8> address_mappings;
- ProcessFlags flags;
- /// Kernel compatibility version for this process
- u16 kernel_version = 0;
- /// The default CPU for this process, threads are scheduled on this cpu by default.
- u8 ideal_processor = 0;
- /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse
- /// this value from the process header.
- u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
- u32 allowed_thread_priority_mask = 0xFFFFFFFF;
- u32 is_virtual_address_memory_enabled = 0;
+ /// Gets the resource limit descriptor for this process
+ const ResourceLimit& GetResourceLimit() const {
+ return *resource_limit;
+ }
+
+ /// Gets the default CPU ID for this process
+ u8 GetDefaultProcessorID() const {
+ return ideal_processor;
+ }
+
+ /// Gets the bitmask of allowed CPUs that this process' threads can run on.
+ u32 GetAllowedProcessorMask() const {
+ return allowed_processor_mask;
+ }
+
+ /// Gets the bitmask of allowed thread priorities.
+ u32 GetAllowedThreadPriorityMask() const {
+ return allowed_thread_priority_mask;
+ }
+
+ u32 IsVirtualMemoryEnabled() const {
+ return is_virtual_address_memory_enabled;
+ }
+
+ /// Whether this process is an AArch64 or AArch32 process.
+ bool Is64BitProcess() const {
+ return is_64bit_process;
+ }
+
+ /**
+ * Loads process-specifics configuration info with metadata provided
+ * by an executable.
+ *
+ * @param metadata The provided metadata to load process specific info.
+ */
+ void LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
/**
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -200,18 +237,43 @@ public:
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
- VMManager vm_manager;
-
private:
explicit Process(KernelCore& kernel);
~Process() override;
+ /// Memory manager for this process.
+ Kernel::VMManager vm_manager;
+
/// Current status of the process
ProcessStatus status;
/// The ID of this process
u32 process_id = 0;
+ /// Title ID corresponding to the process
+ u64 program_id;
+
+ /// Resource limit descriptor for this process
+ SharedPtr<ResourceLimit> resource_limit;
+
+ /// The process may only call SVCs which have the corresponding bit set.
+ std::bitset<0x80> svc_access_mask;
+ /// Maximum size of the handle table for the process.
+ u32 handle_table_size = 0x200;
+ /// Special memory ranges mapped into this processes address space. This is used to give
+ /// processes access to specific I/O regions and device memory.
+ boost::container::static_vector<AddressMapping, 8> address_mappings;
+ ProcessFlags flags;
+ /// Kernel compatibility version for this process
+ u16 kernel_version = 0;
+ /// The default CPU for this process, threads are scheduled on this cpu by default.
+ u8 ideal_processor = 0;
+ /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse
+ /// this value from the process header.
+ u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
+ u32 allowed_thread_priority_mask = 0xFFFFFFFF;
+ u32 is_virtual_address_memory_enabled = 0;
+
// Memory used to back the allocations in the regular heap. A single vector is used to cover
// the entire virtual address space extents that bound the allocations, including any holes.
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
@@ -230,6 +292,11 @@ private:
/// This vector will grow as more pages are allocated for new threads.
std::vector<std::bitset<8>> tls_slots;
+ /// Whether or not this process is AArch64, or AArch32.
+ /// By default, we currently assume this is true, unless otherwise
+ /// specified by metadata provided to the process during loading.
+ bool is_64bit_process = true;
+
std::string name;
};
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 69c812f16..1e82cfffb 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -17,7 +17,7 @@ namespace Kernel {
std::mutex Scheduler::scheduler_mutex;
-Scheduler::Scheduler(Core::ARM_Interface* cpu_core) : cpu_core(cpu_core) {}
+Scheduler::Scheduler(Core::ARM_Interface& cpu_core) : cpu_core(cpu_core) {}
Scheduler::~Scheduler() {
for (auto& thread : thread_list) {
@@ -59,9 +59,9 @@ void Scheduler::SwitchContext(Thread* new_thread) {
// Save context for previous thread
if (previous_thread) {
previous_thread->last_running_ticks = CoreTiming::GetTicks();
- cpu_core->SaveContext(previous_thread->context);
+ cpu_core.SaveContext(previous_thread->context);
// Save the TPIDR_EL0 system register in case it was modified.
- previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0();
+ previous_thread->tpidr_el0 = cpu_core.GetTPIDR_EL0();
if (previous_thread->status == ThreadStatus::Running) {
// This is only the case when a reschedule is triggered without the current thread
@@ -88,13 +88,13 @@ void Scheduler::SwitchContext(Thread* new_thread) {
if (previous_process != current_thread->owner_process) {
Core::CurrentProcess() = current_thread->owner_process;
- SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
+ SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table);
}
- cpu_core->LoadContext(new_thread->context);
- cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
- cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
- cpu_core->ClearExclusiveState();
+ cpu_core.LoadContext(new_thread->context);
+ cpu_core.SetTlsAddress(new_thread->GetTLSAddress());
+ cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
+ cpu_core.ClearExclusiveState();
} else {
current_thread = nullptr;
// Note: We do not reset the current process and current page table when idling because
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 744990c9b..2c94641ec 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -19,7 +19,7 @@ namespace Kernel {
class Scheduler final {
public:
- explicit Scheduler(Core::ARM_Interface* cpu_core);
+ explicit Scheduler(Core::ARM_Interface& cpu_core);
~Scheduler();
/// Returns whether there are any threads that are ready to run.
@@ -72,7 +72,7 @@ private:
SharedPtr<Thread> current_thread = nullptr;
- Core::ARM_Interface* cpu_core;
+ Core::ARM_Interface& cpu_core;
static std::mutex scheduler_mutex;
};
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index abb1d09cd..d061e6155 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -8,6 +8,7 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/memory.h"
@@ -34,11 +35,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce
// Refresh the address mappings for the current process.
if (Core::CurrentProcess() != nullptr) {
- Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(
+ Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings(
shared_memory->backing_block.get());
}
} else {
- auto& vm_manager = shared_memory->owner_process->vm_manager;
+ auto& vm_manager = shared_memory->owner_process->VMManager();
// The memory is already available and mapped in the owner process.
auto vma = vm_manager.FindVMA(address);
@@ -71,7 +72,8 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
shared_memory->other_permissions = other_permissions;
shared_memory->backing_block = std::move(heap_block);
shared_memory->backing_block_offset = offset;
- shared_memory->base_address = Memory::HEAP_VADDR + offset;
+ shared_memory->base_address =
+ kernel.CurrentProcess()->VMManager().GetHeapRegionBaseAddress() + offset;
return shared_memory;
}
@@ -105,7 +107,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
VAddr target_address = address;
// Map the memory block into the target process
- auto result = target_process->vm_manager.MapMemoryBlock(
+ auto result = target_process->VMManager().MapMemoryBlock(
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
if (result.Failed()) {
LOG_ERROR(
@@ -115,14 +117,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
return result.Code();
}
- return target_process->vm_manager.ReprotectRange(target_address, size,
- ConvertPermissions(permissions));
+ return target_process->VMManager().ReprotectRange(target_address, size,
+ ConvertPermissions(permissions));
}
ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not
// mapped to a SharedMemory.
- return target_process->vm_manager.UnmapRange(address, size);
+ return target_process->VMManager().UnmapRange(address, size);
}
VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c9d212a4c..1cdaa740a 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -51,8 +51,9 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
}
auto& process = *Core::CurrentProcess();
+ const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress();
CASCADE_RESULT(*heap_addr,
- process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
+ process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
return RESULT_SUCCESS;
}
@@ -325,26 +326,27 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
- const auto& vm_manager = Core::CurrentProcess()->vm_manager;
+ const auto& current_process = Core::CurrentProcess();
+ const auto& vm_manager = current_process->VMManager();
switch (static_cast<GetInfoType>(info_id)) {
case GetInfoType::AllowedCpuIdBitmask:
- *result = Core::CurrentProcess()->allowed_processor_mask;
+ *result = current_process->GetAllowedProcessorMask();
break;
case GetInfoType::AllowedThreadPrioBitmask:
- *result = Core::CurrentProcess()->allowed_thread_priority_mask;
+ *result = current_process->GetAllowedThreadPriorityMask();
break;
case GetInfoType::MapRegionBaseAddr:
- *result = Memory::MAP_REGION_VADDR;
+ *result = vm_manager.GetMapRegionBaseAddress();
break;
case GetInfoType::MapRegionSize:
- *result = Memory::MAP_REGION_SIZE;
+ *result = vm_manager.GetMapRegionSize();
break;
case GetInfoType::HeapRegionBaseAddr:
- *result = Memory::HEAP_VADDR;
+ *result = vm_manager.GetHeapRegionBaseAddress();
break;
case GetInfoType::HeapRegionSize:
- *result = Memory::HEAP_SIZE;
+ *result = vm_manager.GetHeapRegionSize();
break;
case GetInfoType::TotalMemoryUsage:
*result = vm_manager.GetTotalMemoryUsage();
@@ -359,22 +361,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
*result = 0;
break;
case GetInfoType::AddressSpaceBaseAddr:
- *result = vm_manager.GetAddressSpaceBaseAddr();
+ *result = vm_manager.GetCodeRegionBaseAddress();
break;
- case GetInfoType::AddressSpaceSize:
- *result = vm_manager.GetAddressSpaceSize();
+ case GetInfoType::AddressSpaceSize: {
+ const u64 width = vm_manager.GetAddressSpaceWidth();
+
+ switch (width) {
+ case 32:
+ *result = 0xFFE00000;
+ break;
+ case 36:
+ *result = 0xFF8000000;
+ break;
+ case 39:
+ *result = 0x7FF8000000;
+ break;
+ }
break;
+ }
case GetInfoType::NewMapRegionBaseAddr:
- *result = Memory::NEW_MAP_REGION_VADDR;
+ *result = vm_manager.GetNewMapRegionBaseAddress();
break;
case GetInfoType::NewMapRegionSize:
- *result = Memory::NEW_MAP_REGION_SIZE;
+ *result = vm_manager.GetNewMapRegionSize();
break;
case GetInfoType::IsVirtualAddressMemoryEnabled:
- *result = Core::CurrentProcess()->is_virtual_address_memory_enabled;
+ *result = current_process->IsVirtualMemoryEnabled();
break;
case GetInfoType::TitleId:
- *result = Core::CurrentProcess()->program_id;
+ *result = current_process->GetTitleID();
break;
case GetInfoType::PrivilegedProcessId:
LOG_WARNING(Kernel_SVC,
@@ -400,8 +415,36 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
}
/// Gets the thread context
-static ResultCode GetThreadContext(Handle handle, VAddr addr) {
- LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr);
+static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
+ LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
+ if (!thread) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ const auto current_process = Core::CurrentProcess();
+ if (thread->owner_process != current_process) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ if (thread == GetCurrentThread()) {
+ return ERR_ALREADY_REGISTERED;
+ }
+
+ Core::ARM_Interface::ThreadContext ctx = thread->context;
+ // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
+ ctx.pstate &= 0xFF0FFE20;
+
+ // If 64-bit, we can just write the context registers directly and we're good.
+ // However, if 32-bit, we have to ensure some registers are zeroed out.
+ if (!current_process->Is64BitProcess()) {
+ std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0);
+ std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
+ }
+
+ Memory::WriteBlock(thread_context, &ctx, sizeof(ctx));
return RESULT_SUCCESS;
}
@@ -429,8 +472,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
// Note: The kernel uses the current process's resource limit instead of
// the one from the thread owner's resource limit.
- SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
- if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
+ const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
+ if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
return ERR_NOT_AUTHORIZED;
}
@@ -504,9 +547,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
if (!process) {
return ERR_INVALID_HANDLE;
}
- auto vma = process->vm_manager.FindVMA(addr);
+ auto vma = process->VMManager().FindVMA(addr);
memory_info->attributes = 0;
- if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) {
+ if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) {
memory_info->base_address = 0;
memory_info->permission = static_cast<u32>(VMAPermission::None);
memory_info->size = 0;
@@ -553,14 +596,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
return ERR_INVALID_THREAD_PRIORITY;
}
- SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
- if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
+ const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
+ if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
return ERR_NOT_AUTHORIZED;
}
if (processor_id == THREADPROCESSORID_DEFAULT) {
// Set the target CPU to the one specified in the process' exheader.
- processor_id = Core::CurrentProcess()->ideal_processor;
+ processor_id = Core::CurrentProcess()->GetDefaultProcessorID();
ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
}
@@ -887,10 +930,10 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
}
if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
- ASSERT(thread->owner_process->ideal_processor !=
+ ASSERT(thread->owner_process->GetDefaultProcessorID() !=
static_cast<u8>(THREADPROCESSORID_DEFAULT));
// Set the target CPU to the one specified in the process' exheader.
- core = thread->owner_process->ideal_processor;
+ core = thread->owner_process->GetDefaultProcessorID();
mask = 1ull << core;
}
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index fea9ba5ea..22712e64f 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -64,6 +64,11 @@ void SvcWrap() {
FuncReturn(func(Param(0), (s32)Param(1)).raw);
}
+template <ResultCode func(u64, u32)>
+void SvcWrap() {
+ FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
+}
+
template <ResultCode func(u64*, u64)>
void SvcWrap() {
u64 param_1 = 0;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 315f65338..b5c16cfbb 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -259,11 +259,12 @@ void Thread::BoostPriority(u32 priority) {
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
Process& owner_process) {
// Setup page table so we can write to memory
- SetCurrentPageTable(&owner_process.vm_manager.page_table);
+ SetCurrentPageTable(&owner_process.VMManager().page_table);
// Initialize new "main" thread
+ const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
- Memory::STACK_AREA_VADDR_END, &owner_process);
+ stack_top, &owner_process);
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 608cbd57b..e412309fd 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -9,6 +9,7 @@
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
+#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
@@ -54,30 +55,32 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
}
VMManager::VMManager() {
- Reset();
+ // Default to assuming a 39-bit address space. This way we have a sane
+ // starting point with executables that don't provide metadata.
+ Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
}
VMManager::~VMManager() {
- Reset();
+ Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
}
-void VMManager::Reset() {
- vma_map.clear();
+void VMManager::Reset(FileSys::ProgramAddressSpaceType type) {
+ Clear();
+
+ InitializeMemoryRegionRanges(type);
+
+ page_table.Resize(address_space_width);
// Initialize the map with a single free region covering the entire managed space.
VirtualMemoryArea initial_vma;
- initial_vma.size = MAX_ADDRESS;
+ initial_vma.size = address_space_end;
vma_map.emplace(initial_vma.base, initial_vma);
- page_table.pointers.fill(nullptr);
- page_table.special_regions.clear();
- page_table.attributes.fill(Memory::PageType::Unmapped);
-
UpdatePageTableForVMA(initial_vma);
}
VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
- if (target >= MAX_ADDRESS) {
+ if (target >= address_space_end) {
return vma_map.end();
} else {
return std::prev(vma_map.upper_bound(target));
@@ -291,7 +294,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
const VAddr target_end = target + size;
ASSERT(target_end >= target);
- ASSERT(target_end <= MAX_ADDRESS);
+ ASSERT(target_end <= address_space_end);
ASSERT(size > 0);
VMAIter begin_vma = StripIterConstness(FindVMA(target));
@@ -382,6 +385,85 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
}
}
+void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) {
+ u64 map_region_size = 0;
+ u64 heap_region_size = 0;
+ u64 new_map_region_size = 0;
+ u64 tls_io_region_size = 0;
+
+ switch (type) {
+ case FileSys::ProgramAddressSpaceType::Is32Bit:
+ address_space_width = 32;
+ code_region_base = 0x200000;
+ code_region_end = code_region_base + 0x3FE00000;
+ map_region_size = 0x40000000;
+ heap_region_size = 0x40000000;
+ break;
+ case FileSys::ProgramAddressSpaceType::Is36Bit:
+ address_space_width = 36;
+ code_region_base = 0x8000000;
+ code_region_end = code_region_base + 0x78000000;
+ map_region_size = 0x180000000;
+ heap_region_size = 0x180000000;
+ break;
+ case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
+ address_space_width = 32;
+ code_region_base = 0x200000;
+ code_region_end = code_region_base + 0x3FE00000;
+ map_region_size = 0;
+ heap_region_size = 0x80000000;
+ break;
+ case FileSys::ProgramAddressSpaceType::Is39Bit:
+ address_space_width = 39;
+ code_region_base = 0x8000000;
+ code_region_end = code_region_base + 0x80000000;
+ map_region_size = 0x1000000000;
+ heap_region_size = 0x180000000;
+ new_map_region_size = 0x80000000;
+ tls_io_region_size = 0x1000000000;
+ break;
+ default:
+ UNREACHABLE_MSG("Invalid address space type specified: {}", static_cast<u32>(type));
+ return;
+ }
+
+ address_space_base = 0;
+ address_space_end = 1ULL << address_space_width;
+
+ map_region_base = code_region_end;
+ map_region_end = map_region_base + map_region_size;
+
+ heap_region_base = map_region_end;
+ heap_region_end = heap_region_base + heap_region_size;
+
+ new_map_region_base = heap_region_end;
+ new_map_region_end = new_map_region_base + new_map_region_size;
+
+ tls_io_region_base = new_map_region_end;
+ tls_io_region_end = tls_io_region_base + tls_io_region_size;
+
+ if (new_map_region_size == 0) {
+ new_map_region_base = address_space_base;
+ new_map_region_end = address_space_end;
+ }
+}
+
+void VMManager::Clear() {
+ ClearVMAMap();
+ ClearPageTable();
+}
+
+void VMManager::ClearVMAMap() {
+ vma_map.clear();
+}
+
+void VMManager::ClearPageTable() {
+ std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
+ page_table.special_regions.clear();
+ std::fill(page_table.attributes.begin(), page_table.attributes.end(),
+ Memory::PageType::Unmapped);
+}
+
u64 VMManager::GetTotalMemoryUsage() const {
LOG_WARNING(Kernel, "(STUBBED) called");
return 0xF8000000;
@@ -392,14 +474,80 @@ u64 VMManager::GetTotalHeapUsage() const {
return 0x0;
}
-VAddr VMManager::GetAddressSpaceBaseAddr() const {
- LOG_WARNING(Kernel, "(STUBBED) called");
- return 0x8000000;
+VAddr VMManager::GetAddressSpaceBaseAddress() const {
+ return address_space_base;
+}
+
+VAddr VMManager::GetAddressSpaceEndAddress() const {
+ return address_space_end;
}
u64 VMManager::GetAddressSpaceSize() const {
- LOG_WARNING(Kernel, "(STUBBED) called");
- return MAX_ADDRESS;
+ return address_space_end - address_space_base;
+}
+
+u64 VMManager::GetAddressSpaceWidth() const {
+ return address_space_width;
+}
+
+VAddr VMManager::GetCodeRegionBaseAddress() const {
+ return code_region_base;
+}
+
+VAddr VMManager::GetCodeRegionEndAddress() const {
+ return code_region_end;
+}
+
+u64 VMManager::GetCodeRegionSize() const {
+ return code_region_end - code_region_base;
+}
+
+VAddr VMManager::GetHeapRegionBaseAddress() const {
+ return heap_region_base;
+}
+
+VAddr VMManager::GetHeapRegionEndAddress() const {
+ return heap_region_end;
+}
+
+u64 VMManager::GetHeapRegionSize() const {
+ return heap_region_end - heap_region_base;
+}
+
+VAddr VMManager::GetMapRegionBaseAddress() const {
+ return map_region_base;
+}
+
+VAddr VMManager::GetMapRegionEndAddress() const {
+ return map_region_end;
+}
+
+u64 VMManager::GetMapRegionSize() const {
+ return map_region_end - map_region_base;
+}
+
+VAddr VMManager::GetNewMapRegionBaseAddress() const {
+ return new_map_region_base;
+}
+
+VAddr VMManager::GetNewMapRegionEndAddress() const {
+ return new_map_region_end;
+}
+
+u64 VMManager::GetNewMapRegionSize() const {
+ return new_map_region_end - new_map_region_base;
+}
+
+VAddr VMManager::GetTLSIORegionBaseAddress() const {
+ return tls_io_region_base;
+}
+
+VAddr VMManager::GetTLSIORegionEndAddress() const {
+ return tls_io_region_end;
+}
+
+u64 VMManager::GetTLSIORegionSize() const {
+ return tls_io_region_end - tls_io_region_base;
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index de75036c0..015559a64 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -12,6 +12,10 @@
#include "core/memory.h"
#include "core/memory_hook.h"
+namespace FileSys {
+enum class ProgramAddressSpaceType : u8;
+}
+
namespace Kernel {
enum class VMAType : u8 {
@@ -111,12 +115,6 @@ struct VirtualMemoryArea {
class VMManager final {
public:
/**
- * The maximum amount of address space managed by the kernel.
- * @todo This was selected arbitrarily, and should be verified for Switch OS.
- */
- static constexpr VAddr MAX_ADDRESS{0x1000000000ULL};
-
- /**
* A map covering the entirety of the managed address space, keyed by the `base` field of each
* VMA. It must always be modified by splitting or merging VMAs, so that the invariant
* `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
@@ -130,7 +128,7 @@ public:
~VMManager();
/// Clears the address space map, re-initializing with a single free area.
- void Reset();
+ void Reset(FileSys::ProgramAddressSpaceType type);
/// Finds the VMA in which the given address is included in, or `vma_map.end()`.
VMAHandle FindVMA(VAddr target) const;
@@ -195,12 +193,63 @@ public:
/// Gets the total heap usage, used by svcGetInfo
u64 GetTotalHeapUsage() const;
- /// Gets the total address space base address, used by svcGetInfo
- VAddr GetAddressSpaceBaseAddr() const;
+ /// Gets the address space base address
+ VAddr GetAddressSpaceBaseAddress() const;
- /// Gets the total address space address size, used by svcGetInfo
+ /// Gets the address space end address
+ VAddr GetAddressSpaceEndAddress() const;
+
+ /// Gets the total address space address size in bytes
u64 GetAddressSpaceSize() const;
+ /// Gets the address space width in bits.
+ u64 GetAddressSpaceWidth() const;
+
+ /// Gets the base address of the code region.
+ VAddr GetCodeRegionBaseAddress() const;
+
+ /// Gets the end address of the code region.
+ VAddr GetCodeRegionEndAddress() const;
+
+ /// Gets the total size of the code region in bytes.
+ u64 GetCodeRegionSize() const;
+
+ /// Gets the base address of the heap region.
+ VAddr GetHeapRegionBaseAddress() const;
+
+ /// Gets the end address of the heap region;
+ VAddr GetHeapRegionEndAddress() const;
+
+ /// Gets the total size of the heap region in bytes.
+ u64 GetHeapRegionSize() const;
+
+ /// Gets the base address of the map region.
+ VAddr GetMapRegionBaseAddress() const;
+
+ /// Gets the end address of the map region.
+ VAddr GetMapRegionEndAddress() const;
+
+ /// Gets the total size of the map region in bytes.
+ u64 GetMapRegionSize() const;
+
+ /// Gets the base address of the new map region.
+ VAddr GetNewMapRegionBaseAddress() const;
+
+ /// Gets the end address of the new map region.
+ VAddr GetNewMapRegionEndAddress() const;
+
+ /// Gets the total size of the new map region in bytes.
+ u64 GetNewMapRegionSize() const;
+
+ /// Gets the base address of the TLS IO region.
+ VAddr GetTLSIORegionBaseAddress() const;
+
+ /// Gets the end address of the TLS IO region.
+ VAddr GetTLSIORegionEndAddress() const;
+
+ /// Gets the total size of the TLS IO region in bytes.
+ u64 GetTLSIORegionSize() const;
+
/// Each VMManager has its own page table, which is set as the main one when the owning process
/// is scheduled.
Memory::PageTable page_table;
@@ -240,5 +289,36 @@ private:
/// Updates the pages corresponding to this VMA so they match the VMA's attributes.
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
+
+ /// Initializes memory region ranges to adhere to a given address space type.
+ void InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type);
+
+ /// Clears the underlying map and page table.
+ void Clear();
+
+ /// Clears out the VMA map, unmapping any previously mapped ranges.
+ void ClearVMAMap();
+
+ /// Clears out the page table
+ void ClearPageTable();
+
+ u32 address_space_width = 0;
+ VAddr address_space_base = 0;
+ VAddr address_space_end = 0;
+
+ VAddr code_region_base = 0;
+ VAddr code_region_end = 0;
+
+ VAddr heap_region_base = 0;
+ VAddr heap_region_end = 0;
+
+ VAddr map_region_base = 0;
+ VAddr map_region_end = 0;
+
+ VAddr new_map_region_base = 0;
+ VAddr new_map_region_end = 0;
+
+ VAddr tls_io_region_base = 0;
+ VAddr tls_io_region_end = 0;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index 0bd97133c..f4367ee28 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -69,7 +69,7 @@ private:
template <>
inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
if (object != nullptr && object->IsWaitable()) {
- return boost::static_pointer_cast<WaitObject>(std::move(object));
+ return boost::static_pointer_cast<WaitObject>(object);
}
return nullptr;
}
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 80ed4b152..6073f4ecd 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -10,6 +10,7 @@
#include "common/alignment.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
@@ -65,7 +66,7 @@ private:
void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(renderer->GetState());
+ rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
LOG_DEBUG(Service_Audio, "called");
}
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 6de7edf9e..2f15ac2a6 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -6,11 +6,11 @@
#include <cstring>
#include <ctime>
#include <fmt/time.h>
-#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
#include "common/swap.h"
+#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/fatal/fatal.h"
@@ -51,7 +51,7 @@ enum class FatalType : u32 {
};
static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
- const auto title_id = Core::CurrentProcess()->program_id;
+ const auto title_id = Core::CurrentProcess()->GetTitleID();
std::string crash_report =
fmt::format("Yuzu {}-{} crash report\n"
"Title ID: {:016x}\n"
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index f8d2127d9..8c07a05c2 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/hid/hid.h"
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index c1737defa..261ad539c 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -4,6 +4,7 @@
#include <chrono>
#include <ctime>
+#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/nim/nim.h"
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 1069d103f..4b2f758a8 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -317,9 +317,9 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
// Map backing memory for the font data
- Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
- SHARED_FONT_MEM_SIZE,
- Kernel::MemoryState::Shared);
+ Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
+ SHARED_FONT_MEM_SIZE,
+ Kernel::MemoryState::Shared);
// Create shared font memory object
auto& kernel = Core::System::GetInstance().Kernel();
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index cdf328a26..98f6e4111 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/service/sm/controller.h"
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 2ee60f1ec..bbc02abcc 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -612,7 +612,7 @@ public:
{3000, nullptr, "ListDisplayModes"},
{3001, nullptr, "ListDisplayRgbRanges"},
{3002, nullptr, "ListDisplayContentTypes"},
- {3200, nullptr, "GetDisplayMode"},
+ {3200, &ISystemDisplayService::GetDisplayMode, "GetDisplayMode"},
{3201, nullptr, "SetDisplayMode"},
{3202, nullptr, "GetDisplayUnderscan"},
{3203, nullptr, "SetDisplayUnderscan"},
@@ -663,6 +663,24 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
visibility);
}
+
+ void GetDisplayMode(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(RESULT_SUCCESS);
+
+ if (Settings::values.use_docked_mode) {
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
+ } else {
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
+ }
+
+ rb.PushRaw<float>(60.0f);
+ rb.Push<u32>(0);
+
+ LOG_DEBUG(Service_VI, "called");
+ }
};
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 2b8f78136..c1824b9c3 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -14,11 +14,9 @@
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nso.h"
-#include "core/memory.h"
namespace Loader {
@@ -88,8 +86,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua
return FileType::Error;
}
-ResultStatus AppLoader_DeconstructedRomDirectory::Load(
- Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
}
@@ -127,12 +124,16 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
metadata.Print();
const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
- if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
+ if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit ||
+ arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) {
return ResultStatus::Error32BitISA;
}
+ process.LoadFromMetadata(metadata);
+
// Load NSO modules
- VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
+ const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
+ VAddr next_load_addr = base_address;
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
const FileSys::VirtualFile module_file = dir->GetFile(module);
@@ -145,13 +146,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
}
}
- auto& kernel = Core::System::GetInstance().Kernel();
- process->program_id = metadata.GetTitleID();
- process->svc_access_mask.set();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
- metadata.GetMainThreadStackSize());
+ process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());
// Find the RomFS by searching for a ".romfs" file in this directory
const auto& files = dir->GetFiles();
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 8a0dc1b1e..d109ed2b5 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -7,7 +7,6 @@
#include <string>
#include "common/common_types.h"
#include "core/file_sys/program_metadata.h"
-#include "core/hle/kernel/object.h"
#include "core/loader/loader.h"
namespace Loader {
@@ -38,7 +37,7 @@ public:
return IdentifyType(file);
}
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 0e2af20b4..e67b49fc9 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -12,7 +12,7 @@
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/elf.h"
#include "core/memory.h"
@@ -189,7 +189,7 @@ private:
u32* sectionAddrs;
bool relocate;
- u32 entryPoint;
+ VAddr entryPoint;
public:
explicit ElfReader(void* ptr);
@@ -205,13 +205,13 @@ public:
ElfMachine GetMachine() const {
return (ElfMachine)(header->e_machine);
}
- u32 GetEntryPoint() const {
+ VAddr GetEntryPoint() const {
return entryPoint;
}
u32 GetFlags() const {
return (u32)(header->e_flags);
}
- SharedPtr<CodeSet> LoadInto(u32 vaddr);
+ SharedPtr<CodeSet> LoadInto(VAddr vaddr);
int GetNumSegments() const {
return (int)(header->e_phnum);
@@ -274,7 +274,7 @@ const char* ElfReader::GetSectionName(int section) const {
return nullptr;
}
-SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
+SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) {
LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
// Should we relocate?
@@ -289,11 +289,11 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
LOG_DEBUG(Loader, "{} segments:", header->e_phnum);
// First pass : Get the bits into RAM
- u32 base_addr = relocate ? vaddr : 0;
+ const VAddr base_addr = relocate ? vaddr : 0;
- u32 total_image_size = 0;
+ u64 total_image_size = 0;
for (unsigned int i = 0; i < header->e_phnum; ++i) {
- Elf32_Phdr* p = &segments[i];
+ const Elf32_Phdr* p = &segments[i];
if (p->p_type == PT_LOAD) {
total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
}
@@ -306,7 +306,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
for (unsigned int i = 0; i < header->e_phnum; ++i) {
- Elf32_Phdr* p = &segments[i];
+ const Elf32_Phdr* p = &segments[i];
LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
p->p_vaddr, p->p_filesz, p->p_memsz);
@@ -333,8 +333,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
continue;
}
- u32 segment_addr = base_addr + p->p_vaddr;
- u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
+ const VAddr segment_addr = base_addr + p->p_vaddr;
+ const u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
codeset_segment->offset = current_image_position;
codeset_segment->addr = segment_addr;
@@ -387,7 +387,7 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_ELF::Load(Kernel::Process& process) {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
@@ -395,19 +395,13 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
if (buffer.size() != file->GetSize())
return ResultStatus::ErrorIncorrectELFFileSize;
+ const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
ElfReader elf_reader(&buffer[0]);
- SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
+ SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address);
codeset->name = file->GetName();
- process->LoadModule(codeset, codeset->entrypoint);
- process->svc_access_mask.set();
-
- // Attach the default resource limit (APPLICATION) to the process
- auto& kernel = Core::System::GetInstance().Kernel();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
-
- process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
+ process.LoadModule(codeset, codeset->entrypoint);
+ process.Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index b8fb982d0..6af76441c 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -8,9 +8,6 @@
#include "common/common_types.h"
#include "core/loader/loader.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Loader namespace
-
namespace Loader {
/// Loads an ELF/AXF file
@@ -29,7 +26,7 @@ public:
return IdentifyType(file);
}
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
};
} // namespace Loader
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 843c4bb91..20e66109b 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -12,7 +12,6 @@
#include <boost/optional.hpp>
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
-#include "core/hle/kernel/object.h"
namespace Kernel {
struct AddressMapping;
@@ -136,7 +135,7 @@ public:
* @param process The newly created process.
* @return The status result of the operation.
*/
- virtual ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) = 0;
+ virtual ResultStatus Load(Kernel::Process& process) = 0;
/**
* Loads the system mode that this application needs.
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index 5d4380684..073fb9d2f 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -41,7 +41,7 @@ FileType AppLoader_NAX::GetFileType() {
return IdentifyTypeImpl(*nax);
}
-ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_NAX::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
}
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index 56605fe45..fc3c01876 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -33,7 +33,7 @@ public:
FileType GetFileType() override;
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 6aaffae59..7e1b0d84f 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -30,7 +30,7 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_NCA::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
}
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 10be197c4..95d9b73a1 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -6,7 +6,6 @@
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
-#include "core/hle/kernel/object.h"
#include "core/loader/loader.h"
namespace FileSys {
@@ -34,7 +33,7 @@ public:
return IdentifyType(file);
}
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index c49ec34ab..c10f826a4 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -16,7 +16,7 @@
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/nro.h"
#include "core/memory.h"
@@ -175,23 +175,19 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
return true;
}
-ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
}
// Load NRO
- static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
+ const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
- if (!LoadNro(file, base_addr)) {
+ if (!LoadNro(file, base_address)) {
return ResultStatus::ErrorLoadingNRO;
}
- auto& kernel = Core::System::GetInstance().Kernel();
- process->svc_access_mask.set();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
+ process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 96d2de305..04b46119a 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -6,7 +6,6 @@
#include <string>
#include "common/common_types.h"
-#include "core/hle/kernel/object.h"
#include "core/loader/linker.h"
#include "core/loader/loader.h"
@@ -33,7 +32,7 @@ public:
return IdentifyType(file);
}
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 78a4438c4..cbe2a3e53 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -13,7 +13,7 @@
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/nso.h"
#include "core/memory.h"
@@ -153,21 +153,17 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
return load_base + image_size;
}
-ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
}
// Load module
- LoadModule(file, Memory::PROCESS_IMAGE_VADDR);
- LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
+ const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
+ LoadModule(file, base_address);
+ LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
- auto& kernel = Core::System::GetInstance().Kernel();
- process->svc_access_mask.set();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT,
- Memory::DEFAULT_STACK_SIZE);
+ process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index aaeb1f2a9..7f142405b 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -4,9 +4,7 @@
#pragma once
-#include <string>
#include "common/common_types.h"
-#include "core/hle/kernel/object.h"
#include "core/loader/linker.h"
#include "core/loader/loader.h"
@@ -30,7 +28,7 @@ public:
static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base);
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
};
} // namespace Loader
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 291a9876d..b7ba77ef4 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -10,8 +10,6 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
-#include "core/file_sys/registered_cache.h"
-#include "core/file_sys/romfs.h"
#include "core/file_sys/submission_package.h"
#include "core/hle/kernel/process.h"
#include "core/loader/deconstructed_rom_directory.h"
@@ -62,7 +60,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-ResultStatus AppLoader_NSP::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_NSP::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
}
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 7ef810499..eac9b819a 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -35,7 +35,7 @@ public:
return IdentifyType(file);
}
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 16509229f..eda67a8c8 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -9,8 +9,6 @@
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
-#include "core/file_sys/romfs.h"
-#include "core/file_sys/submission_package.h"
#include "core/hle/kernel/process.h"
#include "core/loader/nca.h"
#include "core/loader/xci.h"
@@ -46,7 +44,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ResultStatus AppLoader_XCI::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
}
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index cc4287e17..17e47b658 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -35,7 +35,7 @@ public:
return IdentifyType(file);
}
- ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+ ResultStatus Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 316b46820..014298ed6 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <array>
#include <cstring>
#include <utility>
@@ -15,11 +14,11 @@
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/hle/lock.h"
#include "core/memory.h"
#include "core/memory_setup.h"
#include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
namespace Memory {
@@ -41,6 +40,21 @@ PageTable* GetCurrentPageTable() {
return current_page_table;
}
+PageTable::PageTable() = default;
+
+PageTable::PageTable(std::size_t address_space_width_in_bits) {
+ Resize(address_space_width_in_bits);
+}
+
+PageTable::~PageTable() = default;
+
+void PageTable::Resize(std::size_t address_space_width_in_bits) {
+ const std::size_t num_page_table_entries = 1ULL << (address_space_width_in_bits - PAGE_BITS);
+
+ pointers.resize(num_page_table_entries);
+ attributes.resize(num_page_table_entries);
+}
+
static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) {
LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
(base + size) * PAGE_SIZE);
@@ -50,7 +64,7 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa
VAddr end = base + size;
while (base != end) {
- ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at {:016X}", base);
+ ASSERT_MSG(base < page_table.pointers.size(), "out of range mapping at {:016X}", base);
page_table.attributes[base] = type;
page_table.pointers[base] = memory;
@@ -105,7 +119,7 @@ void RemoveDebugHook(PageTable& page_table, VAddr base, u64 size, MemoryHookPoin
static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
u8* direct_pointer = nullptr;
- auto& vm_manager = process.vm_manager;
+ auto& vm_manager = process.VMManager();
auto it = vm_manager.FindVMA(vaddr);
ASSERT(it != vm_manager.vma_map.end());
@@ -200,7 +214,7 @@ void Write(const VAddr vaddr, const T data) {
}
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
- auto& page_table = process.vm_manager.page_table;
+ const auto& page_table = process.VMManager().page_table;
const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
if (page_pointer)
@@ -323,7 +337,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
return;
}
- VAddr end = start + size;
+ const VAddr end = start + size;
const auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
if (start >= region_end || end <= region_start) {
@@ -333,7 +347,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
const VAddr overlap_start = std::max(start, region_start);
const VAddr overlap_end = std::min(end, region_end);
- const u64 overlap_size = overlap_end - overlap_start;
+ const VAddr overlap_size = overlap_end - overlap_start;
auto& rasterizer = system_instance.Renderer().Rasterizer();
switch (mode) {
@@ -349,8 +363,10 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
}
};
- CheckRegion(PROCESS_IMAGE_VADDR, PROCESS_IMAGE_VADDR_END);
- CheckRegion(HEAP_VADDR, HEAP_VADDR_END);
+ const auto& vm_manager = Core::CurrentProcess()->VMManager();
+
+ CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress());
+ CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress());
}
u8 Read8(const VAddr addr) {
@@ -371,7 +387,7 @@ u64 Read64(const VAddr addr) {
void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
const std::size_t size) {
- auto& page_table = process.vm_manager.page_table;
+ const auto& page_table = process.VMManager().page_table;
std::size_t remaining_size = size;
std::size_t page_index = src_addr >> PAGE_BITS;
@@ -436,7 +452,7 @@ void Write64(const VAddr addr, const u64 data) {
void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
const std::size_t size) {
- auto& page_table = process.vm_manager.page_table;
+ const auto& page_table = process.VMManager().page_table;
std::size_t remaining_size = size;
std::size_t page_index = dest_addr >> PAGE_BITS;
std::size_t page_offset = dest_addr & PAGE_MASK;
@@ -482,7 +498,7 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t
}
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
- auto& page_table = process.vm_manager.page_table;
+ const auto& page_table = process.VMManager().page_table;
std::size_t remaining_size = size;
std::size_t page_index = dest_addr >> PAGE_BITS;
std::size_t page_offset = dest_addr & PAGE_MASK;
@@ -524,7 +540,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std:
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
const std::size_t size) {
- auto& page_table = process.vm_manager.page_table;
+ const auto& page_table = process.VMManager().page_table;
std::size_t remaining_size = size;
std::size_t page_index = src_addr >> PAGE_BITS;
std::size_t page_offset = src_addr & PAGE_MASK;
diff --git a/src/core/memory.h b/src/core/memory.h
index 2a27c0251..1acf5ce8c 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -4,10 +4,10 @@
#pragma once
-#include <array>
#include <cstddef>
#include <string>
#include <tuple>
+#include <vector>
#include <boost/icl/interval_map.hpp>
#include "common/common_types.h"
#include "core/memory_hook.h"
@@ -23,10 +23,8 @@ namespace Memory {
* be mapped.
*/
constexpr std::size_t PAGE_BITS = 12;
-constexpr u64 PAGE_SIZE = 1 << PAGE_BITS;
+constexpr u64 PAGE_SIZE = 1ULL << PAGE_BITS;
constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
-constexpr std::size_t ADDRESS_SPACE_BITS = 36;
-constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS);
enum class PageType : u8 {
/// Page is unmapped and should cause an access error.
@@ -62,32 +60,39 @@ struct SpecialRegion {
* mimics the way a real CPU page table works.
*/
struct PageTable {
+ explicit PageTable();
+ explicit PageTable(std::size_t address_space_width_in_bits);
+ ~PageTable();
+
+ /**
+ * Resizes the page table to be able to accomodate enough pages within
+ * a given address space.
+ *
+ * @param address_space_width_in_bits The address size width in bits.
+ */
+ void Resize(std::size_t address_space_width_in_bits);
+
/**
- * Array of memory pointers backing each page. An entry can only be non-null if the
- * corresponding entry in the `attributes` array is of type `Memory`.
+ * Vector of memory pointers backing each page. An entry can only be non-null if the
+ * corresponding entry in the `attributes` vector is of type `Memory`.
*/
- std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers;
+ std::vector<u8*> pointers;
/**
- * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of
- * type `Special`.
+ * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is
+ * of type `Special`.
*/
boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions;
/**
- * Array of fine grained page attributes. If it is set to any value other than `Memory`, then
+ * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then
* the corresponding entry in `pointers` MUST be set to null.
*/
- std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
+ std::vector<PageType> attributes;
};
/// Virtual user-space memory regions
enum : VAddr {
- /// Where the application text, data and bss reside.
- PROCESS_IMAGE_VADDR = 0x08000000,
- PROCESS_IMAGE_MAX_SIZE = 0x08000000,
- PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
-
/// Read-only page containing kernel and system configuration values.
CONFIG_MEMORY_VADDR = 0x1FF80000,
CONFIG_MEMORY_SIZE = 0x00001000,
@@ -98,36 +103,12 @@ enum : VAddr {
SHARED_PAGE_SIZE = 0x00001000,
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
- /// Area where TLS (Thread-Local Storage) buffers are allocated.
- TLS_AREA_VADDR = 0x40000000,
+ /// TLS (Thread-Local Storage) related.
TLS_ENTRY_SIZE = 0x200,
- TLS_AREA_SIZE = 0x10000000,
- TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
/// Application stack
- STACK_AREA_VADDR = TLS_AREA_VADDR_END,
- STACK_AREA_SIZE = 0x10000000,
- STACK_AREA_VADDR_END = STACK_AREA_VADDR + STACK_AREA_SIZE,
DEFAULT_STACK_SIZE = 0x100000,
- /// Application heap
- /// Size is confirmed to be a static value on fw 3.0.0
- HEAP_VADDR = 0x108000000,
- HEAP_SIZE = 0x180000000,
- HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE,
-
- /// New map region
- /// Size is confirmed to be a static value on fw 3.0.0
- NEW_MAP_REGION_VADDR = HEAP_VADDR_END,
- NEW_MAP_REGION_SIZE = 0x80000000,
- NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE,
-
- /// Map region
- /// Size is confirmed to be a static value on fw 3.0.0
- MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END,
- MAP_REGION_SIZE = 0x1000000000,
- MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE,
-
/// Kernel Virtual Address Range
KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
KERNEL_REGION_SIZE = 0x7FFFE00000,
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 7c69fc26e..c0a57e71f 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/memory.h"
@@ -14,11 +16,12 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
- page_table = &Core::CurrentProcess()->vm_manager.page_table;
+ page_table = &Core::CurrentProcess()->VMManager().page_table;
- page_table->pointers.fill(nullptr);
+ std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
page_table->special_regions.clear();
- page_table->attributes.fill(Memory::PageType::Unmapped);
+ std::fill(page_table->attributes.begin(), page_table->attributes.end(),
+ Memory::PageType::Unmapped);
Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index b81b0723d..9f5581045 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -41,6 +41,7 @@ public:
static constexpr std::size_t NumCBData = 16;
static constexpr std::size_t NumVertexArrays = 32;
static constexpr std::size_t NumVertexAttributes = 32;
+ static constexpr std::size_t NumTextureSamplers = 32;
static constexpr std::size_t MaxShaderProgram = 6;
static constexpr std::size_t MaxShaderStage = 5;
// Maximum number of const buffers per shader stage.
@@ -461,7 +462,11 @@ public:
u32 entry;
} macros;
- INSERT_PADDING_WORDS(0x1B8);
+ INSERT_PADDING_WORDS(0x189);
+
+ u32 tfb_enabled;
+
+ INSERT_PADDING_WORDS(0x2E);
RenderTargetConfig rt[NumRenderTargets];
@@ -594,7 +599,9 @@ public:
u32 depth_write_enabled;
- INSERT_PADDING_WORDS(0x7);
+ u32 alpha_test_enabled;
+
+ INSERT_PADDING_WORDS(0x6);
u32 d3d_cull_mode;
@@ -635,7 +642,11 @@ public:
u32 vb_element_base;
- INSERT_PADDING_WORDS(0x40);
+ INSERT_PADDING_WORDS(0x38);
+
+ float point_size;
+
+ INSERT_PADDING_WORDS(0x7);
u32 zeta_enable;
@@ -977,6 +988,7 @@ private:
"Field " #field_name " has invalid position")
ASSERT_REG_POSITION(macros, 0x45);
+ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
ASSERT_REG_POSITION(rt, 0x200);
ASSERT_REG_POSITION(viewport_transform[0], 0x280);
ASSERT_REG_POSITION(viewport, 0x300);
@@ -996,6 +1008,7 @@ ASSERT_REG_POSITION(zeta_height, 0x48b);
ASSERT_REG_POSITION(depth_test_enable, 0x4B3);
ASSERT_REG_POSITION(independent_blend_enable, 0x4B9);
ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
+ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
ASSERT_REG_POSITION(depth_test_func, 0x4C3);
ASSERT_REG_POSITION(blend, 0x4CF);
@@ -1009,6 +1022,7 @@ ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
+ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp
index e4e5f9e5e..59e28b22d 100644
--- a/src/video_core/engines/maxwell_compute.cpp
+++ b/src/video_core/engines/maxwell_compute.cpp
@@ -2,12 +2,29 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/core.h"
#include "video_core/engines/maxwell_compute.h"
namespace Tegra {
namespace Engines {
-void MaxwellCompute::WriteReg(u32 method, u32 value) {}
+void MaxwellCompute::WriteReg(u32 method, u32 value) {
+ ASSERT_MSG(method < Regs::NUM_REGS,
+ "Invalid MaxwellCompute register, increase the size of the Regs structure");
+
+ regs.reg_array[method] = value;
+
+ switch (method) {
+ case MAXWELL_COMPUTE_REG_INDEX(compute): {
+ LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented");
+ UNREACHABLE();
+ break;
+ }
+ default:
+ break;
+ }
+}
} // namespace Engines
} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_compute.h b/src/video_core/engines/maxwell_compute.h
index 2b3e4ced6..6ea934fb9 100644
--- a/src/video_core/engines/maxwell_compute.h
+++ b/src/video_core/engines/maxwell_compute.h
@@ -4,17 +4,53 @@
#pragma once
+#include <array>
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Tegra::Engines {
+#define MAXWELL_COMPUTE_REG_INDEX(field_name) \
+ (offsetof(Tegra::Engines::MaxwellCompute::Regs, field_name) / sizeof(u32))
+
class MaxwellCompute final {
public:
MaxwellCompute() = default;
~MaxwellCompute() = default;
+ struct Regs {
+ static constexpr std::size_t NUM_REGS = 0xCF8;
+
+ union {
+ struct {
+ INSERT_PADDING_WORDS(0x281);
+
+ union {
+ u32 compute_end;
+ BitField<0, 1, u32> unknown;
+ } compute;
+
+ INSERT_PADDING_WORDS(0xA76);
+ };
+ std::array<u32, NUM_REGS> reg_array;
+ };
+ } regs{};
+
+ static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
+ "MaxwellCompute Regs has wrong size");
+
/// Write the value to the register identified by method.
void WriteReg(u32 method, u32 value);
};
+#define ASSERT_REG_POSITION(field_name, position) \
+ static_assert(offsetof(MaxwellCompute::Regs, field_name) == position * 4, \
+ "Field " #field_name " has invalid position")
+
+ASSERT_REG_POSITION(compute, 0x281);
+
+#undef ASSERT_REG_POSITION
+
} // namespace Tegra::Engines
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 70fb54507..1fcd13f04 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -450,6 +450,9 @@ void RasterizerOpenGL::DrawArrays() {
SyncBlendState();
SyncLogicOpState();
SyncCullMode();
+ SyncAlphaTest();
+ SyncTransformFeedback();
+ SyncPointState();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@@ -883,4 +886,30 @@ void RasterizerOpenGL::SyncLogicOpState() {
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
}
+void RasterizerOpenGL::SyncAlphaTest() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+
+ // TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be
+ // implemented with a test+discard in fragment shaders.
+ if (regs.alpha_test_enabled != 0) {
+ LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented");
+ UNREACHABLE();
+ }
+}
+
+void RasterizerOpenGL::SyncTransformFeedback() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+
+ if (regs.tfb_enabled != 0) {
+ LOG_CRITICAL(Render_OpenGL, "Transform feedbacks are not implemented");
+ UNREACHABLE();
+ }
+}
+
+void RasterizerOpenGL::SyncPointState() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+
+ state.point.size = regs.point_size;
+}
+
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index bf9560bdc..4c8ecbd1c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -158,6 +158,15 @@ private:
/// Syncs the LogicOp state to match the guest state
void SyncLogicOpState();
+ /// Syncs the alpha test state to match the guest state
+ void SyncAlphaTest();
+
+ /// Syncs the transform feedback state to match the guest state
+ void SyncTransformFeedback();
+
+ /// Syncs the point state to match the guest state
+ void SyncPointState();
+
bool has_ARB_direct_state_access = false;
bool has_ARB_multi_bind = false;
bool has_ARB_separate_shader_objects = false;
@@ -178,7 +187,7 @@ private:
OGLVertexArray>
vertex_array_cache;
- std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
+ std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers;
static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
OGLBufferCache buffer_cache;
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index b86cd96e8..3de15ba9b 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -11,9 +11,6 @@
namespace OpenGL::GLShader {
-/// Number of OpenGL texture samplers that can be used in the fragment shader
-static constexpr std::size_t NumTextureSamplers = 32;
-
using Tegra::Engines::Maxwell3D;
/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index e5173e20a..1fe26a2a9 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -79,6 +79,8 @@ OpenGLState::OpenGLState() {
viewport.height = 0;
clip_distance = {};
+
+ point.size = 1;
}
void OpenGLState::Apply() const {
@@ -205,9 +207,6 @@ void OpenGLState::Apply() const {
glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
glBindTexture(texture_unit.target, texture_unit.texture);
}
- if (texture_unit.sampler != cur_state_texture_unit.sampler) {
- glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
- }
// Update the texture swizzle
if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r ||
texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g ||
@@ -219,6 +218,27 @@ void OpenGLState::Apply() const {
}
}
+ // Samplers
+ {
+ bool has_delta{};
+ std::size_t first{}, last{};
+ std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
+ for (std::size_t i = 0; i < std::size(samplers); ++i) {
+ samplers[i] = texture_units[i].sampler;
+ if (samplers[i] != cur_state.texture_units[i].sampler) {
+ if (!has_delta) {
+ first = i;
+ has_delta = true;
+ }
+ last = i;
+ }
+ }
+ if (has_delta) {
+ glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
+ samplers.data());
+ }
+ }
+
// Framebuffer
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
@@ -283,6 +303,11 @@ void OpenGLState::Apply() const {
}
}
+ // Point
+ if (point.size != cur_state.point.size) {
+ glPointSize(point.size);
+ }
+
cur_state = *this;
}
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 9a93029d8..dc21a2ee3 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -6,6 +6,7 @@
#include <array>
#include <glad/glad.h>
+#include "video_core/engines/maxwell_3d.h"
namespace OpenGL {
@@ -114,7 +115,7 @@ public:
target = GL_TEXTURE_2D;
}
};
- std::array<TextureUnit, 32> texture_units;
+ std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
struct {
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
@@ -141,6 +142,10 @@ public:
GLsizei height;
} viewport;
+ struct {
+ float size; // GL_POINT_SIZE
+ } point;
+
std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE
OpenGLState();
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 20ba6d4f6..3d5476e5d 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -13,47 +13,20 @@
namespace Tegra::Texture {
/**
+ * This table represents the internal swizzle of a gob,
+ * in format 16 bytes x 2 sector packing.
* Calculates the offset of an (x, y) position within a swizzled texture.
- * Taken from the Tegra X1 TRM.
+ * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
*/
-static u32 GetSwizzleOffset(u32 x, u32 y, u32 image_width, u32 bytes_per_pixel, u32 block_height) {
- // Round up to the next gob
- const u32 image_width_in_gobs{(image_width * bytes_per_pixel + 63) / 64};
-
- u32 GOB_address = 0 + (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs +
- (x * bytes_per_pixel / 64) * 512 * block_height +
- (y % (8 * block_height) / 8) * 512;
- x *= bytes_per_pixel;
- u32 address = GOB_address + ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
- (y % 2) * 16 + (x % 16);
-
- return address;
-}
-
-void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
- u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) {
- u8* data_ptrs[2];
- for (unsigned y = 0; y < height; ++y) {
- for (unsigned x = 0; x < width; ++x) {
- u32 swizzle_offset = GetSwizzleOffset(x, y, width, bytes_per_pixel, block_height);
- u32 pixel_index = (x + y * width) * out_bytes_per_pixel;
-
- data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
- data_ptrs[!unswizzle] = &unswizzled_data[pixel_index];
-
- std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
- }
- }
-}
-
-template <std::size_t N, std::size_t M>
+template <std::size_t N, std::size_t M, u32 Align>
struct alignas(64) SwizzleTable {
+ static_assert(M * Align == 64, "Swizzle Table does not align to GOB");
constexpr SwizzleTable() {
for (u32 y = 0; y < N; ++y) {
for (u32 x = 0; x < M; ++x) {
- const u32 x2 = x * 16;
+ const u32 x2 = x * Align;
values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 +
- ((x2 % 32) / 16) * 32 + (y % 2) * 16);
+ ((x2 % 32) / 16) * 32 + (y % 2) * 16 + (x2 % 16));
}
}
}
@@ -63,24 +36,60 @@ struct alignas(64) SwizzleTable {
std::array<std::array<u16, M>, N> values{};
};
-constexpr auto swizzle_table = SwizzleTable<8, 4>();
+constexpr auto legacy_swizzle_table = SwizzleTable<8, 64, 1>();
+constexpr auto fast_swizzle_table = SwizzleTable<8, 4, 16>();
-void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_data,
- u8* unswizzled_data, bool unswizzle, u32 block_height) {
+static void LegacySwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
+ u8* swizzled_data, u8* unswizzled_data, bool unswizzle,
+ u32 block_height) {
+ std::array<u8*, 2> data_ptrs;
+ const std::size_t stride = width * bytes_per_pixel;
+ const std::size_t gobs_in_x = 64;
+ const std::size_t gobs_in_y = 8;
+ const std::size_t gobs_size = gobs_in_x * gobs_in_y;
+ const std::size_t image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x};
+ for (std::size_t y = 0; y < height; ++y) {
+ const std::size_t gob_y_address =
+ (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs +
+ (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size;
+ const auto& table = legacy_swizzle_table[y % gobs_in_y];
+ for (std::size_t x = 0; x < width; ++x) {
+ const std::size_t gob_address =
+ gob_y_address + (x * bytes_per_pixel / gobs_in_x) * gobs_size * block_height;
+ const std::size_t x2 = x * bytes_per_pixel;
+ const std::size_t swizzle_offset = gob_address + table[x2 % gobs_in_x];
+ const std::size_t pixel_index = (x + y * width) * out_bytes_per_pixel;
+
+ data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
+ data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
+
+ std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
+ }
+ }
+}
+
+static void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
+ u8* swizzled_data, u8* unswizzled_data, bool unswizzle,
+ u32 block_height) {
std::array<u8*, 2> data_ptrs;
const std::size_t stride{width * bytes_per_pixel};
- const std::size_t image_width_in_gobs{(stride + 63) / 64};
+ const std::size_t gobs_in_x = 64;
+ const std::size_t gobs_in_y = 8;
+ const std::size_t gobs_size = gobs_in_x * gobs_in_y;
+ const std::size_t image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x};
const std::size_t copy_size{16};
for (std::size_t y = 0; y < height; ++y) {
const std::size_t initial_gob =
- (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs +
- (y % (8 * block_height) / 8) * 512;
- const std::size_t pixel_base{y * width * bytes_per_pixel};
- const auto& table = swizzle_table[y % 8];
+ (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs +
+ (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size;
+ const std::size_t pixel_base{y * width * out_bytes_per_pixel};
+ const auto& table = fast_swizzle_table[y % gobs_in_y];
for (std::size_t xb = 0; xb < stride; xb += copy_size) {
- const std::size_t gob_address{initial_gob + (xb / 64) * 512 * block_height};
+ const std::size_t gob_address{initial_gob +
+ (xb / gobs_in_x) * gobs_size * block_height};
const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]};
- const std::size_t pixel_index{xb + pixel_base};
+ const std::size_t out_x = xb * out_bytes_per_pixel / bytes_per_pixel;
+ const std::size_t pixel_index{out_x + pixel_base};
data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
std::memcpy(data_ptrs[0], data_ptrs[1], copy_size);
@@ -88,6 +97,17 @@ void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_da
}
}
+void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
+ u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) {
+ if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) {
+ FastSwizzleData(width, height, bytes_per_pixel, out_bytes_per_pixel, swizzled_data,
+ unswizzled_data, unswizzle, block_height);
+ } else {
+ LegacySwizzleData(width, height, bytes_per_pixel, out_bytes_per_pixel, swizzled_data,
+ unswizzled_data, unswizzle, block_height);
+ }
+}
+
u32 BytesPerPixel(TextureFormat format) {
switch (format) {
case TextureFormat::DXT1:
@@ -134,13 +154,8 @@ u32 BytesPerPixel(TextureFormat format) {
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
u32 height, u32 block_height) {
std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
- if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) {
- FastSwizzleData(width / tile_size, height / tile_size, bytes_per_pixel,
- Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
- } else {
- CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
- Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
- }
+ CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
+ Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
return unswizzled_data;
}
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 991ae10cd..67890455a 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -26,10 +26,10 @@
#include "yuzu/main.h"
#include "yuzu/ui_settings.h"
-GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
+GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
// EventFilter in order to process systemkeys while editing the searchfield
-bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
+bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
// If it isn't a KeyRelease event then continue with standard event processing
if (event->type() != QEvent::KeyRelease)
return QObject::eventFilter(obj, event);
@@ -88,21 +88,21 @@ bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* e
return QObject::eventFilter(obj, event);
}
-void GameList::SearchField::setFilterResult(int visible, int total) {
+void GameListSearchField::setFilterResult(int visible, int total) {
label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
}
-void GameList::SearchField::clear() {
+void GameListSearchField::clear() {
edit_filter->setText("");
}
-void GameList::SearchField::setFocus() {
+void GameListSearchField::setFocus() {
if (edit_filter->isVisible()) {
edit_filter->setFocus();
}
}
-GameList::SearchField::SearchField(GameList* parent) : QWidget{parent} {
+GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent);
layout_filter = new QHBoxLayout;
layout_filter->setMargin(8);
@@ -202,7 +202,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent)
this->main_window = parent;
layout = new QVBoxLayout;
tree_view = new QTreeView;
- search_field = new SearchField(this);
+ search_field = new GameListSearchField(this);
item_model = new QStandardItemModel(tree_view);
tree_view->setModel(item_model);
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 3bf51870e..05e115e19 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -22,6 +22,7 @@
#include "yuzu/compatibility_list.h"
class GameListWorker;
+class GameListSearchField;
class GMainWindow;
namespace FileSys {
@@ -46,33 +47,6 @@ public:
COLUMN_COUNT, // Number of columns
};
- class SearchField : public QWidget {
- public:
- void setFilterResult(int visible, int total);
- void clear();
- void setFocus();
- explicit SearchField(GameList* parent = nullptr);
-
- private:
- class KeyReleaseEater : public QObject {
- public:
- explicit KeyReleaseEater(GameList* gamelist);
-
- private:
- GameList* gamelist = nullptr;
- QString edit_filter_text_old;
-
- protected:
- bool eventFilter(QObject* obj, QEvent* event) override;
- };
- QHBoxLayout* layout_filter = nullptr;
- QTreeView* tree_view = nullptr;
- QLabel* label_filter = nullptr;
- QLineEdit* edit_filter = nullptr;
- QLabel* label_filter_result = nullptr;
- QToolButton* button_filter_close = nullptr;
- };
-
explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, GMainWindow* parent = nullptr);
~GameList() override;
@@ -110,7 +84,7 @@ private:
void RefreshGameDirectory();
std::shared_ptr<FileSys::VfsFilesystem> vfs;
- SearchField* search_field;
+ GameListSearchField* search_field;
GMainWindow* main_window = nullptr;
QVBoxLayout* layout = nullptr;
QTreeView* tree_view = nullptr;
@@ -118,6 +92,8 @@ private:
GameListWorker* current_worker = nullptr;
QFileSystemWatcher* watcher = nullptr;
CompatibilityList compatibility_list;
+
+ friend class GameListSearchField;
};
Q_DECLARE_METATYPE(GameListOpenTarget);
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index cee109730..3db0e90da 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -16,6 +16,7 @@
#include <QObject>
#include <QStandardItem>
#include <QString>
+#include <QWidget>
#include "common/common_types.h"
#include "common/logging/log.h"
@@ -176,3 +177,42 @@ public:
return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong();
}
};
+
+class GameList;
+class QHBoxLayout;
+class QTreeView;
+class QLabel;
+class QLineEdit;
+class QToolButton;
+
+class GameListSearchField : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit GameListSearchField(GameList* parent = nullptr);
+
+ void setFilterResult(int visible, int total);
+
+ void clear();
+ void setFocus();
+
+private:
+ class KeyReleaseEater : public QObject {
+ public:
+ explicit KeyReleaseEater(GameList* gamelist);
+
+ private:
+ GameList* gamelist = nullptr;
+ QString edit_filter_text_old;
+
+ protected:
+ // EventFilter in order to process systemkeys while editing the searchfield
+ bool eventFilter(QObject* obj, QEvent* event) override;
+ };
+ QHBoxLayout* layout_filter = nullptr;
+ QTreeView* tree_view = nullptr;
+ QLabel* label_filter = nullptr;
+ QLineEdit* edit_filter = nullptr;
+ QLabel* label_filter_result = nullptr;
+ QToolButton* button_filter_close = nullptr;
+};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index cb37796fa..27015d02c 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -622,9 +622,9 @@ void GMainWindow::BootGame(const QString& filename) {
std::string title_name;
const auto res = Core::System::GetInstance().GetGameName(title_name);
if (res != Loader::ResultStatus::Success) {
- const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id;
+ const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
- const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata();
+ const auto [nacp, icon_file] = FileSys::PatchManager(title_id).GetControlMetadata();
if (nacp != nullptr)
title_name = nacp->GetApplicationName();
@@ -756,11 +756,51 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
}
+static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) {
+ std::size_t out = 0;
+
+ for (const auto& subdir : dir->GetSubdirectories()) {
+ out += 1 + CalculateRomFSEntrySize(subdir, full);
+ }
+
+ return out + (full ? dir->GetFiles().size() : 0);
+}
+
+static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src,
+ const FileSys::VirtualDir& dest, std::size_t block_size, bool full) {
+ if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
+ return false;
+ if (dialog.wasCanceled())
+ return false;
+
+ if (full) {
+ for (const auto& file : src->GetFiles()) {
+ const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
+ if (!FileSys::VfsRawCopy(file, out, block_size))
+ return false;
+ dialog.setValue(dialog.value() + 1);
+ if (dialog.wasCanceled())
+ return false;
+ }
+ }
+
+ for (const auto& dir : src->GetSubdirectories()) {
+ const auto out = dest->CreateSubdirectory(dir->GetName());
+ if (!RomFSRawCopy(dialog, dir, out, block_size, full))
+ return false;
+ dialog.setValue(dialog.value() + 1);
+ if (dialog.wasCanceled())
+ return false;
+ }
+
+ return true;
+}
+
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
const auto path = fmt::format("{}{:016X}/romfs",
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id);
- auto failed = [this, &path]() {
+ const auto failed = [this, &path] {
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
tr("There was an error copying the RomFS files or the user "
"cancelled the operation."));
@@ -808,53 +848,13 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
failed();
const auto full = res == "Full";
-
- const static std::function<size_t(const FileSys::VirtualDir&, bool)> calculate_entry_size =
- [](const FileSys::VirtualDir& dir, bool full) {
- size_t out = 0;
- for (const auto& subdir : dir->GetSubdirectories())
- out += 1 + calculate_entry_size(subdir, full);
- return out + full ? dir->GetFiles().size() : 0;
- };
- const auto entry_size = calculate_entry_size(extracted, full);
+ const auto entry_size = CalculateRomFSEntrySize(extracted, full);
QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
- const static std::function<bool(QProgressDialog&, const FileSys::VirtualDir&,
- const FileSys::VirtualDir&, size_t, bool)>
- qt_raw_copy = [](QProgressDialog& dialog, const FileSys::VirtualDir& src,
- const FileSys::VirtualDir& dest, size_t block_size, bool full) {
- if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
- return false;
- if (dialog.wasCanceled())
- return false;
-
- if (full) {
- for (const auto& file : src->GetFiles()) {
- const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
- if (!FileSys::VfsRawCopy(file, out, block_size))
- return false;
- dialog.setValue(dialog.value() + 1);
- if (dialog.wasCanceled())
- return false;
- }
- }
-
- for (const auto& dir : src->GetSubdirectories()) {
- const auto out = dest->CreateSubdirectory(dir->GetName());
- if (!qt_raw_copy(dialog, dir, out, block_size, full))
- return false;
- dialog.setValue(dialog.value() + 1);
- if (dialog.wasCanceled())
- return false;
- }
-
- return true;
- };
-
- if (qt_raw_copy(progress, extracted, out, 0x400000, full)) {
+ if (RomFSRawCopy(progress, extracted, out, 0x400000, full)) {
progress.close();
QMessageBox::information(this, tr("RomFS Extraction Succeeded!"),
tr("The operation completed successfully."));
@@ -931,7 +931,7 @@ void GMainWindow::OnMenuInstallToNAND() {
}
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
- const FileSys::VirtualFile& dest, size_t block_size) {
+ const FileSys::VirtualFile& dest, std::size_t block_size) {
if (src == nullptr || dest == nullptr)
return false;
if (!dest->Resize(src->GetSize()))