Improve NvDevice Registration + Access

This commit is contained in:
◱ PixelyIon 2020-09-18 02:08:23 +05:30 committed by ◱ PixelyIon
parent 4cc3a3b2e8
commit 20253a9573
18 changed files with 149 additions and 166 deletions

3
.gitmodules vendored
View File

@ -14,3 +14,6 @@
[submodule "app/libraries/lz4"] [submodule "app/libraries/lz4"]
path = app/libraries/lz4 path = app/libraries/lz4
url = https://github.com/lz4/lz4.git url = https://github.com/lz4/lz4.git
[submodule "app/libraries/frozen"]
path = app/libraries/frozen
url = https://github.com/serge-sans-paille/frozen

View File

@ -7,6 +7,22 @@
<option name="FORMATTER_OFF_TAG" value="@fmt:off" /> <option name="FORMATTER_OFF_TAG" value="@fmt:off" />
<option name="SOFT_MARGINS" value="80,140" /> <option name="SOFT_MARGINS" value="80,140" />
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="SPACE_BEFORE_TYPE_COLON" value="true" /> <option name="SPACE_BEFORE_TYPE_COLON" value="true" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<Objective-C> <Objective-C>

1
.idea/vcs.xml generated
View File

@ -3,6 +3,7 @@
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" /> <mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/libraries/fmt" vcs="Git" /> <mapping directory="$PROJECT_DIR$/app/libraries/fmt" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/libraries/frozen" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/libraries/lz4" vcs="Git" /> <mapping directory="$PROJECT_DIR$/app/libraries/lz4" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/libraries/oboe" vcs="Git" /> <mapping directory="$PROJECT_DIR$/app/libraries/oboe" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/libraries/tinyxml2" vcs="Git" /> <mapping directory="$PROJECT_DIR$/app/libraries/tinyxml2" vcs="Git" />

View File

