Compare commits

..

17 Commits

Author SHA1 Message Date
Flame Sage
d861122239 Merge 470055f051 into 1add3b20c4 2018-02-10 05:10:09 +00:00
bunnei
1add3b20c4 Merge pull request #171 from bunnei/libnx-fixes
Various fixes for libnx, etc.
2018-02-09 15:51:43 -05:00
bunnei
3b35202280 Merge pull request #173 from MerryMage/feature/dynarmic-fix-windows
dynarmic: Fix bug due to Windows ABI mismatch
2018-02-09 13:07:15 -05:00
MerryMage
45e5a67676 dynarmic: Fix bug due to Windows ABI mismatch 2018-02-09 16:05:28 +00:00
bunnei
22caeee64f nvdrv: Fix QueryEvent for libnx. 2018-02-09 00:56:45 -05:00
bunnei
576f0cf027 IApplicationDisplayService::CloseDisplay: Fix response params size. 2018-02-08 23:20:23 -05:00
bunnei
ca99063600 nvhost_ctrl_gpu: Implement ZCullGetInfo. 2018-02-08 23:17:59 -05:00
bunnei
205daab50d Merge pull request #170 from MerryMage/feature/dynarmic-update-201802
dynarmic: Update to 41ae12263
2018-02-08 23:12:57 -05:00
MerryMage
d3bbed5e78 dynarmic: Update to 41ae12263
Changes: Primarily implementing more A64 instructions
2018-02-09 00:29:36 +00:00
bunnei
dc0a137e5b acc_u0: Implement ListAllUsers. 2018-02-08 18:59:23 -05:00
bunnei
db11c9a0b9 Merge pull request #169 from bunnei/gpu-mem
nvdrv: Implement AllocateSpace and MapBufferEx
2018-02-07 22:10:42 -08:00
bunnei
a39a65cbe0 nvhost_as_gpu: Implement AllocateSpace and MapBufferEx. 2018-02-07 23:31:28 -05:00
bunnei
c711253798 nvdrv: Add MemoryManager class to track GPU memory. 2018-02-07 23:31:26 -05:00
bunnei
196f8dff08 nvmap: Refactor to expose nvmap objects. 2018-02-07 22:55:12 -05:00
bunnei
703880c9ab nvhost_as_gpu: Add nvmap as a class member. 2018-02-07 22:55:09 -05:00
bunnei
869d65e923 Merge pull request #168 from mailwl/new-stubs
Service: stub some functions in am, audio, time, vi services
2018-02-07 07:51:35 -08:00
Flame Sage
470055f051 Update README.md 2018-01-18 04:12:43 +00:00
20 changed files with 312 additions and 74 deletions

View File

@@ -2,7 +2,7 @@
set -o pipefail
export MACOSX_DEPLOYMENT_TARGET=10.9
export MACOSX_DEPLOYMENT_TARGET=10.12
export Qt5_DIR=$(brew --prefix)/opt/qt5
export UNICORNDIR=$(pwd)/externals/unicorn

View File

