mirror of
https://github.com/skyline-emu/skyline.git
synced 2025-01-10 20:19:24 +01:00
Extend NvServices and implement IDirectory (#107)
* Fix alignment handling in NvHostAsGpu::AllocSpace * Implement Ioctl{2,3} ioctls These were added in HOS 3.0.0 in order to ease handling ioctl buffers. * Introduce support for GPU address space remapping * Fix nvdrv and am service bugs Syncpoints are supposed to be allocated from ID 1, they were allocated at 0 before. The ioctl functions were also missing from the service map * Fix friend:u service name * Stub NVGPU_IOCTL_CHANNEL_SET_TIMESLICE * Stub IManagerForApplication::CheckAvailability * Add OsFileSystem Directory support and add a size field to directory entries The size field will be needed by the incoming HOS IDirectory support. * Implement support for IDirectory This is used by applications to list the contents of a directory. * Address feedback
This commit is contained in:
parent
7ad86ec46f
commit
85d5dd3619
@ -114,6 +114,7 @@ add_library(skyline SHARED
|
||||
${source_DIR}/skyline/services/fssrv/IFileSystem.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IFile.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IStorage.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IDirectory.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/INvDrvServices.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/driver.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvdevice.cpp
|
||||
|
@ -14,9 +14,9 @@ namespace skyline::gpu::vmm {
|
||||
chunks.push_back(baseChunk);
|
||||
}
|
||||
|
||||
std::optional<ChunkDescriptor> MemoryManager::FindChunk(u64 size, ChunkState state) {
|
||||
auto chunk{std::find_if(chunks.begin(), chunks.end(), [size, state](const ChunkDescriptor &chunk) -> bool {
|
||||
return chunk.size > size && chunk.state == state;
|
||||
std::optional<ChunkDescriptor> MemoryManager::FindChunk(ChunkState state, u64 size, u64 alignment) {
|
||||
auto chunk{std::find_if(chunks.begin(), chunks.end(), [state, size, alignment](const ChunkDescriptor &chunk) -> bool {
|
||||
return (alignment ? util::IsAligned(chunk.address, alignment) : true) && chunk.size > size && chunk.state == state;
|
||||
})};
|
||||
|
||||
if (chunk != chunks.end())
|
||||
@ -83,9 +83,9 @@ namespace skyline::gpu::vmm {
|
||||
throw exception("Failed to insert chunk into GPU address space!");
|
||||
}
|
||||
|
||||
u64 MemoryManager::ReserveSpace(u64 size) {
|
||||
u64 MemoryManager::ReserveSpace(u64 size, u64 alignment) {
|
||||
size = util::AlignUp(size, constant::GpuPageSize);
|
||||
auto newChunk{FindChunk(size, ChunkState::Unmapped)};
|
||||
auto newChunk{FindChunk(ChunkState::Unmapped, size, alignment)};
|
||||
if (!newChunk)
|
||||
return 0;
|
||||
|
||||
@ -98,7 +98,7 @@ namespace skyline::gpu::vmm {
|
||||
|
||||
u64 MemoryManager::ReserveFixed(u64 address, u64 size) {
|
||||
if (!util::IsAligned(address, constant::GpuPageSize))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
size = util::AlignUp(size, constant::GpuPageSize);
|
||||
|
||||
@ -107,7 +107,7 @@ namespace skyline::gpu::vmm {
|
||||
|
||||
u64 MemoryManager::MapAllocate(u64 address, u64 size) {
|
||||
size = util::AlignUp(size, constant::GpuPageSize);
|
||||
auto mappedChunk{FindChunk(size, ChunkState::Unmapped)};
|
||||
auto mappedChunk{FindChunk(ChunkState::Unmapped, size)};
|
||||
if (!mappedChunk)
|
||||
return 0;
|
||||
|
||||
@ -121,26 +121,22 @@ namespace skyline::gpu::vmm {
|
||||
|
||||
u64 MemoryManager::MapFixed(u64 address, u64 cpuAddress, u64 size) {
|
||||
if (!util::IsAligned(address, constant::GpuPageSize))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
size = util::AlignUp(size, constant::GpuPageSize);
|
||||
|
||||
return InsertChunk(ChunkDescriptor(address, size, cpuAddress, ChunkState::Mapped));
|
||||
}
|
||||
|
||||
bool MemoryManager::Unmap(u64 address) {
|
||||
bool MemoryManager::Unmap(u64 address, u64 size) {
|
||||
if (!util::IsAligned(address, constant::GpuPageSize))
|
||||
return false;
|
||||
|
||||
auto chunk{std::find_if(chunks.begin(), chunks.end(), [address](const ChunkDescriptor &chunk) -> bool {
|
||||
return chunk.address == address;
|
||||
})};
|
||||
|
||||
if (chunk == chunks.end())
|
||||
try {
|
||||
InsertChunk(ChunkDescriptor(address, size, 0, ChunkState::Unmapped));
|
||||
} catch (const std::exception &e) {
|
||||
return false;
|
||||
|
||||
chunk->state = ChunkState::Reserved;
|
||||
chunk->cpuAddress = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -43,11 +43,12 @@ namespace skyline {
|
||||
|
||||
/**
|
||||
* @brief Finds a chunk of the specified type in the GPU address space that is larger than the given size
|
||||
* @param state The state of the chunk to find
|
||||
* @param size The minimum size of the chunk to find
|
||||
* @param state The state desired state of the chunk to find
|
||||
* @return The first unmapped chunk in the GPU address space that fits the requested size
|
||||
* @param alignment The alignment of the chunk to find
|
||||
* @return The first unmapped chunk in the GPU address space that fulfils the requested conditions
|
||||
*/
|
||||
std::optional<ChunkDescriptor> FindChunk(u64 size, ChunkState state);
|
||||
std::optional<ChunkDescriptor> FindChunk(ChunkState state, u64 size, u64 alignment = 0);
|
||||
|
||||
/**
|
||||
* @brief Inserts a chunk into the chunk list, resizing and splitting as necessary
|
||||
@ -62,9 +63,10 @@ namespace skyline {
|
||||
/**
|
||||
* @brief Reserves a region of the GPU address space so it will not be chosen automatically when mapping
|
||||
* @param size The size of the region to reserve
|
||||
* @param alignment The alignment of the region to reserve
|
||||
* @return The virtual GPU base address of the region base
|
||||
*/
|
||||
u64 ReserveSpace(u64 size);
|
||||
u64 ReserveSpace(u64 size, u64 alignment);
|
||||
|
||||
/**
|
||||
* @brief Reserves a fixed region of the GPU address space so it will not be chosen automatically when mapping
|
||||
@ -92,10 +94,10 @@ namespace skyline {
|
||||
u64 MapFixed(u64 address, u64 cpuAddress, u64 size);
|
||||
|
||||
/**
|
||||
* @brief Unmaps the chunk that starts at 'offset' from the GPU address space
|
||||
* @brief Unmaps all chunks in the given region from the GPU address space
|
||||
* @return Whether the operation succeeded
|
||||
*/
|
||||
bool Unmap(u64 address);
|
||||
bool Unmap(u64 address, u64 size);
|
||||
|
||||
void Read(u8 *destination, u64 address, u64 size) const;
|
||||
|
||||
|
@ -5,4 +5,8 @@
|
||||
|
||||
namespace skyline::service::account {
|
||||
IManagerForApplication::IManagerForApplication(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
||||
|
||||
Result IManagerForApplication::CheckAvailability(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -13,5 +13,14 @@ namespace skyline::service::account {
|
||||
class IManagerForApplication : public BaseService {
|
||||
public:
|
||||
IManagerForApplication(const DeviceState &state, ServiceManager &manager);
|
||||
|
||||
/**
|
||||
* @brief This checks if the given user has access to online services
|
||||
*/
|
||||
Result CheckAvailability(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
SERVICE_DECL(
|
||||
SFUNC(0x0, IManagerForApplication, CheckAvailability)
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ namespace skyline::service::am {
|
||||
|
||||
Result IStorageAccessor::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto offset{request.Pop<i64>()};
|
||||
auto size{std::min(static_cast<i64>(request.inputBuf.at(0).size()), static_cast<i64>(parent->content.size()) - offset)};
|
||||
auto size{std::min(static_cast<i64>(request.outputBuf.at(0).size()), static_cast<i64>(parent->content.size()) - offset)};
|
||||
|
||||
if (offset > parent->content.size())
|
||||
return result::OutOfBounds;
|
||||
|
46
app/src/main/cpp/skyline/services/fssrv/IDirectory.cpp
Normal file
46
app/src/main/cpp/skyline/services/fssrv/IDirectory.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include "results.h"
|
||||
#include "IDirectory.h"
|
||||
|
||||
namespace skyline::service::fssrv {
|
||||
struct __attribute__((packed)) DirectoryEntry {
|
||||
std::array<char, 0x301> name;
|
||||
|
||||
struct {
|
||||
bool directory : 1;
|
||||
bool archive : 1;
|
||||
u8 _pad_ : 6;
|
||||
} attributes;
|
||||
|
||||
u16 _pad0_;
|
||||
vfs::Directory::EntryType type;
|
||||
u8 _pad1_[3];
|
||||
u64 size;
|
||||
};
|
||||
|
||||
IDirectory::IDirectory(std::shared_ptr<vfs::Directory> backing, std::shared_ptr<vfs::FileSystem> backingFs, const DeviceState &state, ServiceManager &manager) : backing(backing), backingFs(backingFs), BaseService(state, manager) {}
|
||||
|
||||
Result IDirectory::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto entries{backing->Read()};
|
||||
auto outputEntries{request.inputBuf.at(0).cast<DirectoryEntry>()};
|
||||
size_t i{};
|
||||
|
||||
for (; i < std::min(entries.size(), outputEntries.size()); i++) {
|
||||
auto &entry{entries.at(i)};
|
||||
|
||||
outputEntries[i] = {
|
||||
.type = entry.type,
|
||||
.attributes.directory = (entry.type == vfs::Directory::EntryType::Directory),
|
||||
.size = entry.size,
|
||||
};
|
||||
|
||||
span(outputEntries[i].name).copy_from(entry.name);
|
||||
}
|
||||
|
||||
response.Push<u64>(i);
|
||||
return {};
|
||||
}
|
||||
}
|
33
app/src/main/cpp/skyline/services/fssrv/IDirectory.h
Normal file
33
app/src/main/cpp/skyline/services/fssrv/IDirectory.h
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <services/base_service.h>
|
||||
#include <services/serviceman.h>
|
||||
#include <vfs/directory.h>
|
||||
#include <vfs/filesystem.h>
|
||||
|
||||
namespace skyline::service::fssrv {
|
||||
/**
|
||||
* @brief IDirectory is an interface for accessing directory contents
|
||||
* @url https://switchbrew.org/wiki/Filesystem_services#IDirectory
|
||||
*/
|
||||
class IDirectory : public BaseService {
|
||||
private:
|
||||
std::shared_ptr<vfs::Directory> backing; //!< Backing directory of the IDirectory
|
||||
std::shared_ptr<vfs::FileSystem> backingFs; //!< Backing filesystem of the IDirectory
|
||||
|
||||
public:
|
||||
IDirectory(std::shared_ptr<vfs::Directory> backing, std::shared_ptr<vfs::FileSystem> backingFs, const DeviceState &state, ServiceManager &manager);
|
||||
|
||||
/**
|
||||
* @brief Reads the contents of an IDirectory
|
||||
*/
|
||||
Result Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
SERVICE_DECL(
|
||||
SFUNC(0x0, IDirectory, Read),
|
||||
)
|
||||
};
|
||||
}
|
@ -3,13 +3,14 @@
|
||||
|
||||
#include "results.h"
|
||||
#include "IFile.h"
|
||||
#include "IDirectory.h"
|
||||
#include "IFileSystem.h"
|
||||
|
||||
namespace skyline::service::fssrv {
|
||||
IFileSystem::IFileSystem(std::shared_ptr<vfs::FileSystem> backing, const DeviceState &state, ServiceManager &manager) : backing(backing), BaseService(state, manager) {}
|
||||
|
||||
Result IFileSystem::CreateFile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
std::string path{request.inputBuf.at(0).as<char>()};
|
||||
std::string path(request.inputBuf.at(0).as_string(true));
|
||||
auto mode{request.Pop<u64>()};
|
||||
auto size{request.Pop<u32>()};
|
||||
|
||||
@ -17,7 +18,7 @@ namespace skyline::service::fssrv {
|
||||
}
|
||||
|
||||
Result IFileSystem::GetEntryType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
std::string path{request.inputBuf.at(0).as<char>()};
|
||||
std::string path(request.inputBuf.at(0).as_string(true));
|
||||
|
||||
auto type{backing->GetEntryType(path)};
|
||||
|
||||
@ -31,7 +32,7 @@ namespace skyline::service::fssrv {
|
||||
}
|
||||
|
||||
Result IFileSystem::OpenFile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
std::string path{request.inputBuf.at(0).as<char>()};
|
||||
std::string path(request.inputBuf.at(0).as_string(true));
|
||||
auto mode{request.Pop<vfs::Backing::Mode>()};
|
||||
|
||||
if (!backing->FileExists(path))
|
||||
@ -46,6 +47,19 @@ namespace skyline::service::fssrv {
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IFileSystem::OpenDirectory(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
std::string path(request.inputBuf.at(0).as_string(true));
|
||||
|
||||
if (!path.ends_with("/"))
|
||||
path += "/";
|
||||
|
||||
auto listMode{request.Pop<vfs::Directory::ListMode>()};
|
||||
auto directory{backing->OpenDirectory(path, listMode)};
|
||||
|
||||
manager.RegisterService(std::make_shared<IDirectory>(directory, backing, state, manager), session, response);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IFileSystem::Commit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
}
|
||||
|
@ -35,6 +35,11 @@ namespace skyline::service::fssrv {
|
||||
*/
|
||||
Result OpenFile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief This returns an IDirectory handle for the requested path and mask (https://switchbrew.org/wiki/Filesystem_services#OpenDirectory)
|
||||
*/
|
||||
Result OpenDirectory(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Commits all changes to the filesystem
|
||||
* @url https://switchbrew.org/wiki/Filesystem_services#Commit
|
||||
@ -45,6 +50,7 @@ namespace skyline::service::fssrv {
|
||||
SFUNC(0x0, IFileSystem, CreateFile),
|
||||
SFUNC(0x7, IFileSystem, GetEntryType),
|
||||
SFUNC(0x8, IFileSystem, OpenFile),
|
||||
SFUNC(0x9, IFileSystem, OpenDirectory),
|
||||
SFUNC(0xA, IFileSystem, Commit)
|
||||
)
|
||||
};
|
||||
|
@ -80,6 +80,8 @@ namespace skyline::service::nvdrv {
|
||||
SFUNC(0x3, INvDrvServices, Initialize),
|
||||
SFUNC(0x4, INvDrvServices, QueryEvent),
|
||||
SFUNC(0x8, INvDrvServices, SetAruid),
|
||||
SFUNC(0xB, INvDrvServices, Ioctl2),
|
||||
SFUNC(0xC, INvDrvServices, Ioctl3),
|
||||
SFUNC(0xD, INvDrvServices, SetGraphicsFirmwareMemoryMarginEnabled)
|
||||
)
|
||||
};
|
||||
|
@ -78,7 +78,7 @@ namespace skyline::service::nvdrv::device {
|
||||
* @return The name of the class
|
||||
* @note The lifetime of the returned string is tied to that of the class
|
||||
*/
|
||||
const std::string& GetName();
|
||||
const std::string &GetName();
|
||||
|
||||
/**
|
||||
* @brief Handles IOCTL calls for devices
|
||||
|
@ -7,6 +7,14 @@
|
||||
#include "nvhost_as_gpu.h"
|
||||
|
||||
namespace skyline::service::nvdrv::device {
|
||||
struct MappingFlags {
|
||||
bool fixed : 1;
|
||||
u8 _pad0_ : 7;
|
||||
bool remap : 1;
|
||||
u32 _pad1_ : 23;
|
||||
};
|
||||
static_assert(sizeof(MappingFlags) == sizeof(u32));
|
||||
|
||||
NvHostAsGpu::NvHostAsGpu(const DeviceState &state) : NvDevice(state) {}
|
||||
|
||||
NvStatus NvHostAsGpu::BindChannel(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||
@ -15,22 +23,22 @@ namespace skyline::service::nvdrv::device {
|
||||
|
||||
NvStatus NvHostAsGpu::AllocSpace(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||
struct Data {
|
||||
u32 pages; // In
|
||||
u32 pageSize; // In
|
||||
u32 flags; // In
|
||||
u32 pages; // In
|
||||
u32 pageSize; // In
|
||||
MappingFlags flags; // In
|
||||
u32 _pad_;
|
||||
union {
|
||||
u64 offset; // InOut
|
||||
u64 align; // In
|
||||
u64 offset; // InOut
|
||||
u64 align; // In
|
||||
};
|
||||
} region = buffer.as<Data>();
|
||||
} ®ion = buffer.as<Data>();
|
||||
|
||||
u64 size{static_cast<u64>(region.pages) * static_cast<u64>(region.pageSize)};
|
||||
|
||||
if (region.flags & 1)
|
||||
if (region.flags.fixed)
|
||||
region.offset = state.gpu->memoryManager.ReserveFixed(region.offset, size);
|
||||
else
|
||||
region.offset = state.gpu->memoryManager.ReserveSpace(size);
|
||||
region.offset = state.gpu->memoryManager.ReserveSpace(size, region.align);
|
||||
|
||||
if (region.offset == 0) {
|
||||
state.logger->Warn("Failed to allocate GPU address space region!");
|
||||
@ -43,32 +51,67 @@ namespace skyline::service::nvdrv::device {
|
||||
NvStatus NvHostAsGpu::UnmapBuffer(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||
u64 offset{buffer.as<u64>()};
|
||||
|
||||
if (!state.gpu->memoryManager.Unmap(offset))
|
||||
state.logger->Warn("Failed to unmap chunk at 0x{:X}", offset);
|
||||
try {
|
||||
auto region{regionMap.at(offset)};
|
||||
|
||||
// Non-fixed regions are unmapped so that they can be used by future non-fixed mappings
|
||||
if (!region.fixed)
|
||||
if (!state.gpu->memoryManager.Unmap(offset, region.size))
|
||||
state.logger->Warn("Failed to unmap region at 0x{:X}", offset);
|
||||
|
||||
regionMap.erase(offset);
|
||||
} catch (const std::out_of_range &e) {
|
||||
state.logger->Warn("Couldn't find region to unmap at 0x{:X}", offset);
|
||||
}
|
||||
|
||||
return NvStatus::Success;
|
||||
}
|
||||
|
||||
NvStatus NvHostAsGpu::Modify(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||
struct Data {
|
||||
u32 flags; // In
|
||||
u32 kind; // In
|
||||
u32 nvmapHandle; // In
|
||||
u32 pageSize; // InOut
|
||||
u64 bufferOffset; // In
|
||||
u64 mappingSize; // In
|
||||
u64 offset; // InOut
|
||||
} &data = buffer.as<Data>();
|
||||
MappingFlags flags; // In
|
||||
u32 kind; // In
|
||||
u32 nvmapHandle; // In
|
||||
u32 pageSize; // InOut
|
||||
u64 bufferOffset; // In
|
||||
u64 mappingSize; // In
|
||||
u64 offset; // InOut
|
||||
} &data = buffer.as<Data>();
|
||||
|
||||
try {
|
||||
auto driver{nvdrv::driver.lock()};
|
||||
auto nvmap{driver->nvMap.lock()};
|
||||
auto mapping{nvmap->handleTable.at(data.nvmapHandle)};
|
||||
|
||||
if (data.flags.remap) {
|
||||
auto region{regionMap.upper_bound(data.offset)};
|
||||
if ((region == regionMap.begin()) || (region == regionMap.end())) {
|
||||
state.logger->Warn("Cannot remap an unmapped GPU address space region: 0x{:X}", data.offset);
|
||||
return NvStatus::BadParameter;
|
||||
}
|
||||
|
||||
region--; // Upper bound gives us the region after the one we want
|
||||
|
||||
if (region->second.size < data.mappingSize) {
|
||||
state.logger->Warn("Cannot remap an partially mapped GPU address space region: 0x{:X}", data.offset);
|
||||
return NvStatus::BadParameter;
|
||||
}
|
||||
|
||||
u64 gpuAddress{data.offset + data.bufferOffset};
|
||||
u64 cpuAddress{region->second.cpuAddress + data.bufferOffset};
|
||||
|
||||
if (state.gpu->memoryManager.MapFixed(gpuAddress, cpuAddress, data.mappingSize)) {
|
||||
state.logger->Warn("Failed to remap GPU address space region: 0x{:X}", gpuAddress);
|
||||
return NvStatus::BadParameter;
|
||||
}
|
||||
|
||||
return NvStatus::Success;
|
||||
}
|
||||
|
||||
u64 mapPhysicalAddress{data.bufferOffset + mapping->address};
|
||||
u64 mapSize{data.mappingSize ? data.mappingSize : mapping->size};
|
||||
|
||||
if (data.flags & 1)
|
||||
if (data.flags.fixed)
|
||||
data.offset = state.gpu->memoryManager.MapFixed(data.offset, mapPhysicalAddress, mapSize);
|
||||
else
|
||||
data.offset = state.gpu->memoryManager.MapAllocate(mapPhysicalAddress, mapSize);
|
||||
@ -78,6 +121,8 @@ namespace skyline::service::nvdrv::device {
|
||||
return NvStatus::BadParameter;
|
||||
}
|
||||
|
||||
regionMap[data.offset] = {mapPhysicalAddress, mapSize, data.flags.fixed};
|
||||
|
||||
return NvStatus::Success;
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.nvmapHandle);
|
||||
|
@ -11,6 +11,15 @@ namespace skyline::service::nvdrv::device {
|
||||
* @url https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-as-gpu
|
||||
*/
|
||||
class NvHostAsGpu : public NvDevice {
|
||||
private:
|
||||
struct AddressSpaceRegion {
|
||||
u64 cpuAddress;
|
||||
u64 size;
|
||||
bool fixed;
|
||||
};
|
||||
|
||||
std::map<u64, AddressSpaceRegion> regionMap; //!< This maps the base addresses of mapped buffers to their total sizes and mapping type, this is needed as what was originally a single buffer may have been split into multiple GPU side buffers with the remap flag.
|
||||
|
||||
public:
|
||||
NvHostAsGpu(const DeviceState &state);
|
||||
|
||||
|
@ -54,7 +54,12 @@ namespace skyline::service::nvdrv::device {
|
||||
throw exception("Waiting on a fence through SubmitGpfifo is unimplemented");
|
||||
}
|
||||
|
||||
state.gpu->gpfifo.Push(span(state.process->GetPointer<gpu::gpfifo::GpEntry>(data.address), data.numEntries));
|
||||
state.gpu->gpfifo.Push([&]() {
|
||||
if (type == IoctlType::Ioctl2)
|
||||
return inlineBuffer.cast<gpu::gpfifo::GpEntry>();
|
||||
else
|
||||
return span(state.process->GetPointer<gpu::gpfifo::GpEntry>(data.address), data.numEntries);
|
||||
}());
|
||||
|
||||
data.fence.id = channelFence.id;
|
||||
|
||||
@ -113,6 +118,10 @@ namespace skyline::service::nvdrv::device {
|
||||
return NvStatus::Success;
|
||||
}
|
||||
|
||||
NvStatus NvHostChannel::SetTimeslice(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
|
||||
return NvStatus::Success;
|
||||
}
|
||||
|
||||
NvStatus NvHostChannel::SetUserData(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||
return NvStatus::Success;
|
||||
}
|
||||
|
@ -76,6 +76,12 @@ namespace skyline::service::nvdrv::device {
|
||||
*/
|
||||
NvStatus AllocGpfifoEx2(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
|
||||
|
||||
/**
|
||||
* @brief Sets the timeslice of the channel
|
||||
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_TIMESLICE)
|
||||
*/
|
||||
NvStatus SetTimeslice(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
|
||||
|
||||
/**
|
||||
* @brief Sets the user specific data
|
||||
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA
|
||||
@ -93,6 +99,7 @@ namespace skyline::service::nvdrv::device {
|
||||
NVFUNC(0x480C, NvHostChannel, SetErrorNotifier),
|
||||
NVFUNC(0x480D, NvHostChannel, SetPriority),
|
||||
NVFUNC(0x481A, NvHostChannel, AllocGpfifoEx2),
|
||||
NVFUNC(0x481B, NvHostChannel, SubmitGpfifo), // Our SubmitGpfifo implementation also handles SubmitGpfifoEx
|
||||
NVFUNC(0x4714, NvHostChannel, SetUserData)
|
||||
)
|
||||
};
|
||||
|
@ -112,7 +112,7 @@ namespace skyline::service::nvdrv::device {
|
||||
userEventId = FindFreeEvent(data.fence.id);
|
||||
}
|
||||
|
||||
auto& event{*events.at(userEventId)};
|
||||
auto &event{*events.at(userEventId)};
|
||||
if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signaled) {
|
||||
state.logger->Debug("Now waiting on nvhost event: {} with fence: {}", userEventId, data.fence.id);
|
||||
event.Wait(state.gpu, data.fence);
|
||||
|
@ -77,7 +77,13 @@ namespace skyline::service::nvdrv::device {
|
||||
if (data.gpuCharacteristicsBufSize < sizeof(GpuCharacteristics))
|
||||
return NvStatus::InvalidSize;
|
||||
|
||||
data.gpuCharacteristics = GpuCharacteristics{};
|
||||
// The IOCTL3 version of GetCharacteristics additionally outputs to the inline output buffer
|
||||
if (type == IoctlType::Ioctl3) {
|
||||
auto &inlineCharacteristics{inlineBuffer.as<GpuCharacteristics>()};
|
||||
data.gpuCharacteristics = inlineCharacteristics = GpuCharacteristics{};
|
||||
} else {
|
||||
data.gpuCharacteristics = GpuCharacteristics{};
|
||||
}
|
||||
data.gpuCharacteristicsBufSize = sizeof(GpuCharacteristics);
|
||||
|
||||
return NvStatus::Success;
|
||||
@ -90,8 +96,14 @@ namespace skyline::service::nvdrv::device {
|
||||
u64 maskBuf; // Out
|
||||
} &data = buffer.as<Data>();
|
||||
|
||||
if (data.maskBufSize)
|
||||
data.maskBuf = 0x3;
|
||||
if (data.maskBufSize) {
|
||||
if (type == IoctlType::Ioctl3) {
|
||||
auto &inlineMask{inlineBuffer.as<u32>()};
|
||||
data.maskBuf = inlineMask = 0x3;
|
||||
} else {
|
||||
data.maskBuf = 0x3;
|
||||
}
|
||||
}
|
||||
|
||||
return NvStatus::Success;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace skyline::service::nvdrv {
|
||||
}
|
||||
|
||||
u32 NvHostSyncpoint::FindFreeSyncpoint() {
|
||||
for (u32 i{}; i < constant::MaxHwSyncpointCount; i++)
|
||||
for (u32 i{1}; i < constant::MaxHwSyncpointCount; i++)
|
||||
if (!syncpoints[i].reserved)
|
||||
return i;
|
||||
|
||||
|
@ -73,7 +73,7 @@ namespace skyline::service {
|
||||
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl:r")
|
||||
SERVICE_CASE(lm::ILogService, "lm")
|
||||
SERVICE_CASE(account::IAccountServiceForApplication, "acc:u0")
|
||||
SERVICE_CASE(friends::IServiceCreator, "friend")
|
||||
SERVICE_CASE(friends::IServiceCreator, "friend:u")
|
||||
SERVICE_CASE(nfp::IUserManager, "nfp:user")
|
||||
SERVICE_CASE(nifm::IStaticService, "nifm:u")
|
||||
SERVICE_CASE(socket::IClient, "bsd:u")
|
||||
|
@ -19,6 +19,7 @@ namespace skyline::vfs {
|
||||
struct Entry {
|
||||
std::string name;
|
||||
EntryType type;
|
||||
size_t size; //!< 0 if a directory
|
||||
};
|
||||
|
||||
/**
|
||||
@ -29,7 +30,7 @@ namespace skyline::vfs {
|
||||
bool directory : 1; //!< The directory listing will contain subdirectories
|
||||
bool file : 1; //!< The directory listing will contain files
|
||||
};
|
||||
u32 raw;
|
||||
u32 raw{};
|
||||
};
|
||||
static_assert(sizeof(ListMode) == 0x4);
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include "os_backing.h"
|
||||
@ -84,4 +83,45 @@ namespace skyline::vfs {
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<Directory> OsFileSystem::OpenDirectory(const std::string &path, Directory::ListMode listMode) {
|
||||
return std::make_shared<OsFileSystemDirectory>(basePath + path, listMode);
|
||||
}
|
||||
|
||||
OsFileSystemDirectory::OsFileSystemDirectory(const std::string &path, Directory::ListMode listMode) : Directory(listMode), path(path) {}
|
||||
|
||||
std::vector<Directory::Entry> OsFileSystemDirectory::Read() {
|
||||
if (!listMode.file && !listMode.directory)
|
||||
return {};
|
||||
|
||||
std::vector<Directory::Entry> outputEntries;
|
||||
|
||||
struct dirent *entry;
|
||||
auto directory{opendir(path.c_str())};
|
||||
if (!directory)
|
||||
throw exception("Failed to open directory: {}, error: {}", path, strerror(errno));
|
||||
|
||||
while ((entry = readdir(directory))) {
|
||||
struct stat entryInfo;
|
||||
if (stat((path + std::string(entry->d_name)).c_str(), &entryInfo))
|
||||
throw exception("Failed to stat directory entry: {}, error: {}", entry->d_name, strerror(errno));
|
||||
|
||||
std::string name(entry->d_name);
|
||||
if (S_ISDIR(entryInfo.st_mode) && listMode.directory && (name != ".") && (name != "..")) {
|
||||
outputEntries.push_back(Directory::Entry{
|
||||
.type = Directory::EntryType::Directory,
|
||||
.name = std::string(entry->d_name),
|
||||
.size = 0,
|
||||
});
|
||||
} else if (S_ISREG(entryInfo.st_mode) && listMode.file) {
|
||||
outputEntries.push_back(Directory::Entry{
|
||||
.type = Directory::EntryType::File,
|
||||
.name = std::string(entry->d_name),
|
||||
.size = static_cast<size_t>(entryInfo.st_size),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return outputEntries;
|
||||
}
|
||||
}
|
||||
|
@ -23,5 +23,19 @@ namespace skyline::vfs {
|
||||
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false});
|
||||
|
||||
std::optional<Directory::EntryType> GetEntryType(const std::string &path);
|
||||
|
||||
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief OsFileSystemDirectory abstracts access to a native linux directory through the VFS APIs
|
||||
*/
|
||||
class OsFileSystemDirectory : public Directory {
|
||||
private:
|
||||
std::string path;
|
||||
|
||||
public:
|
||||
OsFileSystemDirectory(const std::string &path, ListMode listMode);
|
||||
|
||||
std::vector<Entry> Read();
|
||||
};}
|
||||
|
@ -54,7 +54,7 @@ namespace skyline::vfs {
|
||||
|
||||
std::vector<Directory::Entry> fileList;
|
||||
for (const auto &file : fileMap)
|
||||
fileList.emplace_back(Directory::Entry{file.first, Directory::EntryType::File});
|
||||
fileList.emplace_back(Directory::Entry{file.first, Directory::EntryType::File, file.second.size});
|
||||
|
||||
return std::make_shared<PartitionFileSystemDirectory>(fileList, listMode);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace skyline::vfs {
|
||||
*/
|
||||
RegionBacking(const std::shared_ptr<vfs::Backing> &backing, size_t offset, size_t size, Mode mode = {true, false, false}) : Backing(mode, size), backing(backing), baseOffset(offset) {};
|
||||
|
||||
virtual size_t Read(span<u8> output, size_t offset = 0) {
|
||||
size_t Read(span<u8> output, size_t offset = 0) {
|
||||
if (!mode.read)
|
||||
throw exception("Attempting to read a backing that is not readable");
|
||||
if (size - offset < output.size())
|
||||
|
@ -92,7 +92,7 @@ namespace skyline::vfs {
|
||||
std::vector<char> name(romFsFileEntry.nameSize);
|
||||
backing->Read(span(name).cast<u8>(), header.fileMetaTableOffset + offset + sizeof(RomFileSystem::RomFsFileEntry));
|
||||
|
||||
contents.emplace_back(Entry{std::string(name.data(), romFsFileEntry.nameSize), EntryType::File});
|
||||
contents.emplace_back(Entry{std::string(name.data(), romFsFileEntry.nameSize), EntryType::File, romFsFileEntry.size});
|
||||
}
|
||||
|
||||
offset = romFsFileEntry.siblingOffset;
|
||||
|
Loading…
x
Reference in New Issue
Block a user