Merge pull request #3169 from lioncash/memory

core/memory: Deglobalize memory management code
This commit is contained in:
bunnei 2019-11-28 11:43:17 -05:00 committed by GitHub
commit e3ee017e91
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 1386 additions and 793 deletions

View file

@ -36,9 +36,9 @@ public:
}
void SetWaveIndex(std::size_t index);
std::vector<s16> DequeueSamples(std::size_t sample_count);
std::vector<s16> DequeueSamples(std::size_t sample_count, Memory::Memory& memory);
void UpdateState();
void RefreshBuffer();
void RefreshBuffer(Memory::Memory& memory);
private:
bool is_in_use{};
@ -66,17 +66,18 @@ public:
return info;
}
void UpdateState();
void UpdateState(Memory::Memory& memory);
private:
EffectOutStatus out_status{};
EffectInStatus info{};
};
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params,
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Memory::Memory& memory_,
AudioRendererParameter params,
std::shared_ptr<Kernel::WritableEvent> buffer_event,
std::size_t instance_number)
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
effects(params.effect_count) {
effects(params.effect_count), memory{memory_} {
audio_out = std::make_unique<AudioCore::AudioOut>();
stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
@ -162,7 +163,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
}
for (auto& effect : effects) {
effect.UpdateState();
effect.UpdateState(memory);
}
// Release previous buffers and queue next ones for playback
@ -206,13 +207,14 @@ void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
is_refresh_pending = true;
}
std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count) {
std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count,
Memory::Memory& memory) {
if (!IsPlaying()) {
return {};
}
if (is_refresh_pending) {
RefreshBuffer();
RefreshBuffer(memory);
}
const std::size_t max_size{samples.size() - offset};
@ -256,10 +258,11 @@ void AudioRenderer::VoiceState::UpdateState() {
is_in_use = info.is_in_use;
}
void AudioRenderer::VoiceState::RefreshBuffer() {
std::vector<s16> new_samples(info.wave_buffer[wave_index].buffer_sz / sizeof(s16));
Memory::ReadBlock(info.wave_buffer[wave_index].buffer_addr, new_samples.data(),
info.wave_buffer[wave_index].buffer_sz);
void AudioRenderer::VoiceState::RefreshBuffer(Memory::Memory& memory) {
const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr;
const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz;
std::vector<s16> new_samples(wave_buffer_size / sizeof(s16));
memory.ReadBlock(wave_buffer_address, new_samples.data(), wave_buffer_size);
switch (static_cast<Codec::PcmFormat>(info.sample_format)) {
case Codec::PcmFormat::Int16: {
@ -269,7 +272,7 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
case Codec::PcmFormat::Adpcm: {
// Decode ADPCM to PCM16
Codec::ADPCM_Coeff coeffs;
Memory::ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff));
memory.ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff));
new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()),
new_samples.size() * sizeof(s16), coeffs, adpcm_state);
break;
@ -307,18 +310,18 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
is_refresh_pending = false;
}
void AudioRenderer::EffectState::UpdateState() {
void AudioRenderer::EffectState::UpdateState(Memory::Memory& memory) {
if (info.is_new) {
out_status.state = EffectStatus::New;
} else {
if (info.type == Effect::Aux) {
ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0,
ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_info) == 0,
"Aux buffers tried to update");
ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0,
ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_info) == 0,
"Aux buffers tried to update");
ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0,
ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_base) == 0,
"Aux buffers tried to update");
ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0,
ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_base) == 0,
"Aux buffers tried to update");
}
}
@ -340,7 +343,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
std::size_t offset{};
s64 samples_remaining{BUFFER_SIZE};
while (samples_remaining > 0) {
const std::vector<s16> samples{voice.DequeueSamples(samples_remaining)};
const std::vector<s16> samples{voice.DequeueSamples(samples_remaining, memory)};
if (samples.empty()) {
break;

View file

@ -22,6 +22,10 @@ namespace Kernel {
class WritableEvent;
}
namespace Memory {
class Memory;
}
namespace AudioCore {
class AudioOut;
@ -217,7 +221,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
class AudioRenderer {
public:
AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params,
AudioRenderer(Core::Timing::CoreTiming& core_timing, Memory::Memory& memory_,
AudioRendererParameter params,
std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
~AudioRenderer();
@ -238,7 +243,8 @@ private:
std::vector<VoiceState> voices;
std::vector<EffectState> effects;
std::unique_ptr<AudioOut> audio_out;
AudioCore::StreamPtr stream;
StreamPtr stream;
Memory::Memory& memory;
};
} // namespace AudioCore

View file

@ -509,7 +509,6 @@ add_library(core STATIC
memory/dmnt_cheat_vm.h
memory.cpp
memory.h
memory_setup.h
perf_stats.cpp
perf_stats.h
reporter.cpp

View file

@ -13,7 +13,6 @@
#include "core/memory.h"
namespace Core {
namespace {
constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
@ -61,15 +60,15 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size.");
using Symbols = std::vector<std::pair<ELFSymbol, std::string>>;
Symbols GetSymbols(VAddr text_offset) {
const auto mod_offset = text_offset + Memory::Read32(text_offset + 4);
Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) {
const auto mod_offset = text_offset + memory.Read32(text_offset + 4);
if (mod_offset < text_offset || (mod_offset & 0b11) != 0 ||
Memory::Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
return {};
}
const auto dynamic_offset = Memory::Read32(mod_offset + 0x4) + mod_offset;
const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset;
VAddr string_table_offset{};
VAddr symbol_table_offset{};
@ -77,8 +76,8 @@ Symbols GetSymbols(VAddr text_offset) {
VAddr dynamic_index = dynamic_offset;
while (true) {
const auto tag = Memory::Read64(dynamic_index);
const auto value = Memory::Read64(dynamic_index + 0x8);
const u64 tag = memory.Read64(dynamic_index);
const u64 value = memory.Read64(dynamic_index + 0x8);
dynamic_index += 0x10;
if (tag == ELF_DYNAMIC_TAG_NULL) {
@ -106,11 +105,11 @@ Symbols GetSymbols(VAddr text_offset) {
VAddr symbol_index = symbol_table_address;
while (symbol_index < string_table_address) {
ELFSymbol symbol{};
Memory::ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
VAddr string_offset = string_table_address + symbol.name_index;
std::string name;
for (u8 c = Memory::Read8(string_offset); c != 0; c = Memory::Read8(++string_offset)) {
for (u8 c = memory.Read8(string_offset); c != 0; c = memory.Read8(++string_offset)) {
name += static_cast<char>(c);
}
@ -142,28 +141,28 @@ constexpr u64 SEGMENT_BASE = 0x7100000000ull;
std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
std::vector<BacktraceEntry> out;
auto& memory = system.Memory();
auto fp = GetReg(29);
auto lr = GetReg(30);
while (true) {
out.push_back({"", 0, lr, 0});
if (!fp) {
break;
}
lr = Memory::Read64(fp + 8) - 4;
fp = Memory::Read64(fp);
lr = memory.Read64(fp + 8) - 4;
fp = memory.Read64(fp);
}
std::map<VAddr, std::string> modules;
auto& loader{System::GetInstance().GetAppLoader()};
auto& loader{system.GetAppLoader()};
if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) {
return {};
}
std::map<std::string, Symbols> symbols;
for (const auto& module : modules) {
symbols.insert_or_assign(module.second, GetSymbols(module.first));
symbols.insert_or_assign(module.second, GetSymbols(module.first, memory));
}
for (auto& entry : out) {

View file

@ -17,11 +17,13 @@ enum class VMAPermission : u8;
}
namespace Core {
class System;
/// Generic ARMv8 CPU interface
class ARM_Interface : NonCopyable {
public:
virtual ~ARM_Interface() {}
explicit ARM_Interface(System& system_) : system{system_} {}
virtual ~ARM_Interface() = default;
struct ThreadContext {
std::array<u64, 31> cpu_registers;
@ -163,6 +165,10 @@ public:
/// fp+0 : pointer to previous frame record
/// fp+8 : value of lr for frame
void LogBacktrace() const;
protected:
/// System context that this ARM interface is running under.
System& system;
};
} // namespace Core

View file

@ -28,36 +28,38 @@ public:
explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
u8 MemoryRead8(u64 vaddr) override {
return Memory::Read8(vaddr);
return parent.system.Memory().Read8(vaddr);
}
u16 MemoryRead16(u64 vaddr) override {
return Memory::Read16(vaddr);
return parent.system.Memory().Read16(vaddr);
}
u32 MemoryRead32(u64 vaddr) override {
return Memory::Read32(vaddr);
return parent.system.Memory().Read32(vaddr);
}
u64 MemoryRead64(u64 vaddr) override {
return Memory::Read64(vaddr);
return parent.system.Memory().Read64(vaddr);
}
Vector MemoryRead128(u64 vaddr) override {
return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)};
auto& memory = parent.system.Memory();
return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};
}
void MemoryWrite8(u64 vaddr, u8 value) override {
Memory::Write8(vaddr, value);
parent.system.Memory().Write8(vaddr, value);
}
void MemoryWrite16(u64 vaddr, u16 value) override {
Memory::Write16(vaddr, value);
parent.system.Memory().Write16(vaddr, value);
}
void MemoryWrite32(u64 vaddr, u32 value) override {
Memory::Write32(vaddr, value);
parent.system.Memory().Write32(vaddr, value);
}
void MemoryWrite64(u64 vaddr, u64 value) override {
Memory::Write64(vaddr, value);
parent.system.Memory().Write64(vaddr, value);
}
void MemoryWrite128(u64 vaddr, Vector value) override {
Memory::Write64(vaddr, value[0]);
Memory::Write64(vaddr + 8, value[1]);
auto& memory = parent.system.Memory();
memory.Write64(vaddr, value[0]);
memory.Write64(vaddr + 8, value[1]);
}
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
@ -171,9 +173,10 @@ void ARM_Dynarmic::Step() {
ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index)
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
core_index{core_index}, system{system},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
: ARM_Interface{system},
cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
core_index{core_index}, exclusive_monitor{
dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Dynarmic::~ARM_Dynarmic() = default;
@ -264,7 +267,9 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
jit = MakeJit(page_table, new_address_space_size_in_bits);
}
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count)
: monitor(core_count), memory{memory_} {}
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) {
@ -277,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() {
}
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 1,
[&] { Memory::Write8(vaddr, value); });
return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 2,
[&] { Memory::Write16(vaddr, value); });
[&] { memory.Write16(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 4,
[&] { Memory::Write32(vaddr, value); });
[&] { memory.Write32(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 8,
[&] { Memory::Write64(vaddr, value); });
[&] { memory.Write64(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
Memory::Write64(vaddr + 0, value[0]);
Memory::Write64(vaddr + 8, value[1]);
memory.Write64(vaddr + 0, value[0]);
memory.Write64(vaddr + 8, value[1]);
});
}

View file

@ -12,6 +12,10 @@
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
namespace Memory {
class Memory;
}
namespace Core {
class ARM_Dynarmic_Callbacks;
@ -58,13 +62,12 @@ private:
ARM_Unicorn inner_unicorn;
std::size_t core_index;
System& system;
DynarmicExclusiveMonitor& exclusive_monitor;
};
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public:
explicit DynarmicExclusiveMonitor(std::size_t core_count);
explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count);
~DynarmicExclusiveMonitor() override;
void SetExclusive(std::size_t core_index, VAddr addr) override;
@ -79,6 +82,7 @@ public:
private:
friend class ARM_Dynarmic;
Dynarmic::A64::ExclusiveMonitor monitor;
Memory::Memory& memory;
};
} // namespace Core

View file

@ -60,7 +60,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
return false;
}
ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
ARM_Unicorn::ARM_Unicorn(System& system) : ARM_Interface{system} {
CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
auto fpv = 3 << 20;

View file

@ -45,7 +45,6 @@ private:
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
uc_engine* uc{};
System& system;
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit = false;
};

View file

@ -39,6 +39,7 @@
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
#include "core/memory.h"
#include "core/memory/cheat_engine.h"
#include "core/perf_stats.h"
#include "core/reporter.h"
@ -112,8 +113,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
}
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, cpu_core_manager{system}, reporter{system},
applet_manager{system} {}
: kernel{system}, fs_controller{system}, memory{system},
cpu_core_manager{system}, reporter{system}, applet_manager{system} {}
Cpu& CurrentCpuCore() {
return cpu_core_manager.GetCurrentCore();
@ -341,7 +342,8 @@ struct System::Impl {
std::unique_ptr<VideoCore::RendererBase> renderer;
std::unique_ptr<Tegra::GPU> gpu_core;
std::shared_ptr<Tegra::DebugContext> debug_context;
std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager;
std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
Memory::Memory memory;
CpuCoreManager cpu_core_manager;
bool is_powered_on = false;
bool exit_lock = false;
@ -498,6 +500,14 @@ const ExclusiveMonitor& System::Monitor() const {
return impl->cpu_core_manager.GetExclusiveMonitor();
}
Memory::Memory& System::Memory() {
return impl->memory;
}
const Memory::Memory& System::Memory() const {
return impl->memory;
}
Tegra::GPU& System::GPU() {
return *impl->gpu_core;
}

View file

@ -86,6 +86,10 @@ namespace Core::Hardware {
class InterruptManager;
}
namespace Memory {
class Memory;
}
namespace Core {
class ARM_Interface;
@ -225,6 +229,12 @@ public:
/// Gets a constant reference to the exclusive monitor
const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance.
Memory::Memory& Memory();
/// Gets a constant reference to the system memory instance.
const Memory::Memory& Memory() const;
/// Gets a mutable reference to the GPU interface
Tegra::GPU& GPU();

View file

@ -66,9 +66,10 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
Cpu::~Cpu() = default;
std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(
[[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) {
#ifdef ARCHITECTURE_x86_64
return std::make_unique<DynarmicExclusiveMonitor>(num_cores);
return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores);
#else
// TODO(merry): Passthrough exclusive monitor
return nullptr;

View file

@ -24,6 +24,10 @@ namespace Core::Timing {
class CoreTiming;
}
namespace Memory {
class Memory;
}
namespace Core {
class ARM_Interface;
@ -86,7 +90,19 @@ public:
void Shutdown();
static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores);
/**
* Creates an exclusive monitor to handle exclusive reads/writes.
*
* @param memory The current memory subsystem that the monitor may wish
* to keep track of.
*
* @param num_cores The number of cores to assume about the CPU.
*
* @returns The constructed exclusive monitor instance, or nullptr if the current
* CPU backend is unable to use an exclusive monitor.
*/
static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
std::size_t num_cores);
private:
void Reschedule();

View file

@ -25,7 +25,7 @@ CpuCoreManager::~CpuCoreManager() = default;
void CpuCoreManager::Initialize() {
barrier = std::make_unique<CpuBarrier>();
exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size());
for (std::size_t index = 0; index < cores.size(); ++index) {
cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);

View file

@ -508,8 +508,9 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
bp->second.len, bp->second.addr, static_cast<int>(type));
if (type == BreakpointType::Execute) {
Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
Core::System::GetInstance().InvalidateCpuInstructionCaches();
auto& system = Core::System::GetInstance();
system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
system.InvalidateCpuInstructionCaches();
}
p.erase(addr);
}
@ -969,12 +970,13 @@ static void ReadMemory() {
SendReply("E01");
}
if (!Memory::IsValidVirtualAddress(addr)) {
auto& memory = Core::System::GetInstance().Memory();
if (!memory.IsValidVirtualAddress(addr)) {
return SendReply("E00");
}
std::vector<u8> data(len);
Memory::ReadBlock(addr, data.data(), len);
memory.ReadBlock(addr, data.data(), len);
MemToGdbHex(reply, data.data(), len);
reply[len * 2] = '\0';
@ -984,22 +986,23 @@ static void ReadMemory() {
/// Modify location in memory with data received from the gdb client.
static void WriteMemory() {
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;
auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
const auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
if (!Memory::IsValidVirtualAddress(addr)) {
auto& system = Core::System::GetInstance();
auto& memory = system.Memory();
if (!memory.IsValidVirtualAddress(addr)) {
return SendReply("E00");
}
std::vector<u8> data(len);
GdbHexToMem(data.data(), len_pos + 1, len);
Memory::WriteBlock(addr, data.data(), len);
Core::System::GetInstance().InvalidateCpuInstructionCaches();
memory.WriteBlock(addr, data.data(), len);
system.InvalidateCpuInstructionCaches();
SendReply("OK");
}
@ -1055,12 +1058,15 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
breakpoint.active = true;
breakpoint.addr = addr;
breakpoint.len = len;
Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
auto& system = Core::System::GetInstance();
auto& memory = system.Memory();
memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
if (type == BreakpointType::Execute) {
Memory::WriteBlock(addr, btrap.data(), btrap.size());
Core::System::GetInstance().InvalidateCpuInstructionCaches();
memory.WriteBlock(addr, btrap.data(), btrap.size());
system.InvalidateCpuInstructionCaches();
}
p.insert({addr, breakpoint});

View file

@ -67,23 +67,27 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value,
s32 num_to_wake) {
auto& memory = system.Memory();
// Ensure that we can write to the address.
if (!Memory::IsValidVirtualAddress(address)) {
if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
if (static_cast<s32>(Memory::Read32(address)) != value) {
if (static_cast<s32>(memory.Read32(address)) != value) {
return ERR_INVALID_STATE;
}
Memory::Write32(address, static_cast<u32>(value + 1));
memory.Write32(address, static_cast<u32>(value + 1));
return SignalToAddressOnly(address, num_to_wake);
}
ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
s32 num_to_wake) {
auto& memory = system.Memory();
// Ensure that we can write to the address.
if (!Memory::IsValidVirtualAddress(address)) {
if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
@ -109,11 +113,11 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
}
}
if (static_cast<s32>(Memory::Read32(address)) != value) {
if (static_cast<s32>(memory.Read32(address)) != value) {
return ERR_INVALID_STATE;
}
Memory::Write32(address, static_cast<u32>(updated_value));
memory.Write32(address, static_cast<u32>(updated_value));
WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS;
}
@ -134,18 +138,20 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s
ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
bool should_decrement) {
auto& memory = system.Memory();
// Ensure that we can read the address.
if (!Memory::IsValidVirtualAddress(address)) {
if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
const s32 cur_value = static_cast<s32>(Memory::Read32(address));
const s32 cur_value = static_cast<s32>(memory.Read32(address));
if (cur_value >= value) {
return ERR_INVALID_STATE;
}
if (should_decrement) {
Memory::Write32(address, static_cast<u32>(cur_value - 1));
memory.Write32(address, static_cast<u32>(cur_value - 1));
}
// Short-circuit without rescheduling, if timeout is zero.
@ -157,15 +163,19 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
}
ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
auto& memory = system.Memory();
// Ensure that we can read the address.
if (!Memory::IsValidVirtualAddress(address)) {
if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
// Only wait for the address if equal.
if (static_cast<s32>(Memory::Read32(address)) != value) {
if (static_cast<s32>(memory.Read32(address)) != value) {
return ERR_INVALID_STATE;
}
// Short-circuit without rescheduling, if timeout is zero.
// Short-circuit without rescheduling if timeout is zero.
if (timeout == 0) {
return RESULT_TIMEOUT;
}

View file

@ -21,10 +21,10 @@ ClientSession::~ClientSession() {
}
}
ResultCode ClientSession::SendSyncRequest(Thread* thread) {
ResultCode ClientSession::SendSyncRequest(Thread* thread, Memory::Memory& memory) {
// Signal the server session that new data is available
if (auto server = parent->server.lock()) {
return server->HandleSyncRequest(SharedFrom(thread));
return server->HandleSyncRequest(SharedFrom(thread), memory);
}
return ERR_SESSION_CLOSED_BY_REMOTE;

View file

@ -10,6 +10,10 @@
union ResultCode;
namespace Memory {
class Memory;
}
namespace Kernel {
class KernelCore;
@ -37,7 +41,7 @@ public:
return HANDLE_TYPE;
}
ResultCode SendSyncRequest(Thread* thread);
ResultCode SendSyncRequest(Thread* thread, Memory::Memory& memory);
private:
/// The parent session, which links to the server endpoint.

View file

@ -214,10 +214,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
auto& owner_process = *thread.GetOwnerProcess();
auto& handle_table = owner_process.GetHandleTable();
auto& memory = Core::System::GetInstance().Memory();
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
dst_cmdbuf.size() * sizeof(u32));
memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
dst_cmdbuf.size() * sizeof(u32));
// The header was already built in the internal command buffer. Attempt to parse it to verify
// the integrity and then copy it over to the target command buffer.
@ -273,8 +274,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
}
// Copy the translated command buffer back into the thread's command buffer area.
Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
dst_cmdbuf.size() * sizeof(u32));
memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
dst_cmdbuf.size() * sizeof(u32));
return RESULT_SUCCESS;
}
@ -282,15 +283,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
std::vector<u8> buffer;
const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_a) {
buffer.resize(BufferDescriptorA()[buffer_index].Size());
Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(),
buffer.size());
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
} else {
buffer.resize(BufferDescriptorX()[buffer_index].Size());
Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(),
buffer.size());
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
}
return buffer;
@ -311,10 +311,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
size = buffer_size; // TODO(bunnei): This needs to be HW tested
}
auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_b) {
Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
} else {
Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
}
return size;