@@ -1,4 +1,4 @@
yuzu emulator
yuzu emulator (canary)
=============
[![Travis CI Build Status](https://travis-ci.org/yuzu-emu/yuzu.svg?branch=master)](https://travis-ci.org/yuzu-emu/yuzu)
[![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/77k97svb2usreu68?svg=true)](https://ci.appveyor.com/project/bunnei/yuzu)

View File

@@ -137,6 +137,8 @@ add_library(core STATIC
hle/service/nvdrv/devices/nvmap.h
hle/service/nvdrv/interface.cpp
hle/service/nvdrv/interface.h
hle/service/nvdrv/memory_manager.cpp
hle/service/nvdrv/memory_manager.h
hle/service/nvdrv/nvdrv.cpp
hle/service/nvdrv/nvdrv.h
hle/service/nvdrv/nvmemp.cpp

View File

@@ -8,9 +8,12 @@
#include <dynarmic/A64/config.h>
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/core_timing.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
using Vector = Dynarmic::A64::Vector;
class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks {
public:
explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
@@ -28,6 +31,9 @@ public:
u64 MemoryRead64(u64 vaddr) override {
return Memory::Read64(vaddr);
}
Vector MemoryRead128(u64 vaddr) override {
return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)};
}
void MemoryWrite8(u64 vaddr, u8 value) override {
Memory::Write8(vaddr, value);
@@ -41,6 +47,10 @@ public:
void MemoryWrite64(u64 vaddr, u64 value) override {
Memory::Write64(vaddr, value);
}
void MemoryWrite128(u64 vaddr, Vector value) override {
Memory::Write64(vaddr, value[0]);
Memory::Write64(vaddr + 8, value[1]);
}
void InterpreterFallback(u64 pc, size_t num_instructions) override {
ARM_Interface::ThreadContext ctx;
@@ -52,12 +62,12 @@ public:
num_interpreted_instructions += num_instructions;
}
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception /*exception*/) override {
ASSERT_MSG(false, "ExceptionRaised(%" PRIx64 ")", pc);
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")",
static_cast<size_t>(exception), pc);
}
void CallSVC(u32 swi) override {
printf("svc %x\n", swi);
Kernel::CallSVC(swi);
}
@@ -78,9 +88,13 @@ public:
u64 tpidrr0_el0 = 0;
};
std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) {
Dynarmic::A64::UserConfig config{cb.get()};
return std::make_unique<Dynarmic::A64::Jit>(config);
}
ARM_Dynarmic::ARM_Dynarmic()
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)),
jit(Dynarmic::A64::UserConfig{cb.get()}) {
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), jit(MakeJit(cb)) {
ARM_Interface::ThreadContext ctx;
inner_unicorn.SaveContext(ctx);
LoadContext(ctx);
@@ -94,27 +108,27 @@ void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory,
}
void ARM_Dynarmic::SetPC(u64 pc) {
jit.SetPC(pc);
jit->SetPC(pc);
}
u64 ARM_Dynarmic::GetPC() const {
return jit.GetPC();
return jit->GetPC();
}
u64 ARM_Dynarmic::GetReg(int index) const {
return jit.GetRegister(index);
return jit->GetRegister(index);
}
void ARM_Dynarmic::SetReg(int index, u64 value) {
jit.SetRegister(index, value);
jit->SetRegister(index, value);
}
u128 ARM_Dynarmic::GetExtReg(int index) const {
return jit.GetVector(index);
return jit->GetVector(index);
}
void ARM_Dynarmic::SetExtReg(int index, u128 value) {
jit.SetVector(index, value);
jit->SetVector(index, value);
}
u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const {
@@ -127,11 +141,11 @@ void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) {
}
u32 ARM_Dynarmic::GetCPSR() const {
return jit.GetPstate();
return jit->GetPstate();
}
void ARM_Dynarmic::SetCPSR(u32 cpsr) {
jit.SetPstate(cpsr);
jit->SetPstate(cpsr);
}
u64 ARM_Dynarmic::GetTlsAddress() const {
@@ -144,41 +158,41 @@ void ARM_Dynarmic::SetTlsAddress(u64 address) {
void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
cb->ticks_remaining = num_instructions;
jit.Run();
jit->Run();
CoreTiming::AddTicks(num_instructions - cb->num_interpreted_instructions);
cb->num_interpreted_instructions = 0;
}
void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
ctx.cpu_registers = jit.GetRegisters();
ctx.sp = jit.GetSP();
ctx.pc = jit.GetPC();
ctx.cpsr = jit.GetPstate();
ctx.fpu_registers = jit.GetVectors();
ctx.fpscr = jit.GetFpcr();
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
ctx.cpsr = jit->GetPstate();
ctx.fpu_registers = jit->GetVectors();
ctx.fpscr = jit->GetFpcr();
ctx.tls_address = cb->tpidrr0_el0;
}
void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
jit.SetRegisters(ctx.cpu_registers);
jit.SetSP(ctx.sp);
jit.SetPC(ctx.pc);
jit.SetPstate(static_cast<u32>(ctx.cpsr));
jit.SetVectors(ctx.fpu_registers);
jit.SetFpcr(static_cast<u32>(ctx.fpscr));
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
jit->SetPstate(static_cast<u32>(ctx.cpsr));
jit->SetVectors(ctx.fpu_registers);
jit->SetFpcr(static_cast<u32>(ctx.fpscr));
cb->tpidrr0_el0 = ctx.tls_address;
}
void ARM_Dynarmic::PrepareReschedule() {
if (jit.IsExecuting()) {
jit.HaltExecution();
if (jit->IsExecuting()) {
jit->HaltExecution();
}
}
void ARM_Dynarmic::ClearInstructionCache() {
jit.ClearCache();
jit->ClearCache();
}
void ARM_Dynarmic::PageTableChanged() {
UNIMPLEMENTED();
jit = MakeJit(cb);
}

View File

@@ -45,6 +45,6 @@ public:
private:
friend class ARM_Dynarmic_Callbacks;
std::unique_ptr<ARM_Dynarmic_Callbacks> cb;
Dynarmic::A64::Jit jit;
std::unique_ptr<Dynarmic::A64::Jit> jit;
ARM_Unicorn inner_unicorn;
};

