mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 21:45:28 +03:00
Dynamic Guest Memory Base Allocation
This commit is contained in:
parent
cffbfc8034
commit
369bd469f6
@ -68,9 +68,6 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace constant {
|
namespace constant {
|
||||||
// Memory
|
|
||||||
constexpr u64 BaseAddress{0x8000000}; //!< The address space base
|
|
||||||
constexpr u64 DefaultStackSize{0x1E8480}; //!< The default amount of stack: 2 MB
|
|
||||||
// Display
|
// Display
|
||||||
constexpr u16 HandheldResolutionW{1280}; //!< The width component of the handheld resolution
|
constexpr u16 HandheldResolutionW{1280}; //!< The width component of the handheld resolution
|
||||||
constexpr u16 HandheldResolutionH{720}; //!< The height component of the handheld resolution
|
constexpr u16 HandheldResolutionH{720}; //!< The height component of the handheld resolution
|
||||||
@ -140,12 +137,12 @@ namespace skyline {
|
|||||||
template<class T>
|
template<class T>
|
||||||
T PointerValue(T item) {
|
T PointerValue(T item) {
|
||||||
return item;
|
return item;
|
||||||
};
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
size_t PointerValue(T *item) {
|
size_t PointerValue(T *item) {
|
||||||
return reinterpret_cast<size_t>(item);
|
return reinterpret_cast<size_t>(item);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The value aligned up to the next multiple
|
* @return The value aligned up to the next multiple
|
||||||
@ -210,7 +207,7 @@ namespace skyline {
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u8 HexDigitToByte(char digit) {
|
constexpr u8 HexDigitToNibble(char digit) {
|
||||||
if (digit >= '0' && digit <= '9')
|
if (digit >= '0' && digit <= '9')
|
||||||
return digit - '0';
|
return digit - '0';
|
||||||
else if (digit >= 'a' && digit <= 'f')
|
else if (digit >= 'a' && digit <= 'f')
|
||||||
@ -221,17 +218,35 @@ namespace skyline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t Size>
|
template<size_t Size>
|
||||||
constexpr std::array<u8, Size> HexStringToArray(std::string_view hexString) {
|
constexpr std::array<u8, Size> HexStringToArray(std::string_view string) {
|
||||||
if (hexString.size() != Size * 2)
|
if (string.size() != Size * 2)
|
||||||
throw exception("Invalid size");
|
throw exception("Invalid size");
|
||||||
std::array<u8, Size> result;
|
std::array<u8, Size> result;
|
||||||
for (size_t i{}; i < Size; i++) {
|
for (size_t i{}; i < Size; i++) {
|
||||||
size_t hexStrIndex{i * 2};
|
size_t index{i * 2};
|
||||||
result[i] = (HexDigitToByte(hexString[hexStrIndex]) << 4) | HexDigitToByte(hexString[hexStrIndex + 1]);
|
result[i] = (HexDigitToNibble(string[index]) << 4) | HexDigitToNibble(string[index + 1]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
constexpr Type HexStringToInt(std::string_view string) {
|
||||||
|
Type result{};
|
||||||
|
size_t offset{(sizeof(Type) * 8) - 4};
|
||||||
|
for (size_t index{}; index < std::min(sizeof(Type) * 2, string.size()); index++, offset -= 4) {
|
||||||
|
char digit{string[index]};
|
||||||
|
if (digit >= '0' && digit <= '9')
|
||||||
|
result |= static_cast<Type>(digit - '0') << offset;
|
||||||
|
else if (digit >= 'a' && digit <= 'f')
|
||||||
|
result |= static_cast<Type>(digit - 'a' + 10) << offset;
|
||||||
|
else if (digit >= 'A' && digit <= 'F')
|
||||||
|
result |= static_cast<Type>(digit - 'A' + 10) << offset;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result >> (offset + 4);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A compile-time hash function as std::hash isn't constexpr
|
* @brief A compile-time hash function as std::hash isn't constexpr
|
||||||
*/
|
*/
|
||||||
|
@ -15,16 +15,14 @@ namespace skyline::kernel {
|
|||||||
case memory::AddressSpaceType::AddressSpace36Bit: {
|
case memory::AddressSpaceType::AddressSpace36Bit: {
|
||||||
addressSpace.address = 0;
|
addressSpace.address = 0;
|
||||||
addressSpace.size = 1UL << 36;
|
addressSpace.size = 1UL << 36;
|
||||||
base.address = constant::BaseAddress;
|
base.size = 0x78000000 + 0x180000000 + 0x180000000 + 0x180000000;
|
||||||
base.size = 0xFF8000000;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case memory::AddressSpaceType::AddressSpace39Bit: {
|
case memory::AddressSpaceType::AddressSpace39Bit: {
|
||||||
addressSpace.address = 0;
|
addressSpace.address = 0;
|
||||||
addressSpace.size = 1UL << 39;
|
addressSpace.size = 1UL << 39;
|
||||||
base.address = constant::BaseAddress;
|
base.size = 0x78000000 + 0x1000000000 + 0x180000000 + 0x80000000 + 0x1000000000;
|
||||||
base.size = 0x7FF8000000;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +30,27 @@ namespace skyline::kernel {
|
|||||||
throw exception("VMM initialization with unknown address space");
|
throw exception("VMM initialization with unknown address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ifstream mapsFile("/proc/self/maps");
|
||||||
|
std::string maps((std::istreambuf_iterator<char>(mapsFile)), std::istreambuf_iterator<char>());
|
||||||
|
size_t line{}, start{}, alignedStart{};
|
||||||
|
do {
|
||||||
|
auto end{util::HexStringToInt<u64>(std::string_view(maps.data() + line, sizeof(u64) * 2))};
|
||||||
|
if (end - start > base.size + (alignedStart - start)) { // We don't want to overflow if alignedStart > start
|
||||||
|
base.address = alignedStart;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = util::HexStringToInt<u64>(std::string_view(maps.data() + maps.find_first_of('-', line) + 1, sizeof(u64) * 2));
|
||||||
|
alignedStart = util::AlignUp(start, 1ULL << 21);
|
||||||
|
if (alignedStart + base.size > addressSpace.size)
|
||||||
|
break;
|
||||||
|
} while ((line = maps.find_first_of('\n', line)) != std::string::npos && line++);
|
||||||
|
|
||||||
|
if (!base.address)
|
||||||
|
throw exception("Cannot find a suitable carveout for the guest address space");
|
||||||
|
|
||||||
|
mmap(reinterpret_cast<void*>(base.address), base.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
|
||||||
chunks = {ChunkDescriptor{
|
chunks = {ChunkDescriptor{
|
||||||
.ptr = reinterpret_cast<u8 *>(addressSpace.address),
|
.ptr = reinterpret_cast<u8 *>(addressSpace.address),
|
||||||
.size = addressSpace.size,
|
.size = addressSpace.size,
|
||||||
@ -50,7 +69,7 @@ namespace skyline::kernel {
|
|||||||
alias.address = code.address + code.size;
|
alias.address = code.address + code.size;
|
||||||
alias.size = 0x180000000;
|
alias.size = 0x180000000;
|
||||||
stack.address = alias.address;
|
stack.address = alias.address;
|
||||||
stack.size = alias.size;
|
stack.size = 0x180000000;
|
||||||
heap.address = alias.address + alias.size;
|
heap.address = alias.address + alias.size;
|
||||||
heap.size = 0x180000000;
|
heap.size = 0x180000000;
|
||||||
tlsIo.address = code.address;
|
tlsIo.address = code.address;
|
||||||
@ -59,8 +78,8 @@ namespace skyline::kernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 1UL << 39: {
|
case 1UL << 39: {
|
||||||
code.address = util::AlignDown(address, 0x200000);
|
code.address = base.address;
|
||||||
code.size = util::AlignUp(address + size, 0x200000) - code.address;
|
code.size = 0x78000000;
|
||||||
alias.address = code.address + code.size;
|
alias.address = code.address + code.size;
|
||||||
alias.size = 0x1000000000;
|
alias.size = 0x1000000000;
|
||||||
heap.address = alias.address + alias.size;
|
heap.address = alias.address + alias.size;
|
||||||
@ -76,7 +95,10 @@ namespace skyline::kernel {
|
|||||||
throw exception("Regions initialized without VMM initialization");
|
throw exception("Regions initialized without VMM initialization");
|
||||||
}
|
}
|
||||||
|
|
||||||
state.logger->Debug("Region Map:\nCode Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nAlias Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nHeap Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nStack Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nTLS/IO Region: 0x{:X} - 0x{:X} (Size: 0x{:X})", code.address, code.address + code.size, code.size, alias.address, alias.address + alias.size, alias.size, heap.address, heap
|
if (size > code.size)
|
||||||
|
throw exception("Code region ({}) is smaller than mapped code size ({})", code.size, size);
|
||||||
|
|
||||||
|
state.logger->Debug("Region Map:\nVMM Base: 0x{:X}\nCode Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nAlias Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nHeap Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nStack Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nTLS/IO Region: 0x{:X} - 0x{:X} (Size: 0x{:X})", base.address, code.address, code.address + code.size, code.size, alias.address, alias.address + alias.size, alias.size, heap.address, heap
|
||||||
.address + heap.size, heap.size, stack.address, stack.address + stack.size, stack.size, tlsIo.address, tlsIo.address + tlsIo.size, tlsIo.size);
|
.address + heap.size, heap.size, stack.address, stack.address + stack.size, stack.size, tlsIo.address, tlsIo.address + tlsIo.size, tlsIo.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,15 +674,15 @@ namespace skyline::kernel::svc {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::TotalMemoryUsage:
|
case constant::infoState::TotalMemoryUsage:
|
||||||
out = state.process->heap->size + constant::DefaultStackSize + state.process->memory.GetProgramSize();
|
out = state.process->heap->size + state.thread->stack->size + state.process->memory.GetProgramSize();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::AddressSpaceBaseAddr:
|
case constant::infoState::AddressSpaceBaseAddr:
|
||||||
out = state.process->memory.base.address;
|
out = state.process->memory.addressSpace.address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::AddressSpaceSize:
|
case constant::infoState::AddressSpaceSize:
|
||||||
out = state.process->memory.base.size;
|
out = state.process->memory.addressSpace.size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::StackRegionBaseAddr:
|
case constant::infoState::StackRegionBaseAddr:
|
||||||
@ -698,7 +698,7 @@ namespace skyline::kernel::svc {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::PersonalMmHeapUsage:
|
case constant::infoState::PersonalMmHeapUsage:
|
||||||
out = state.process->heap->size + constant::DefaultStackSize;
|
out = state.process->heap->size + state.thread->stack->size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::TotalMemoryAvailableWithoutMmHeap:
|
case constant::infoState::TotalMemoryAvailableWithoutMmHeap:
|
||||||
@ -706,7 +706,7 @@ namespace skyline::kernel::svc {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::TotalMemoryUsedWithoutMmHeap:
|
case constant::infoState::TotalMemoryUsedWithoutMmHeap:
|
||||||
out = state.process->heap->size + constant::DefaultStackSize; // TODO: Same as above
|
out = state.process->heap->size + state.thread->stack->size; // TODO: Same as above
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::UserExceptionContextAddr:
|
case constant::infoState::UserExceptionContextAddr:
|
||||||
|
@ -8,16 +8,17 @@
|
|||||||
#include "KProcess.h"
|
#include "KProcess.h"
|
||||||
|
|
||||||
namespace skyline::kernel::type {
|
namespace skyline::kernel::type {
|
||||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u8* ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) {
|
KPrivateMemory::KPrivateMemory(const DeviceState &state, u8* ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) {
|
||||||
if (ptr && !util::PageAligned(ptr))
|
if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size))
|
||||||
|
throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size);
|
||||||
|
if (!util::PageAligned(ptr))
|
||||||
throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", ptr);
|
throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", ptr);
|
||||||
|
|
||||||
this->ptr = reinterpret_cast<u8*>(mmap(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, (ptr ? MAP_FIXED : 0) | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
if (mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) // We only need to reprotect as the allocation has already been reserved by the MemoryManager
|
||||||
if (this->ptr == MAP_FAILED)
|
|
||||||
throw exception("An occurred while mapping private memory: {} with 0x{:X} @ 0x{:X}", strerror(errno), ptr, size);
|
throw exception("An occurred while mapping private memory: {} with 0x{:X} @ 0x{:X}", strerror(errno), ptr, size);
|
||||||
|
|
||||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||||
.ptr = this->ptr,
|
.ptr = ptr,
|
||||||
.size = size,
|
.size = size,
|
||||||
.permission = permission,
|
.permission = permission,
|
||||||
.state = memState,
|
.state = memState,
|
||||||
@ -25,8 +26,7 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KPrivateMemory::Resize(size_t nSize) {
|
void KPrivateMemory::Resize(size_t nSize) {
|
||||||
ptr = reinterpret_cast<u8*>(mremap(ptr, size, nSize, 0));
|
if (mprotect(ptr, nSize, PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
|
||||||
if (ptr == MAP_FAILED)
|
|
||||||
throw exception("An occurred while resizing private memory: {}", strerror(errno));
|
throw exception("An occurred while resizing private memory: {}", strerror(errno));
|
||||||
|
|
||||||
if (nSize < size) {
|
if (nSize < size) {
|
||||||
@ -48,6 +48,9 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KPrivateMemory::UpdatePermission(u8* ptr, size_t size, memory::Permission permission) {
|
void KPrivateMemory::UpdatePermission(u8* ptr, size_t size, memory::Permission permission) {
|
||||||
|
ptr = std::clamp(ptr, this->ptr, this->ptr + this->size);
|
||||||
|
size = std::min(size, static_cast<size_t>((this->ptr + this->size) - ptr));
|
||||||
|
|
||||||
if (ptr && !util::PageAligned(ptr))
|
if (ptr && !util::PageAligned(ptr))
|
||||||
throw exception("KPrivateMemory permission updated with a non-page-aligned address: 0x{:X}", ptr);
|
throw exception("KPrivateMemory permission updated with a non-page-aligned address: 0x{:X}", ptr);
|
||||||
|
|
||||||
@ -64,7 +67,7 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KPrivateMemory::~KPrivateMemory() {
|
KPrivateMemory::~KPrivateMemory() {
|
||||||
munmap(ptr, size);
|
mprotect(ptr, size, PROT_NONE);
|
||||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||||
.ptr = ptr,
|
.ptr = ptr,
|
||||||
.size = size,
|
.size = size,
|
||||||
|
@ -17,8 +17,8 @@ namespace skyline::kernel::type {
|
|||||||
memory::MemoryState memState;
|
memory::MemoryState memState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ptr The address to map to (If NULL then an arbitrary address is picked)
|
|
||||||
* @param permission The permissions for the allocated memory (As reported to the application, host memory permissions aren't reflected by this)
|
* @param permission The permissions for the allocated memory (As reported to the application, host memory permissions aren't reflected by this)
|
||||||
|
* @note 'ptr' needs to be in guest-reserved address space
|
||||||
*/
|
*/
|
||||||
KPrivateMemory(const DeviceState &state, u8* ptr, size_t size, memory::Permission permission, memory::MemoryState memState);
|
KPrivateMemory(const DeviceState &state, u8* ptr, size_t size, memory::Permission permission, memory::MemoryState memState);
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ namespace skyline::kernel::type {
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
throw exception("An error occurred while creating shared memory: {}", fd);
|
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||||
|
|
||||||
kernel.ptr = reinterpret_cast<u8*>(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0));
|
kernel.ptr = reinterpret_cast<u8 *>(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0));
|
||||||
if (kernel.ptr == MAP_FAILED)
|
if (kernel.ptr == MAP_FAILED)
|
||||||
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||||
|
|
||||||
@ -21,10 +21,12 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8 *KSharedMemory::Map(u8 *ptr, u64 size, memory::Permission permission) {
|
u8 *KSharedMemory::Map(u8 *ptr, u64 size, memory::Permission permission) {
|
||||||
|
if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size))
|
||||||
|
throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size);
|
||||||
if (ptr && !util::PageAligned(ptr))
|
if (ptr && !util::PageAligned(ptr))
|
||||||
throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", ptr);
|
throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", ptr);
|
||||||
|
|
||||||
guest.ptr = reinterpret_cast<u8*>(mmap(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | (ptr ? MAP_FIXED_NOREPLACE : 0), fd, 0));
|
guest.ptr = reinterpret_cast<u8 *>(mmap(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | (ptr ? MAP_FIXED_NOREPLACE : 0), fd, 0));
|
||||||
if (guest.ptr == MAP_FAILED)
|
if (guest.ptr == MAP_FAILED)
|
||||||
throw exception("An error occurred while mapping shared memory in guest");
|
throw exception("An error occurred while mapping shared memory in guest");
|
||||||
guest.size = size;
|
guest.size = size;
|
||||||
@ -39,7 +41,7 @@ namespace skyline::kernel::type {
|
|||||||
return guest.ptr;
|
return guest.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSharedMemory::UpdatePermission(u8* ptr, size_t size, memory::Permission permission) {
|
void KSharedMemory::UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) {
|
||||||
if (ptr && !util::PageAligned(ptr))
|
if (ptr && !util::PageAligned(ptr))
|
||||||
throw exception("KSharedMemory permission updated with a non-page-aligned address: 0x{:X}", ptr);
|
throw exception("KSharedMemory permission updated with a non-page-aligned address: 0x{:X}", ptr);
|
||||||
|
|
||||||
@ -63,7 +65,7 @@ namespace skyline::kernel::type {
|
|||||||
munmap(kernel.ptr, kernel.size);
|
munmap(kernel.ptr, kernel.size);
|
||||||
|
|
||||||
if (guest.Valid()) {
|
if (guest.Valid()) {
|
||||||
munmap(guest.ptr, guest.size);
|
mmap(guest.ptr, guest.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||||
.ptr = guest.ptr,
|
.ptr = guest.ptr,
|
||||||
.size = guest.size,
|
.size = guest.size,
|
||||||
|
@ -27,8 +27,7 @@ namespace skyline::kernel::type {
|
|||||||
KSharedMemory(const DeviceState &state, size_t size, memory::MemoryState memState = memory::states::SharedMemory, KType type = KType::KSharedMemory);
|
KSharedMemory(const DeviceState &state, size_t size, memory::MemoryState memState = memory::states::SharedMemory, KType type = KType::KSharedMemory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ptr The address to map to (If NULL an arbitrary address is picked, it may be outside of the HOS address space)
|
* @note 'ptr' needs to be in guest-reserved address space
|
||||||
* @return The address of the allocation
|
|
||||||
*/
|
*/
|
||||||
u8 *Map(u8 *ptr, u64 size, memory::Permission permission);
|
u8 *Map(u8 *ptr, u64 size, memory::Permission permission);
|
||||||
|
|
||||||
|
@ -123,7 +123,8 @@ namespace skyline::kernel::type {
|
|||||||
state.logger->Debug("Starting thread #{}", id);
|
state.logger->Debug("Starting thread #{}", id);
|
||||||
|
|
||||||
if (!stack) {
|
if (!stack) {
|
||||||
stack = stack.make_shared(state, reinterpret_cast<u8 *>(state.process->memory.stack.address), constant::DefaultStackSize, memory::Permission{true, true, false}, memory::states::Stack);
|
constexpr u64 DefaultStackSize{0x1E8480}; //!< The default amount of stack: 2 MB
|
||||||
|
stack = stack.make_shared(state, reinterpret_cast<u8 *>(state.process->memory.stack.address), DefaultStackSize, memory::Permission{true, true, false}, memory::states::Stack);
|
||||||
if (mprotect(stack->ptr, PAGE_SIZE, PROT_NONE))
|
if (mprotect(stack->ptr, PAGE_SIZE, PROT_NONE))
|
||||||
throw exception("Failed to create guard page for thread stack at 0x{:X}", stack->ptr);
|
throw exception("Failed to create guard page for thread stack at 0x{:X}", stack->ptr);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@ namespace skyline::kernel::type {
|
|||||||
*/
|
*/
|
||||||
class KTransferMemory : public KSharedMemory {
|
class KTransferMemory : public KSharedMemory {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @note 'ptr' needs to be in guest-reserved address space
|
||||||
|
*/
|
||||||
KTransferMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory) : KSharedMemory(state, size, memState, KType::KTransferMemory) {
|
KTransferMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory) : KSharedMemory(state, size, memState, KType::KTransferMemory) {
|
||||||
std::memcpy(kernel.ptr, ptr, size);
|
std::memcpy(kernel.ptr, ptr, size);
|
||||||
Map(ptr, size, permission);
|
Map(ptr, size, permission);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace skyline::loader {
|
namespace skyline::loader {
|
||||||
Loader::ExecutableLoadInfo Loader::LoadExecutable(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, Executable &executable, size_t offset) {
|
Loader::ExecutableLoadInfo Loader::LoadExecutable(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, Executable &executable, size_t offset) {
|
||||||
u8 *base{reinterpret_cast<u8 *>(constant::BaseAddress + offset)};
|
u8 *base{reinterpret_cast<u8 *>(process->memory.base.address + offset)};
|
||||||
|
|
||||||
u64 textSize{executable.text.contents.size()};
|
u64 textSize{executable.text.contents.size()};
|
||||||
u64 roSize{executable.ro.contents.size()};
|
u64 roSize{executable.ro.contents.size()};
|
||||||
@ -45,6 +45,6 @@ namespace skyline::loader {
|
|||||||
std::memcpy(base + executable.data.offset, executable.data.contents.data(), dataSize - executable.bssSize);
|
std::memcpy(base + executable.data.offset, executable.data.contents.data(), dataSize - executable.bssSize);
|
||||||
std::memcpy(base + patchOffset, patch.data(), patchSize);
|
std::memcpy(base + patchOffset, patch.data(), patchSize);
|
||||||
|
|
||||||
return {base, patchOffset + patchSize + padding};
|
return {base, patchOffset + patchSize + padding, base};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ namespace skyline::loader {
|
|||||||
struct ExecutableLoadInfo {
|
struct ExecutableLoadInfo {
|
||||||
u8* base; //!< The base of the loaded executable
|
u8* base; //!< The base of the loaded executable
|
||||||
size_t size; //!< The total size of the loaded executable
|
size_t size; //!< The total size of the loaded executable
|
||||||
|
void* entry; //!< The entry point of the loaded executable
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +75,9 @@ namespace skyline::loader {
|
|||||||
return std::vector<u8>();
|
return std::vector<u8>();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) = 0;
|
/**
|
||||||
|
* @return Entry point to the start of the main executable in the ROM
|
||||||
|
*/
|
||||||
|
virtual void* LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace skyline::loader {
|
|||||||
throw exception("Only NCAs with an ExeFS can be loaded directly");
|
throw exception("Only NCAs with an ExeFS can be loaded directly");
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaLoader::LoadExeFs(const std::shared_ptr<vfs::FileSystem> &exeFs, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
void* NcaLoader::LoadExeFs(const std::shared_ptr<vfs::FileSystem> &exeFs, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
||||||
if (exeFs == nullptr)
|
if (exeFs == nullptr)
|
||||||
throw exception("Cannot load a null ExeFS");
|
throw exception("Cannot load a null ExeFS");
|
||||||
|
|
||||||
@ -25,6 +25,7 @@ namespace skyline::loader {
|
|||||||
auto loadInfo{NsoLoader::LoadNso(nsoFile, process, state)};
|
auto loadInfo{NsoLoader::LoadNso(nsoFile, process, state)};
|
||||||
u64 offset{loadInfo.size};
|
u64 offset{loadInfo.size};
|
||||||
u8* base{loadInfo.base};
|
u8* base{loadInfo.base};
|
||||||
|
void* entry{loadInfo.entry};
|
||||||
|
|
||||||
state.logger->Info("Loaded nso 'rtld' at 0x{:X}", base);
|
state.logger->Info("Loaded nso 'rtld' at 0x{:X}", base);
|
||||||
|
|
||||||
@ -40,9 +41,11 @@ namespace skyline::loader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state.process->memory.InitializeRegions(base, offset);
|
state.process->memory.InitializeRegions(base, offset);
|
||||||
|
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
void* NcaLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
||||||
LoadExeFs(nca.exeFs, process, state);
|
return LoadExeFs(nca.exeFs, process, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ namespace skyline::loader {
|
|||||||
* @param exefs A filesystem object containing the ExeFS filesystem to load into memory
|
* @param exefs A filesystem object containing the ExeFS filesystem to load into memory
|
||||||
* @param process The process to load the ExeFS into
|
* @param process The process to load the ExeFS into
|
||||||
*/
|
*/
|
||||||
static void LoadExeFs(const std::shared_ptr<vfs::FileSystem> &exefs, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
static void* LoadExeFs(const std::shared_ptr<vfs::FileSystem> &exefs, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
||||||
|
|
||||||
void LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
void* LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ namespace skyline::loader {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NroLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
void* NroLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
||||||
Executable nroExecutable{};
|
Executable nroExecutable{};
|
||||||
|
|
||||||
nroExecutable.text.contents = GetSegment(header.text);
|
nroExecutable.text.contents = GetSegment(header.text);
|
||||||
@ -61,5 +61,7 @@ namespace skyline::loader {
|
|||||||
state.process->memory.InitializeVmm(memory::AddressSpaceType::AddressSpace39Bit);
|
state.process->memory.InitializeVmm(memory::AddressSpaceType::AddressSpace39Bit);
|
||||||
auto loadInfo{LoadExecutable(process, state, nroExecutable)};
|
auto loadInfo{LoadExecutable(process, state, nroExecutable)};
|
||||||
state.process->memory.InitializeRegions(loadInfo.base, loadInfo.size);
|
state.process->memory.InitializeRegions(loadInfo.base, loadInfo.size);
|
||||||
|
|
||||||
|
return loadInfo.entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,6 @@ namespace skyline::loader {
|
|||||||
|
|
||||||
std::vector<u8> GetIcon();
|
std::vector<u8> GetIcon();
|
||||||
|
|
||||||
void LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
void* LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,10 @@ namespace skyline::loader {
|
|||||||
return LoadExecutable(process, state, nsoExecutable, offset);
|
return LoadExecutable(process, state, nsoExecutable, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NsoLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
void* NsoLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
||||||
state.process->memory.InitializeVmm(memory::AddressSpaceType::AddressSpace39Bit);
|
state.process->memory.InitializeVmm(memory::AddressSpaceType::AddressSpace39Bit);
|
||||||
auto loadInfo{LoadNso(backing, process, state)};
|
auto loadInfo{LoadNso(backing, process, state)};
|
||||||
state.process->memory.InitializeRegions(loadInfo.base, loadInfo.size);
|
state.process->memory.InitializeRegions(loadInfo.base, loadInfo.size);
|
||||||
|
return loadInfo.entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,6 @@ namespace skyline::loader {
|
|||||||
*/
|
*/
|
||||||
static ExecutableLoadInfo LoadNso(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, size_t offset = 0);
|
static ExecutableLoadInfo LoadNso(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, size_t offset = 0);
|
||||||
|
|
||||||
void LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
void* LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,8 @@ namespace skyline::loader {
|
|||||||
nacp = std::make_shared<vfs::NACP>(controlRomFs->OpenFile("control.nacp"));
|
nacp = std::make_shared<vfs::NACP>(controlRomFs->OpenFile("control.nacp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NspLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
void* NspLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
||||||
NcaLoader::LoadExeFs(programNca->exeFs, process, state);
|
return NcaLoader::LoadExeFs(programNca->exeFs, process, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> NspLoader::GetIcon() {
|
std::vector<u8> NspLoader::GetIcon() {
|
||||||
|
@ -26,6 +26,6 @@ namespace skyline::loader {
|
|||||||
|
|
||||||
std::vector<u8> GetIcon();
|
std::vector<u8> GetIcon();
|
||||||
|
|
||||||
void LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
void* LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,9 @@ namespace skyline::kernel {
|
|||||||
throw exception("Unsupported ROM extension.");
|
throw exception("Unsupported ROM extension.");
|
||||||
|
|
||||||
process = std::make_shared<kernel::type::KProcess>(state);
|
process = std::make_shared<kernel::type::KProcess>(state);
|
||||||
state.loader->LoadProcessData(process, state);
|
auto entry{state.loader->LoadProcessData(process, state)};
|
||||||
process->InitializeHeap();
|
process->InitializeHeap();
|
||||||
process->CreateThread(reinterpret_cast<void*>(constant::BaseAddress))->Start();
|
process->CreateThread(entry)->Start();
|
||||||
|
|
||||||
state.nce->Execute();
|
state.nce->Execute();
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,6 @@ namespace skyline::service::fssrv {
|
|||||||
|
|
||||||
manager.RegisterService(std::make_shared<IFileSystem>(std::make_shared<vfs::OsFileSystem>(state.os->appFilesPath + "/switch" + saveDataPath), state, manager), session, response);
|
manager.RegisterService(std::make_shared<IFileSystem>(std::make_shared<vfs::OsFileSystem>(state.os->appFilesPath + "/switch" + saveDataPath), state, manager), session, response);
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IFileSystemProxy::OpenDataStorageByCurrentProcess(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IFileSystemProxy::OpenDataStorageByCurrentProcess(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
Loading…
Reference in New Issue
Block a user