@ -22,6 +22,7 @@ add_subdirectory("libraries/lz4/contrib/cmake_unofficial")
include_directories("libraries/lz4/lib") include_directories("libraries/lz4/lib")
include_directories("libraries/oboe/include") include_directories("libraries/oboe/include")
include_directories("libraries/vkhpp/include") include_directories("libraries/vkhpp/include")
include_directories("libraries/frozen/include")
set(CMAKE_POLICY_DEFAULT_CMP0048 NEW) set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
find_package(mbedtls REQUIRED CONFIG) find_package(mbedtls REQUIRED CONFIG)
@ -114,6 +115,7 @@ add_library(skyline SHARED
${source_DIR}/skyline/services/fssrv/IStorage.cpp ${source_DIR}/skyline/services/fssrv/IStorage.cpp
${source_DIR}/skyline/services/nvdrv/INvDrvServices.cpp ${source_DIR}/skyline/services/nvdrv/INvDrvServices.cpp
${source_DIR}/skyline/services/nvdrv/driver.cpp ${source_DIR}/skyline/services/nvdrv/driver.cpp
${source_DIR}/skyline/services/nvdrv/devices/nvdevice.cpp
${source_DIR}/skyline/services/nvdrv/devices/nvmap.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvmap.cpp
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp

View File

@ -4,11 +4,11 @@ apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 30 compileSdkVersion 30
buildToolsVersion '30.0.0' buildToolsVersion '30.0.2'
defaultConfig { defaultConfig {
applicationId "skyline.emu" applicationId "skyline.emu"
minSdkVersion 26 minSdkVersion 26
targetSdkVersion 29 targetSdkVersion 30
versionCode 3 versionCode 3
versionName "0.3" versionName "0.3"
ndk { ndk {
@ -59,7 +59,7 @@ android {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.preference:preference:1.1.1'
implementation 'com.google.android.material:material:1.3.0-alpha02' implementation 'com.google.android.material:material:1.3.0-alpha02'
implementation "androidx.core:core-ktx:1.3.1" implementation "androidx.core:core-ktx:1.3.1"

1
app/libraries/frozen Submodule

@ -0,0 +1 @@
Subproject commit 30b475274c044f456c37b6d15de3d04c85112698

View File

@ -8,21 +8,24 @@
#include <span> #include <span>
#include <vector> #include <vector>
#include <fstream> #include <fstream>
#include <syslog.h>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <string> #include <string>
#include <sstream>
#include <memory>
#include <fmt/format.h>
#include <sys/mman.h>
#include <cstdint> #include <cstdint>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <sstream>
#include <memory>
#include <syslog.h>
#include <sys/mman.h>
#include <fmt/format.h>
#include <frozen/unordered_map.h>
#include <frozen/string.h>
#include <jni.h> #include <jni.h>
#include "nce/guest_common.h" #include "nce/guest_common.h"
namespace skyline { namespace skyline {
namespace frz = frozen;
using KHandle = u32; //!< The type of a kernel handle using KHandle = u32; //!< The type of a kernel handle
/** /**
@ -194,6 +197,10 @@ namespace skyline {
} }
return result; return result;
} }
constexpr std::size_t Hash(const std::string_view& view) {
return frz::elsa<frz::string>{}(frz::string(view.data(), view.size()), 0);
}
} }
/** /**

View File

@ -124,7 +124,7 @@ namespace skyline::service::hosbinder {
std::shared_ptr<nvdrv::device::NvMap::NvMapObject> nvBuffer{}; std::shared_ptr<nvdrv::device::NvMap::NvMapObject> nvBuffer{};
auto driver = nvdrv::driver.lock(); auto driver = nvdrv::driver.lock();
auto nvmap = driver->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap); auto nvmap = driver->nvMap.lock();
if (gbpBuffer.nvmapHandle) { if (gbpBuffer.nvmapHandle) {
nvBuffer = nvmap->handleTable.at(gbpBuffer.nvmapHandle); nvBuffer = nvmap->handleTable.at(gbpBuffer.nvmapHandle);

View File

@ -0,0 +1,34 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include "nvdevice.h"
namespace skyline::service::nvdrv::device {
NvDevice::NvDevice(const DeviceState &state, std::unordered_map <u32, std::function<void(IoctlData &)>> vTable) : state(state), vTable(vTable) {}
std::string NvDevice::GetName() {
int status{};
size_t length{};
auto mangledName{typeid(*this).name()};
std::unique_ptr<char, decltype(&std::free)> demangled{ abi::__cxa_demangle(mangledName, nullptr, &length, &status), std::free};
return (status == 0) ? std::string(demangled.get() + std::char_traits<char>::length("skyline::service::nvdrv::device")) : mangledName;
}
void NvDevice::HandleIoctl(u32 cmd, IoctlData &input) {
std::function<void(IoctlData &)> function;
try {
function = vTable.at(cmd);
} catch (std::out_of_range &) {
state.logger->Warn("Cannot find IOCTL for device '{}': 0x{:X}", GetName(), cmd);
input.status = NvStatus::NotImplemented;
return;
}
try {
function(input);
} catch (std::exception &e) {
throw exception("{} (Device: {})", e.what(), GetName());
}
}
}

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <cxxabi.h>
#include <common.h> #include <common.h>
#include <kernel/ipc.h> #include <kernel/ipc.h>
#include <kernel/types/KEvent.h> #include <kernel/types/KEvent.h>
@ -12,54 +13,6 @@
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
using namespace kernel; using namespace kernel;
/**
* @brief An enumeration of all the devices that can be opened by nvdrv
*/
enum class NvDeviceType {
nvhost_ctrl, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-ctrl
nvhost_gpu, //!< https://switchbrew.org/wiki/NV_services#Channels
nvhost_nvdec, //!< https://switchbrew.org/wiki/NV_services#Channels
nvhost_vic, //!< https://switchbrew.org/wiki/NV_services#Channels
nvmap, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvmap
nvdisp_ctrl, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvdisp-ctrl
nvdisp_disp0, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvdisp-disp0.2C_.2Fdev.2Fnvdisp-disp1
nvdisp_disp1, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvdisp-disp0.2C_.2Fdev.2Fnvdisp-disp1
nvcec_ctrl, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvcec-ctrl
nvhdcp_up_ctrl, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhdcp_up-ctrl
nvdcutil_disp0, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvdcutil-disp0.2C_.2Fdev.2Fnvdcutil-disp1
nvdcutil_disp1, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvdcutil-disp0.2C_.2Fdev.2Fnvdcutil-disp1
nvsched_ctrl, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvsched-ctrl
nverpt_ctrl, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnverpt-ctrl
nvhost_as_gpu, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-as-gpu
nvhost_dbg_gpu, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-dbg-gpu
nvhost_prof_gpu, //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-prof-gpu
nvhost_ctrl_gpu //!< https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-ctrl-gpu
};
/**
* @brief A mapping from a device's path to it's nvDevice entry
*/
const static std::unordered_map<std::string, NvDeviceType> nvDeviceMap{
{"/dev/nvhost-ctrl", NvDeviceType::nvhost_ctrl},
{"/dev/nvhost-gpu", NvDeviceType::nvhost_gpu},
{"/dev/nvhost-nvdec", NvDeviceType::nvhost_nvdec},
{"/dev/nvhost-vic", NvDeviceType::nvhost_vic},
{"/dev/nvmap", NvDeviceType::nvmap},
{"/dev/nvdisp-ctrl", NvDeviceType::nvdisp_ctrl},
{"/dev/nvdisp-disp0", NvDeviceType::nvdisp_disp0},
{"/dev/nvdisp-disp1", NvDeviceType::nvdisp_disp1},
{"/dev/nvcec-ctrl", NvDeviceType::nvcec_ctrl},
{"/dev/nvhdcp_up-ctrl", NvDeviceType::nvhdcp_up_ctrl},
{"/dev/nvdcutil-disp0", NvDeviceType::nvdcutil_disp0},
{"/dev/nvdcutil-disp1", NvDeviceType::nvdcutil_disp1},
{"/dev/nvsched-ctrl", NvDeviceType::nvsched_ctrl},
{"/dev/nverpt-ctrl", NvDeviceType::nverpt_ctrl},
{"/dev/nvhost-as-gpu", NvDeviceType::nvhost_as_gpu},
{"/dev/nvhost-dbg-gpu", NvDeviceType::nvhost_dbg_gpu},
{"/dev/nvhost-prof-gpu", NvDeviceType::nvhost_prof_gpu},
{"/dev/nvhost-ctrl-gpu", NvDeviceType::nvhost_ctrl_gpu},
};
/** /**
* @brief This enumerates all the possible error codes returned by the Nvidia driver (https://switchbrew.org/wiki/NV_services#Errors) * @brief This enumerates all the possible error codes returned by the Nvidia driver (https://switchbrew.org/wiki/NV_services#Errors)
*/ */
@ -134,7 +87,7 @@ namespace skyline::service::nvdrv::device {
}; };
/** /**
* @brief NvDevice is the base class all /dev/nv* devices inherit from * @brief NvDevice is the base class that all /dev/nv* devices inherit from
*/ */
class NvDevice { class NvDevice {
protected: protected:
@ -142,53 +95,27 @@ namespace skyline::service::nvdrv::device {
std::unordered_map<u32, std::function<void(IoctlData &)>> vTable; //!< This holds the mapping from an Ioctl to the actual function std::unordered_map<u32, std::function<void(IoctlData &)>> vTable; //!< This holds the mapping from an Ioctl to the actual function
public: public:
u16 refCount{1}; //!< The amount of handles to the device
NvDeviceType deviceType; //!< The type of the device
/** /**
* @param state The state of the device * @param state The state of the device
* @param deviceType The type of the device
* @param vTable The functions in this device * @param vTable The functions in this device
*/ */
NvDevice(const DeviceState &state, NvDeviceType deviceType, std::unordered_map<u32, std::function<void(IoctlData &)>> vTable) : state(state), deviceType(deviceType), vTable(vTable) {} NvDevice(const DeviceState &state, std::unordered_map<u32, std::function<void(IoctlData & )>> vTable);
virtual ~NvDevice() = default; virtual ~NvDevice() = default;
/** /**
* @brief This returns the name of the current service * @return The name of the class
* @note It may not return the exact name the service was initialized with if there are multiple entries in ServiceString
* @return The name of the service
*/ */
std::string getName() { std::string GetName();
std::string serviceName;
for (const auto&[name, type] : nvDeviceMap)
if (type == deviceType)
serviceName = name;
return serviceName;
}
/** /**
* @brief This handles IOCTL calls for devices * @brief This handles IOCTL calls for devices
* @param cmd The IOCTL command that was called * @param cmd The IOCTL command that was called
* @param input The input to the IOCTL call * @param input The input to the IOCTL call
*/ */
void HandleIoctl(u32 cmd, IoctlData &input) { void HandleIoctl(u32 cmd, IoctlData &input);
std::function<void(IoctlData &)> function;
try {
function = vTable.at(cmd);
} catch (std::out_of_range &) {
state.logger->Warn("Cannot find IOCTL for device '{}': 0x{:X}", getName(), cmd);
input.status = NvStatus::NotImplemented;
return;
}
try {
function(input);
} catch (std::exception &e) {
throw exception("{} (Device: {})", e.what(), getName());
}
}
virtual std::shared_ptr<kernel::type::KEvent> QueryEvent(u32 eventId) { inline virtual std::shared_ptr<kernel::type::KEvent> QueryEvent(u32 eventId) {
return nullptr; return nullptr;
} }
}; };

View File

@ -9,7 +9,7 @@
#include "nvhost_as_gpu.h" #include "nvhost_as_gpu.h"
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
NvHostAsGpu::NvHostAsGpu(const DeviceState &state) : NvDevice(state, NvDeviceType::nvhost_as_gpu, { NvHostAsGpu::NvHostAsGpu(const DeviceState &state) : NvDevice(state, {
{0x4101, NFUNC(NvHostAsGpu::BindChannel)}, {0x4101, NFUNC(NvHostAsGpu::BindChannel)},
{0x4102, NFUNC(NvHostAsGpu::AllocSpace)}, {0x4102, NFUNC(NvHostAsGpu::AllocSpace)},
{0x4105, NFUNC(NvHostAsGpu::UnmapBuffer)}, {0x4105, NFUNC(NvHostAsGpu::UnmapBuffer)},
@ -71,10 +71,11 @@ namespace skyline::service::nvdrv::device {
return; return;
auto driver = nvdrv::driver.lock(); auto driver = nvdrv::driver.lock();
auto nvmap = driver->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(region.nvmapHandle); auto nvmap = driver->nvMap.lock();
auto mapping = nvmap->handleTable.at(region.nvmapHandle);
u64 mapPhysicalAddress = region.bufferOffset + nvmap->address; u64 mapPhysicalAddress = region.bufferOffset + mapping->address;
u64 mapSize = region.mappingSize ? region.mappingSize : nvmap->size; u64 mapSize = region.mappingSize ? region.mappingSize : mapping->size;
if (region.flags & 1) if (region.flags & 1)
region.offset = state.gpu->memoryManager.MapFixed(region.offset, mapPhysicalAddress, mapSize); region.offset = state.gpu->memoryManager.MapFixed(region.offset, mapPhysicalAddress, mapSize);
@ -135,10 +136,11 @@ namespace skyline::service::nvdrv::device {
for (auto entry : entries) { for (auto entry : entries) {
try { try {
auto driver = nvdrv::driver.lock(); auto driver = nvdrv::driver.lock();
auto nvmap = driver->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(entry.nvmapHandle); auto nvmap = driver->nvMap.lock();
auto mapping = nvmap->handleTable.at(entry.nvmapHandle);
u64 mapAddress = static_cast<u64>(entry.gpuOffset) << MinAlignmentShift; u64 mapAddress = static_cast<u64>(entry.gpuOffset) << MinAlignmentShift;
u64 mapPhysicalAddress = nvmap->address + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift); u64 mapPhysicalAddress = mapping->address + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift);
u64 mapSize = static_cast<u64>(entry.pages) << MinAlignmentShift; u64 mapSize = static_cast<u64>(entry.pages) << MinAlignmentShift;
state.gpu->memoryManager.MapFixed(mapAddress, mapPhysicalAddress, mapSize); state.gpu->memoryManager.MapFixed(mapAddress, mapPhysicalAddress, mapSize);

View File

@ -8,7 +8,7 @@
#include "nvhost_channel.h" #include "nvhost_channel.h"
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
NvHostChannel::NvHostChannel(const DeviceState &state, NvDeviceType type) : smExceptionBreakpointIntReportEvent(std::make_shared<type::KEvent>(state)), smExceptionBreakpointPauseReportEvent(std::make_shared<type::KEvent>(state)), errorNotifierEvent(std::make_shared<type::KEvent>(state)), NvDevice(state, type, { NvHostChannel::NvHostChannel(const DeviceState &state) : smExceptionBreakpointIntReportEvent(std::make_shared<type::KEvent>(state)), smExceptionBreakpointPauseReportEvent(std::make_shared<type::KEvent>(state)), errorNotifierEvent(std::make_shared<type::KEvent>(state)), NvDevice(state, {
{0x4801, NFUNC(NvHostChannel::SetNvmapFd)}, {0x4801, NFUNC(NvHostChannel::SetNvmapFd)},
{0x4803, NFUNC(NvHostChannel::SetSubmitTimeout)}, {0x4803, NFUNC(NvHostChannel::SetSubmitTimeout)},
{0x4808, NFUNC(NvHostChannel::SubmitGpfifo)}, {0x4808, NFUNC(NvHostChannel::SubmitGpfifo)},

View File

@ -25,7 +25,7 @@ namespace skyline::service::nvdrv::device {
std::shared_ptr<type::KEvent> errorNotifierEvent; std::shared_ptr<type::KEvent> errorNotifierEvent;
public: public:
NvHostChannel(const DeviceState &state, NvDeviceType type); NvHostChannel(const DeviceState &state);
/** /**
* @brief This sets the nvmap file descriptor (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD) * @brief This sets the nvmap file descriptor (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD)

View File

@ -37,7 +37,7 @@ namespace skyline::service::nvdrv::device {
} }
} }
NvHostCtrl::NvHostCtrl(const DeviceState &state) : NvDevice(state, NvDeviceType::nvhost_ctrl, { NvHostCtrl::NvHostCtrl(const DeviceState &state) : NvDevice(state, {
{0x001B, NFUNC(NvHostCtrl::GetConfig)}, {0x001B, NFUNC(NvHostCtrl::GetConfig)},
{0x001C, NFUNC(NvHostCtrl::EventSignal)}, {0x001C, NFUNC(NvHostCtrl::EventSignal)},
{0x001D, NFUNC(NvHostCtrl::EventWait)}, {0x001D, NFUNC(NvHostCtrl::EventWait)},

View File

@ -5,7 +5,7 @@
#include "nvhost_ctrl_gpu.h" #include "nvhost_ctrl_gpu.h"
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
NvHostCtrlGpu::NvHostCtrlGpu(const DeviceState &state) : errorNotifierEvent(std::make_shared<type::KEvent>(state)), unknownEvent(std::make_shared<type::KEvent>(state)), NvDevice(state, NvDeviceType::nvhost_ctrl_gpu, { NvHostCtrlGpu::NvHostCtrlGpu(const DeviceState &state) : errorNotifierEvent(std::make_shared<type::KEvent>(state)), unknownEvent(std::make_shared<type::KEvent>(state)), NvDevice(state, {
{0x4701, NFUNC(NvHostCtrlGpu::ZCullGetCtxSize)}, {0x4701, NFUNC(NvHostCtrlGpu::ZCullGetCtxSize)},
{0x4702, NFUNC(NvHostCtrlGpu::ZCullGetInfo)}, {0x4702, NFUNC(NvHostCtrlGpu::ZCullGetInfo)},
{0x4706, NFUNC(NvHostCtrlGpu::GetTpcMasks)}, {0x4706, NFUNC(NvHostCtrlGpu::GetTpcMasks)},

View File

@ -7,7 +7,7 @@
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
NvMap::NvMapObject::NvMapObject(u32 id, u32 size) : id(id), size(size) {} NvMap::NvMapObject::NvMapObject(u32 id, u32 size) : id(id), size(size) {}
NvMap::NvMap(const DeviceState &state) : NvDevice(state, NvDeviceType::nvmap, { NvMap::NvMap(const DeviceState &state) : NvDevice(state, {
{0x0101, NFUNC(NvMap::Create)}, {0x0101, NFUNC(NvMap::Create)},
{0x0103, NFUNC(NvMap::FromId)}, {0x0103, NFUNC(NvMap::FromId)},
{0x0104, NFUNC(NvMap::Alloc)}, {0x0104, NFUNC(NvMap::Alloc)},

View File

@ -13,56 +13,45 @@ namespace skyline::service::nvdrv {
u32 Driver::OpenDevice(const std::string &path) { u32 Driver::OpenDevice(const std::string &path) {
state.logger->Debug("Opening NVDRV device ({}): {}", fdIndex, path); state.logger->Debug("Opening NVDRV device ({}): {}", fdIndex, path);
auto type = device::nvDeviceMap.at(path);
for (const auto &device : fdMap) { switch (util::Hash(path)) {
if (device.second->deviceType == type) { #define NVDEVICE(type, name, devicePath) \
device.second->refCount++; case util::Hash(devicePath): { \
fdMap[fdIndex] = device.second; std::shared_ptr<device::type> device{}; \
return fdIndex++; if (name.expired()) { \
device = device.make_shared(state); \
name = device; \
} else { \
device = name.lock(); \
} \
devices.push_back(device); \
break; \
} }
} NVDEVICE_LIST
#undef NVDEVICE
std::shared_ptr<device::NvDevice> object;
switch (type) {
case device::NvDeviceType::nvhost_ctrl:
object = std::make_shared<device::NvHostCtrl>(state);
break;
case device::NvDeviceType::nvhost_gpu:
case device::NvDeviceType::nvhost_vic:
case device::NvDeviceType::nvhost_nvdec:
object = std::make_shared<device::NvHostChannel>(state, type);
break;
case device::NvDeviceType::nvhost_ctrl_gpu:
object = std::make_shared<device::NvHostCtrlGpu>(state);
break;
case device::NvDeviceType::nvmap:
object = std::make_shared<device::NvMap>(state);
break;
case device::NvDeviceType::nvhost_as_gpu:
object = std::make_shared<device::NvHostAsGpu>(state);
break;
default: default:
throw exception("Cannot find NVDRV device"); throw exception("Cannot find NVDRV device");
} }
deviceMap[type] = object;
fdMap[fdIndex] = object;
return fdIndex++; return fdIndex++;
} }
void Driver::CloseDevice(skyline::u32 fd) { std::shared_ptr<device::NvDevice> Driver::GetDevice(u32 fd) {
try { try {
auto& device = fdMap.at(fd); auto item = devices.at(fd);
if (!--device->refCount) if (!item)
deviceMap.erase(device->deviceType); throw exception("GetDevice was called with a closed file descriptor: 0x{:X}", fd);
return item;
} catch (std::out_of_range) {
throw exception("GetDevice was called with invalid file descriptor: 0x{:X}", fd);
}
}
fdMap.erase(fd); void Driver::CloseDevice(u32 fd) {
try {
auto &device = devices.at(fd);
device.reset();
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
state.logger->Warn("Trying to close non-existent FD"); state.logger->Warn("Trying to close non-existent FD");
} }

View File

@ -5,10 +5,22 @@
#include "devices/nvhost_syncpoint.h" #include "devices/nvhost_syncpoint.h"
#define NVDEVICE_LIST \
NVDEVICE(NvHostCtrl, nvHostCtrl, "/dev/nvhost-ctrl") \
NVDEVICE(NvHostChannel, nvHostGpu, "/dev/nvhost-gpu") \
NVDEVICE(NvHostChannel, nvHostNvdec, "/dev/nvhost-nvdec") \
NVDEVICE(NvHostChannel, nvHostVic, "/dev/nvhost-vic") \
NVDEVICE(NvMap, nvMap, "/dev/nvmap") \
NVDEVICE(NvHostAsGpu, nvHostAsGpu, "/dev/nvhost-as-gpu") \
NVDEVICE(NvHostCtrlGpu, nvHostCtrlGpu, "/dev/nvhost-ctrl-gpu")
namespace skyline::service::nvdrv { namespace skyline::service::nvdrv {
namespace device { namespace device {
class NvDevice; class NvDevice;
enum class NvDeviceType;
#define NVDEVICE(type, name, path) class type;
NVDEVICE_LIST
#undef NVDEVICE
} }
/** /**
@ -17,13 +29,16 @@ namespace skyline::service::nvdrv {
class Driver { class Driver {
private: private:
const DeviceState &state; const DeviceState &state;
std::unordered_map<device::NvDeviceType, std::shared_ptr<device::NvDevice>> deviceMap; //!< A map from a NvDeviceType to the NvDevice object std::vector<std::shared_ptr<device::NvDevice>> devices; //!< A map from an FD to a shared pointer to it's NvDevice object
std::unordered_map<u32, std::shared_ptr<device::NvDevice>> fdMap; //!< A map from an FD to a shared pointer to it's NvDevice object
u32 fdIndex{}; //!< The index of a file descriptor u32 fdIndex{}; //!< The index of a file descriptor
public: public:
NvHostSyncpoint hostSyncpoint; NvHostSyncpoint hostSyncpoint;
#define NVDEVICE(type, name, path) std::weak_ptr<device::type> name;
NVDEVICE_LIST
#undef NVDEVICE
Driver(const DeviceState &state); Driver(const DeviceState &state);
/** /**
@ -34,9 +49,11 @@ namespace skyline::service::nvdrv {
u32 OpenDevice(const std::string &path); u32 OpenDevice(const std::string &path);
/** /**
* @brief Closes the specified device with it's file descriptor * @brief Returns a particular device with a specific FD
* @param fd The file descriptor to retrieve
* @return A shared pointer to the device
*/ */
void CloseDevice(u32 fd); std::shared_ptr<device::NvDevice> GetDevice(u32 fd);
/** /**
* @brief Returns a particular device with a specific FD * @brief Returns a particular device with a specific FD
@ -44,31 +61,15 @@ namespace skyline::service::nvdrv {
* @param fd The file descriptor to retrieve * @param fd The file descriptor to retrieve
* @return A shared pointer to the device * @return A shared pointer to the device
*/ */
template<typename objectClass = device::NvDevice> template<typename objectClass>
std::shared_ptr<objectClass> GetDevice(u32 fd) { inline std::shared_ptr<objectClass> GetDevice(u32 fd) {
try { return std::static_pointer_cast<objectClass>(GetDevice(fd));
auto item = fdMap.at(fd);
return std::static_pointer_cast<objectClass>(item);
} catch (std::out_of_range) {
throw exception("GetDevice was called with invalid file descriptor: 0x{:X}", fd);
}
} }
/** /**
* @brief Returns a particular device with a specific type * @brief Closes the specified device with it's file descriptor
* @tparam objectClass The class of the device to return
* @param type The type of the device to return
* @return A shared pointer to the device
*/ */
template<typename objectClass = device::NvDevice> void CloseDevice(u32 fd);
std::shared_ptr<objectClass> GetDevice(device::NvDeviceType type) {
try {
auto item = deviceMap.at(type);
return std::static_pointer_cast<objectClass>(item);
} catch (std::out_of_range) {
throw exception("GetDevice was called with invalid type: 0x{:X}", type);
}
}
}; };
extern std::weak_ptr<Driver> driver; //!< A globally shared instance of the Driver extern std::weak_ptr<Driver> driver; //!< A globally shared instance of the Driver