View File

@@ -9,6 +9,9 @@
namespace Service {
namespace Account {
using Uid = std::array<u64, 2>;
static constexpr Uid DEFAULT_USER_ID{0x10ull, 0x20ull};
class IProfile final : public ServiceFramework<IProfile> {
public:
IProfile() : ServiceFramework("IProfile") {
@@ -61,6 +64,15 @@ void ACC_U0::GetUserExistence(Kernel::HLERequestContext& ctx) {
rb.Push(true); // TODO: Check when this is supposed to return true and when not
}
void ACC_U0::ListAllUsers(Kernel::HLERequestContext& ctx) {
constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID};
const auto& output_buffer = ctx.BufferDescriptorC()[0];
Memory::WriteBlock(output_buffer.Address(), user_ids.data(), user_ids.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_DEBUG(Service_ACC, "called");
}
void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -85,13 +97,13 @@ void ACC_U0::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0x0);
rb.Push<u64>(0x0);
rb.PushRaw(DEFAULT_USER_ID);
}
ACC_U0::ACC_U0() : ServiceFramework("acc:u0") {
static const FunctionInfo functions[] = {
{1, &ACC_U0::GetUserExistence, "GetUserExistence"},
{2, &ACC_U0::ListAllUsers, "ListAllUsers"},
{4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"},
{5, &ACC_U0::GetProfile, "GetProfile"},
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},

View File

@@ -28,6 +28,7 @@ public:
private:
void GetUserExistence(Kernel::HLERequestContext& ctx);
void ListAllUsers(Kernel::HLERequestContext& ctx);
void GetLastOpenedUser(Kernel::HLERequestContext& ctx);
void GetProfile(Kernel::HLERequestContext& ctx);
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
namespace Service {
namespace Nvidia {
@@ -40,9 +41,16 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlAllocSpace params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, pages=%x, page_size=%x, flags=%x", params.pages,
params.page_size, params.flags);
params.offset = 0xdeadbeef; // TODO(ogniK): Actually allocate space and give a real offset
LOG_DEBUG(Service_NVDRV, "called, pages=%x, page_size=%x, flags=%x", params.pages,
params.page_size, params.flags);
const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)};
if (params.flags & 1) {
params.offset = memory_manager->AllocateSpace(params.offset, size, 1);
} else {
params.offset = memory_manager->AllocateSpace(size, params.align);
}
std::memcpy(output.data(), &params, output.size());
return 0;
}
@@ -51,12 +59,24 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
IoctlMapBufferEx params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV,
"(STUBBED) called, flags=%x, nvmap_handle=%x, buffer_offset=%lx, mapping_size=%lx, "
"offset=%lx",
params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
params.offset);
params.offset = 0x0; // TODO(ogniK): Actually map and give a real offset
LOG_DEBUG(Service_NVDRV,
"called, flags=%x, nvmap_handle=%x, buffer_offset=%lx, mapping_size=%lx, offset=%lx",
params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
params.offset);
if (!params.nvmap_handle) {
return 0;
}
auto object = nvmap_dev->GetObject(params.nvmap_handle);
ASSERT(object);
if (params.flags & 1) {
params.offset = memory_manager->MapBufferEx(object->addr, params.offset, object->size);
} else {
params.offset = memory_manager->MapBufferEx(object->addr, object->size);
}
std::memcpy(output.data(), &params, output.size());
return 0;
}

View File

@@ -4,18 +4,25 @@
#pragma once
#include <memory>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvdrv/memory_manager.h"
namespace Service {
namespace Nvidia {
namespace Devices {
class nvmap;
class nvhost_as_gpu final : public nvdevice {
public:
nvhost_as_gpu() = default;
nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {
memory_manager = std::make_shared<MemoryManager>();
}
~nvhost_as_gpu() override = default;
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
@@ -92,6 +99,9 @@ private:
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
std::shared_ptr<nvmap> nvmap_dev;
std::shared_ptr<MemoryManager> memory_manager;
};
} // namespace Devices

View File

@@ -104,8 +104,20 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
}
u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
std::memset(output.data(), 0, output.size());
LOG_DEBUG(Service_NVDRV, "called");
IoctlNvgpuGpuZcullGetInfoArgs params{};
std::memcpy(&params, input.data(), input.size());
params.width_align_pixels = 0x20;
params.height_align_pixels = 0x20;
params.pixel_squares_by_aliquots = 0x400;
params.aliquot_total = 0x800;
params.region_byte_multiplier = 0x20;
params.region_header_size = 0x20;
params.subregion_header_size = 0xc0;
params.subregion_width_align_pixels = 0x20;
params.subregion_height_align_pixels = 0x40;
params.subregion_count = 0x10;
std::memcpy(output.data(), &params, output.size());
return 0;
}