View file

@ -154,6 +154,16 @@ struct KernelCore::Impl {
system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
}
void MakeCurrentProcess(Process* process) {
current_process = process;
if (process == nullptr) {
return;
}
system.Memory().SetCurrentPageTable(*process);
}
std::atomic<u32> next_object_id{0};
std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
@ -208,13 +218,7 @@ void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
}
void KernelCore::MakeCurrentProcess(Process* process) {
impl->current_process = process;
if (process == nullptr) {
return;
}
Memory::SetCurrentPageTable(*process);
impl->MakeCurrentProcess(process);
}
Process* KernelCore::CurrentProcess() {

View file

@ -79,7 +79,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
// thread.
ASSERT(requesting_thread == current_thread);
const u32 addr_value = Memory::Read32(address);
const u32 addr_value = system.Memory().Read32(address);
// If the mutex isn't being held, just return success.
if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
@ -117,7 +117,7 @@ ResultCode Mutex::Release(VAddr address) {
// There are no more threads waiting for the mutex, release it completely.
if (thread == nullptr) {
Memory::Write32(address, 0);
system.Memory().Write32(address, 0);
return RESULT_SUCCESS;
}
@ -132,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) {
}
// Grant the mutex to the next waiting thread and resume it.
Memory::Write32(address, mutex_value);
system.Memory().Write32(address, mutex_value);
ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
thread->ResumeFromWait();

View file

@ -19,6 +19,7 @@
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
#include "core/memory.h"
namespace Kernel {
@ -127,12 +128,13 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
return RESULT_SUCCESS;
}
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
Memory::Memory& memory) {
// The ServerSession received a sync request, this means that there's new data available
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
// similar.
Kernel::HLERequestContext context(SharedFrom(this), thread);
u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
u32* cmd_buf = (u32*)memory.GetPointer(thread->GetTLSAddress());
context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
ResultCode result = RESULT_SUCCESS;

View file

@ -13,6 +13,10 @@
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
namespace Memory {
class Memory;
}
namespace Kernel {
class ClientPort;
@ -85,10 +89,13 @@ public:
/**
* Handle a sync request from the emulated application.
*
* @param thread Thread that initiated the request.
* @param memory Memory context to handle the sync request under.
*
* @returns ResultCode from the operation.
*/
ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread);
ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory);
bool ShouldWait(const Thread* thread) const override;

