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)
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;
} else if (chunk->address + chunk->size > newChunk.address) {
@ -65,7 +65,7 @@ namespace skyline::gpu::vmm {
tailChunk->address += chunkSliceOffset;
tailChunk->size -= chunkSliceOffset;
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
auto headChunk{std::prev(tailChunk)};
@ -103,27 +103,27 @@ namespace skyline::gpu::vmm {
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);
auto mappedChunk{FindChunk(ChunkState::Unmapped, size)};
if (!mappedChunk)
return 0;
auto chunk{*mappedChunk};
chunk.cpuAddress = address;
chunk.pointer = pointer;
chunk.size = size;
chunk.state = ChunkState::Mapped;
return InsertChunk(chunk);
}
u64 MemoryManager::MapFixed(u64 address, u64 cpuAddress, u64 size) {
if (!util::IsAligned(address, constant::GpuPageSize))
return 0;
u64 MemoryManager::MapFixed(u64 address, u8 *pointer, u64 size) {
if (!util::IsAligned(pointer, constant::GpuPageSize))
return false;
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) {
@ -151,20 +151,20 @@ namespace skyline::gpu::vmm {
u64 initialSize{size};
u64 chunkOffset{address - chunk->address};
u64 readAddress{chunk->cpuAddress + chunkOffset};
u64 readSize{std::min(chunk->size - chunkOffset, size)};
u8 *source{chunk->pointer + chunkOffset};
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
while (size) {
state.process->ReadMemory(destination + (initialSize - size), readAddress, readSize);
std::memcpy(destination + (initialSize - size), source, sourceSize);
size -= readSize;
size -= sourceSize;
if (size) {
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);
readAddress = chunk->cpuAddress;
readSize = std::min(chunk->size, size);
source = chunk->pointer;
sourceSize = std::min(chunk->size, size);
}
}
}
@ -181,20 +181,20 @@ namespace skyline::gpu::vmm {
u64 initialSize{size};
u64 chunkOffset{address - chunk->address};
u64 writeAddress{chunk->cpuAddress + chunkOffset};
u64 writeSize{std::min(chunk->size - chunkOffset, size)};
u8 *destination{chunk->pointer + chunkOffset};
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
while (size) {
state.process->WriteMemory(source + (initialSize - size), writeAddress, writeSize);
std::memcpy(destination, source + (initialSize - size), destinationSize);
size -= writeSize;
size -= destinationSize;
if (size) {
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);
writeAddress = chunk->cpuAddress;
writeSize = std::min(chunk->size, size);
destination = chunk->pointer;
destinationSize = std::min(chunk->size, size);
}
}
}

View File

@ -20,10 +20,10 @@ namespace skyline {
struct ChunkDescriptor {
u64 address; //!< The address of the chunk in the GPU address space
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;
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
@ -78,20 +78,20 @@ namespace skyline {
/**
* @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
* @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
* @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
* @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

View File

@ -7,7 +7,7 @@
#include "texture.h"
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) {
if (!host.expired())
@ -30,7 +30,7 @@ namespace skyline::gpu {
}
void Texture::SynchronizeHost() {
auto texture{state.process->GetPointer<u8>(guest->address)};
auto pointer{guest->pointer};
auto size{format.GetSize(dimensions)};
backing.resize(size);
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 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
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 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
for (u32 line{}; line < dimensions.height; line++) {
@ -89,7 +89,7 @@ namespace skyline::gpu {
outputLine += sizeLine;
}
} 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;
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
texture::Dimensions dimensions;
texture::Format format;
texture::TileMode tileMode;
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() {
return format.GetSize(dimensions);

View File

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

View File

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

View File

@ -7,7 +7,8 @@
namespace skyline::kernel {
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) {
case memory::AddressSpaceType::AddressSpace32Bit:
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
* @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);

View File

@ -28,10 +28,10 @@ namespace skyline::kernel::svc {
}
void SetMemoryAttribute(DeviceState &state) {
auto ptr{reinterpret_cast<u8 *>(state.ctx->registers.x0)};
if (!util::PageAligned(ptr)) {
auto pointer{reinterpret_cast<u8 *>(state.ctx->registers.x0)};
if (!util::PageAligned(pointer)) {
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;
}
@ -52,26 +52,26 @@ namespace skyline::kernel::svc {
return;
}
auto chunk{state.os->memory.Get(ptr)};
auto chunk{state.os->memory.Get(pointer)};
if (!chunk) {
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;
}
if (!chunk->state.attributeChangeAllowed) {
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;
}
auto newChunk{*chunk};
newChunk.ptr = ptr;
newChunk.ptr = pointer;
newChunk.size = size;
newChunk.attributes.isUncached = value.isUncached;
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{};
}
@ -182,8 +182,8 @@ namespace skyline::kernel::svc {
void QueryMemory(DeviceState &state) {
memory::MemoryInfo memInfo{};
auto ptr{reinterpret_cast<u8*>(state.ctx->registers.x2)};
auto chunk{state.os->memory.Get(ptr)};
auto pointer{reinterpret_cast<u8*>(state.ctx->registers.x2)};
auto chunk{state.os->memory.Get(pointer)};
if (chunk) {
memInfo = {
@ -206,10 +206,10 @@ namespace skyline::kernel::svc {
.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{};
}
@ -312,11 +312,11 @@ namespace skyline::kernel::svc {
void MapSharedMemory(DeviceState &state) {
try {
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.logger->Warn("svcMapSharedMemory: 'ptr' not page aligned: 0x{:X}", ptr);
state.logger->Warn("svcMapSharedMemory: 'pointer' not page aligned: 0x{:X}", pointer);
return;
}
@ -334,9 +334,9 @@ namespace skyline::kernel::svc {
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{};
} catch (const std::exception &) {
@ -346,10 +346,10 @@ namespace skyline::kernel::svc {
}
void CreateTransferMemory(DeviceState &state) {
auto ptr{reinterpret_cast<u8 *>(state.ctx->registers.x1)};
if (!util::PageAligned(ptr)) {
auto pointer{reinterpret_cast<u8 *>(state.ctx->registers.x1)};
if (!util::PageAligned(pointer)) {
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;
}
@ -367,8 +367,8 @@ namespace skyline::kernel::svc {
return;
}
auto tmem{state.process->NewHandle<type::KTransferMemory>(ptr, 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' : '-');
auto tmem{state.process->NewHandle<type::KTransferMemory>(pointer, size, permission)};
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.w1 = tmem.handle;
@ -426,9 +426,7 @@ namespace skyline::kernel::svc {
std::string handleStr;
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
std::vector<KHandle> waitHandles(numHandles);
state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(KHandle));
span waitHandles(reinterpret_cast<KHandle*>(state.ctx->registers.x1), numHandles);
for (const auto &handle : waitHandles) {
handleStr += fmt::format("* 0x{:X}\n", handle);
@ -464,7 +462,7 @@ namespace skyline::kernel::svc {
uint index{};
for (const auto &object : objectTable) {
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.w1 = index;
return;
@ -490,9 +488,9 @@ namespace skyline::kernel::svc {
}
void ArbitrateLock(DeviceState &state) {
auto address{state.ctx->registers.x1};
if (!util::WordAligned(address)) {
state.logger->Warn("svcArbitrateLock: 'address' not word aligned: 0x{:X}", address);
auto pointer{reinterpret_cast<u32*>(state.ctx->registers.x1)};
if (!util::WordAligned(pointer)) {
state.logger->Warn("svcArbitrateLock: 'pointer' not word aligned: 0x{:X}", fmt::ptr(pointer));
state.ctx->registers.w0 = result::InvalidAddress;
return;
}
@ -502,58 +500,58 @@ namespace skyline::kernel::svc {
if (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))
state.logger->Debug("svcArbitrateLock: Locked mutex at 0x{:X}", address);
if (state.process->MutexLock(pointer, ownerHandle))
state.logger->Debug("svcArbitrateLock: Locked mutex at 0x{:X}", fmt::ptr(pointer));
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{};
}
void ArbitrateUnlock(DeviceState &state) {
auto address{state.ctx->registers.x0};
if (!util::WordAligned(address)) {
state.logger->Warn("svcArbitrateUnlock: 'address' not word aligned: 0x{:X}", address);
auto mutex{reinterpret_cast<u32*>(state.ctx->registers.x0)};
if (!util::WordAligned(mutex)) {
state.logger->Warn("svcArbitrateUnlock: mutex pointer not word aligned: 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = result::InvalidAddress;
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)) {
state.logger->Debug("svcArbitrateUnlock: Unlocked mutex at 0x{:X}", address);
if (state.process->MutexUnlock(mutex)) {
state.logger->Debug("svcArbitrateUnlock: Unlocked mutex at 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = Result{};
} 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;
}
}
void WaitProcessWideKeyAtomic(DeviceState &state) {
auto mtxAddress{state.ctx->registers.x0};
if (!util::WordAligned(mtxAddress)) {
state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: 0x{:X}", mtxAddress);
auto mutex{reinterpret_cast<u32*>(state.ctx->registers.x0)};
if (!util::WordAligned(mutex)) {
state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex pointer not word aligned: 0x{:X}", fmt::ptr(mutex));
state.ctx->registers.w0 = result::InvalidAddress;
return;
}
auto condAddress{state.ctx->registers.x1};
auto conditional{reinterpret_cast<void*>(state.ctx->registers.x1)};
auto handle{state.ctx->registers.w2};
if (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)) {
state.logger->Debug("WaitProcessWideKeyAtomic: A non-owner thread tried to release a mutex at 0x{:X}", mtxAddress);
if (!state.process->MutexUnlock(mutex)) {
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;
return;
}
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.ctx->registers.w0 = Result{};
} else {
@ -563,11 +561,11 @@ namespace skyline::kernel::svc {
}
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};
state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count);
state.process->ConditionalVariableSignal(address, count);
state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", conditional, count);
state.process->ConditionalVariableSignal(conditional, count);
state.ctx->registers.w0 = Result{};
}
@ -586,7 +584,7 @@ namespace skyline::kernel::svc {
void ConnectToNamedPort(DeviceState &state) {
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{};
if (port.compare("sm:") >= 0) {

View File

@ -102,54 +102,6 @@ namespace skyline::kernel::type {
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) {
for (KHandle index{}; index < handles.size(); index++) {
auto& object{handles[index]};
@ -169,19 +121,17 @@ namespace skyline::kernel::type {
return std::nullopt;
}
bool KProcess::MutexLock(u64 address, KHandle owner) {
bool KProcess::MutexLock(u32* mutex, KHandle owner) {
std::unique_lock lock(mutexLock);
auto mtx{GetPointer<u32>(address)};
auto &mtxWaiters{mutexes[address]};
auto &mtxWaiters{mutexes[reinterpret_cast<u64>(mutex)]};
if (mtxWaiters.empty()) {
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;
}
if (__atomic_load_n(mtx, __ATOMIC_SEQ_CST) != (owner | ~constant::MtxOwnerMask))
if (__atomic_load_n(mutex, __ATOMIC_SEQ_CST) != (owner | ~constant::MtxOwnerMask))
return false;
std::shared_ptr<WaitStatus> status;
@ -209,20 +159,19 @@ namespace skyline::kernel::type {
return true;
}
bool KProcess::MutexUnlock(u64 address) {
bool KProcess::MutexUnlock(u32* mutex) {
std::unique_lock lock(mutexLock);
auto mtx{GetPointer<u32>(address)};
auto &mtxWaiters{mutexes[address]};
auto &mtxWaiters{mutexes[reinterpret_cast<u64>(mutex)]};
u32 mtxDesired{};
if (!mtxWaiters.empty())
mtxDesired = (*mtxWaiters.begin())->handle | ((mtxWaiters.size() > 1) ? ~constant::MtxOwnerMask : 0);
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;
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;
}
@ -237,16 +186,16 @@ namespace skyline::kernel::type {
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);
auto &condWaiters{conditionals[conditionalAddress]};
auto &condWaiters{conditionals[reinterpret_cast<u64>(conditional)]};
std::shared_ptr<WaitStatus> status;
for (auto it{condWaiters.begin()};; it++) {
if (it != condWaiters.end() && (*it)->priority >= state.thread->priority)
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);
break;
}
@ -278,16 +227,16 @@ namespace skyline::kernel::type {
return !timedOut;
}
void KProcess::ConditionalVariableSignal(u64 address, u64 amount) {
void KProcess::ConditionalVariableSignal(void* conditional, u64 amount) {
std::unique_lock condLock(conditionalLock);
auto &condWaiters{conditionals[address]};
auto &condWaiters{conditionals[reinterpret_cast<u64>(conditional)]};
u64 count{};
auto iter{condWaiters.begin()};
while (iter != condWaiters.end() && count < amount) {
auto &thread{*iter};
auto mtx{GetPointer<u32>(thread->mutexAddress)};
auto mtx{thread->mutex};
u32 mtxValue{__atomic_load_n(mtx, __ATOMIC_SEQ_CST)};
while (true) {
@ -308,7 +257,7 @@ namespace skyline::kernel::type {
if (mtxValue && ((mtxValue & constant::MtxOwnerMask) != state.thread->handle)) {
std::unique_lock mtxLock(mutexLock);
auto &mtxWaiters{mutexes[thread->mutexAddress]};
auto &mtxWaiters{mutexes[reinterpret_cast<u64>(thread->mutex)]};
std::shared_ptr<WaitStatus> status;
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
u8 priority; //!< The priority 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, 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
@ -136,67 +136,6 @@ namespace skyline {
*/
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
* @tparam objectClass The class of the kernel object to create
@ -279,33 +218,28 @@ namespace skyline {
/**
* @brief Locks the Mutex at the specified address
* @param address The address of the mutex
* @param owner The handle of the current mutex owner
* @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
* @param address The address of the mutex
* @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
* @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
* @param address The address of the conditional variable
* @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

View File

@ -9,7 +9,7 @@
namespace skyline::loader {
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 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
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);
process->WriteMemory(executable.ro.contents.data(), reinterpret_cast<u64>(base + executable.ro.offset), roSize);
process->WriteMemory(executable.data.contents.data(), reinterpret_cast<u64>(base + executable.data.offset), dataSize - executable.bssSize);
process->WriteMemory(patch.data(), reinterpret_cast<u64>(base + patchOffset), patchSize);
std::memcpy(executable.text.contents.data(), base + executable.text.offset, textSize);
std::memcpy(executable.ro.contents.data(), base + executable.ro.offset, roSize);
std::memcpy(executable.data.contents.data(), base + executable.data.offset, dataSize - executable.bssSize);
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
*/
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
};

View File

@ -23,9 +23,9 @@ namespace skyline::loader {
auto loadInfo{NsoLoader::LoadNso(nsoFile, process, state)};
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"}) {
nsoFile = exeFs->OpenFile(nso);
@ -34,7 +34,7 @@ namespace skyline::loader {
continue;
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;
}

View File

@ -162,29 +162,26 @@ namespace skyline {
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 trace;
std::string regStr;
ctx = ctx ? ctx : state.ctx;
if (numHist) {
std::vector<u32> instrs(numHist);
u64 size{sizeof(u32) * numHist};
u64 offset{ctx->pc - size + (2 * sizeof(u32))};
if (instructionCount) {
auto offset{ctx->pc - ((instructionCount - 2) * sizeof(u32))};
span instructions(reinterpret_cast<u32*>(offset), instructionCount);
state.process->ReadMemory(instrs.data(), offset, size);
for (auto &instr : instrs) {
instr = __builtin_bswap32(instr);
for (auto &instruction : instructions) {
instruction = __builtin_bswap32(instruction);
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
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);
}
}
@ -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]);
}
if (numHist) {
if (instructionCount) {
state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw);
state.logger->Debug("CPU Context:{}", regStr);

View File

@ -66,10 +66,10 @@ namespace skyline {
/**
* @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
*/
void ThreadTrace(u16 numHist = 10, ThreadContext *ctx = nullptr);
void ThreadTrace(u16 instructionCount = 10, ThreadContext *ctx = nullptr);
/**
* @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) {
struct Data {
u64 nextBufferPtr;
u64 sampleBufferPtr;
i16* nextBuffer;
i16* sampleBuffer;
u64 sampleCapacity;
u64 sampleSize;
u64 sampleOffset;
} &data{request.inputBuf.at(0).as<Data>()};
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) {
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);
} else {
track->AppendBuffer(tag, span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)));
track->AppendBuffer(tag, samples);
}
return {};

View File

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

View File

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

View File

@ -149,7 +149,7 @@ namespace skyline::service::hosbinder {
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());
state.gpu->bufferEvent->Signal();

View File

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

View File

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

View File

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

View File

@ -47,7 +47,7 @@ namespace skyline::service::nvdrv::device {
u32 align; // In
u8 kind; // In
u8 _pad0_[7];
u64 address; // InOut
u8* pointer; // InOut
} &data = buffer.as<Data>();
try {
@ -56,10 +56,10 @@ namespace skyline::service::nvdrv::device {
object->flags = data.flags;
object->align = data.align;
object->kind = data.kind;
object->address = data.address;
object->pointer = data.pointer;
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;
} catch (const std::out_of_range &) {
state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle);
@ -71,7 +71,7 @@ namespace skyline::service::nvdrv::device {
struct Data {
u32 handle; // In
u32 _pad0_;
u64 address; // Out
u8* pointer; // Out
u32 size; // Out
u32 flags; // Out
} &data = buffer.as<Data>();
@ -79,17 +79,17 @@ namespace skyline::service::nvdrv::device {
try {
const auto &object{handleTable.at(data.handle)};
if (object.use_count() > 1) {
data.address = static_cast<u32>(object->address);
data.pointer = object->pointer;
data.flags = 0x0;
} else {
data.address = 0x0;
data.pointer = nullptr;
data.flags = 0x1; // Not free yet
}
data.size = object->size;
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;
} catch (const std::out_of_range &) {
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
*/
struct NvMapObject {
u32 id; //!< The ID of this object
u32 size; //!< The size of this object
u64 address{}; //!< The address of the allocation
u32 id;
u32 size;
u8* pointer{};
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
u8 kind{}; //!< This is same as heapMask