View File

@@ -13,10 +13,8 @@ namespace Nvidia {
namespace Devices {
VAddr nvmap::GetObjectAddress(u32 handle) const {
auto itr = handles.find(handle);
ASSERT(itr != handles.end());
auto object = itr->second;
auto object = GetObject(handle);
ASSERT(object);
ASSERT(object->status == Object::Status::Allocated);
return object->addr;
}
@@ -52,7 +50,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
u32 handle = next_handle++;
handles[handle] = std::move(object);
LOG_WARNING(Service_NVDRV, "(STUBBED) size 0x%08X", params.size);
LOG_DEBUG(Service_NVDRV, "size=0x%08X", params.size);
params.handle = handle;
@@ -64,17 +62,16 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
IocAllocParams params;
std::memcpy(&params, input.data(), sizeof(params));
auto itr = handles.find(params.handle);
ASSERT(itr != handles.end());
auto object = GetObject(params.handle);
ASSERT(object);
auto object = itr->second;
object->flags = params.flags;
object->align = params.align;
object->kind = params.kind;
object->addr = params.addr;
object->status = Object::Status::Allocated;
LOG_WARNING(Service_NVDRV, "(STUBBED) Allocated address 0x%llx", params.addr);
LOG_DEBUG(Service_NVDRV, "called, addr=0x%llx", params.addr);
std::memcpy(output.data(), &params, sizeof(params));
return 0;
@@ -86,10 +83,10 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "called");
auto itr = handles.find(params.handle);
ASSERT(itr != handles.end());
auto object = GetObject(params.handle);
ASSERT(object);
params.id = itr->second->id;
params.id = object->id;
std::memcpy(output.data(), &params, sizeof(params));
return 0;
@@ -123,10 +120,8 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called type=%u", params.type);
auto itr = handles.find(params.handle);
ASSERT(itr != handles.end());
auto object = itr->second;
auto object = GetObject(params.handle);
ASSERT(object);
ASSERT(object->status == Object::Status::Allocated);
switch (static_cast<ParamTypes>(params.type)) {

View File

@@ -26,8 +26,7 @@ public:
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
private:
// Represents an nvmap object.
/// Represents an nvmap object.
struct Object {
enum class Status { Created, Allocated };
u32 id;
@@ -39,10 +38,19 @@ private:
Status status;
};
std::shared_ptr<Object> GetObject(u32 handle) const {
auto itr = handles.find(handle);
if (itr != handles.end()) {
return itr->second;
}
return {};
}
private:
/// Id to use for the next handle that is created.
u32 next_handle = 1;
// Id to use for the next object that is created.
/// Id to use for the next object that is created.
u32 next_id = 1;
/// Mapping of currently allocated handles to the objects they represent.

View File

@@ -78,11 +78,10 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
u32 event_id = rp.Pop<u32>();
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd=%x, event_id=%x", fd, event_id);
IPC::ResponseBuilder rb{ctx, 2, 1};
IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(RESULT_SUCCESS);
auto event = Kernel::Event::Create(Kernel::ResetType::Pulse, "NVEvent");
event->Signal();
rb.PushCopyObjects(event);
rb.PushCopyObjects(query_event);
rb.Push<u32>(0);
}
void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
@@ -113,6 +112,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
{13, &NVDRV::FinishInitialize, "FinishInitialize"},
};
RegisterHandlers(functions);
query_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NVDRV::query_event");
}
} // namespace Nvidia

View File

@@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include "core/hle/kernel/event.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
@@ -29,6 +30,8 @@ private:
std::shared_ptr<Module> nvdrv;
u64 pid{};
Kernel::SharedPtr<Kernel::Event> query_event;
};
} // namespace Nvidia

View File