View file

@ -332,7 +332,9 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
/// Connect to an OS service given the port name, returns the handle to the port to out
static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
VAddr port_name_address) {
if (!Memory::IsValidVirtualAddress(port_name_address)) {
auto& memory = system.Memory();
if (!memory.IsValidVirtualAddress(port_name_address)) {
LOG_ERROR(Kernel_SVC,
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
port_name_address);
@ -341,7 +343,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
static constexpr std::size_t PortNameMaxLength = 11;
// Read 1 char beyond the max allowed port name to detect names that are too long.
std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
if (port_name.size() > PortNameMaxLength) {
LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
port_name.size());
@ -383,7 +385,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
// TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
// responds and cause a reschedule.
return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread());
return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread(), system.Memory());
}
/// Get the ID for the specified thread.
@ -452,7 +454,8 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
handles_address, handle_count, nano_seconds);
if (!Memory::IsValidVirtualAddress(handles_address)) {
auto& memory = system.Memory();
if (!memory.IsValidVirtualAddress(handles_address)) {
LOG_ERROR(Kernel_SVC,
"Handle address is not a valid virtual address, handle_address=0x{:016X}",
handles_address);
@ -474,7 +477,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
for (u64 i = 0; i < handle_count; ++i) {
const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
const auto object = handle_table.Get<WaitObject>(handle);
if (object == nullptr) {
@ -616,13 +619,15 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
return;
}
auto& memory = system.Memory();
// This typically is an error code so we're going to assume this is the case
if (sz == sizeof(u32)) {
LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr));
LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
} else {
// We don't know what's in here so we'll hexdump it
debug_buffer.resize(sz);
Memory::ReadBlock(addr, debug_buffer.data(), sz);
memory.ReadBlock(addr, debug_buffer.data(), sz);
std::string hexdump;
for (std::size_t i = 0; i < debug_buffer.size(); i++) {
hexdump += fmt::format("{:02X} ", debug_buffer[i]);
@ -712,7 +717,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre
}
std::string str(len, '\0');
Memory::ReadBlock(address, str.data(), str.size());
system.Memory().ReadBlock(address, str.data(), str.size());
LOG_DEBUG(Debug_Emulated, "{}", str);
}
@ -1115,7 +1120,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
}
Memory::WriteBlock(thread_context, &ctx, sizeof(ctx));
system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
return RESULT_SUCCESS;
}
@ -1275,20 +1280,21 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
return ERR_INVALID_HANDLE;
}
auto& memory = system.Memory();
const auto& vm_manager = process->VMManager();
const MemoryInfo memory_info = vm_manager.QueryMemory(address);
Memory::Write64(memory_info_address, memory_info.base_address);
Memory::Write64(memory_info_address + 8, memory_info.size);
Memory::Write32(memory_info_address + 16, memory_info.state);
Memory::Write32(memory_info_address + 20, memory_info.attributes);
Memory::Write32(memory_info_address + 24, memory_info.permission);
Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count);
Memory::Write32(memory_info_address + 28, memory_info.device_ref_count);
Memory::Write32(memory_info_address + 36, 0);
memory.Write64(memory_info_address, memory_info.base_address);
memory.Write64(memory_info_address + 8, memory_info.size);
memory.Write32(memory_info_address + 16, memory_info.state);
memory.Write32(memory_info_address + 20, memory_info.attributes);
memory.Write32(memory_info_address + 24, memory_info.permission);
memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count);
memory.Write32(memory_info_address + 28, memory_info.device_ref_count);
memory.Write32(memory_info_address + 36, 0);
// Page info appears to be currently unused by the kernel and is always set to zero.
Memory::Write32(page_info_address, 0);
memory.Write32(page_info_address, 0);
return RESULT_SUCCESS;
}
@ -1672,6 +1678,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
const std::size_t current_core = system.CurrentCoreIndex();
auto& monitor = system.Monitor();
auto& memory = system.Memory();
// Atomically read the value of the mutex.
u32 mutex_val = 0;
@ -1681,7 +1688,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
monitor.SetExclusive(current_core, mutex_address);
// If the mutex is not yet acquired, acquire it.
mutex_val = Memory::Read32(mutex_address);
mutex_val = memory.Read32(mutex_address);
if (mutex_val != 0) {
update_val = mutex_val | Mutex::MutexHasWaitersFlag;
@ -2284,12 +2291,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
return ERR_INVALID_ADDRESS_STATE;
}
auto& memory = system.Memory();
const auto& process_list = kernel.GetProcessList();
const auto num_processes = process_list.size();
const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
for (std::size_t i = 0; i < copy_amount; ++i) {
Memory::Write64(out_process_ids, process_list[i]->GetProcessID());
memory.Write64(out_process_ids, process_list[i]->GetProcessID());
out_process_ids += sizeof(u64);
}
@ -2323,13 +2331,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
return ERR_INVALID_ADDRESS_STATE;
}
auto& memory = system.Memory();
const auto& thread_list = current_process->GetThreadList();
const auto num_threads = thread_list.size();
const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
auto list_iter = thread_list.cbegin();
for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID());
memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
out_thread_ids += sizeof(u64);
}

