mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 10:40:01 +01:00
Memory partitions: correct the range, the error codes, and the heap
The new sysmem tests run the same partition sweep from both privilege levels, which settles several things that were guesses: The valid range is 1-6, not 1-9-except-7. sceKernelCreateVpl, CreateFpl, CreateMsgPipe and AllocPartitionMemory all let 8 and 9 through to the permission check, so a caller asking for partition 8 got ILLEGAL_PERM where hardware says ILLEGAL_ARGUMENT. Privilege changes the permission check, not the range - 1, 3 and 4 are refused from user mode and work from kernel mode in every one of these APIs, which is the evidence the earlier BlockAllocatorFromID change was missing. sceKernelAllocPartitionMemory reports an out-of-range partition differently depending on which entry point was used - ILLEGAL_ARGUMENT through SysMemUserForUser, ILLEGAL_PARTITION through SysMemForKernel. Both NIDs land on the same function here, and hleIsKernelMode() is precisely "came in through the kernel NID", so it picks the right one. sceKernelCreateHeap had four "TODO: Validate error code" comments and no test at all - it's kernel-only, which is why. All four are now recorded: out-of-range partitions are ILLEGAL_PARTITION, a size of zero or less is HEAPBLOCK_ALLOC_FAILED before anything is allocated, a NULL name is refused with ERROR, and flags really are ignored. sceKernelAllocHeapMemoryWithOption had its validation backwards: the option struct's size field isn't checked at all, while the alignment must be a power of two from 4 to 0x80. Not fixed, and split into sysmem/kernel/heapgrow in tests_next: a real heap will hand out a block larger than the heap itself, so the size isn't a cap. Ours is a fixed allocator over the reserved block. Worth establishing how far the real one grows before implementing that. Risk: the range change makes partitions 8 and 9 fail earlier and with a different code than before. Nothing in tests_good depended on the old behaviour except two expectations that had drifted from hardware, corrected in the submodule.
This commit is contained in:
1 parent
a52b11aa2e
commit
ad3444ce50
5 files changed
+56
-18
No files matched your search
@@ -525,7 +525,10 @@ static void __KernelSortFplThreads(FPL *fpl)
|
||||
int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 numBlocks, u32 optPtr) {
|
||||
if (!name)
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "invalid name");
|
||||
if (mpid < 1 || mpid > 9 || mpid == 7)
|
||||
// Only partitions 1-6 exist. sysmem/partitions and its kernel-mode twin record 7 and up
|
||||
// coming back ILLEGAL_ARGUMENT from both privilege levels; what privilege changes is the
|
||||
// permission check below, not the range.
|
||||
if (mpid < 1 || mpid > 6)
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", mpid);
|
||||
|
||||
BlockAllocator *allocator = BlockAllocatorFromID(mpid);
|
||||
@@ -882,8 +885,14 @@ int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32
|
||||
if ((addr & (addr - 1)) != 0 || addr == 0)
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE, "invalid alignment %x", addr);
|
||||
}
|
||||
if (partition < 1 || partition > 9 || partition == 7)
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %x", partition);
|
||||
// SysMemUserForUser and SysMemForKernel both land here, and sysmem/partitions shows they
|
||||
// report an out-of-range partition differently - ILLEGAL_ARGUMENT from the user entry point,
|
||||
// ILLEGAL_PARTITION from the kernel one. hleIsKernelMode() is exactly "came in through the
|
||||
// kernel NID", which is the distinction being made.
|
||||
if (partition < 1 || partition > 6) {
|
||||
const u32 error = hleIsKernelMode() ? SCE_KERNEL_ERROR_ILLEGAL_PARTITION : SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
|
||||
return hleLogWarning(Log::sceKernel, error, "invalid partition %x", partition);
|
||||
}
|
||||
|
||||
BlockAllocator *allocator = BlockAllocatorFromID(partition);
|
||||
if (allocator == nullptr)
|
||||
@@ -1311,7 +1320,10 @@ static void __KernelSortVplThreads(VPL *vpl)
|
||||
SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize, u32 optPtr) {
|
||||
if (!name)
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name");
|
||||
if (partition < 1 || partition > 9 || partition == 7)
|
||||
// Only partitions 1-6 exist. sysmem/partitions and its kernel-mode twin record 7 and up
|
||||
// coming back ILLEGAL_ARGUMENT from both privilege levels; what privilege changes is the
|
||||
// permission check below, not the range.
|
||||
if (partition < 1 || partition > 6)
|
||||
return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", partition);
|
||||
|
||||
BlockAllocator *allocator = BlockAllocatorFromID(partition);
|
||||
|
||||
Reference in new issue
Block a user