mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-23 08:39:16 +01:00
Cleanup & Use C++ Concepts in utils.h
This commit is contained in:
parent
ea2626bcc6
commit
92a21ea616
@ -55,6 +55,9 @@ namespace skyline::util {
|
||||
return item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
concept IsPointerOrIntegral = std::is_integral_v<T> || std::is_pointer_v<T>;
|
||||
|
||||
/**
|
||||
* @return The value aligned up to the next multiple
|
||||
* @note The multiple needs to be a power of 2
|
||||
@ -78,6 +81,7 @@ namespace skyline::util {
|
||||
* @return If the address is aligned with the multiple
|
||||
*/
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
requires (IsPointerOrIntegral<TypeVal> && IsPointerOrIntegral<TypeMul>)
|
||||
constexpr bool IsAligned(TypeVal value, TypeMul multiple) {
|
||||
if ((multiple & (multiple - 1)) == 0)
|
||||
return !(PointerValue(value) & (multiple - 1U));
|
||||
@ -85,19 +89,15 @@ namespace skyline::util {
|
||||
return (PointerValue(value) % multiple) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the value is page aligned
|
||||
*/
|
||||
template<typename TypeVal>
|
||||
constexpr bool PageAligned(TypeVal value) {
|
||||
requires IsPointerOrIntegral<TypeVal>
|
||||
constexpr bool IsPageAligned(TypeVal value) {
|
||||
return IsAligned(value, PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the value is word aligned
|
||||
*/
|
||||
template<typename TypeVal>
|
||||
constexpr bool WordAligned(TypeVal value) {
|
||||
requires IsPointerOrIntegral<TypeVal>
|
||||
constexpr bool IsWordAligned(TypeVal value) {
|
||||
return IsAligned(value, WORD_BIT / 8);
|
||||
}
|
||||
|
||||
@ -106,6 +106,7 @@ namespace skyline::util {
|
||||
* @return The magic of the supplied string
|
||||
*/
|
||||
template<typename Type>
|
||||
requires std::is_integral_v<Type>
|
||||
constexpr Type MakeMagic(std::string_view string) {
|
||||
Type object{};
|
||||
size_t offset{};
|
||||
@ -129,10 +130,10 @@ namespace skyline::util {
|
||||
}
|
||||
|
||||
template<size_t Size>
|
||||
constexpr std::array <u8, Size> HexStringToArray(std::string_view string) {
|
||||
constexpr std::array<u8, Size> HexStringToArray(std::string_view string) {
|
||||
if (string.size() != Size * 2)
|
||||
throw exception("String size: {} (Expected {})", string.size(), Size);
|
||||
std::array <u8, Size> result;
|
||||
std::array<u8, Size> result;
|
||||
for (size_t i{}; i < Size; i++) {
|
||||
size_t index{i * 2};
|
||||
result[i] = (HexDigitToNibble(string[index]) << 4) | HexDigitToNibble(string[index + 1]);
|
||||
@ -141,6 +142,7 @@ namespace skyline::util {
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
requires std::is_integral_v<Type>
|
||||
constexpr Type HexStringToInt(std::string_view string) {
|
||||
if (string.size() > sizeof(Type) * 2)
|
||||
throw exception("String size larger than type: {} (sizeof(Type): {})", string.size(), sizeof(Type));
|
||||
@ -161,7 +163,7 @@ namespace skyline::util {
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
constexpr std::array <u8, N> SwapEndianness(std::array <u8, N> in) {
|
||||
constexpr std::array<u8, N> SwapEndianness(std::array<u8, N> in) {
|
||||
std::reverse(in.begin(), in.end());
|
||||
return in;
|
||||
}
|
||||
@ -190,13 +192,13 @@ namespace skyline::util {
|
||||
*/
|
||||
template<class T>
|
||||
struct IntegerFor {
|
||||
using type = std::conditional_t<sizeof(T) % sizeof(u64) == 0, u64,
|
||||
std::conditional_t<sizeof(T) % sizeof(u32) == 0, u32,
|
||||
std::conditional_t<sizeof(T) % sizeof(u16) == 0, u16, u8>
|
||||
>
|
||||
using Type = std::conditional_t<sizeof(T) % sizeof(u64) == 0, u64,
|
||||
std::conditional_t<sizeof(T) % sizeof(u32) == 0, u32,
|
||||
std::conditional_t<sizeof(T) % sizeof(u16) == 0, u16, u8>
|
||||
>
|
||||
>;
|
||||
|
||||
static constexpr size_t count{sizeof(T) / sizeof(type)};
|
||||
static constexpr size_t Count{sizeof(T) / sizeof(Type)};
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@ -207,22 +209,24 @@ namespace skyline::util {
|
||||
* @brief Fills an array with random data from a Mersenne Twister pseudo-random generator
|
||||
* @note The generator is seeded with the the current time in ticks
|
||||
*/
|
||||
template<typename T> requires (std::is_integral_v<T>)
|
||||
template<typename T>
|
||||
requires std::is_integral_v<T>
|
||||
void FillRandomBytes(std::span<T> in) {
|
||||
std::independent_bits_engine<std::mt19937_64, std::numeric_limits<T>::digits, T> gen(detail::generator);
|
||||
std::generate(in.begin(), in.end(), gen);
|
||||
}
|
||||
|
||||
template<class T> requires (!std::is_integral_v<T> && std::is_trivially_copyable_v<T>)
|
||||
template<class T>
|
||||
requires (!std::is_integral_v<T> && std::is_trivially_copyable_v<T>)
|
||||
void FillRandomBytes(T &object) {
|
||||
FillRandomBytes(std::span(reinterpret_cast<typename IntegerFor<T>::type *>(&object), IntegerFor<T>::count));
|
||||
FillRandomBytes(std::span(reinterpret_cast<typename IntegerFor<T>::Type *>(&object), IntegerFor<T>::Count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A temporary shim for C++ 20's bit_cast to make transitioning to it easier
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
To BitCast(const From& from) {
|
||||
return *reinterpret_cast<const To*>(&from);
|
||||
To BitCast(const From &from) {
|
||||
return *reinterpret_cast<const To *>(&from);
|
||||
}
|
||||
}
|
||||
|
@ -32,14 +32,14 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void SetMemoryAttribute(const DeviceState &state) {
|
||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||
if (!util::PageAligned(pointer)) {
|
||||
if (!util::IsPageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size{state.ctx->gpr.x1};
|
||||
if (!util::PageAligned(size)) {
|
||||
if (!util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -83,13 +83,13 @@ namespace skyline::kernel::svc {
|
||||
auto source{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||
size_t size{state.ctx->gpr.x2};
|
||||
|
||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||
if (!util::IsPageAligned(destination) || !util::IsPageAligned(source)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!util::PageAligned(size)) {
|
||||
if (!util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -131,13 +131,13 @@ namespace skyline::kernel::svc {
|
||||
auto destination{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||
size_t size{state.ctx->gpr.x2};
|
||||
|
||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||
if (!util::IsPageAligned(destination) || !util::IsPageAligned(source)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!util::PageAligned(size)) {
|
||||
if (!util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -477,14 +477,14 @@ namespace skyline::kernel::svc {
|
||||
auto object{state.process->GetHandle<type::KSharedMemory>(handle)};
|
||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||
|
||||
if (!util::PageAligned(pointer)) {
|
||||
if (!util::IsPageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size{state.ctx->gpr.x2};
|
||||
if (!util::PageAligned(size)) {
|
||||
if (!util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -514,14 +514,14 @@ namespace skyline::kernel::svc {
|
||||
auto object{state.process->GetHandle<type::KSharedMemory>(handle)};
|
||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||
|
||||
if (!util::PageAligned(pointer)) {
|
||||
if (!util::IsPageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size{state.ctx->gpr.x2};
|
||||
if (!util::PageAligned(size)) {
|
||||
if (!util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -540,14 +540,14 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void CreateTransferMemory(const DeviceState &state) {
|
||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||
if (!util::PageAligned(pointer)) {
|
||||
if (!util::IsPageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size{state.ctx->gpr.x2};
|
||||
if (!util::PageAligned(size)) {
|
||||
if (!util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -741,7 +741,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void ArbitrateLock(const DeviceState &state) {
|
||||
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x1)};
|
||||
if (!util::WordAligned(mutex)) {
|
||||
if (!util::IsWordAligned(mutex)) {
|
||||
state.logger->Warn("'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
@ -764,7 +764,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void ArbitrateUnlock(const DeviceState &state) {
|
||||
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(mutex)) {
|
||||
if (!util::IsWordAligned(mutex)) {
|
||||
state.logger->Warn("'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
@ -779,7 +779,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void WaitProcessWideKeyAtomic(const DeviceState &state) {
|
||||
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(mutex)) {
|
||||
if (!util::IsWordAligned(mutex)) {
|
||||
state.logger->Warn("'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
@ -1016,12 +1016,12 @@ namespace skyline::kernel::svc {
|
||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||
size_t size{state.ctx->gpr.x1};
|
||||
|
||||
if (!util::PageAligned(pointer)) {
|
||||
if (!util::IsPageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!size || !util::PageAligned(size)) {
|
||||
if (!size || !util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
return;
|
||||
}
|
||||
@ -1040,12 +1040,12 @@ namespace skyline::kernel::svc {
|
||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||
size_t size{state.ctx->gpr.x1};
|
||||
|
||||
if (!util::PageAligned(pointer)) {
|
||||
if (!util::IsPageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!size || !util::PageAligned(size)) {
|
||||
if (!size || !util::IsPageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
return;
|
||||
}
|
||||
@ -1087,7 +1087,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void WaitForAddress(const DeviceState &state) {
|
||||
auto address{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(address)) [[unlikely]] {
|
||||
if (!util::IsWordAligned(address)) [[unlikely]] {
|
||||
state.logger->Warn("'address' not word aligned: 0x{:X}", address);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
@ -1149,7 +1149,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void SignalToAddress(const DeviceState &state) {
|
||||
auto address{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(address)) [[unlikely]] {
|
||||
if (!util::IsWordAligned(address)) [[unlikely]] {
|
||||
state.logger->Warn("'address' not word aligned: 0x{:X}", address);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
|
@ -11,7 +11,7 @@ namespace skyline::kernel::type {
|
||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memoryState(memState), KMemory(state, KType::KPrivateMemory) {
|
||||
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) || !util::PageAligned(size))
|
||||
if (!util::IsPageAligned(ptr) || !util::IsPageAligned(size))
|
||||
throw exception("KPrivateMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size);
|
||||
|
||||
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
|
||||
@ -50,7 +50,7 @@ namespace skyline::kernel::type {
|
||||
void KPrivateMemory::Remap(u8 *nPtr, size_t nSize) {
|
||||
if (!state.process->memory.base.IsInside(nPtr) || !state.process->memory.base.IsInside(nPtr + nSize))
|
||||
throw exception("KPrivateMemory remapping isn't inside guest address space: 0x{:X} - 0x{:X}", nPtr, nPtr + nSize);
|
||||
if (!util::PageAligned(nPtr) || !util::PageAligned(nSize))
|
||||
if (!util::IsPageAligned(nPtr) || !util::IsPageAligned(nSize))
|
||||
throw exception("KPrivateMemory remapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", nPtr, nPtr + nSize, nSize);
|
||||
|
||||
if (mprotect(ptr, size, PROT_NONE) < 0)
|
||||
@ -64,7 +64,7 @@ namespace skyline::kernel::type {
|
||||
pPtr = std::clamp(pPtr, ptr, ptr + size);
|
||||
pSize = std::min(pSize, static_cast<size_t>((ptr + size) - pPtr));
|
||||
|
||||
if (pPtr && !util::PageAligned(pPtr))
|
||||
if (pPtr && !util::IsPageAligned(pPtr))
|
||||
throw exception("KPrivateMemory permission updated with a non-page-aligned address: 0x{:X}", pPtr);
|
||||
|
||||
// If a static code region has been mapped as writable it needs to be changed to mutable
|
||||
|
@ -23,7 +23,7 @@ namespace skyline::kernel::type {
|
||||
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 (!util::PageAligned(ptr) || !util::PageAligned(size))
|
||||
if (!util::IsPageAligned(ptr) || !util::IsPageAligned(size))
|
||||
throw exception("KSharedMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size);
|
||||
if (guest.Valid())
|
||||
throw exception("Mapping KSharedMemory multiple times on guest is not supported: Requested Mapping: 0x{:X} - 0x{:X} (0x{:X}), Current Mapping: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size, guest.ptr, guest.ptr + guest.size, guest.size);
|
||||
@ -49,7 +49,7 @@ namespace skyline::kernel::type {
|
||||
void KSharedMemory::Unmap(u8 *ptr, u64 size) {
|
||||
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) || !util::PageAligned(size))
|
||||
if (!util::IsPageAligned(ptr) || !util::IsPageAligned(size))
|
||||
throw exception("KSharedMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size);
|
||||
if (guest.ptr != ptr && guest.size != size)
|
||||
throw exception("Unmapping KSharedMemory partially is not supported: Requested Unmap: 0x{:X} - 0x{:X} (0x{:X}), Current Mapping: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size, guest.ptr, guest.ptr + guest.size, guest.size);
|
||||
@ -66,7 +66,7 @@ namespace skyline::kernel::type {
|
||||
}
|
||||
|
||||
void KSharedMemory::UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) {
|
||||
if (ptr && !util::PageAligned(ptr))
|
||||
if (ptr && !util::IsPageAligned(ptr))
|
||||
throw exception("KSharedMemory permission updated with a non-page-aligned address: 0x{:X}", ptr);
|
||||
|
||||
if (guest.Valid()) {
|
||||
@ -100,7 +100,6 @@ namespace skyline::kernel::type {
|
||||
constexpr memory::Permission UnborrowPermission{true, true, false};
|
||||
|
||||
if (mmap(guest.ptr, guest.size, UnborrowPermission.Get(), MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0) == MAP_FAILED)
|
||||
// It is likely that these exceptions will end up as asserts as the destructor is implicitly noexcept but we want to be notified about these not working so that's fine as it can be discovered in the debugger
|
||||
state.logger->Warn("An error occurred while remapping transfer memory as anonymous memory in guest: {}", strerror(errno));
|
||||
else if (!host.Valid())
|
||||
state.logger->Warn("Expected host mapping of transfer memory to be valid during KTransferMemory destruction");
|
||||
|
@ -17,10 +17,10 @@ namespace skyline::loader {
|
||||
u64 roSize{executable.ro.contents.size()};
|
||||
u64 dataSize{executable.data.contents.size() + executable.bssSize};
|
||||
|
||||
if (!util::PageAligned(textSize) || !util::PageAligned(roSize) || !util::PageAligned(dataSize))
|
||||
if (!util::IsPageAligned(textSize) || !util::IsPageAligned(roSize) || !util::IsPageAligned(dataSize))
|
||||
throw exception("LoadProcessData: Sections are not aligned with page size: 0x{:X}, 0x{:X}, 0x{:X}", textSize, roSize, dataSize);
|
||||
|
||||
if (!util::PageAligned(executable.text.offset) || !util::PageAligned(executable.ro.offset) || !util::PageAligned(executable.data.offset))
|
||||
if (!util::IsPageAligned(executable.text.offset) || !util::IsPageAligned(executable.ro.offset) || !util::IsPageAligned(executable.data.offset))
|
||||
throw exception("LoadProcessData: Section offsets are not aligned with page size: 0x{:X}, 0x{:X}, 0x{:X}", executable.text.offset, executable.ro.offset, executable.data.offset);
|
||||
|
||||
auto patch{state.nce->GetPatchData(executable.text.contents)};
|
||||
|
@ -40,7 +40,7 @@ namespace skyline::vfs {
|
||||
meta = backing->Read<NpdmMeta>();
|
||||
if (meta.magic != MetaMagic)
|
||||
throw exception("NPDM Meta Magic isn't correct: 0x{:X} (\"META\" = 0x{:X})", meta.magic, MetaMagic);
|
||||
if (!util::PageAligned(meta.mainThreadStackSize))
|
||||
if (!util::IsPageAligned(meta.mainThreadStackSize))
|
||||
throw exception("NPDM Main Thread Stack isn't page aligned: 0x{:X}", meta.mainThreadStackSize);
|
||||
|
||||
aci0 = meta.aci0.Read<NpdmAci0>(backing);
|
||||
|
Loading…
Reference in New Issue
Block a user