View file

@ -162,13 +162,13 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
return ERR_INVALID_PROCESSOR_ID;
}
if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
auto& system = Core::System::GetInstance();
if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) {
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
// TODO (bunnei): Find the correct error code to use here
return RESULT_UNKNOWN;
}
auto& system = Core::System::GetInstance();
std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel);
thread->thread_id = kernel.CreateNewThreadID();

View file

@ -16,7 +16,6 @@
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
#include "core/memory_setup.h"
namespace Kernel {
namespace {
@ -786,19 +785,21 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre
}
void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
auto& memory = system.Memory();
switch (vma.type) {
case VMAType::Free:
Memory::UnmapRegion(page_table, vma.base, vma.size);
memory.UnmapRegion(page_table, vma.base, vma.size);
break;
case VMAType::AllocatedMemoryBlock:
Memory::MapMemoryRegion(page_table, vma.base, vma.size,
vma.backing_block->data() + vma.offset);
memory.MapMemoryRegion(page_table, vma.base, vma.size,
vma.backing_block->data() + vma.offset);
break;
case VMAType::BackingMemory:
Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
break;
case VMAType::MMIO:
Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
break;
}
}

View file

@ -43,7 +43,8 @@ public:
IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core,
std::string&& device_name, std::string&& unique_name)
: ServiceFramework("IAudioOut"), audio_core(audio_core),
device_name(std::move(device_name)), audio_params(audio_params) {
device_name(std::move(device_name)),
audio_params(audio_params), main_memory{system.Memory()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@ -137,7 +138,7 @@ private:
const u64 tag{rp.Pop<u64>()};
std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
main_memory.ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
IPC::ResponseBuilder rb{ctx, 2};
@ -209,6 +210,7 @@ private:
/// This is the event handle used to check if the audio buffer was released
Kernel::EventPair buffer_event;
Memory::Memory& main_memory;
};
AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} {

View file

@ -49,8 +49,9 @@ public:
system_event =
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
renderer = std::make_unique<AudioCore::AudioRenderer>(
system.CoreTiming(), audren_params, system_event.writable, instance_number);
renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(),
audren_params, system_event.writable,
instance_number);
}
private:

View file

@ -391,13 +391,10 @@ public:
}
void RenameFile(Kernel::HLERequestContext& ctx) {
std::vector<u8> buffer;
buffer.resize(ctx.BufferDescriptorX()[0].Size());
Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size());
std::vector<u8> buffer = ctx.ReadBuffer(0);
const std::string src_name = Common::StringFromBuffer(buffer);
buffer.resize(ctx.BufferDescriptorX()[1].Size());
Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size());
buffer = ctx.ReadBuffer(1);
const std::string dst_name = Common::StringFromBuffer(buffer);
LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);

View file

@ -140,9 +140,10 @@ public:
rb.Push(ERROR_INVALID_SIZE);
return;
}
// Read NRR data from memory
std::vector<u8> nrr_data(nrr_size);
Memory::ReadBlock(nrr_address, nrr_data.data(), nrr_size);
system.Memory().ReadBlock(nrr_address, nrr_data.data(), nrr_size);
NRRHeader header;
std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
@ -291,7 +292,7 @@ public:
// Read NRO data from memory
std::vector<u8> nro_data(nro_size);
Memory::ReadBlock(nro_address, nro_data.data(), nro_size);
system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size);
SHA256Hash hash{};
mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);

View file

@ -17,7 +17,8 @@ namespace Service::LM {
class ILogger final : public ServiceFramework<ILogger> {
public:
ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) {
explicit ILogger(Manager& manager_, Memory::Memory& memory_)
: ServiceFramework("ILogger"), manager{manager_}, memory{memory_} {
static const FunctionInfo functions[] = {
{0, &ILogger::Log, "Log"},
{1, &ILogger::SetDestination, "SetDestination"},
@ -35,15 +36,15 @@ private:
MessageHeader header{};
VAddr addr{ctx.BufferDescriptorX()[0].Address()};
const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size};
Memory::ReadBlock(addr, &header, sizeof(MessageHeader));
memory.ReadBlock(addr, &header, sizeof(MessageHeader));
addr += sizeof(MessageHeader);
FieldMap fields;
while (addr < end_addr) {
const auto field = static_cast<Field>(Memory::Read8(addr++));
const auto length = Memory::Read8(addr++);
const auto field = static_cast<Field>(memory.Read8(addr++));
const auto length = memory.Read8(addr++);
if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) {
++addr;
}
@ -54,7 +55,7 @@ private:
}
std::vector<u8> data(length);
Memory::ReadBlock(addr, data.data(), length);
memory.ReadBlock(addr, data.data(), length);
fields.emplace(field, std::move(data));
}
@ -74,11 +75,13 @@ private:
}
Manager& manager;
Memory::Memory& memory;
};
class LM final : public ServiceFramework<LM> {
public:
explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) {
explicit LM(Manager& manager_, Memory::Memory& memory_)
: ServiceFramework{"lm"}, manager{manager_}, memory{memory_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LM::OpenLogger, "OpenLogger"},
@ -94,14 +97,16 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILogger>(manager);
rb.PushIpcInterface<ILogger>(manager, memory);
}
Manager& manager;
Memory::Memory& memory;
};
void InstallInterfaces(Core::System& system) {
std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager());
std::make_shared<LM>(system.GetLogManager(), system.Memory())
->InstallAsService(system.ServiceManager());
}
} // namespace Service::LM

View file