@@ -0,0 +1,112 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/hle/service/nvdrv/memory_manager.h"
namespace Service {
namespace Nvidia {
PAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
boost::optional<PAddr> paddr = FindFreeBlock(size, align);
ASSERT(paddr);
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
PageSlot(*paddr + offset) = static_cast<u64>(PageStatus::Allocated);
}
return *paddr;
}
PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) {
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
if (IsPageMapped(paddr + offset)) {
return AllocateSpace(size, align);
}
}
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
PageSlot(paddr + offset) = static_cast<u64>(PageStatus::Allocated);
}
return paddr;
}
PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) {
vaddr &= ~Memory::PAGE_MASK;
boost::optional<PAddr> paddr = FindFreeBlock(size);
ASSERT(paddr);
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
PageSlot(*paddr + offset) = vaddr + offset;
}
return *paddr;
}
PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) {
vaddr &= ~Memory::PAGE_MASK;
paddr &= ~Memory::PAGE_MASK;
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
if (PageSlot(paddr + offset) != static_cast<u64>(PageStatus::Allocated)) {
return MapBufferEx(vaddr, size);
}
}
for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
PageSlot(paddr + offset) = vaddr + offset;
}
return paddr;
}
boost::optional<PAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
PAddr paddr{};
u64 free_space{};
align = (align + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
while (paddr + free_space < MAX_ADDRESS) {
if (!IsPageMapped(paddr + free_space)) {
free_space += Memory::PAGE_SIZE;
if (free_space >= size) {
return paddr;
}
} else {
paddr += free_space + Memory::PAGE_SIZE;
free_space = 0;
const u64 remainder{paddr % align};
if (!remainder) {
paddr = (paddr - remainder) + align;
}
}
}
return {};
}
VAddr MemoryManager::PhysicalToVirtualAddress(PAddr paddr) {
VAddr base_addr = PageSlot(paddr);
ASSERT(base_addr != static_cast<u64>(PageStatus::Unmapped));
return base_addr + (paddr & Memory::PAGE_MASK);
}
bool MemoryManager::IsPageMapped(PAddr paddr) {
return PageSlot(paddr) != static_cast<u64>(PageStatus::Unmapped);
}
VAddr& MemoryManager::PageSlot(PAddr paddr) {
auto& block = page_table[(paddr >> (Memory::PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
if (!block) {
block = std::make_unique<PageBlock>();
for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) {
(*block)[index] = static_cast<u64>(PageStatus::Unmapped);
}
}
return (*block)[(paddr >> Memory::PAGE_BITS) & PAGE_BLOCK_MASK];
}
} // namespace Nvidia
} // namespace Service

View File

@@ -0,0 +1,48 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <memory>
#include "common/common_types.h"
#include "core/memory.h"
namespace Service {
namespace Nvidia {
class MemoryManager final {
public:
MemoryManager() = default;
PAddr AllocateSpace(u64 size, u64 align);
PAddr AllocateSpace(PAddr paddr, u64 size, u64 align);
PAddr MapBufferEx(VAddr vaddr, u64 size);
PAddr MapBufferEx(VAddr vaddr, PAddr paddr, u64 size);
VAddr PhysicalToVirtualAddress(PAddr paddr);
private:
boost::optional<PAddr> FindFreeBlock(u64 size, u64 align = 1);
bool IsPageMapped(PAddr paddr);
VAddr& PageSlot(PAddr paddr);
enum class PageStatus : u64 {
Unmapped = 0xFFFFFFFFFFFFFFFFULL,
Allocated = 0xFFFFFFFFFFFFFFFEULL,
};
static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
static constexpr u64 PAGE_TABLE_BITS{14};
static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
static constexpr u64 PAGE_TABLE_MASK{PAGE_TABLE_SIZE - 1};
static constexpr u64 PAGE_BLOCK_BITS{14};
static constexpr u64 PAGE_BLOCK_SIZE{1 << PAGE_BLOCK_BITS};
static constexpr u64 PAGE_BLOCK_MASK{PAGE_BLOCK_SIZE - 1};
using PageBlock = std::array<VAddr, PAGE_BLOCK_SIZE>;
std::array<std::unique_ptr<PageBlock>, PAGE_TABLE_SIZE> page_table{};
};
} // namespace Nvidia
} // namespace Service

View File

@@ -31,7 +31,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
Module::Module() {
auto nvmap_dev = std::make_shared<Devices::nvmap>();
devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>();
devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(nvmap_dev);
devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>();
devices["/dev/nvmap"] = nvmap_dev;
devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);

View File

@@ -657,7 +657,7 @@ void IApplicationDisplayService::CloseDisplay(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u64 display_id = rp.Pop<u64>();
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}