mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 09:51:48 +01:00
Remove KProcess Memory Functions
This commit is contained in:
parent
60e82e6af0
commit
02f3e37c4f
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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++) {
|
||||
|
@ -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
|
||||
|
@ -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};
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 {};
|
||||
|
@ -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 ¤tBuffer{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:
|
||||
|
@ -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_;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -13,7 +13,7 @@ namespace skyline::service::nvdrv::device {
|
||||
class NvHostAsGpu : public NvDevice {
|
||||
private:
|
||||
struct AddressSpaceRegion {
|
||||
u64 cpuAddress;
|
||||
u8 *cpuPtr;
|
||||
u64 size;
|
||||
bool fixed;
|
||||
};
|
||||
|
@ -26,8 +26,8 @@ namespace skyline::service::nvdrv::device {
|
||||
|
||||
NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||
struct Data {
|
||||
u64 address; // In
|
||||
u32 numEntries; // In
|
||||
gpu::gpfifo::GpEntry* entries; // In
|
||||
u32 numEntries; // In
|
||||
union {
|
||||
struct __attribute__((__packed__)) {
|
||||
bool fenceWait : 1;
|
||||
@ -39,8 +39,8 @@ namespace skyline::service::nvdrv::device {
|
||||
bool incrementWithValue : 1;
|
||||
};
|
||||
u32 raw;
|
||||
} flags; // In
|
||||
Fence fence; // InOut
|
||||
} flags; // In
|
||||
Fence fence; // InOut
|
||||
} &data = buffer.as<Data>();
|
||||
|
||||
auto driver{nvdrv::driver.lock()};
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user