@ -191,8 +191,8 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
std::memcpy(entries.data(), input2.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
} else {
Memory::ReadBlock(params.address, entries.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
system.Memory().ReadBlock(params.address, entries.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
}
UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,18 @@
#pragma once
#include <cstddef>
#include <memory>
#include <string>
#include "common/common_types.h"
#include "common/memory_hook.h"
namespace Common {
struct PageTable;
}
namespace Core {
class System;
}
namespace Kernel {
class Process;
@ -36,41 +46,369 @@ enum : VAddr {
KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
};
/// Changes the currently active page table to that of
/// the given process instance.
void SetCurrentPageTable(Kernel::Process& process);
/// Central class that handles all memory operations and state.
class Memory {
public:
explicit Memory(Core::System& system);
~Memory();
Memory(const Memory&) = delete;
Memory& operator=(const Memory&) = delete;
Memory(Memory&&) = default;
Memory& operator=(Memory&&) = default;
/**
* Changes the currently active page table to that of the given process instance.
*
* @param process The process to use the page table of.
*/
void SetCurrentPageTable(Kernel::Process& process);
/**
* Maps an allocated buffer onto a region of the emulated process address space.
*
* @param page_table The page table of the emulated process.
* @param base The address to start mapping at. Must be page-aligned.
* @param size The amount of bytes to map. Must be page-aligned.
* @param target Buffer with the memory backing the mapping. Must be of length at least
* `size`.
*/
void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
/**
* Maps a region of the emulated process address space as a IO region.
*
* @param page_table The page table of the emulated process.
* @param base The address to start mapping at. Must be page-aligned.
* @param size The amount of bytes to map. Must be page-aligned.
* @param mmio_handler The handler that backs the mapping.
*/
void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
Common::MemoryHookPointer mmio_handler);
/**
* Unmaps a region of the emulated process address space.
*
* @param page_table The page table of the emulated process.
* @param base The address to begin unmapping at.
* @param size The amount of bytes to unmap.
*/
void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
/**
* Adds a memory hook to intercept reads and writes to given region of memory.
*
* @param page_table The page table of the emulated process
* @param base The starting address to apply the hook to.
* @param size The size of the memory region to apply the hook to, in bytes.
* @param hook The hook to apply to the region of memory.
*/
void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
Common::MemoryHookPointer hook);
/**
* Removes a memory hook from a given range of memory.
*
* @param page_table The page table of the emulated process.
* @param base The starting address to remove the hook from.
* @param size The size of the memory region to remove the hook from, in bytes.
* @param hook The hook to remove from the specified region of memory.
*/
void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
Common::MemoryHookPointer hook);
/**
* Checks whether or not the supplied address is a valid virtual
* address for the given process.
*
* @param process The emulated process to check the address against.
* @param vaddr The virtual address to check the validity of.
*
* @returns True if the given virtual address is valid, false otherwise.
*/
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const;
/**
* Checks whether or not the supplied address is a valid virtual
* address for the current process.
*
* @param vaddr The virtual address to check the validity of.
*
* @returns True if the given virtual address is valid, false otherwise.
*/
bool IsValidVirtualAddress(VAddr vaddr) const;
/**
* Gets a pointer to the given address.
*
* @param vaddr Virtual address to retrieve a pointer to.
*
* @returns The pointer to the given address, if the address is valid.
* If the address is not valid, nullptr will be returned.
*/
u8* GetPointer(VAddr vaddr);
/**
* Gets a pointer to the given address.
*
* @param vaddr Virtual address to retrieve a pointer to.
*
* @returns The pointer to the given address, if the address is valid.
* If the address is not valid, nullptr will be returned.
*/
const u8* GetPointer(VAddr vaddr) const;
/**
* Reads an 8-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 8-bit value from.
*
* @returns the read 8-bit unsigned value.
*/
u8 Read8(VAddr addr);
/**
* Reads a 16-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 16-bit value from.
*
* @returns the read 16-bit unsigned value.
*/
u16 Read16(VAddr addr);
/**
* Reads a 32-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 32-bit value from.
*
* @returns the read 32-bit unsigned value.
*/
u32 Read32(VAddr addr);
/**
* Reads a 64-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 64-bit value from.
*
* @returns the read 64-bit value.
*/
u64 Read64(VAddr addr);
/**
* Writes an 8-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 8-bit unsigned integer to.
* @param data The 8-bit unsigned integer to write to the given virtual address.
*
* @post The memory at the given virtual address contains the specified data value.
*/
void Write8(VAddr addr, u8 data);
/**
* Writes a 16-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 16-bit unsigned integer to.
* @param data The 16-bit unsigned integer to write to the given virtual address.
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
void Write16(VAddr addr, u16 data);
/**
* Writes a 32-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 32-bit unsigned integer to.
* @param data The 32-bit unsigned integer to write to the given virtual address.
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
void Write32(VAddr addr, u32 data);
/**
* Writes a 64-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 64-bit unsigned integer to.
* @param data The 64-bit unsigned integer to write to the given virtual address.
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
void Write64(VAddr addr, u64 data);
/**
* Reads a null-terminated string from the given virtual address.
* This function will continually read characters until either:
*
* - A null character ('\0') is reached.
* - max_length characters have been read.
*
* @note The final null-terminating character (if found) is not included
* in the returned string.
*
* @param vaddr The address to begin reading the string from.
* @param max_length The maximum length of the string to read in characters.
*
* @returns The read string.
*/
std::string ReadCString(VAddr vaddr, std::size_t max_length);
/**
* Reads a contiguous block of bytes from a specified process' address space.
*
* @param process The process to read the data from.
* @param src_addr The virtual address to begin reading from.
* @param dest_buffer The buffer to place the read bytes into.
* @param size The amount of data to read, in bytes.
*
* @note If a size of 0 is specified, then this function reads nothing and
* no attempts to access memory are made at all.
*
* @pre dest_buffer must be at least size bytes in length, otherwise a
* buffer overrun will occur.
*
* @post The range [dest_buffer, size) contains the read bytes from the
* process' address space.
*/
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
std::size_t size);
/**
* Reads a contiguous block of bytes from the current process' address space.
*
* @param src_addr The virtual address to begin reading from.
* @param dest_buffer The buffer to place the read bytes into.
* @param size The amount of data to read, in bytes.
*
* @note If a size of 0 is specified, then this function reads nothing and
* no attempts to access memory are made at all.
*
* @pre dest_buffer must be at least size bytes in length, otherwise a
* buffer overrun will occur.
*
* @post The range [dest_buffer, size) contains the read bytes from the
* current process' address space.
*/
void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
/**
* Writes a range of bytes into a given process' address space at the specified
* virtual address.
*
* @param process The process to write data into the address space of.
* @param dest_addr The destination virtual address to begin writing the data at.
* @param src_buffer The data to write into the process' address space.
* @param size The size of the data to write, in bytes.
*
* @post The address range [dest_addr, size) in the process' address space
* contains the data that was within src_buffer.
*
* @post If an attempt is made to write into an unmapped region of memory, the writes
* will be ignored and an error will be logged.
*
* @post If a write is performed into a region of memory that is considered cached
* rasterizer memory, will cause the currently active rasterizer to be notified
* and will mark that region as invalidated to caches that the active
* graphics backend may be maintaining over the course of execution.
*/
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
std::size_t size);
/**
* Writes a range of bytes into the current process' address space at the specified
* virtual address.
*
* @param dest_addr The destination virtual address to begin writing the data at.
* @param src_buffer The data to write into the current process' address space.
* @param size The size of the data to write, in bytes.
*
* @post The address range [dest_addr, size) in the current process' address space
* contains the data that was within src_buffer.
*
* @post If an attempt is made to write into an unmapped region of memory, the writes
* will be ignored and an error will be logged.
*
* @post If a write is performed into a region of memory that is considered cached
* rasterizer memory, will cause the currently active rasterizer to be notified
* and will mark that region as invalidated to caches that the active
* graphics backend may be maintaining over the course of execution.
*/
void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
/**
* Fills the specified address range within a process' address space with zeroes.
*
* @param process The process that will have a portion of its memory zeroed out.
* @param dest_addr The starting virtual address of the range to zero out.
* @param size The size of the address range to zero out, in bytes.
*
* @post The range [dest_addr, size) within the process' address space is
* filled with zeroes.
*/
void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
/**
* Fills the specified address range within the current process' address space with zeroes.
*
* @param dest_addr The starting virtual address of the range to zero out.
* @param size The size of the address range to zero out, in bytes.
*
* @post The range [dest_addr, size) within the current process' address space is
* filled with zeroes.
*/
void ZeroBlock(VAddr dest_addr, std::size_t size);
/**
* Copies data within a process' address space to another location within the
* same address space.
*
* @param process The process that will have data copied within its address space.
* @param dest_addr The destination virtual address to begin copying the data into.
* @param src_addr The source virtual address to begin copying the data from.
* @param size The size of the data to copy, in bytes.
*
* @post The range [dest_addr, size) within the process' address space contains the
* same data within the range [src_addr, size).
*/
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
std::size_t size);
/**
* Copies data within the current process' address space to another location within the
* same address space.
*
* @param dest_addr The destination virtual address to begin copying the data into.
* @param src_addr The source virtual address to begin copying the data from.
* @param size The size of the data to copy, in bytes.
*
* @post The range [dest_addr, size) within the current process' address space
* contains the same data within the range [src_addr, size).
*/
void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
/**
* Marks each page within the specified address range as cached or uncached.
*
* @param vaddr The virtual address indicating the start of the address range.
* @param size The size of the address range in bytes.
* @param cached Whether or not any pages within the address range should be
* marked as cached or uncached.
*/
void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
/// Determines if the given VAddr is valid for the specified process.
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
bool IsValidVirtualAddress(VAddr vaddr);
/// Determines if the given VAddr is a kernel address
bool IsKernelVirtualAddress(VAddr vaddr);
u8 Read8(VAddr addr);
u16 Read16(VAddr addr);
u32 Read32(VAddr addr);
u64 Read64(VAddr addr);
void Write8(VAddr addr, u8 data);
void Write16(VAddr addr, u16 data);
void Write32(VAddr addr, u32 data);
void Write64(VAddr addr, u64 data);
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size);
void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
std::size_t size);
void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
u8* GetPointer(VAddr vaddr);
std::string ReadCString(VAddr vaddr, std::size_t max_length);
/**
* Mark each page touching the region as cached.
*/
void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
} // namespace Memory

