Remove KProcess Memory Functions

This commit is contained in:
◱ PixelyIon 2020-10-04 23:48:34 +05:30 committed by ◱ PixelyIon
parent 60e82e6af0
commit 02f3e37c4f
25 changed files with 192 additions and 309 deletions

View File

@ -41,7 +41,7 @@ namespace skyline::gpu::vmm {
} }
if (extension) if (extension)
chunks.insert(std::next(chunk), ChunkDescriptor(newChunk.address + newChunk.size, extension, (oldChunk.state == ChunkState::Mapped) ? (oldChunk.cpuAddress + newSize + newChunk.size) : 0, oldChunk.state)); chunks.insert(std::next(chunk), ChunkDescriptor(newChunk.address + newChunk.size, extension, (oldChunk.state == ChunkState::Mapped) ? (oldChunk.pointer + newSize + newChunk.size) : 0, oldChunk.state));
return newChunk.address; return newChunk.address;
} else if (chunk->address + chunk->size > newChunk.address) { } else if (chunk->address + chunk->size > newChunk.address) {
@ -65,7 +65,7 @@ namespace skyline::gpu::vmm {
tailChunk->address += chunkSliceOffset; tailChunk->address += chunkSliceOffset;
tailChunk->size -= chunkSliceOffset; tailChunk->size -= chunkSliceOffset;
if (tailChunk->state == ChunkState::Mapped) if (tailChunk->state == ChunkState::Mapped)
tailChunk->cpuAddress += chunkSliceOffset; tailChunk->pointer += chunkSliceOffset;
// If the size of the head chunk is zero then we can directly replace it with our new one rather than inserting it // If the size of the head chunk is zero then we can directly replace it with our new one rather than inserting it
auto headChunk{std::prev(tailChunk)}; auto headChunk{std::prev(tailChunk)};
@ -103,27 +103,27 @@ namespace skyline::gpu::vmm {
return InsertChunk(ChunkDescriptor(address, size, 0, ChunkState::Reserved)); return InsertChunk(ChunkDescriptor(address, size, 0, ChunkState::Reserved));
} }
u64 MemoryManager::MapAllocate(u64 address, u64 size) { u64 MemoryManager::MapAllocate(u8 *pointer, u64 size) {
size = util::AlignUp(size, constant::GpuPageSize); size = util::AlignUp(size, constant::GpuPageSize);
auto mappedChunk{FindChunk(ChunkState::Unmapped, size)}; auto mappedChunk{FindChunk(ChunkState::Unmapped, size)};
if (!mappedChunk) if (!mappedChunk)
return 0; return 0;
auto chunk{*mappedChunk}; auto chunk{*mappedChunk};
chunk.cpuAddress = address; chunk.pointer = pointer;
chunk.size = size; chunk.size = size;
chunk.state = ChunkState::Mapped; chunk.state = ChunkState::Mapped;
return InsertChunk(chunk); return InsertChunk(chunk);
} }
u64 MemoryManager::MapFixed(u64 address, u64 cpuAddress, u64 size) { u64 MemoryManager::MapFixed(u64 address, u8 *pointer, u64 size) {
if (!util::IsAligned(address, constant::GpuPageSize)) if (!util::IsAligned(pointer, constant::GpuPageSize))
return 0; return false;
size = util::AlignUp(size, constant::GpuPageSize); size = util::AlignUp(size, constant::GpuPageSize);
return InsertChunk(ChunkDescriptor(address, size, cpuAddress, ChunkState::Mapped)); return InsertChunk(ChunkDescriptor(address, size, pointer, ChunkState::Mapped));
} }
bool MemoryManager::Unmap(u64 address, u64 size) { bool MemoryManager::Unmap(u64 address, u64 size) {
@ -151,20 +151,20 @@ namespace skyline::gpu::vmm {
u64 initialSize{size}; u64 initialSize{size};
u64 chunkOffset{address - chunk->address}; u64 chunkOffset{address - chunk->address};
u64 readAddress{chunk->cpuAddress + chunkOffset}; u8 *source{chunk->pointer + chunkOffset};
u64 readSize{std::min(chunk->size - chunkOffset, size)}; u64 sourceSize{std::min(chunk->size - chunkOffset, size)};
// A continuous region in the GPU address space may be made up of several discontinuous regions in physical memory so we have to iterate over all chunks // A continuous region in the GPU address space may be made up of several discontinuous regions in physical memory so we have to iterate over all chunks
while (size) { while (size) {
state.process->ReadMemory(destination + (initialSize - size), readAddress, readSize); std::memcpy(destination + (initialSize - size), source, sourceSize);
size -= readSize; size -= sourceSize;
if (size) { if (size) {
if (++chunk == chunks.end() || chunk->state != ChunkState::Mapped) if (++chunk == chunks.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to read region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size); throw exception("Failed to read region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
readAddress = chunk->cpuAddress; source = chunk->pointer;
readSize = std::min(chunk->size, size); sourceSize = std::min(chunk->size, size);
} }
} }
} }
@ -181,20 +181,20 @@ namespace skyline::gpu::vmm {
u64 initialSize{size}; u64 initialSize{size};
u64 chunkOffset{address - chunk->address}; u64 chunkOffset{address - chunk->address};
u64 writeAddress{chunk->cpuAddress + chunkOffset}; u8 *destination{chunk->pointer + chunkOffset};
u64 writeSize{std::min(chunk->size - chunkOffset, size)}; u64 destinationSize{std::min(chunk->size - chunkOffset, size)};
// A continuous region in the GPU address space may be made up of several discontinuous regions in physical memory so we have to iterate over all chunks // A continuous region in the GPU address space may be made up of several discontinuous regions in physical memory so we have to iterate over all chunks
while (size) { while (size) {
state.process->WriteMemory(source + (initialSize - size), writeAddress, writeSize); std::memcpy(destination, source + (initialSize - size), destinationSize);
size -= writeSize; size -= destinationSize;
if (size) { if (size) {
if (++chunk == chunks.end() || chunk->state != ChunkState::Mapped) if (++chunk == chunks.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to write region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size); throw exception("Failed to write region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
writeAddress = chunk->cpuAddress; destination = chunk->pointer;
writeSize = std::min(chunk->size, size); destinationSize = std::min(chunk->size, size);
} }
} }
} }

View File

@ -20,10 +20,10 @@ namespace skyline {
struct ChunkDescriptor { struct ChunkDescriptor {
u64 address; //!< The address of the chunk in the GPU address space u64 address; //!< The address of the chunk in the GPU address space
u64 size; //!< The size of the chunk in bytes u64 size; //!< The size of the chunk in bytes
u64 cpuAddress; //!< The address of the chunk in the CPU address space (if mapped) u8* pointer; //!< A pointer to the chunk in the CPU address space (if mapped)
ChunkState state; ChunkState state;
ChunkDescriptor(u64 address, u64 size, u64 cpuAddress, ChunkState state) : address(address), size(size), cpuAddress(cpuAddress), state(state) {} ChunkDescriptor(u64 address, u64 size, u8* pointer, ChunkState state) : address(address), size(size), pointer(pointer), state(state) {}
/** /**
* @return If the given chunk can be contained wholly within this chunk * @return If the given chunk can be contained wholly within this chunk
@ -78,20 +78,20 @@ namespace skyline {
/** /**
* @brief Maps a physical CPU memory region to an automatically chosen virtual memory region * @brief Maps a physical CPU memory region to an automatically chosen virtual memory region
* @param address The physical CPU address of the region to be mapped into the GPU's address space * @param pointer A pointer to the region to be mapped into the GPU's address space
* @param size The size of the region to map * @param size The size of the region to map
* @return The virtual address of the region base * @return The virtual address of the region base
*/ */
u64 MapAllocate(u64 address, u64 size); u64 MapAllocate(u8* pointer, u64 size);
/** /**
* @brief Maps a physical CPU memory region to a fixed virtual memory region * @brief Maps a physical CPU memory region to a fixed virtual memory region
* @param address The target virtual address of the region * @param address The target virtual address of the region
* @param cpuAddress The physical CPU address of the region to be mapped into the GPU's address space * @param pointer A pointer to the region to be mapped into the GPU's address space
* @param size The size of the region to map * @param size The size of the region to map
* @return The virtual address of the region base * @return The virtual address of the region base
*/ */
u64 MapFixed(u64 address, u64 cpuAddress, u64 size); u64 MapFixed(u64 address, u8* pointer, u64 size);
/** /**
* @brief Unmaps all chunks in the given region from the GPU address space * @brief Unmaps all chunks in the given region from the GPU address space

View File

@ -7,7 +7,7 @@
#include "texture.h" #include "texture.h"
namespace skyline::gpu { namespace skyline::gpu {
GuestTexture::GuestTexture(const DeviceState &state, u64 address, texture::Dimensions dimensions, texture::Format format, texture::TileMode tiling, texture::TileConfig layout) : state(state), address(address), dimensions(dimensions), format(format), tileMode(tiling), tileConfig(layout) {} GuestTexture::GuestTexture(const DeviceState &state, u8* pointer, texture::Dimensions dimensions, texture::Format format, texture::TileMode tiling, texture::TileConfig layout) : state(state), pointer(pointer), dimensions(dimensions), format(format), tileMode(tiling), tileConfig(layout) {}
std::shared_ptr<Texture> GuestTexture::InitializeTexture(std::optional<texture::Format> format, std::optional<texture::Dimensions> dimensions, texture::Swizzle swizzle) { std::shared_ptr<Texture> GuestTexture::InitializeTexture(std::optional<texture::Format> format, std::optional<texture::Dimensions> dimensions, texture::Swizzle swizzle) {
if (!host.expired()) if (!host.expired())
@ -30,7 +30,7 @@ namespace skyline::gpu {
} }
void Texture::SynchronizeHost() { void Texture::SynchronizeHost() {
auto texture{state.process->GetPointer<u8>(guest->address)}; auto pointer{guest->pointer};
auto size{format.GetSize(dimensions)}; auto size{format.GetSize(dimensions)};
backing.resize(size); backing.resize(size);
auto output{reinterpret_cast<u8 *>(backing.data())}; auto output{reinterpret_cast<u8 *>(backing.data())};
@ -51,7 +51,7 @@ namespace skyline::gpu {
auto robBytes{robWidthBytes * robHeight}; // The size of a ROB in bytes auto robBytes{robWidthBytes * robHeight}; // The size of a ROB in bytes
auto gobYOffset{robWidthBytes * gobHeight}; // The offset of the next Y-axis GOB from the current one in linear space auto gobYOffset{robWidthBytes * gobHeight}; // The offset of the next Y-axis GOB from the current one in linear space
auto inputSector{texture}; // The address of the input sector auto inputSector{pointer}; // The address of the input sector
auto outputRob{output}; // The address of the output block auto outputRob{output}; // The address of the output block
for (u32 rob{}, y{}, paddingY{}; rob < surfaceHeightRobs; rob++) { // Every Surface contains `surfaceHeightRobs` ROBs for (u32 rob{}, y{}, paddingY{}; rob < surfaceHeightRobs; rob++) { // Every Surface contains `surfaceHeightRobs` ROBs
@ -80,7 +80,7 @@ namespace skyline::gpu {
auto sizeLine{guest->format.GetSize(dimensions.width, 1)}; // The size of a single line of pixel data auto sizeLine{guest->format.GetSize(dimensions.width, 1)}; // The size of a single line of pixel data
auto sizeStride{guest->format.GetSize(guest->tileConfig.pitch, 1)}; // The size of a single stride of pixel data auto sizeStride{guest->format.GetSize(guest->tileConfig.pitch, 1)}; // The size of a single stride of pixel data
auto inputLine{texture}; // The address of the input line auto inputLine{pointer}; // The address of the input line
auto outputLine{output}; // The address of the output line auto outputLine{output}; // The address of the output line
for (u32 line{}; line < dimensions.height; line++) { for (u32 line{}; line < dimensions.height; line++) {
@ -89,7 +89,7 @@ namespace skyline::gpu {
outputLine += sizeLine; outputLine += sizeLine;
} }
} else if (guest->tileMode == texture::TileMode::Linear) { } else if (guest->tileMode == texture::TileMode::Linear) {
std::memcpy(output, texture, size); std::memcpy(output, pointer, size);
} }
} }

View File

@ -124,14 +124,14 @@ namespace skyline {
const DeviceState &state; const DeviceState &state;
public: public:
u64 address; //!< The address of the texture in guest memory u8* pointer; //!< The address of the texture in guest memory
std::weak_ptr<Texture> host; //!< A host texture (if any) that was created from this guest texture std::weak_ptr<Texture> host; //!< A host texture (if any) that was created from this guest texture
texture::Dimensions dimensions; texture::Dimensions dimensions;
texture::Format format; texture::Format format;
texture::TileMode tileMode; texture::TileMode tileMode;
texture::TileConfig tileConfig; texture::TileConfig tileConfig;
GuestTexture(const DeviceState &state, u64 address, texture::Dimensions dimensions, texture::Format format, texture::TileMode tileMode = texture::TileMode::Linear, texture::TileConfig tileConfig = {}); GuestTexture(const DeviceState &state, u8* pointer, texture::Dimensions dimensions, texture::Format format, texture::TileMode tileMode = texture::TileMode::Linear, texture::TileConfig tileConfig = {});
constexpr size_t Size() { constexpr size_t Size() {
return format.GetSize(dimensions); return format.GetSize(dimensions);

View File

@ -29,37 +29,37 @@ namespace skyline::kernel::ipc {
for (u8 index{}; header->xNo > index; index++) { for (u8 index{}; header->xNo > index; index++) {
auto bufX{reinterpret_cast<BufferDescriptorX *>(pointer)}; auto bufX{reinterpret_cast<BufferDescriptorX *>(pointer)};
if (bufX->Address()) { if (bufX->Pointer()) {
inputBuf.emplace_back(state.process->GetPointer<u8>(bufX->Address()), u16(bufX->size)); inputBuf.emplace_back(bufX->Pointer(), u16(bufX->size));
state.logger->Debug("Buf X #{} AD: 0x{:X} SZ: 0x{:X} CTR: {}", index, u64(bufX->Address()), u16(bufX->size), u16(bufX->Counter())); state.logger->Debug("Buf X #{} AD: 0x{:X} SZ: 0x{:X} CTR: {}", index, u64(bufX->Pointer()), u16(bufX->size), u16(bufX->Counter()));
} }
pointer += sizeof(BufferDescriptorX); pointer += sizeof(BufferDescriptorX);
} }
for (u8 index{}; header->aNo > index; index++) { for (u8 index{}; header->aNo > index; index++) {
auto bufA{reinterpret_cast<BufferDescriptorABW *>(pointer)}; auto bufA{reinterpret_cast<BufferDescriptorABW *>(pointer)};
if (bufA->Address()) { if (bufA->Pointer()) {
inputBuf.emplace_back(state.process->GetPointer<u8>(bufA->Address()), bufA->Size()); inputBuf.emplace_back(bufA->Pointer(), bufA->Size());
state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Address()), u64(bufA->Size())); state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Pointer()), u64(bufA->Size()));
} }
pointer += sizeof(BufferDescriptorABW); pointer += sizeof(BufferDescriptorABW);
} }
for (u8 index{}; header->bNo > index; index++) { for (u8 index{}; header->bNo > index; index++) {
auto bufB{reinterpret_cast<BufferDescriptorABW *>(pointer)}; auto bufB{reinterpret_cast<BufferDescriptorABW *>(pointer)};
if (bufB->Address()) { if (bufB->Pointer()) {
outputBuf.emplace_back(state.process->GetPointer<u8>(bufB->Address()), bufB->Size()); outputBuf.emplace_back(bufB->Pointer(), bufB->Size());
state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Address()), u64(bufB->Size())); state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Pointer()), u64(bufB->Size()));
} }
pointer += sizeof(BufferDescriptorABW); pointer += sizeof(BufferDescriptorABW);
} }
for (u8 index{}; header->wNo > index; index++) { for (u8 index{}; header->wNo > index; index++) {
auto bufW{reinterpret_cast<BufferDescriptorABW *>(pointer)}; auto bufW{reinterpret_cast<BufferDescriptorABW *>(pointer)};
if (bufW->Address()) { if (bufW->Pointer()) {
outputBuf.emplace_back(state.process->GetPointer<u8>(bufW->Address()), bufW->Size()); outputBuf.emplace_back(bufW->Pointer(), bufW->Size());
outputBuf.emplace_back(state.process->GetPointer<u8>(bufW->Address()), bufW->Size()); outputBuf.emplace_back(bufW->Pointer(), bufW->Size());
state.logger->Debug("Buf W #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufW->Address()), u16(bufW->Size())); state.logger->Debug("Buf W #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufW->Pointer()), u16(bufW->Size()));
} }
pointer += sizeof(BufferDescriptorABW); pointer += sizeof(BufferDescriptorABW);
} }
@ -102,15 +102,15 @@ namespace skyline::kernel::ipc {
if (header->cFlag == BufferCFlag::SingleDescriptor) { if (header->cFlag == BufferCFlag::SingleDescriptor) {
auto bufC{reinterpret_cast<BufferDescriptorC *>(pointer)}; auto bufC{reinterpret_cast<BufferDescriptorC *>(pointer)};
if (bufC->address) { if (bufC->address) {
outputBuf.emplace_back(state.process->GetPointer<u8>(bufC->address), u16(bufC->size)); outputBuf.emplace_back(bufC->Pointer(), u16(bufC->size));
state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size)); state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", fmt::ptr(bufC->Pointer()), u16(bufC->size));
} }
} else if (header->cFlag > BufferCFlag::SingleDescriptor) { } else if (header->cFlag > BufferCFlag::SingleDescriptor) {
for (u8 index{}; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present for (u8 index{}; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
auto bufC{reinterpret_cast<BufferDescriptorC *>(pointer)}; auto bufC{reinterpret_cast<BufferDescriptorC *>(pointer)};
if (bufC->address) { if (bufC->address) {
outputBuf.emplace_back(state.process->GetPointer<u8>(bufC->address), u16(bufC->size)); outputBuf.emplace_back(bufC->Pointer(), u16(bufC->size));
state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufC->address), u16(bufC->size)); state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, fmt::ptr(bufC->Pointer()), u16(bufC->size));
} }
pointer += sizeof(BufferDescriptorC); pointer += sizeof(BufferDescriptorC);
} }

View File

@ -137,8 +137,8 @@ namespace skyline {
counter9_11 = static_cast<u16>(address & 0x38); counter9_11 = static_cast<u16>(address & 0x38);
} }
inline u64 Address() { inline u8* Pointer() {
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36; return reinterpret_cast<u8*>(static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36);
} }
inline u16 Counter() { inline u16 Counter() {
@ -167,8 +167,8 @@ namespace skyline {
size32_35 = static_cast<u8>(size & 0x78000000); size32_35 = static_cast<u8>(size & 0x78000000);
} }
inline u64 Address() { inline u8* Pointer() {
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36; return reinterpret_cast<u8*>(static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36);
} }
inline u64 Size() { inline u64 Size() {
@ -184,6 +184,10 @@ namespace skyline {
u64 address : 48; //!< The 48-bit address of the buffer u64 address : 48; //!< The 48-bit address of the buffer
u32 size : 16; //!< The 16-bit size of the buffer u32 size : 16; //!< The 16-bit size of the buffer
inline u8* Pointer() {
return reinterpret_cast<u8*>(address);
}
BufferDescriptorC(u64 address, u16 size) : address(address), size(size) {} BufferDescriptorC(u64 address, u16 size) : address(address), size(size) {}
}; };
static_assert(sizeof(BufferDescriptorC) == 8); static_assert(sizeof(BufferDescriptorC) == 8);

View File

@ -7,7 +7,8 @@
namespace skyline::kernel { namespace skyline::kernel {
MemoryManager::MemoryManager(const DeviceState &state) : state(state) {} MemoryManager::MemoryManager(const DeviceState &state) : state(state) {}
void MemoryManager::InitializeRegions(u64 address, u64 size, memory::AddressSpaceType type) { void MemoryManager::InitializeRegions(u8* codeStart, u64 size, memory::AddressSpaceType type) {
u64 address{reinterpret_cast<u64>(codeStart)};
switch (type) { switch (type) {
case memory::AddressSpaceType::AddressSpace32Bit: case memory::AddressSpaceType::AddressSpace32Bit:
throw exception("32-bit address spaces are not supported"); throw exception("32-bit address spaces are not supported");

View File

@ -219,10 +219,8 @@ namespace skyline {
/** /**
* @brief Initializes all of the regions in the address space * @brief Initializes all of the regions in the address space
* @param address The starting address of the code region
* @param size The size of the code region
*/ */
void InitializeRegions(u64 address, u64 size, memory::AddressSpaceType type); void InitializeRegions(u8* codeStart, u64 size, memory::AddressSpaceType type);
void InsertChunk(const ChunkDescriptor &chunk); void InsertChunk(const ChunkDescriptor &chunk);

View File

@ -28,10 +28,10 @@ namespace skyline::kernel::svc {
} }
void SetMemoryAttribute(DeviceState &state) { void SetMemoryAttribute(DeviceState &state) {
auto ptr{reinterpret_cast<u8 *>(state.ctx->registers.x0)}; auto pointer{reinterpret_cast<u8 *>(state.ctx->registers.x0)};
if (!util::PageAligned(ptr)) { if (!util::PageAligned(pointer)) {
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: 0x{:X}", fmt::ptr(ptr)); state.logger->Warn("svcSetMemoryAttribute: 'pointer' not page aligned: 0x{:X}", fmt::ptr(pointer));
return; return;
} }
@ -52,26 +52,26 @@ namespace skyline::kernel::svc {
return; return;
} }
auto chunk{state.os->memory.Get(ptr)}; auto chunk{state.os->memory.Get(pointer)};
if (!chunk) { if (!chunk) {
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", fmt::ptr(ptr)); state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", fmt::ptr(pointer));
return; return;
} }
if (!chunk->state.attributeChangeAllowed) { if (!chunk->state.attributeChangeAllowed) {
state.ctx->registers.w0 = result::InvalidState; state.ctx->registers.w0 = result::InvalidState;
state.logger->Warn("svcSetMemoryAttribute: Attribute change not allowed for chunk: 0x{:X}", fmt::ptr(ptr)); state.logger->Warn("svcSetMemoryAttribute: Attribute change not allowed for chunk: 0x{:X}", fmt::ptr(pointer));
return; return;
} }
auto newChunk{*chunk}; auto newChunk{*chunk};
newChunk.ptr = ptr; newChunk.ptr = pointer;
newChunk.size = size; newChunk.size = size;
newChunk.attributes.isUncached = value.isUncached; newChunk.attributes.isUncached = value.isUncached;
state.os->memory.InsertChunk(newChunk); state.os->memory.InsertChunk(newChunk);
state.logger->Debug("svcSetMemoryAttribute: Set caching to {} at 0x{:X} for 0x{:X} bytes", bool(value.isUncached), fmt::ptr(ptr), size); state.logger->Debug("svcSetMemoryAttribute: Set caching to {} at 0x{:X} for 0x{:X} bytes", bool(value.isUncached), fmt::ptr(pointer), size);
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
} }
@ -182,8 +182,8 @@ namespace skyline::kernel::svc {
void QueryMemory(DeviceState &state) { void QueryMemory(DeviceState &state) {
memory::MemoryInfo memInfo{}; memory::MemoryInfo memInfo{};
auto ptr{reinterpret_cast<u8*>(state.ctx->registers.x2)}; auto pointer{reinterpret_cast<u8*>(state.ctx->registers.x2)};
auto chunk{state.os->memory.Get(ptr)}; auto chunk{state.os->memory.Get(pointer)};
if (chunk) { if (chunk) {
memInfo = { memInfo = {
@ -206,10 +206,10 @@ namespace skyline::kernel::svc {
.type = static_cast<u32>(memory::MemoryType::Reserved), .type = static_cast<u32>(memory::MemoryType::Reserved),
}; };
state.logger->Debug("svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X}", fmt::ptr(ptr)); state.logger->Debug("svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X}", fmt::ptr(pointer));
} }
state.process->WriteMemory(memInfo, state.ctx->registers.x0); *reinterpret_cast<memory::MemoryInfo*>(state.ctx->registers.x0) = memInfo;
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
} }
@ -312,11 +312,11 @@ namespace skyline::kernel::svc {
void MapSharedMemory(DeviceState &state) { void MapSharedMemory(DeviceState &state) {
try { try {
auto object{state.process->GetHandle<type::KSharedMemory>(state.ctx->registers.w0)}; auto object{state.process->GetHandle<type::KSharedMemory>(state.ctx->registers.w0)};
auto ptr{reinterpret_cast<u8 *>(state.ctx->registers.x1)}; auto pointer{reinterpret_cast<u8 *>(state.ctx->registers.x1)};
if (!util::PageAligned(ptr)) { if (!util::PageAligned(pointer)) {
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
state.logger->Warn("svcMapSharedMemory: 'ptr' not page aligned: 0x{:X}", ptr); state.logger->Warn("svcMapSharedMemory: 'pointer' not page aligned: 0x{:X}", pointer);
return; return;
} }
@ -334,9 +334,9 @@ namespace skyline::kernel::svc {
return; return;
} }
state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} for {} bytes ({}{}{})", ptr, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} for {} bytes ({}{}{})", pointer, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
object->Map(ptr, size, permission); object->Map(pointer, size, permission);
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
} catch (const std::exception &) { } catch (const std::exception &) {
@ -346,10 +346,10 @@ namespace skyline::kernel::svc {
} }
void CreateTransferMemory(DeviceState &state) { void CreateTransferMemory(DeviceState &state) {
auto ptr{reinterpret_cast<u8 *>(state.ctx->registers.x1)}; auto pointer{reinterpret_cast<u8 *>(state.ctx->registers.x1)};
if (!util::PageAligned(ptr)) { if (!util::PageAligned(pointer)) {
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
state.logger->Warn("svcCreateTransferMemory: 'ptr' not page aligned: 0x{:X}", ptr); state.logger->Warn("svcCreateTransferMemory: 'pointer' not page aligned: 0x{:X}", pointer);
return; return;
} }
@ -367,8 +367,8 @@ namespace skyline::kernel::svc {
return; return;
} }
auto tmem{state.process->NewHandle<type::KTransferMemory>(ptr, size, permission)}; auto tmem{state.process->NewHandle<type::KTransferMemory>(pointer, size, permission)};
state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} for {} bytes ({}{}{})", fmt::ptr(ptr), size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} for {} bytes ({}{}{})", fmt::ptr(pointer), size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
state.ctx->registers.w1 = tmem.handle; state.ctx->registers.w1 = tmem.handle;
@ -426,9 +426,7 @@ namespace skyline::kernel::svc {
std::string handleStr; std::string handleStr;
std::vector<std::shared_ptr<type::KSyncObject>> objectTable; std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
std::vector<KHandle> waitHandles(numHandles); span waitHandles(reinterpret_cast<KHandle*>(state.ctx->registers.x1), numHandles);
state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(KHandle));
for (const auto &handle : waitHandles) { for (const auto &handle : waitHandles) {
handleStr += fmt::format("* 0x{:X}\n", handle); handleStr += fmt::format("* 0x{:X}\n", handle);
@ -464,7 +462,7 @@ namespace skyline::kernel::svc {
uint index{}; uint index{};
for (const auto &object : objectTable) { for (const auto &object : objectTable) {
if (object->signalled) { if (object->signalled) {
state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles.at(index)); state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles[index]);
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
state.ctx->registers.w1 = index; state.ctx->registers.w1 = index;
return; return;
@ -490,9 +488,9 @@ namespace skyline::kernel::svc {
} }
void ArbitrateLock(DeviceState &state) { void ArbitrateLock(DeviceState &state) {
auto address{state.ctx->registers.x1}; auto pointer{reinterpret_cast<u32*>(state.ctx->registers.x1)};
if (!util::WordAligned(address)) { if (!util::WordAligned(pointer)) {
state.logger->Warn("svcArbitrateLock: 'address' not word aligned: 0x{:X}", address); state.logger->Warn("svcArbitrateLock: 'pointer' not word aligned: 0x{:X}", fmt::ptr(pointer));
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
return; return;
} }
@ -502,58 +500,58 @@ namespace skyline::kernel::svc {
if (requesterHandle != state.thread->handle) if (requesterHandle != state.thread->handle)
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", requesterHandle, state.thread->handle); throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", requesterHandle, state.thread->handle);
state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X}", address); state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X}", fmt::ptr(pointer));
if (state.process->MutexLock(address, ownerHandle)) if (state.process->MutexLock(pointer, ownerHandle))
state.logger->Debug("svcArbitrateLock: Locked mutex at 0x{:X}", address); state.logger->Debug("svcArbitrateLock: Locked mutex at 0x{:X}", fmt::ptr(pointer));
else else
state.logger->Debug("svcArbitrateLock: Owner handle did not match current owner for mutex or didn't have waiter flag at 0x{:X}", address); state.logger->Debug("svcArbitrateLock: Owner handle did not match current owner for mutex or didn't have waiter flag at 0x{:X}", fmt::ptr(pointer));
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
} }
void ArbitrateUnlock(DeviceState &state) { void ArbitrateUnlock(DeviceState &state) {
auto address{state.ctx->registers.x0}; auto mutex{reinterpret_cast<u32*>(state.ctx->registers.x0)};
if (!util::WordAligned(address)) { if (!util::WordAligned(mutex)) {
state.logger->Warn("svcArbitrateUnlock: 'address' not word aligned: 0x{:X}", address); state.logger->Warn("svcArbitrateUnlock: mutex pointer not word aligned: 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
return; return;
} }
state.logger->Debug("svcArbitrateUnlock: Unlocking mutex at 0x{:X}", address); state.logger->Debug("svcArbitrateUnlock: Unlocking mutex at 0x{:X}", fmt::ptr(mutex));
if (state.process->MutexUnlock(address)) { if (state.process->MutexUnlock(mutex)) {
state.logger->Debug("svcArbitrateUnlock: Unlocked mutex at 0x{:X}", address); state.logger->Debug("svcArbitrateUnlock: Unlocked mutex at 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
} else { } else {
state.logger->Debug("svcArbitrateUnlock: A non-owner thread tried to release a mutex at 0x{:X}", address); state.logger->Debug("svcArbitrateUnlock: A non-owner thread tried to release a mutex at 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
} }
} }
void WaitProcessWideKeyAtomic(DeviceState &state) { void WaitProcessWideKeyAtomic(DeviceState &state) {
auto mtxAddress{state.ctx->registers.x0}; auto mutex{reinterpret_cast<u32*>(state.ctx->registers.x0)};
if (!util::WordAligned(mtxAddress)) { if (!util::WordAligned(mutex)) {
state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: 0x{:X}", mtxAddress); state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex pointer not word aligned: 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
return; return;
} }
auto condAddress{state.ctx->registers.x1}; auto conditional{reinterpret_cast<void*>(state.ctx->registers.x1)};
auto handle{state.ctx->registers.w2}; auto handle{state.ctx->registers.w2};
if (handle != state.thread->handle) if (handle != state.thread->handle)
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", handle, state.thread->handle); throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", handle, state.thread->handle);
if (!state.process->MutexUnlock(mtxAddress)) { if (!state.process->MutexUnlock(mutex)) {
state.logger->Debug("WaitProcessWideKeyAtomic: A non-owner thread tried to release a mutex at 0x{:X}", mtxAddress); state.logger->Debug("WaitProcessWideKeyAtomic: A non-owner thread tried to release a mutex at 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = result::InvalidAddress; state.ctx->registers.w0 = result::InvalidAddress;
return; return;
} }
auto timeout{state.ctx->registers.x3}; auto timeout{state.ctx->registers.x3};
state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {} ns", mtxAddress, condAddress, timeout); state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {} ns", fmt::ptr(mutex), conditional, timeout);
if (state.process->ConditionalVariableWait(condAddress, mtxAddress, timeout)) { if (state.process->ConditionalVariableWait(conditional, mutex, timeout)) {
state.logger->Debug("svcWaitProcessWideKeyAtomic: Waited for conditional variable and relocked mutex"); state.logger->Debug("svcWaitProcessWideKeyAtomic: Waited for conditional variable and relocked mutex");
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
} else { } else {
@ -563,11 +561,11 @@ namespace skyline::kernel::svc {
} }
void SignalProcessWideKey(DeviceState &state) { void SignalProcessWideKey(DeviceState &state) {
auto address{state.ctx->registers.x0}; auto conditional{reinterpret_cast<void*>(state.ctx->registers.x0)};
auto count{state.ctx->registers.w1}; auto count{state.ctx->registers.w1};
state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count); state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", conditional, count);
state.process->ConditionalVariableSignal(address, count); state.process->ConditionalVariableSignal(conditional, count);
state.ctx->registers.w0 = Result{}; state.ctx->registers.w0 = Result{};
} }
@ -586,7 +584,7 @@ namespace skyline::kernel::svc {
void ConnectToNamedPort(DeviceState &state) { void ConnectToNamedPort(DeviceState &state) {
constexpr u8 portSize = 0x8; //!< The size of a port name string constexpr u8 portSize = 0x8; //!< The size of a port name string
std::string_view port(span(state.process->GetPointer<char>(state.ctx->registers.x1), portSize).as_string(true)); std::string_view port(span(reinterpret_cast<char*>(state.ctx->registers.x1), portSize).as_string(true));
KHandle handle{}; KHandle handle{};
if (port.compare("sm:") >= 0) { if (port.compare("sm:") >= 0) {

View File

@ -102,54 +102,6 @@ namespace skyline::kernel::type {
return thread; return thread;
} }
void KProcess::ReadMemory(void *destination, u64 offset, size_t size, bool forceGuest) {
if (!forceGuest) {
auto source{reinterpret_cast<u8*>(offset)};
if (source) {
std::memcpy(destination, reinterpret_cast<void *>(source), size);
return;
}
}
struct iovec local{
.iov_base = destination,
.iov_len = size,
};
struct iovec remote{
.iov_base = reinterpret_cast<void *>(offset),
.iov_len = size,
};
if (process_vm_readv(pid, &local, 1, &remote, 1, 0) < 0)
pread64(memFd, destination, size, offset);
}
void KProcess::WriteMemory(const void *source, u64 offset, size_t size, bool forceGuest) {
if (!forceGuest) {
auto destination{reinterpret_cast<u8*>(offset)};
if (destination) {
std::memcpy(reinterpret_cast<void *>(destination), source, size);
return;
}
}
struct iovec local{
.iov_base = const_cast<void *>(source),
.iov_len = size,
};
struct iovec remote{
.iov_base = reinterpret_cast<void *>(offset),
.iov_len = size,
};
if (process_vm_writev(pid, &local, 1, &remote, 1, 0) < 0)
pwrite64(memFd, source, size, offset);
}
std::optional<KProcess::HandleOut<KMemory>> KProcess::GetMemoryObject(u8* ptr) { std::optional<KProcess::HandleOut<KMemory>> KProcess::GetMemoryObject(u8* ptr) {
for (KHandle index{}; index < handles.size(); index++) { for (KHandle index{}; index < handles.size(); index++) {
auto& object{handles[index]}; auto& object{handles[index]};
@ -169,19 +121,17 @@ namespace skyline::kernel::type {
return std::nullopt; return std::nullopt;
} }
bool KProcess::MutexLock(u64 address, KHandle owner) { bool KProcess::MutexLock(u32* mutex, KHandle owner) {
std::unique_lock lock(mutexLock); std::unique_lock lock(mutexLock);
auto mtx{GetPointer<u32>(address)}; auto &mtxWaiters{mutexes[reinterpret_cast<u64>(mutex)]};
auto &mtxWaiters{mutexes[address]};
if (mtxWaiters.empty()) { if (mtxWaiters.empty()) {
u32 mtxExpected{}; u32 mtxExpected{};
if (__atomic_compare_exchange_n(mtx, &mtxExpected, (constant::MtxOwnerMask & state.thread->handle), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) if (__atomic_compare_exchange_n(mutex, &mtxExpected, (constant::MtxOwnerMask & state.thread->handle), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
return true; return true;
} }
if (__atomic_load_n(mtx, __ATOMIC_SEQ_CST) != (owner | ~constant::MtxOwnerMask)) if (__atomic_load_n(mutex, __ATOMIC_SEQ_CST) != (owner | ~constant::MtxOwnerMask))
return false; return false;
std::shared_ptr<WaitStatus> status; std::shared_ptr<WaitStatus> status;
@ -209,20 +159,19 @@ namespace skyline::kernel::type {
return true; return true;
} }
bool KProcess::MutexUnlock(u64 address) { bool KProcess::MutexUnlock(u32* mutex) {
std::unique_lock lock(mutexLock); std::unique_lock lock(mutexLock);
auto mtx{GetPointer<u32>(address)}; auto &mtxWaiters{mutexes[reinterpret_cast<u64>(mutex)]};
auto &mtxWaiters{mutexes[address]};
u32 mtxDesired{}; u32 mtxDesired{};
if (!mtxWaiters.empty()) if (!mtxWaiters.empty())
mtxDesired = (*mtxWaiters.begin())->handle | ((mtxWaiters.size() > 1) ? ~constant::MtxOwnerMask : 0); mtxDesired = (*mtxWaiters.begin())->handle | ((mtxWaiters.size() > 1) ? ~constant::MtxOwnerMask : 0);
u32 mtxExpected{(constant::MtxOwnerMask & state.thread->handle) | ~constant::MtxOwnerMask}; u32 mtxExpected{(constant::MtxOwnerMask & state.thread->handle) | ~constant::MtxOwnerMask};
if (!__atomic_compare_exchange_n(mtx, &mtxExpected, mtxDesired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (!__atomic_compare_exchange_n(mutex, &mtxExpected, mtxDesired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
mtxExpected &= constant::MtxOwnerMask; mtxExpected &= constant::MtxOwnerMask;
if (!__atomic_compare_exchange_n(mtx, &mtxExpected, mtxDesired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) if (!__atomic_compare_exchange_n(mutex, &mtxExpected, mtxDesired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
return false; return false;
} }
@ -237,16 +186,16 @@ namespace skyline::kernel::type {
return true; return true;
} }
bool KProcess::ConditionalVariableWait(u64 conditionalAddress, u64 mutexAddress, u64 timeout) { bool KProcess::ConditionalVariableWait(void* conditional, u32* mutex, u64 timeout) {
std::unique_lock lock(conditionalLock); std::unique_lock lock(conditionalLock);
auto &condWaiters{conditionals[conditionalAddress]};
auto &condWaiters{conditionals[reinterpret_cast<u64>(conditional)]};
std::shared_ptr<WaitStatus> status; std::shared_ptr<WaitStatus> status;
for (auto it{condWaiters.begin()};; it++) { for (auto it{condWaiters.begin()};; it++) {
if (it != condWaiters.end() && (*it)->priority >= state.thread->priority) if (it != condWaiters.end() && (*it)->priority >= state.thread->priority)
continue; continue;
status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->handle, mutexAddress); status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->handle, mutex);
condWaiters.insert(it, status); condWaiters.insert(it, status);
break; break;
} }
@ -278,16 +227,16 @@ namespace skyline::kernel::type {
return !timedOut; return !timedOut;
} }
void KProcess::ConditionalVariableSignal(u64 address, u64 amount) { void KProcess::ConditionalVariableSignal(void* conditional, u64 amount) {
std::unique_lock condLock(conditionalLock); std::unique_lock condLock(conditionalLock);
auto &condWaiters{conditionals[address]}; auto &condWaiters{conditionals[reinterpret_cast<u64>(conditional)]};
u64 count{}; u64 count{};
auto iter{condWaiters.begin()}; auto iter{condWaiters.begin()};
while (iter != condWaiters.end() && count < amount) { while (iter != condWaiters.end() && count < amount) {
auto &thread{*iter}; auto &thread{*iter};
auto mtx{GetPointer<u32>(thread->mutexAddress)}; auto mtx{thread->mutex};
u32 mtxValue{__atomic_load_n(mtx, __ATOMIC_SEQ_CST)}; u32 mtxValue{__atomic_load_n(mtx, __ATOMIC_SEQ_CST)};
while (true) { while (true) {
@ -308,7 +257,7 @@ namespace skyline::kernel::type {
if (mtxValue && ((mtxValue & constant::MtxOwnerMask) != state.thread->handle)) { if (mtxValue && ((mtxValue & constant::MtxOwnerMask) != state.thread->handle)) {
std::unique_lock mtxLock(mutexLock); std::unique_lock mtxLock(mutexLock);
auto &mtxWaiters{mutexes[thread->mutexAddress]}; auto &mtxWaiters{mutexes[reinterpret_cast<u64>(thread->mutex)]};
std::shared_ptr<WaitStatus> status; std::shared_ptr<WaitStatus> status;
for (auto it{mtxWaiters.begin()};; it++) { for (auto it{mtxWaiters.begin()};; it++) {

View File

@ -95,11 +95,11 @@ namespace skyline {
std::atomic_bool flag{false}; //!< The underlying atomic flag of the thread std::atomic_bool flag{false}; //!< The underlying atomic flag of the thread
u8 priority; //!< The priority of the thread u8 priority; //!< The priority of the thread
KHandle handle; //!< The handle of the thread KHandle handle; //!< The handle of the thread
u64 mutexAddress{}; //!< The address of the mutex u32* mutex{};
WaitStatus(u8 priority, KHandle handle) : priority(priority), handle(handle) {} WaitStatus(u8 priority, KHandle handle) : priority(priority), handle(handle) {}
WaitStatus(u8 priority, KHandle handle, u64 mutexAddress) : priority(priority), handle(handle), mutexAddress(mutexAddress) {} WaitStatus(u8 priority, KHandle handle, u32* mutex) : priority(priority), handle(handle), mutex(mutex) {}
}; };
pid_t pid; //!< The PID of the process or TGID of the threads pid_t pid; //!< The PID of the process or TGID of the threads
@ -136,67 +136,6 @@ namespace skyline {
*/ */
std::shared_ptr<KThread> CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, i8 priority); std::shared_ptr<KThread> CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, i8 priority);
/**
* @tparam Type The type of the pointer to return
* @param address The address on the guest
* @return A pointer corresponding to a certain address on the guest
* @note If the address is invalid then nullptr will be returned
*/
template<typename Type>
inline Type *GetPointer(u64 address) {
return reinterpret_cast<Type *>(address);
}
/**
* @brief Writes an object to guest memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(Type &item, u64 address) {
auto destination{GetPointer<Type>(address)};
if (destination) {
*destination = item;
} else {
WriteMemory(&item, address, sizeof(Type));
}
}
/**
* @brief Writes an object to guest memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(const Type &item, u64 address) {
auto destination{GetPointer<Type>(address)};
if (destination) {
*destination = item;
} else {
WriteMemory(&item, address, sizeof(Type));
}
}
/**
* @brief Read data from the guest's memory
* @param destination The address to the location where the process memory is written
* @param offset The address to read from in process memory
* @param size The amount of memory to be read
* @param forceGuest Forces the write to be performed in guest address space
*/
void ReadMemory(void *destination, u64 offset, size_t size, bool forceGuest = false);
/**
* @brief Write to the guest's memory
* @param source The address of where the data to be written is present
* @param offset The address to write to in process memory
* @param size The amount of memory to be written
* @param forceGuest Forces the write to be performed in guest address space
*/
void WriteMemory(const void *source, u64 offset, size_t size, bool forceGuest = false);
/** /**
* @brief Creates a new handle to a KObject and adds it to the process handle_table * @brief Creates a new handle to a KObject and adds it to the process handle_table
* @tparam objectClass The class of the kernel object to create * @tparam objectClass The class of the kernel object to create
@ -279,33 +218,28 @@ namespace skyline {
/** /**
* @brief Locks the Mutex at the specified address * @brief Locks the Mutex at the specified address
* @param address The address of the mutex
* @param owner The handle of the current mutex owner * @param owner The handle of the current mutex owner
* @return If the mutex was successfully locked * @return If the mutex was successfully locked
*/ */
bool MutexLock(u64 address, KHandle owner); bool MutexLock(u32* mutex, KHandle owner);
/** /**
* @brief Unlocks the Mutex at the specified address * @brief Unlocks the Mutex at the specified address
* @param address The address of the mutex
* @return If the mutex was successfully unlocked * @return If the mutex was successfully unlocked
*/ */
bool MutexUnlock(u64 address); bool MutexUnlock(u32* mutex);
/** /**
* @param conditionalAddress The address of the conditional variable
* @param mutexAddress The address of the mutex
* @param timeout The amount of time to wait for the conditional variable * @param timeout The amount of time to wait for the conditional variable
* @return If the conditional variable was successfully waited for or timed out * @return If the conditional variable was successfully waited for or timed out
*/ */
bool ConditionalVariableWait(u64 conditionalAddress, u64 mutexAddress, u64 timeout); bool ConditionalVariableWait(void* conditional, u32* mutex, u64 timeout);
/** /**
* @brief Signals a number of conditional variable waiters * @brief Signals a number of conditional variable waiters
* @param address The address of the conditional variable
* @param amount The amount of waiters to signal * @param amount The amount of waiters to signal
*/ */
void ConditionalVariableSignal(u64 address, u64 amount); void ConditionalVariableSignal(void* conditional, u64 amount);
/** /**
* @brief Resets the object to an unsignalled state * @brief Resets the object to an unsignalled state

View File

@ -9,7 +9,7 @@
namespace skyline::loader { namespace skyline::loader {
Loader::ExecutableLoadInfo Loader::LoadExecutable(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, Executable &executable, size_t offset) { Loader::ExecutableLoadInfo Loader::LoadExecutable(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, Executable &executable, size_t offset) {
u8* base{reinterpret_cast<u8*>(constant::BaseAddress + offset)}; u8 *base{reinterpret_cast<u8 *>(constant::BaseAddress + offset)};
u64 textSize{executable.text.contents.size()}; u64 textSize{executable.text.contents.size()};
u64 roSize{executable.ro.contents.size()}; u64 roSize{executable.ro.contents.size()};
@ -40,11 +40,11 @@ namespace skyline::loader {
process->NewHandle<kernel::type::KPrivateMemory>(base + patchOffset, patchSize + padding, memory::Permission{true, true, true}, memory::states::CodeMutable); // RWX process->NewHandle<kernel::type::KPrivateMemory>(base + patchOffset, patchSize + padding, memory::Permission{true, true, true}, memory::states::CodeMutable); // RWX
state.logger->Debug("Successfully mapped section .patch @ 0x{0:X}, Size = 0x{1:X}", base + patchOffset, patchSize + padding); state.logger->Debug("Successfully mapped section .patch @ 0x{0:X}, Size = 0x{1:X}", base + patchOffset, patchSize + padding);
process->WriteMemory(executable.text.contents.data(), reinterpret_cast<u64>(base + executable.text.offset), textSize); std::memcpy(executable.text.contents.data(), base + executable.text.offset, textSize);
process->WriteMemory(executable.ro.contents.data(), reinterpret_cast<u64>(base + executable.ro.offset), roSize); std::memcpy(executable.ro.contents.data(), base + executable.ro.offset, roSize);
process->WriteMemory(executable.data.contents.data(), reinterpret_cast<u64>(base + executable.data.offset), dataSize - executable.bssSize); std::memcpy(executable.data.contents.data(), base + executable.data.offset, dataSize - executable.bssSize);
process->WriteMemory(patch.data(), reinterpret_cast<u64>(base + patchOffset), patchSize); std::memcpy(patch.data(), base + patchOffset, patchSize);
return {reinterpret_cast<u64>(base), patchOffset + patchSize + padding}; return {base, patchOffset + patchSize + padding};
} }
} }

View File

@ -51,7 +51,7 @@ namespace skyline::loader {
* @brief Information about the placement of an executable in memory * @brief Information about the placement of an executable in memory
*/ */
struct ExecutableLoadInfo { struct ExecutableLoadInfo {
size_t base; //!< The base of the loaded executable u8* base; //!< The base of the loaded executable
size_t size; //!< The total size of the loaded executable size_t size; //!< The total size of the loaded executable
}; };

View File

@ -23,9 +23,9 @@ namespace skyline::loader {
auto loadInfo{NsoLoader::LoadNso(nsoFile, process, state)}; auto loadInfo{NsoLoader::LoadNso(nsoFile, process, state)};
u64 offset{loadInfo.size}; u64 offset{loadInfo.size};
u64 base{loadInfo.base}; u8* base{loadInfo.base};
state.logger->Info("Loaded nso 'rtld' at 0x{:X}", base); state.logger->Info("Loaded nso 'rtld' at 0x{:X}", fmt::ptr(base));
for (const auto &nso : {"main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { for (const auto &nso : {"main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
nsoFile = exeFs->OpenFile(nso); nsoFile = exeFs->OpenFile(nso);
@ -34,7 +34,7 @@ namespace skyline::loader {
continue; continue;
loadInfo = NsoLoader::LoadNso(nsoFile, process, state, offset); loadInfo = NsoLoader::LoadNso(nsoFile, process, state, offset);
state.logger->Info("Loaded nso '{}' at 0x{:X}", nso, base + offset); state.logger->Info("Loaded nso '{}' at 0x{:X}", nso, fmt::ptr(base + offset));
offset += loadInfo.size; offset += loadInfo.size;
} }

View File

@ -162,29 +162,26 @@ namespace skyline {
threadMap[thread->tid] = std::make_shared<std::thread>(&NCE::KernelThread, this, thread->tid); threadMap[thread->tid] = std::make_shared<std::thread>(&NCE::KernelThread, this, thread->tid);
} }
void NCE::ThreadTrace(u16 numHist, ThreadContext *ctx) { void NCE::ThreadTrace(u16 instructionCount, ThreadContext *ctx) {
std::string raw; std::string raw;
std::string trace; std::string trace;
std::string regStr; std::string regStr;
ctx = ctx ? ctx : state.ctx; ctx = ctx ? ctx : state.ctx;
if (numHist) { if (instructionCount) {
std::vector<u32> instrs(numHist); auto offset{ctx->pc - ((instructionCount - 2) * sizeof(u32))};
u64 size{sizeof(u32) * numHist}; span instructions(reinterpret_cast<u32*>(offset), instructionCount);
u64 offset{ctx->pc - size + (2 * sizeof(u32))};
state.process->ReadMemory(instrs.data(), offset, size); for (auto &instruction : instructions) {
instruction = __builtin_bswap32(instruction);
for (auto &instr : instrs) {
instr = __builtin_bswap32(instr);
if (offset == ctx->pc) if (offset == ctx->pc)
trace += fmt::format("\n-> 0x{:X} : 0x{:08X}", offset, instr); trace += fmt::format("\n-> 0x{:X} : 0x{:08X}", offset, instruction);
else else
trace += fmt::format("\n 0x{:X} : 0x{:08X}", offset, instr); trace += fmt::format("\n 0x{:X} : 0x{:08X}", offset, instruction);
raw += fmt::format("{:08X}", instr); raw += fmt::format("{:08X}", instruction);
offset += sizeof(u32); offset += sizeof(u32);
} }
} }
@ -201,7 +198,7 @@ namespace skyline {
regStr += fmt::format("\n{}{}: 0x{:<16X} {}{}: 0x{:X}", xStr, index, ctx->registers.regs[index], xStr, index + 1, ctx->registers.regs[index + 1]); regStr += fmt::format("\n{}{}: 0x{:<16X} {}{}: 0x{:X}", xStr, index, ctx->registers.regs[index], xStr, index + 1, ctx->registers.regs[index + 1]);
} }
if (numHist) { if (instructionCount) {
state.logger->Debug("Process Trace:{}", trace); state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw); state.logger->Debug("Raw Instructions: 0x{}", raw);
state.logger->Debug("CPU Context:{}", regStr); state.logger->Debug("CPU Context:{}", regStr);

View File

@ -66,10 +66,10 @@ namespace skyline {
/** /**
* @brief Prints out a trace and the CPU context * @brief Prints out a trace and the CPU context
* @param numHist The amount of previous instructions to print (Can be 0) * @param instructionCount The amount of previous instructions to print (Can be 0)
* @param ctx The ThreadContext of the thread to log * @param ctx The ThreadContext of the thread to log
*/ */
void ThreadTrace(u16 numHist = 10, ThreadContext *ctx = nullptr); void ThreadTrace(u16 instructionCount = 10, ThreadContext *ctx = nullptr);
/** /**
* @brief Patches specific parts of the code * @brief Patches specific parts of the code

View File

@ -32,21 +32,22 @@ namespace skyline::service::audio {
Result IAudioOut::AppendAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result IAudioOut::AppendAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct Data { struct Data {
u64 nextBufferPtr; i16* nextBuffer;
u64 sampleBufferPtr; i16* sampleBuffer;
u64 sampleCapacity; u64 sampleCapacity;
u64 sampleSize; u64 sampleSize;
u64 sampleOffset; u64 sampleOffset;
} &data{request.inputBuf.at(0).as<Data>()}; } &data{request.inputBuf.at(0).as<Data>()};
auto tag{request.Pop<u64>()}; auto tag{request.Pop<u64>()};
state.logger->Debug("Appending buffer with address: 0x{:X}, size: 0x{:X}", data.sampleBufferPtr, data.sampleSize); state.logger->Debug("Appending buffer with address: 0x{:X}, size: 0x{:X}", fmt::ptr(data.sampleBuffer), data.sampleSize);
span samples(data.sampleBuffer, data.sampleSize / sizeof(i16));
if (sampleRate != constant::SampleRate) { if (sampleRate != constant::SampleRate) {
auto resampledBuffer{resampler.ResampleBuffer(span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)), static_cast<double>(sampleRate) / constant::SampleRate, channelCount)}; auto resampledBuffer{resampler.ResampleBuffer(samples, static_cast<double>(sampleRate) / constant::SampleRate, channelCount)};
track->AppendBuffer(tag, resampledBuffer); track->AppendBuffer(tag, resampledBuffer);
} else { } else {
track->AppendBuffer(tag, span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16))); track->AppendBuffer(tag, samples);
} }
return {}; return {};

View File

@ -43,7 +43,7 @@ namespace skyline::service::audio::IAudioRenderer {
if (input.format == skyline::audio::AudioFormat::ADPCM) { if (input.format == skyline::audio::AudioFormat::ADPCM) {
std::vector<std::array<i16, 2>> adpcmCoefficients(input.adpcmCoeffsSize / (sizeof(u16) * 2)); std::vector<std::array<i16, 2>> adpcmCoefficients(input.adpcmCoeffsSize / (sizeof(u16) * 2));
state.process->ReadMemory(adpcmCoefficients.data(), input.adpcmCoeffsPosition, input.adpcmCoeffsSize); span(adpcmCoefficients).copy_from(span(input.adpcmCoeffs, input.adpcmCoeffsSize));
adpcmDecoder = skyline::audio::AdpcmDecoder(adpcmCoefficients); adpcmDecoder = skyline::audio::AdpcmDecoder(adpcmCoefficients);
} }
@ -58,6 +58,7 @@ namespace skyline::service::audio::IAudioRenderer {
void Voice::UpdateBuffers() { void Voice::UpdateBuffers() {
const auto &currentBuffer{waveBuffers.at(bufferIndex)}; const auto &currentBuffer{waveBuffers.at(bufferIndex)};
span buffer(currentBuffer.pointer, currentBuffer.size);
if (currentBuffer.size == 0) if (currentBuffer.size == 0)
return; return;
@ -65,10 +66,10 @@ namespace skyline::service::audio::IAudioRenderer {
switch (format) { switch (format) {
case skyline::audio::AudioFormat::Int16: case skyline::audio::AudioFormat::Int16:
samples.resize(currentBuffer.size / sizeof(i16)); samples.resize(currentBuffer.size / sizeof(i16));
state.process->ReadMemory(samples.data(), currentBuffer.address, currentBuffer.size); buffer.copy_from(samples);
break; break;
case skyline::audio::AudioFormat::ADPCM: { case skyline::audio::AudioFormat::ADPCM: {
samples = adpcmDecoder->Decode(span(state.process->GetPointer<u8>(currentBuffer.address), currentBuffer.size)); samples = adpcmDecoder->Decode(buffer);
break; break;
} }
default: default:

View File

@ -20,7 +20,7 @@ namespace skyline::service::audio::IAudioRenderer {
static_assert(sizeof(BiquadFilter) == 0xC); static_assert(sizeof(BiquadFilter) == 0xC);
struct WaveBuffer { struct WaveBuffer {
u64 address; u8* pointer;
u64 size; u64 size;
u32 firstSampleOffset; u32 firstSampleOffset;
u32 lastSampleOffset; u32 lastSampleOffset;
@ -51,7 +51,7 @@ namespace skyline::service::audio::IAudioRenderer {
u32 appendedWaveBuffersCount; u32 appendedWaveBuffersCount;
u32 baseWaveBufferIndex; u32 baseWaveBufferIndex;
u32 _unk1_; u32 _unk1_;
u64 adpcmCoeffsPosition; u32* adpcmCoeffs;
u64 adpcmCoeffsSize; u64 adpcmCoeffsSize;
u32 destination; u32 destination;
u32 _pad0_; u32 _pad0_;

View File

@ -149,7 +149,7 @@ namespace skyline::service::hosbinder {
throw exception("Unknown pixel format used for FB"); throw exception("Unknown pixel format used for FB");
} }
auto texture{std::make_shared<gpu::GuestTexture>(state, nvBuffer->address + gbpBuffer.offset, gpu::texture::Dimensions(gbpBuffer.width, gbpBuffer.height), format, gpu::texture::TileMode::Block, gpu::texture::TileConfig{.surfaceWidth = static_cast<u16>(gbpBuffer.stride), .blockHeight = static_cast<u8>(1U << gbpBuffer.blockHeightLog2), .blockDepth = 1})}; auto texture{std::make_shared<gpu::GuestTexture>(state, nvBuffer->pointer + gbpBuffer.offset, gpu::texture::Dimensions(gbpBuffer.width, gbpBuffer.height), format, gpu::texture::TileMode::Block, gpu::texture::TileConfig{.surfaceWidth = static_cast<u16>(gbpBuffer.stride), .blockHeight = static_cast<u8>(1U << gbpBuffer.blockHeightLog2), .blockDepth = 1})};
queue[data.slot] = std::make_shared<Buffer>(gbpBuffer, texture->InitializePresentationTexture()); queue[data.slot] = std::make_shared<Buffer>(gbpBuffer, texture->InitializePresentationTexture());
state.gpu->bufferEvent->Signal(); state.gpu->bufferEvent->Signal();

View File

@ -98,9 +98,9 @@ namespace skyline::service::nvdrv::device {
} }
u64 gpuAddress{data.offset + data.bufferOffset}; u64 gpuAddress{data.offset + data.bufferOffset};
u64 cpuAddress{region->second.cpuAddress + data.bufferOffset}; u8 *cpuPtr{region->second.cpuPtr + data.bufferOffset};
if (state.gpu->memoryManager.MapFixed(gpuAddress, cpuAddress, data.mappingSize)) { if (state.gpu->memoryManager.MapFixed(gpuAddress, cpuPtr, data.mappingSize)) {
state.logger->Warn("Failed to remap GPU address space region: 0x{:X}", gpuAddress); state.logger->Warn("Failed to remap GPU address space region: 0x{:X}", gpuAddress);
return NvStatus::BadParameter; return NvStatus::BadParameter;
} }
@ -108,20 +108,20 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success; return NvStatus::Success;
} }
u64 mapPhysicalAddress{data.bufferOffset + mapping->address}; u8* mapPointer{data.bufferOffset + mapping->pointer};
u64 mapSize{data.mappingSize ? data.mappingSize : mapping->size}; u64 mapSize{data.mappingSize ? data.mappingSize : mapping->size};
if (data.flags.fixed) if (data.flags.fixed)
data.offset = state.gpu->memoryManager.MapFixed(data.offset, mapPhysicalAddress, mapSize); data.offset = state.gpu->memoryManager.MapFixed(data.offset, mapPointer, mapSize);
else else
data.offset = state.gpu->memoryManager.MapAllocate(mapPhysicalAddress, mapSize); data.offset = state.gpu->memoryManager.MapAllocate(mapPointer, mapSize);
if (data.offset == 0) { if (data.offset == 0) {
state.logger->Warn("Failed to map GPU address space region!"); state.logger->Warn("Failed to map GPU address space region!");
return NvStatus::BadParameter; return NvStatus::BadParameter;
} }
regionMap[data.offset] = {mapPhysicalAddress, mapSize, data.flags.fixed}; regionMap[data.offset] = {mapPointer, mapSize, data.flags.fixed};
return NvStatus::Success; return NvStatus::Success;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
@ -183,10 +183,10 @@ namespace skyline::service::nvdrv::device {
auto mapping{nvmap->handleTable.at(entry.nvmapHandle)}; 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{mapping->address + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift)}; u8* mapPointer{mapping->pointer + (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, mapPointer, mapSize);
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
state.logger->Warn("Invalid NvMap handle: 0x{:X}", entry.nvmapHandle); state.logger->Warn("Invalid NvMap handle: 0x{:X}", entry.nvmapHandle);
return NvStatus::BadParameter; return NvStatus::BadParameter;

View File

@ -13,7 +13,7 @@ namespace skyline::service::nvdrv::device {
class NvHostAsGpu : public NvDevice { class NvHostAsGpu : public NvDevice {
private: private:
struct AddressSpaceRegion { struct AddressSpaceRegion {
u64 cpuAddress; u8 *cpuPtr;
u64 size; u64 size;
bool fixed; bool fixed;
}; };

View File

@ -26,7 +26,7 @@ namespace skyline::service::nvdrv::device {
NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) { NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data { struct Data {
u64 address; // In gpu::gpfifo::GpEntry* entries; // In
u32 numEntries; // In u32 numEntries; // In
union { union {
struct __attribute__((__packed__)) { struct __attribute__((__packed__)) {
@ -58,7 +58,7 @@ namespace skyline::service::nvdrv::device {
if (type == IoctlType::Ioctl2) if (type == IoctlType::Ioctl2)
return inlineBuffer.cast<gpu::gpfifo::GpEntry>(); return inlineBuffer.cast<gpu::gpfifo::GpEntry>();
else else
return span(state.process->GetPointer<gpu::gpfifo::GpEntry>(data.address), data.numEntries); return span(data.entries, data.numEntries);
}()); }());
data.fence.id = channelFence.id; data.fence.id = channelFence.id;

View File

@ -47,7 +47,7 @@ namespace skyline::service::nvdrv::device {
u32 align; // In u32 align; // In
u8 kind; // In u8 kind; // In
u8 _pad0_[7]; u8 _pad0_[7];
u64 address; // InOut u8* pointer; // InOut
} &data = buffer.as<Data>(); } &data = buffer.as<Data>();
try { try {
@ -56,10 +56,10 @@ namespace skyline::service::nvdrv::device {
object->flags = data.flags; object->flags = data.flags;
object->align = data.align; object->align = data.align;
object->kind = data.kind; object->kind = data.kind;
object->address = data.address; object->pointer = data.pointer;
object->status = NvMapObject::Status::Allocated; object->status = NvMapObject::Status::Allocated;
state.logger->Debug("Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address); state.logger->Debug("Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}", data.handle, data.heapMask, data.flags, data.align, data.kind, fmt::ptr(data.pointer));
return NvStatus::Success; return NvStatus::Success;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle); state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle);
@ -71,7 +71,7 @@ namespace skyline::service::nvdrv::device {
struct Data { struct Data {
u32 handle; // In u32 handle; // In
u32 _pad0_; u32 _pad0_;
u64 address; // Out u8* pointer; // Out
u32 size; // Out u32 size; // Out
u32 flags; // Out u32 flags; // Out
} &data = buffer.as<Data>(); } &data = buffer.as<Data>();
@ -79,17 +79,17 @@ namespace skyline::service::nvdrv::device {
try { try {
const auto &object{handleTable.at(data.handle)}; const auto &object{handleTable.at(data.handle)};
if (object.use_count() > 1) { if (object.use_count() > 1) {
data.address = static_cast<u32>(object->address); data.pointer = object->pointer;
data.flags = 0x0; data.flags = 0x0;
} else { } else {
data.address = 0x0; data.pointer = nullptr;
data.flags = 0x1; // Not free yet data.flags = 0x1; // Not free yet
} }
data.size = object->size; data.size = object->size;
handleTable.erase(data.handle); handleTable.erase(data.handle);
state.logger->Debug("Handle: 0x{:X} -> Address: 0x{:X}, Size: 0x{:X}, Flags: 0x{:X}", data.handle, data.address, data.size, data.flags); state.logger->Debug("Handle: 0x{:X} -> Address: 0x{:X}, Size: 0x{:X}, Flags: 0x{:X}", data.handle, fmt::ptr(data.pointer), data.size, data.flags);
return NvStatus::Success; return NvStatus::Success;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle); state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle);

View File

@ -16,11 +16,11 @@ namespace skyline::service::nvdrv::device {
* @brief NvMapObject is used to hold the state of held objects * @brief NvMapObject is used to hold the state of held objects
*/ */
struct NvMapObject { struct NvMapObject {
u32 id; //!< The ID of this object u32 id;
u32 size; //!< The size of this object u32 size;
u64 address{}; //!< The address of the allocation u8* pointer{};
u32 flags{}; //!< The flag of the memory (0 = Read Only, 1 = Read-Write) u32 flags{}; //!< The flag of the memory (0 = Read Only, 1 = Read-Write)
u32 align{}; //!< The alignment of the allocation u32 align{};
u32 heapMask{}; //!< This is set during Alloc and returned during Param u32 heapMask{}; //!< This is set during Alloc and returned during Param
u8 kind{}; //!< This is same as heapMask u8 kind{}; //!< This is same as heapMask