skyline/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp

161 lines
5.8 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <kernel/types/KProcess.h>
#include "nvmap.h"
namespace skyline::service::nvdrv::device {
NvMap::NvMapObject::NvMapObject(u32 id, u32 size) : id(id), size(size) {}
NvMap::NvMap(const DeviceState &state) : NvDevice(state, NvDeviceType::nvmap, {
{0xC0080101, NFUNC(NvMap::Create)},
{0xC0080103, NFUNC(NvMap::FromId)},
{0xC0200104, NFUNC(NvMap::Alloc)},
{0xC0180105, NFUNC(NvMap::Free)},
{0xC00C0109, NFUNC(NvMap::Param)},
{0xC008010E, NFUNC(NvMap::GetId)}
}) {}
void NvMap::Create(IoctlData &buffer) {
struct Data {
u32 size; // In
u32 handle; // Out
} data = state.process->GetObject<Data>(buffer.input[0].address);
handleTable[handleIndex] = std::make_shared<NvMapObject>(idIndex++, data.size);
data.handle = handleIndex++;
state.process->WriteMemory(data, buffer.output[0].address);
state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status);
}
void NvMap::FromId(IoctlData &buffer) {
struct Data {
u32 id; // In
u32 handle; // Out
} data = state.process->GetObject<Data>(buffer.input[0].address);
bool found{};
for (const auto &object : handleTable) {
if (object.second->id == data.id) {
data.handle = object.first;
found = true;
break;
}
}
if (found)
state.process->WriteMemory(data, buffer.output[0].address);
else
buffer.status = NvStatus::BadValue;
state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status);
}
void NvMap::Alloc(IoctlData &buffer) {
struct Data {
u32 handle; // In
u32 heapMask; // In
u32 flags; // In
u32 align; // In
u8 kind; // In
u8 _pad0_[7];
u64 address; // InOut
} data = state.process->GetObject<Data>(buffer.input[0].address);
auto &object = handleTable.at(data.handle);
object->heapMask = data.heapMask;
object->flags = data.flags;
object->align = data.align;
object->kind = data.kind;
object->address = data.address;
object->status = NvMapObject::Status::Allocated;
state.logger->Debug("Alloc: Input: Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}, Output: Status: {}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address, buffer.status);
}
void NvMap::Free(IoctlData &buffer) {
struct Data {
u32 handle; // In
u32 _pad0_;
u32 address; // Out
u32 size; // Out
u64 flags; // Out
} data = state.process->GetObject<Data>(buffer.input[0].address);
const auto &object = handleTable.at(data.handle);
if (object.use_count() > 1) {
data.address = static_cast<u32>(object->address);
data.flags = 0x0;
} else {
data.address = 0x0;
data.flags = 0x1; // Not free yet
}
data.size = object->size;
handleTable.erase(data.handle);
state.process->WriteMemory(data, buffer.output[0].address);
}
void NvMap::Param(IoctlData &buffer) {
enum class Parameter : u32 { Size = 1, Alignment = 2, Base = 3, HeapMask = 4, Kind = 5, Compr = 6 }; // https://android.googlesource.com/kernel/tegra/+/refs/heads/android-tegra-flounder-3.10-marshmallow/include/linux/nvmap.h#102
struct Data {
u32 handle; // In
Parameter parameter; // In
u32 result; // Out
} data = state.process->GetObject<Data>(buffer.input[0].address);
auto &object = handleTable.at(data.handle);
switch (data.parameter) {
case Parameter::Size:
data.result = object->size;
break;
case Parameter::Alignment:
case Parameter::HeapMask:
case Parameter::Kind: {
if (object->status != NvMapObject::Status::Allocated)
data.result = NvStatus::BadParameter;
switch (data.parameter) {
case Parameter::Alignment:
data.result = object->align;
break;
case Parameter::HeapMask:
data.result = object->heapMask;
break;
case Parameter::Kind:
data.result = object->kind;
break;
default:
break;
}
break;
}
case Parameter::Base:
buffer.status = NvStatus::NotImplemented;
break;
case Parameter::Compr:
buffer.status = NvStatus::NotImplemented;
break;
}
state.process->WriteMemory(data, buffer.output[0].address);
state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status);
}
void NvMap::GetId(IoctlData &buffer) {
struct Data {
u32 id; // Out
u32 handle; // In
} data = state.process->GetObject<Data>(buffer.input[0].address);
data.id = handleTable.at(data.handle)->id;
state.process->WriteMemory(data, buffer.output[0].address);
state.logger->Debug("GetId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status);
}
}