View file

@ -20,18 +20,17 @@ namespace Memory {
constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12);
constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
StandardVmCallbacks::StandardVmCallbacks(const Core::System& system,
const CheatProcessMetadata& metadata)
StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
: metadata(metadata), system(system) {}
StandardVmCallbacks::~StandardVmCallbacks() = default;
void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
ReadBlock(SanitizeAddress(address), data, size);
system.Memory().ReadBlock(SanitizeAddress(address), data, size);
}
void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
WriteBlock(SanitizeAddress(address), data, size);
system.Memory().WriteBlock(SanitizeAddress(address), data, size);
}
u64 StandardVmCallbacks::HidKeysDown() {

View file

@ -24,7 +24,7 @@ namespace Memory {
class StandardVmCallbacks : public DmntCheatVm::Callbacks {
public:
StandardVmCallbacks(const Core::System& system, const CheatProcessMetadata& metadata);
StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata);
~StandardVmCallbacks() override;
void MemoryRead(VAddr address, void* data, u64 size) override;
@ -37,7 +37,7 @@ private:
VAddr SanitizeAddress(VAddr address) const;
const CheatProcessMetadata& metadata;
const Core::System& system;
Core::System& system;
};
// Intermediary class that parses a text file or other disk format for storing cheats into a

View file

@ -1,43 +0,0 @@
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "common/memory_hook.h"
namespace Common {
struct PageTable;
}
namespace Memory {
/**
* Maps an allocated buffer onto a region of the emulated process address space.
*
* @param page_table The page table of the emulated process.
* @param base The address to start mapping at. Must be page-aligned.
* @param size The amount of bytes to map. Must be page-aligned.
* @param target Buffer with the memory backing the mapping. Must be of length at least `size`.
*/
void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
/**
* Maps a region of the emulated process address space as a IO region.
* @param page_table The page table of the emulated process.
* @param base The address to start mapping at. Must be page-aligned.
* @param size The amount of bytes to map. Must be page-aligned.
* @param mmio_handler The handler that backs the mapping.
*/
void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
Common::MemoryHookPointer mmio_handler);
void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
Common::MemoryHookPointer hook);
void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
Common::MemoryHookPointer hook);
} // namespace Memory

View file

@ -147,7 +147,7 @@ json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& s
}
template <bool read_value, typename DescriptorType>
json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer, Memory::Memory& memory) {
auto buffer_out = json::array();
for (const auto& desc : buffer) {
auto entry = json{
@ -157,7 +157,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
if constexpr (read_value) {
std::vector<u8> data(desc.Size());
Memory::ReadBlock(desc.Address(), data.data(), desc.Size());
memory.ReadBlock(desc.Address(), data.data(), desc.Size());
entry["data"] = Common::HexToString(data);
}
@ -167,7 +167,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
return buffer_out;
}
json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {
json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Memory::Memory& memory) {
json out;
auto cmd_buf = json::array();
@ -177,10 +177,10 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {
out["command_buffer"] = std::move(cmd_buf);
out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA());
out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB());
out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC());
out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX());
out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA(), memory);
out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB(), memory);
out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC(), memory);
out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX(), memory);
return out;
}
@ -259,7 +259,7 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u
const auto title_id = system.CurrentProcess()->GetTitleID();
auto out = GetFullDataAuto(timestamp, title_id, system);
auto function_out = GetHLERequestContextData(ctx);
auto function_out = GetHLERequestContextData(ctx, system.Memory());
function_out["command_id"] = command_id;
function_out["function_name"] = name;
function_out["service_name"] = service_name;

View file

@ -11,40 +11,39 @@
#include "core/tools/freezer.h"
namespace Tools {
namespace {
constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
u64 MemoryReadWidth(u32 width, VAddr addr) {
u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
switch (width) {
case 1:
return Memory::Read8(addr);
return memory.Read8(addr);
case 2:
return Memory::Read16(addr);
return memory.Read16(addr);
case 4:
return Memory::Read32(addr);
return memory.Read32(addr);
case 8:
return Memory::Read64(addr);
return memory.Read64(addr);
default:
UNREACHABLE();
return 0;
}
}
void MemoryWriteWidth(u32 width, VAddr addr, u64 value) {
void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) {
switch (width) {
case 1:
Memory::Write8(addr, static_cast<u8>(value));
memory.Write8(addr, static_cast<u8>(value));
break;
case 2:
Memory::Write16(addr, static_cast<u16>(value));
memory.Write16(addr, static_cast<u16>(value));
break;
case 4:
Memory::Write32(addr, static_cast<u32>(value));
memory.Write32(addr, static_cast<u32>(value));
break;
case 8:
Memory::Write64(addr, value);
memory.Write64(addr, value);
break;
default:
UNREACHABLE();
@ -53,7 +52,8 @@ void MemoryWriteWidth(u32 width, VAddr addr, u64 value) {
} // Anonymous namespace
Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) {
Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_)
: core_timing{core_timing_}, memory{memory_} {
event = Core::Timing::CreateEvent(
"MemoryFreezer::FrameCallback",
[this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
@ -89,7 +89,7 @@ void Freezer::Clear() {
u64 Freezer::Freeze(VAddr address, u32 width) {
std::lock_guard lock{entries_mutex};
const auto current_value = MemoryReadWidth(width, address);
const auto current_value = MemoryReadWidth(memory, width, address);
entries.push_back({address, width, current_value});
LOG_DEBUG(Common_Memory,
@ -169,7 +169,7 @@ void Freezer::FrameCallback(u64 userdata, s64 cycles_late) {
LOG_DEBUG(Common_Memory,
"Enforcing memory freeze at address={:016X}, value={:016X}, width={:02X}",
entry.address, entry.value, entry.width);
MemoryWriteWidth(entry.width, entry.address, entry.value);
MemoryWriteWidth(memory, entry.width, entry.address, entry.value);
}
core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - cycles_late, event);
@ -181,7 +181,7 @@ void Freezer::FillEntryReads() {
LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values.");
for (auto& entry : entries) {
entry.value = MemoryReadWidth(entry.width, entry.address);
entry.value = MemoryReadWidth(memory, entry.width, entry.address);
}
}

View file

@ -16,6 +16,10 @@ class CoreTiming;
struct EventType;
} // namespace Core::Timing
namespace Memory {
class Memory;
}
namespace Tools {
/**
@ -34,7 +38,7 @@ public:
u64 value;
};
explicit Freezer(Core::Timing::CoreTiming& core_timing);
explicit Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_);
~Freezer();
// Enables or disables the entire memory freezer.
@ -78,6 +82,7 @@ private:
std::shared_ptr<Core::Timing::EventType> event;
Core::Timing::CoreTiming& core_timing;
Memory::Memory& memory;
};
} // namespace Tools

View file

@ -8,7 +8,6 @@
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/memory.h"
#include "core/memory_setup.h"
#include "tests/core/arm/arm_test_common.h"
namespace ArmTests {
@ -16,8 +15,9 @@ namespace ArmTests {
TestEnvironment::TestEnvironment(bool mutable_memory_)
: mutable_memory(mutable_memory_),
test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
auto process = Kernel::Process::Create(Core::System::GetInstance(), "",
Kernel::Process::ProcessType::Userland);
auto& system = Core::System::GetInstance();
auto process = Kernel::Process::Create(system, "", Kernel::Process::ProcessType::Userland);
page_table = &process->VMManager().page_table;
std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
@ -25,15 +25,16 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
std::fill(page_table->attributes.begin(), page_table->attributes.end(),
Common::PageType::Unmapped);
Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
system.Memory().MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
system.Memory().MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
kernel.MakeCurrentProcess(process.get());
}
TestEnvironment::~TestEnvironment() {
Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000);
Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000);
auto& system = Core::System::GetInstance();
system.Memory().UnmapRegion(*page_table, 0x80000000, 0x80000000);
system.Memory().UnmapRegion(*page_table, 0x00000000, 0x80000000);
}
void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {

View file

@ -52,7 +52,7 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
const u64 aligned_size{Common::AlignUp(size, page_size)};
const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)};
MapBackingMemory(gpu_addr, Memory::GetPointer(cpu_addr), aligned_size, cpu_addr);
MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr);
ASSERT(system.CurrentProcess()
->VMManager()
.SetMemoryAttribute(cpu_addr, size, Kernel::MemoryAttribute::DeviceMapped,
@ -67,7 +67,7 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
const u64 aligned_size{Common::AlignUp(size, page_size)};
MapBackingMemory(gpu_addr, Memory::GetPointer(cpu_addr), aligned_size, cpu_addr);
MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr);
ASSERT(system.CurrentProcess()
->VMManager()
.SetMemoryAttribute(cpu_addr, size, Kernel::MemoryAttribute::DeviceMapped,

View file

@ -22,7 +22,8 @@ constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
} // Anonymous namespace
RasterizerAccelerated::RasterizerAccelerated() = default;
RasterizerAccelerated::RasterizerAccelerated(Memory::Memory& cpu_memory_)
: cpu_memory{cpu_memory_} {}
RasterizerAccelerated::~RasterizerAccelerated() = default;
@ -47,9 +48,9 @@ void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int del
const u64 interval_size = interval_end_addr - interval_start_addr;
if (delta > 0 && count == delta) {
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
} else if (delta < 0 && count == -delta) {
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
} else {
ASSERT(count >= 0);
}

View file

@ -11,12 +11,16 @@
#include "common/common_types.h"
#include "video_core/rasterizer_interface.h"
namespace Memory {
class Memory;
}
namespace VideoCore {
/// Implements the shared part in GPU accelerated rasterizers in RasterizerInterface.
class RasterizerAccelerated : public RasterizerInterface {
public:
explicit RasterizerAccelerated();
explicit RasterizerAccelerated(Memory::Memory& cpu_memory_);
~RasterizerAccelerated() override;
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
@ -24,8 +28,9 @@ public:
private:
using CachedPageMap = boost::icl::interval_map<u64, int>;
CachedPageMap cached_pages;
std::mutex pages_mutex;
Memory::Memory& cpu_memory;
};
} // namespace VideoCore

View file

@ -19,6 +19,7 @@
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/memory.h"
#include "core/settings.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/maxwell_3d.h"
@ -86,8 +87,9 @@ std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
ScreenInfo& info)
: texture_cache{system, *this, device}, shader_cache{*this, system, emu_window, device},
system{system}, screen_info{info}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} {
: RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device},
shader_cache{*this, system, emu_window, device}, system{system}, screen_info{info},
buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} {
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
state.draw.shader_program = 0;
state.Apply();
@ -837,7 +839,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
const auto surface{
texture_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))};
texture_cache.TryFindFramebufferSurface(system.Memory().GetPointer(framebuffer_addr))};
if (!surface) {
return {};
}

View file

@ -158,7 +158,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)};
const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
const auto host_ptr{Memory::GetPointer(framebuffer_addr)};
u8* const host_ptr{system.Memory().GetPointer(framebuffer_addr)};
rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes);
// TODO(Rodrigo): Read this from HLE

View file

@ -24,9 +24,11 @@ CachedBufferEntry::CachedBufferEntry(VAddr cpu_addr, std::size_t size, u64 offse
alignment{alignment} {}
VKBufferCache::VKBufferCache(Tegra::MemoryManager& tegra_memory_manager,
Memory::Memory& cpu_memory_,
VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size)
: RasterizerCache{rasterizer}, tegra_memory_manager{tegra_memory_manager} {
: RasterizerCache{rasterizer}, tegra_memory_manager{tegra_memory_manager}, cpu_memory{
cpu_memory_} {
const auto usage = vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eIndexBuffer |
vk::BufferUsageFlagBits::eUniformBuffer;
@ -48,9 +50,9 @@ u64 VKBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, u64 alignme
// TODO: Figure out which size is the best for given games.
cache &= size >= 2048;
const auto& host_ptr{Memory::GetPointer(*cpu_addr)};
u8* const host_ptr{cpu_memory.GetPointer(*cpu_addr)};
if (cache) {
auto entry = TryGet(host_ptr);
const auto entry = TryGet(host_ptr);
if (entry) {
if (entry->GetSize() >= size && entry->GetAlignment() == alignment) {
return entry->GetOffset();
@ -62,7 +64,7 @@ u64 VKBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, u64 alignme
AlignBuffer(alignment);
const u64 uploaded_offset = buffer_offset;
if (!host_ptr) {
if (host_ptr == nullptr) {
return uploaded_offset;
}

View file

@ -13,6 +13,10 @@
#include "video_core/renderer_vulkan/declarations.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
namespace Memory {
class Memory;
}
namespace Tegra {
class MemoryManager;
}
@ -58,7 +62,7 @@ private:
class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
public:
explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager,
explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager, Memory::Memory& cpu_memory_,
VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size);
~VKBufferCache();
@ -92,6 +96,7 @@ private:
void AlignBuffer(std::size_t alignment);
Tegra::MemoryManager& tegra_memory_manager;
Memory::Memory& cpu_memory;
std::unique_ptr<VKStreamBuffer> stream_buffer;
vk::Buffer buffer_handle;

View file

@ -80,7 +80,7 @@ QString WaitTreeText::GetText() const {
WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table)
: mutex_address(mutex_address) {
mutex_value = Memory::Read32(mutex_address);
mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);
owner = handle_table.Get<Kernel::Thread>(owner_handle);
}
@ -115,10 +115,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
std::vector<std::unique_ptr<WaitTreeItem>> list;
constexpr std::size_t BaseRegister = 29;
auto& memory = Core::System::GetInstance().Memory();
u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister];
while (base_pointer != 0) {
const u64 lr = Memory::Read64(base_pointer + sizeof(u64));
const u64 lr = memory.Read64(base_pointer + sizeof(u64));
if (lr == 0) {
break;
}
@ -126,7 +127,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
list.push_back(std::make_unique<WaitTreeText>(
tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'})));
base_pointer = Memory::Read64(base_pointer);
base_pointer = memory.Read64(base_pointer);
}
return list;