~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/HLE/sceKernelMemory.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2012- PPSSPP Project.
 
2
 
 
3
// This program is free software: you can redistribute it and/or modify
 
4
// it under the terms of the GNU General Public License as published by
 
5
// the Free Software Foundation, version 2.0 or later versions.
 
6
 
 
7
// This program is distributed in the hope that it will be useful,
 
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
// GNU General Public License 2.0 for more details.
 
11
 
 
12
// A copy of the GPL 2.0 should have been included with the program.
 
13
// If not, see http://www.gnu.org/licenses/
 
14
 
 
15
// Official git repository and contact information can be found at
 
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 
17
 
 
18
#include <algorithm>
 
19
#include <string>
 
20
#include <vector>
 
21
#include <map>
 
22
 
 
23
#include "base/compat.h"
 
24
 
 
25
#include "Common/ChunkFile.h"
 
26
#include "Core/HLE/HLE.h"
 
27
#include "Core/HLE/FunctionWrappers.h"
 
28
#include "Core/System.h"
 
29
#include "Core/MIPS/MIPS.h"
 
30
#include "Core/MemMapHelpers.h"
 
31
#include "Core/CoreTiming.h"
 
32
#include "Core/Reporting.h"
 
33
 
 
34
#include "Core/HLE/sceKernel.h"
 
35
#include "Core/HLE/sceKernelThread.h"
 
36
#include "Core/HLE/sceKernelInterrupt.h"
 
37
#include "Core/HLE/sceKernelMemory.h"
 
38
#include "Core/HLE/KernelWaitHelpers.h"
 
39
 
 
40
const int TLSPL_NUM_INDEXES = 16;
 
41
 
 
42
//////////////////////////////////////////////////////////////////////////
 
43
// STATE BEGIN
 
44
BlockAllocator userMemory(256);
 
45
BlockAllocator kernelMemory(256);
 
46
 
 
47
static int vplWaitTimer = -1;
 
48
static int fplWaitTimer = -1;
 
49
static bool tlsplUsedIndexes[TLSPL_NUM_INDEXES];
 
50
 
 
51
// Thread -> TLSPL uids for thread end.
 
52
typedef std::multimap<SceUID, SceUID> TlsplMap;
 
53
static TlsplMap tlsplThreadEndChecks;
 
54
// STATE END
 
55
//////////////////////////////////////////////////////////////////////////
 
56
 
 
57
#define SCE_KERNEL_HASCOMPILEDSDKVERSION 0x1000
 
58
#define SCE_KERNEL_HASCOMPILERVERSION    0x2000
 
59
 
 
60
int flags_ = 0;
 
61
int sdkVersion_;
 
62
int compilerVersion_;
 
63
 
 
64
struct FplWaitingThread
 
65
{
 
66
        SceUID threadID;
 
67
        u32 addrPtr;
 
68
        u64 pausedTimeout;
 
69
 
 
70
        bool operator ==(const SceUID &otherThreadID) const
 
71
        {
 
72
                return threadID == otherThreadID;
 
73
        }
 
74
};
 
75
 
 
76
struct NativeFPL
 
77
{
 
78
        u32_le size;
 
79
        char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
 
80
        u32_le attr;
 
81
 
 
82
        s32_le blocksize;
 
83
        s32_le numBlocks;
 
84
        s32_le numFreeBlocks;
 
85
        s32_le numWaitThreads;
 
86
};
 
87
 
 
88
//FPL - Fixed Length Dynamic Memory Pool - every item has the same length
 
89
struct FPL : public KernelObject
 
90
{
 
91
        FPL() : blocks(NULL), nextBlock(0) {}
 
92
        ~FPL() {
 
93
                if (blocks != NULL) {
 
94
                        delete [] blocks;
 
95
                }
 
96
        }
 
97
        const char *GetName() override { return nf.name; }
 
98
        const char *GetTypeName() override { return "FPL"; }
 
99
        static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_FPLID; }
 
100
        static int GetStaticIDType() { return SCE_KERNEL_TMID_Fpl; }
 
101
        int GetIDType() const override { return SCE_KERNEL_TMID_Fpl; }
 
102
 
 
103
        int findFreeBlock() {
 
104
                for (int i = 0; i < nf.numBlocks; i++) {
 
105
                        int b = nextBlock++ % nf.numBlocks;
 
106
                        if (!blocks[b]) {
 
107
                                return b;
 
108
                        }
 
109
                }
 
110
                return -1;
 
111
        }
 
112
 
 
113
        int allocateBlock() {
 
114
                int block = findFreeBlock();
 
115
                if (block >= 0)
 
116
                        blocks[block] = true;
 
117
                return block;
 
118
        }
 
119
        
 
120
        bool freeBlock(int b) {
 
121
                if (blocks[b]) {
 
122
                        blocks[b] = false;
 
123
                        return true;
 
124
                }
 
125
                return false;
 
126
        }
 
127
 
 
128
        void DoState(PointerWrap &p) override
 
129
        {
 
130
                auto s = p.Section("FPL", 1);
 
131
                if (!s)
 
132
                        return;
 
133
 
 
134
                p.Do(nf);
 
135
                if (p.mode == p.MODE_READ)
 
136
                        blocks = new bool[nf.numBlocks];
 
137
                p.DoArray(blocks, nf.numBlocks);
 
138
                p.Do(address);
 
139
                p.Do(alignedSize);
 
140
                p.Do(nextBlock);
 
141
                FplWaitingThread dv = {0};
 
142
                p.Do(waitingThreads, dv);
 
143
                p.Do(pausedWaits);
 
144
        }
 
145
 
 
146
        NativeFPL nf;
 
147
        bool *blocks;
 
148
        u32 address;
 
149
        int alignedSize;
 
150
        int nextBlock;
 
151
        std::vector<FplWaitingThread> waitingThreads;
 
152
        // Key is the callback id it was for, or if no callback, the thread id.
 
153
        std::map<SceUID, FplWaitingThread> pausedWaits;
 
154
};
 
155
 
 
156
struct VplWaitingThread
 
157
{
 
158
        SceUID threadID;
 
159
        u32 addrPtr;
 
160
        u64 pausedTimeout;
 
161
 
 
162
        bool operator ==(const SceUID &otherThreadID) const
 
163
        {
 
164
                return threadID == otherThreadID;
 
165
        }
 
166
};
 
167
 
 
168
struct SceKernelVplInfo
 
169
{
 
170
        SceSize_le size;
 
171
        char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
 
172
        SceUInt_le attr;
 
173
        s32_le poolSize;
 
174
        s32_le freeSize;
 
175
        s32_le numWaitThreads;
 
176
};
 
177
 
 
178
struct SceKernelVplBlock
 
179
{
 
180
        PSPPointer<SceKernelVplBlock> next;
 
181
        // Includes this info (which is 1 block / 8 bytes.)
 
182
        u32_le sizeInBlocks;
 
183
};
 
184
 
 
185
struct SceKernelVplHeader {
 
186
        u32_le startPtr_;
 
187
        // TODO: Why twice?  Is there a case it changes?
 
188
        u32_le startPtr2_;
 
189
        u32_le sentinel_;
 
190
        u32_le sizeMinus8_;
 
191
        u32_le allocatedInBlocks_;
 
192
        PSPPointer<SceKernelVplBlock> nextFreeBlock_;
 
193
        SceKernelVplBlock firstBlock_;
 
194
 
 
195
        void Init(u32 ptr, u32 size) {
 
196
                startPtr_ = ptr;
 
197
                startPtr2_ = ptr;
 
198
                sentinel_ = ptr + 7;
 
199
                sizeMinus8_ = size - 8;
 
200
                allocatedInBlocks_ = 0;
 
201
                nextFreeBlock_ = FirstBlockPtr();
 
202
 
 
203
                firstBlock_.next = LastBlockPtr();
 
204
                // Includes its own header, which is one block.
 
205
                firstBlock_.sizeInBlocks = (size - 0x28) / 8 + 1;
 
206
 
 
207
                auto lastBlock = LastBlock();
 
208
                lastBlock->next = FirstBlockPtr();
 
209
                lastBlock->sizeInBlocks = 0;
 
210
        }
 
211
 
 
212
        u32 Allocate(u32 size) {
 
213
                u32 allocBlocks = ((size + 7) / 8) + 1;
 
214
                auto prev = nextFreeBlock_;
 
215
                do {
 
216
                        auto b = prev->next;
 
217
                        if (b->sizeInBlocks > allocBlocks) {
 
218
                                if (nextFreeBlock_ == b) {
 
219
                                        nextFreeBlock_ = prev;
 
220
                                }
 
221
                                prev = b;
 
222
                                b = SplitBlock(b, allocBlocks);
 
223
                        }
 
224
 
 
225
                        if (b->sizeInBlocks == allocBlocks) {
 
226
                                UnlinkFreeBlock(b, prev);
 
227
                                return b.ptr + 8;
 
228
                        }
 
229
 
 
230
                        prev = b;
 
231
                } while (prev.IsValid() && prev != nextFreeBlock_);
 
232
 
 
233
                return (u32)-1;
 
234
        }
 
235
 
 
236
        bool Free(u32 ptr) {
 
237
                auto b = PSPPointer<SceKernelVplBlock>::Create(ptr - 8);
 
238
                // Is it even in the right range?  Can't be the last block, which is always 0.
 
239
                if (!b.IsValid() || ptr < FirstBlockPtr() || ptr >= LastBlockPtr()) {
 
240
                        return false;
 
241
                }
 
242
                // Great, let's check if it matches our magic.
 
243
                if (b->next.ptr != SentinelPtr() || b->sizeInBlocks > allocatedInBlocks_) {
 
244
                        return false;
 
245
                }
 
246
 
 
247
                auto prev = LastBlock();
 
248
                do {
 
249
                        auto next = prev->next;
 
250
                        // Already free.
 
251
                        if (next == b) {
 
252
                                return false;
 
253
                        } else if (next > b) {
 
254
                                LinkFreeBlock(b, prev, next);
 
255
                                return true;
 
256
                        }
 
257
 
 
258
                        prev = next;
 
259
                } while (prev.IsValid() && prev != LastBlock());
 
260
 
 
261
                // TODO: Log?
 
262
                return false;
 
263
        }
 
264
 
 
265
        u32 FreeSize() const {
 
266
                // Size less the header and number of allocated bytes.
 
267
                return sizeMinus8_ + 8 - 0x20 - allocatedInBlocks_ * 8;
 
268
        }
 
269
 
 
270
        bool LinkFreeBlock(PSPPointer<SceKernelVplBlock> b, PSPPointer<SceKernelVplBlock> prev, PSPPointer<SceKernelVplBlock> next) {
 
271
                allocatedInBlocks_ -= b->sizeInBlocks;
 
272
                nextFreeBlock_ = prev;
 
273
 
 
274
                // Make sure we don't consider it free later by erasing the magic.
 
275
                b->next = next.ptr;
 
276
                const auto afterB = b + b->sizeInBlocks;
 
277
                if (afterB == next && next->sizeInBlocks != 0) {
 
278
                        b = MergeBlocks(b, next);
 
279
                }
 
280
 
 
281
                const auto afterPrev = prev + prev->sizeInBlocks;
 
282
                if (afterPrev == b) {
 
283
                        b = MergeBlocks(prev, b);
 
284
                } else {
 
285
                        prev->next = b.ptr;
 
286
                }
 
287
 
 
288
                return true;
 
289
        }
 
290
 
 
291
        void UnlinkFreeBlock(PSPPointer<SceKernelVplBlock> b, PSPPointer<SceKernelVplBlock> prev) {
 
292
                allocatedInBlocks_ += b->sizeInBlocks;
 
293
                prev->next = b->next;
 
294
                if (nextFreeBlock_ == b) {
 
295
                        nextFreeBlock_ = prev;
 
296
                }
 
297
                b->next = SentinelPtr();
 
298
        }
 
299
 
 
300
        PSPPointer<SceKernelVplBlock> SplitBlock(PSPPointer<SceKernelVplBlock> b, u32 allocBlocks) {
 
301
                u32 prev = b->next.ptr;
 
302
                b->sizeInBlocks -= allocBlocks;
 
303
                b->next = b + b->sizeInBlocks;
 
304
 
 
305
                b += b->sizeInBlocks;
 
306
                b->sizeInBlocks = allocBlocks;
 
307
                b->next = prev;
 
308
 
 
309
                return b;
 
310
        }
 
311
 
 
312
        inline void Validate() {
 
313
                auto lastBlock = LastBlock();
 
314
                _dbg_assert_msg_(SCEKERNEL, nextFreeBlock_->next.ptr != SentinelPtr(), "Next free block should not be allocated.");
 
315
                _dbg_assert_msg_(SCEKERNEL, nextFreeBlock_->next.ptr != sentinel_, "Next free block should not point to sentinel.");
 
316
                _dbg_assert_msg_(SCEKERNEL, lastBlock->sizeInBlocks == 0, "Last block should have size of 0.");
 
317
                _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr != SentinelPtr(), "Last block should not be allocated.");
 
318
                _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr != sentinel_, "Last block should not point to sentinel.");
 
319
 
 
320
                auto b = PSPPointer<SceKernelVplBlock>::Create(FirstBlockPtr());
 
321
                bool sawFirstFree = false;
 
322
                while (b.ptr < lastBlock.ptr) {
 
323
                        bool isFree = b->next.ptr != SentinelPtr();
 
324
                        if (isFree) {
 
325
                                if (!sawFirstFree) {
 
326
                                        _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr == b.ptr, "Last block should point to first free block.");
 
327
                                        sawFirstFree = true;
 
328
                                }
 
329
                                _dbg_assert_msg_(SCEKERNEL, b->next.ptr != SentinelPtr(), "Free blocks should only point to other free blocks.");
 
330
                                _dbg_assert_msg_(SCEKERNEL, b->next.ptr > b.ptr, "Free blocks should be in order.");
 
331
                                _dbg_assert_msg_(SCEKERNEL, b + b->sizeInBlocks < b->next || b->next.ptr == lastBlock.ptr, "Two free blocks should not be next to each other.");
 
332
                        } else {
 
333
                                _dbg_assert_msg_(SCEKERNEL, b->next.ptr == SentinelPtr(), "Allocated blocks should point to the sentinel.");
 
334
                        }
 
335
                        _dbg_assert_msg_(SCEKERNEL, b->sizeInBlocks != 0, "Only the last block should have a size of 0.");
 
336
                        b += b->sizeInBlocks;
 
337
                }
 
338
                if (!sawFirstFree) {
 
339
                        _dbg_assert_msg_(SCEKERNEL, lastBlock->next.ptr == lastBlock.ptr, "Last block should point to itself when full.");
 
340
                }
 
341
                _dbg_assert_msg_(SCEKERNEL, b.ptr == lastBlock.ptr, "Blocks should not extend outside vpl.");
 
342
        }
 
343
 
 
344
        void ListBlocks() {
 
345
                auto b = PSPPointer<SceKernelVplBlock>::Create(FirstBlockPtr());
 
346
                auto lastBlock = LastBlock();
 
347
                while (b.ptr < lastBlock.ptr) {
 
348
                        bool isFree = b->next.ptr != SentinelPtr();
 
349
                        if (nextFreeBlock_ == b && isFree) {
 
350
                                NOTICE_LOG(HLE, "NEXT:  %x -> %x (size %x)", b.ptr - startPtr_, b->next.ptr - startPtr_, b->sizeInBlocks * 8);
 
351
                        } else if (isFree) {
 
352
                                NOTICE_LOG(HLE, "FREE:  %x -> %x (size %x)", b.ptr - startPtr_, b->next.ptr - startPtr_, b->sizeInBlocks * 8);
 
353
                        } else {
 
354
                                NOTICE_LOG(HLE, "BLOCK: %x (size %x)", b.ptr - startPtr_, b->sizeInBlocks * 8);
 
355
                        }
 
356
                        b += b->sizeInBlocks;
 
357
                }
 
358
                NOTICE_LOG(HLE, "LAST:  %x -> %x (size %x)", lastBlock.ptr - startPtr_, lastBlock->next.ptr - startPtr_, lastBlock->sizeInBlocks * 8);
 
359
        }
 
360
 
 
361
        PSPPointer<SceKernelVplBlock> MergeBlocks(PSPPointer<SceKernelVplBlock> first, PSPPointer<SceKernelVplBlock> second) {
 
362
                first->sizeInBlocks += second->sizeInBlocks;
 
363
                first->next = second->next;
 
364
                return first;
 
365
        }
 
366
 
 
367
        u32 FirstBlockPtr() const {
 
368
                return startPtr_ + 0x18;
 
369
        }
 
370
 
 
371
        u32 LastBlockPtr() const {
 
372
                return startPtr_ + sizeMinus8_;
 
373
        }
 
374
 
 
375
        PSPPointer<SceKernelVplBlock> LastBlock() {
 
376
                return PSPPointer<SceKernelVplBlock>::Create(LastBlockPtr());
 
377
        }
 
378
 
 
379
        u32 SentinelPtr() const {
 
380
                return startPtr_ + 8;
 
381
        }
 
382
};
 
383
 
 
384
struct VPL : public KernelObject
 
385
{
 
386
        const char *GetName() override { return nv.name; }
 
387
        const char *GetTypeName() override { return "VPL"; }
 
388
        static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VPLID; }
 
389
        static int GetStaticIDType() { return SCE_KERNEL_TMID_Vpl; }
 
390
        int GetIDType() const override { return SCE_KERNEL_TMID_Vpl; }
 
391
 
 
392
        VPL() : alloc(8) {
 
393
                header = 0;
 
394
        }
 
395
 
 
396
        void DoState(PointerWrap &p) override {
 
397
                auto s = p.Section("VPL", 1, 2);
 
398
                if (!s) {
 
399
                        return;
 
400
                }
 
401
 
 
402
                p.Do(nv);
 
403
                p.Do(address);
 
404
                VplWaitingThread dv = {0};
 
405
                p.Do(waitingThreads, dv);
 
406
                alloc.DoState(p);
 
407
                p.Do(pausedWaits);
 
408
 
 
409
                if (s >= 2) {
 
410
                        p.Do(header);
 
411
                }
 
412
        }
 
413
 
 
414
        SceKernelVplInfo nv;
 
415
        u32 address;
 
416
        std::vector<VplWaitingThread> waitingThreads;
 
417
        // Key is the callback id it was for, or if no callback, the thread id.
 
418
        std::map<SceUID, VplWaitingThread> pausedWaits;
 
419
        BlockAllocator alloc;
 
420
        PSPPointer<SceKernelVplHeader> header;
 
421
};
 
422
 
 
423
void __KernelVplTimeout(u64 userdata, int cyclesLate);
 
424
void __KernelFplTimeout(u64 userdata, int cyclesLate);
 
425
void __KernelTlsplThreadEnd(SceUID threadID);
 
426
 
 
427
void __KernelVplBeginCallback(SceUID threadID, SceUID prevCallbackId);
 
428
void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId);
 
429
void __KernelFplBeginCallback(SceUID threadID, SceUID prevCallbackId);
 
430
void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId);
 
431
 
 
432
void __KernelMemoryInit()
 
433
{
 
434
        kernelMemory.Init(PSP_GetKernelMemoryBase(), PSP_GetKernelMemoryEnd()-PSP_GetKernelMemoryBase());
 
435
        userMemory.Init(PSP_GetUserMemoryBase(), PSP_GetUserMemoryEnd()-PSP_GetUserMemoryBase());
 
436
        INFO_LOG(SCEKERNEL, "Kernel and user memory pools initialized");
 
437
 
 
438
        vplWaitTimer = CoreTiming::RegisterEvent("VplTimeout", __KernelVplTimeout);
 
439
        fplWaitTimer = CoreTiming::RegisterEvent("FplTimeout", __KernelFplTimeout);
 
440
 
 
441
        flags_ = 0;
 
442
        sdkVersion_ = 0;
 
443
        compilerVersion_ = 0;
 
444
        memset(tlsplUsedIndexes, 0, sizeof(tlsplUsedIndexes));
 
445
 
 
446
        __KernelListenThreadEnd(&__KernelTlsplThreadEnd);
 
447
 
 
448
        __KernelRegisterWaitTypeFuncs(WAITTYPE_VPL, __KernelVplBeginCallback, __KernelVplEndCallback);
 
449
        __KernelRegisterWaitTypeFuncs(WAITTYPE_FPL, __KernelFplBeginCallback, __KernelFplEndCallback);
 
450
 
 
451
        // The kernel statically allocates this memory, which has some code in it.
 
452
        // It appears this is used for some common funcs in Kernel_Library (memcpy, lwmutex, suspend intr, etc.)
 
453
        // Allocating this block is necessary to have the same memory semantics as real firmware.
 
454
        userMemory.AllocAt(PSP_GetUserMemoryBase(), 0x4000, "usersystemlib");
 
455
}
 
456
 
 
457
void __KernelMemoryDoState(PointerWrap &p)
 
458
{
 
459
        auto s = p.Section("sceKernelMemory", 1, 2);
 
460
        if (!s)
 
461
                return;
 
462
 
 
463
        kernelMemory.DoState(p);
 
464
        userMemory.DoState(p);
 
465
 
 
466
        p.Do(vplWaitTimer);
 
467
        CoreTiming::RestoreRegisterEvent(vplWaitTimer, "VplTimeout", __KernelVplTimeout);
 
468
        p.Do(fplWaitTimer);
 
469
        CoreTiming::RestoreRegisterEvent(fplWaitTimer, "FplTimeout", __KernelFplTimeout);
 
470
        p.Do(flags_);
 
471
        p.Do(sdkVersion_);
 
472
        p.Do(compilerVersion_);
 
473
        p.DoArray(tlsplUsedIndexes, ARRAY_SIZE(tlsplUsedIndexes));
 
474
        if (s >= 2) {
 
475
                p.Do(tlsplThreadEndChecks);
 
476
        }
 
477
}
 
478
 
 
479
void __KernelMemoryShutdown()
 
480
{
 
481
#ifdef _DEBUG
 
482
        INFO_LOG(SCEKERNEL,"Shutting down user memory pool: ");
 
483
        userMemory.ListBlocks();
 
484
#endif
 
485
        userMemory.Shutdown();
 
486
#ifdef _DEBUG
 
487
        INFO_LOG(SCEKERNEL,"Shutting down \"kernel\" memory pool: ");
 
488
        kernelMemory.ListBlocks();
 
489
#endif
 
490
        kernelMemory.Shutdown();
 
491
        tlsplThreadEndChecks.clear();
 
492
}
 
493
 
 
494
enum SceKernelFplAttr
 
495
{
 
496
        PSP_FPL_ATTR_FIFO     = 0x0000,
 
497
        PSP_FPL_ATTR_PRIORITY = 0x0100,
 
498
        PSP_FPL_ATTR_HIGHMEM  = 0x4000,
 
499
        PSP_FPL_ATTR_KNOWN    = PSP_FPL_ATTR_FIFO | PSP_FPL_ATTR_PRIORITY | PSP_FPL_ATTR_HIGHMEM,
 
500
};
 
501
 
 
502
static bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u32 &error, int result, bool &wokeThreads)
 
503
{
 
504
        const SceUID threadID = threadInfo.threadID;
 
505
        if (!HLEKernel::VerifyWait(threadID, WAITTYPE_FPL, fpl->GetUID()))
 
506
                return true;
 
507
 
 
508
        // If result is an error code, we're just letting it go.
 
509
        if (result == 0)
 
510
        {
 
511
                int blockNum = fpl->allocateBlock();
 
512
                if (blockNum >= 0)
 
513
                {
 
514
                        u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
 
515
                        Memory::Write_U32(blockPtr, threadInfo.addrPtr);
 
516
                }
 
517
                else
 
518
                        return false;
 
519
        }
 
520
 
 
521
        u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
 
522
        if (timeoutPtr != 0 && fplWaitTimer != -1)
 
523
        {
 
524
                // Remove any event for this thread.
 
525
                s64 cyclesLeft = CoreTiming::UnscheduleEvent(fplWaitTimer, threadID);
 
526
                Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
 
527
        }
 
528
 
 
529
        __KernelResumeThreadFromWait(threadID, result);
 
530
        wokeThreads = true;
 
531
        return true;
 
532
}
 
533
 
 
534
void __KernelFplBeginCallback(SceUID threadID, SceUID prevCallbackId)
 
535
{
 
536
        auto result = HLEKernel::WaitBeginCallback<FPL, WAITTYPE_FPL, FplWaitingThread>(threadID, prevCallbackId, fplWaitTimer);
 
537
        if (result == HLEKernel::WAIT_CB_SUCCESS)
 
538
                DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFplCB: Suspending fpl wait for callback");
 
539
        else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
 
540
                ERROR_LOG_REPORT(SCEKERNEL, "sceKernelAllocateFplCB: wait not found to pause for callback");
 
541
        else
 
542
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelAllocateFplCB: beginning callback with bad wait id?");
 
543
}
 
544
 
 
545
void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId)
 
546
{
 
547
        auto result = HLEKernel::WaitEndCallback<FPL, WAITTYPE_FPL, FplWaitingThread>(threadID, prevCallbackId, fplWaitTimer, __KernelUnlockFplForThread);
 
548
        if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
 
549
                DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Resuming mbx wait from callback");
 
550
}
 
551
 
 
552
static bool __FplThreadSortPriority(FplWaitingThread thread1, FplWaitingThread thread2)
 
553
{
 
554
        return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
 
555
}
 
556
 
 
557
static bool __KernelClearFplThreads(FPL *fpl, int reason)
 
558
{
 
559
        u32 error;
 
560
        bool wokeThreads = false;
 
561
        for (auto iter = fpl->waitingThreads.begin(), end = fpl->waitingThreads.end(); iter != end; ++iter)
 
562
                __KernelUnlockFplForThread(fpl, *iter, error, reason, wokeThreads);
 
563
        fpl->waitingThreads.clear();
 
564
 
 
565
        return wokeThreads;
 
566
}
 
567
 
 
568
static void __KernelSortFplThreads(FPL *fpl)
 
569
{
 
570
        // Remove any that are no longer waiting.
 
571
        SceUID uid = fpl->GetUID();
 
572
        HLEKernel::CleanupWaitingThreads(WAITTYPE_FPL, uid, fpl->waitingThreads);
 
573
 
 
574
        if ((fpl->nf.attr & PSP_FPL_ATTR_PRIORITY) != 0)
 
575
                std::stable_sort(fpl->waitingThreads.begin(), fpl->waitingThreads.end(), __FplThreadSortPriority);
 
576
}
 
577
 
 
578
int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 numBlocks, u32 optPtr)
 
579
{
 
580
        if (!name)
 
581
        {
 
582
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateFpl(): invalid name", SCE_KERNEL_ERROR_NO_MEMORY);
 
583
                return SCE_KERNEL_ERROR_NO_MEMORY;
 
584
        }
 
585
        if (mpid < 1 || mpid > 9 || mpid == 7)
 
586
        {
 
587
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateFpl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, mpid);
 
588
                return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
 
589
        }
 
590
        // We only support user right now.
 
591
        if (mpid != 2 && mpid != 6)
 
592
        {
 
593
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateFpl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_PERM, mpid);
 
594
                return SCE_KERNEL_ERROR_ILLEGAL_PERM;
 
595
        }
 
596
        if (((attr & ~PSP_FPL_ATTR_KNOWN) & ~0xFF) != 0)
 
597
        {
 
598
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateFpl(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
 
599
                return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
 
600
        }
 
601
        // There's probably a simpler way to get this same basic formula...
 
602
        // This is based on results from a PSP.
 
603
        bool illegalMemSize = blockSize == 0 || numBlocks == 0;
 
604
        if (!illegalMemSize && (u64) blockSize > ((0x100000000ULL / (u64) numBlocks) - 4ULL))
 
605
                illegalMemSize = true;
 
606
        if (!illegalMemSize && (u64) numBlocks >= 0x100000000ULL / (((u64) blockSize + 3ULL) & ~3ULL))
 
607
                illegalMemSize = true;
 
608
        if (illegalMemSize)
 
609
        {
 
610
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateFpl(): invalid blockSize/count", SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE);
 
611
                return SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE;
 
612
        }
 
613
 
 
614
        int alignment = 4;
 
615
        if (optPtr != 0)
 
616
        {
 
617
                u32 size = Memory::Read_U32(optPtr);
 
618
                if (size > 8)
 
619
                        WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateFpl(): unsupported extra options, size = %d", size);
 
620
                if (size >= 4)
 
621
                        alignment = Memory::Read_U32(optPtr + 4);
 
622
                // Must be a power of 2 to be valid.
 
623
                if ((alignment & (alignment - 1)) != 0)
 
624
                {
 
625
                        WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateFpl(): invalid alignment %d", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, alignment);
 
626
                        return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
 
627
                }
 
628
        }
 
629
 
 
630
        if (alignment < 4)
 
631
                alignment = 4;
 
632
 
 
633
        int alignedSize = ((int)blockSize + alignment - 1) & ~(alignment - 1);
 
634
        u32 totalSize = alignedSize * numBlocks;
 
635
        bool atEnd = (attr & PSP_FPL_ATTR_HIGHMEM) != 0;
 
636
        u32 address = userMemory.Alloc(totalSize, atEnd, "FPL");
 
637
        if (address == (u32)-1)
 
638
        {
 
639
                DEBUG_LOG(SCEKERNEL, "sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i) FAILED - out of ram", 
 
640
                        name, mpid, attr, blockSize, numBlocks);
 
641
                return SCE_KERNEL_ERROR_NO_MEMORY;
 
642
        }
 
643
 
 
644
        FPL *fpl = new FPL;
 
645
        SceUID id = kernelObjects.Create(fpl);
 
646
 
 
647
        strncpy(fpl->nf.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
 
648
        fpl->nf.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
 
649
        fpl->nf.attr = attr;
 
650
        fpl->nf.size = sizeof(fpl->nf);
 
651
        fpl->nf.blocksize = blockSize;
 
652
        fpl->nf.numBlocks = numBlocks;
 
653
        fpl->nf.numFreeBlocks = numBlocks;
 
654
        fpl->nf.numWaitThreads = 0;
 
655
 
 
656
        fpl->blocks = new bool[fpl->nf.numBlocks];
 
657
        memset(fpl->blocks, 0, fpl->nf.numBlocks * sizeof(bool));
 
658
        fpl->address = address;
 
659
        fpl->alignedSize = alignedSize;
 
660
 
 
661
        DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i)", 
 
662
                id, name, mpid, attr, blockSize, numBlocks);
 
663
 
 
664
        return id;
 
665
}
 
666
 
 
667
int sceKernelDeleteFpl(SceUID uid)
 
668
{
 
669
        hleEatCycles(600);
 
670
        u32 error;
 
671
        FPL *fpl = kernelObjects.Get<FPL>(uid, error);
 
672
        if (fpl)
 
673
        {
 
674
                DEBUG_LOG(SCEKERNEL, "sceKernelDeleteFpl(%i)", uid);
 
675
 
 
676
                bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_DELETE);
 
677
                if (wokeThreads)
 
678
                        hleReSchedule("fpl deleted");
 
679
 
 
680
                userMemory.Free(fpl->address);
 
681
                return kernelObjects.Destroy<FPL>(uid);
 
682
        }
 
683
        else
 
684
        {
 
685
                DEBUG_LOG(SCEKERNEL, "sceKernelDeleteFpl(%i): invalid fpl", uid);
 
686
                return error;
 
687
        }
 
688
}
 
689
 
 
690
void __KernelFplTimeout(u64 userdata, int cyclesLate)
 
691
{
 
692
        SceUID threadID = (SceUID) userdata;
 
693
        HLEKernel::WaitExecTimeout<FPL, WAITTYPE_FPL>(threadID);
 
694
}
 
695
 
 
696
static void __KernelSetFplTimeout(u32 timeoutPtr)
 
697
{
 
698
        if (timeoutPtr == 0 || fplWaitTimer == -1)
 
699
                return;
 
700
 
 
701
        int micro = (int) Memory::Read_U32(timeoutPtr);
 
702
 
 
703
        // TODO: test for fpls.
 
704
        // This happens to be how the hardware seems to time things.
 
705
        if (micro <= 5)
 
706
                micro = 20;
 
707
        // Yes, this 7 is reproducible.  6 is (a lot) longer than 7.
 
708
        else if (micro == 7)
 
709
                micro = 25;
 
710
        else if (micro <= 215)
 
711
                micro = 250;
 
712
 
 
713
        CoreTiming::ScheduleEvent(usToCycles(micro), fplWaitTimer, __KernelGetCurThread());
 
714
}
 
715
 
 
716
int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr)
 
717
{
 
718
        u32 error;
 
719
        FPL *fpl = kernelObjects.Get<FPL>(uid, error);
 
720
        if (fpl)
 
721
        {
 
722
                DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFpl(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr);
 
723
 
 
724
                int blockNum = fpl->allocateBlock();
 
725
                if (blockNum >= 0) {
 
726
                        u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
 
727
                        Memory::Write_U32(blockPtr, blockPtrAddr);
 
728
                } else {
 
729
                        SceUID threadID = __KernelGetCurThread();
 
730
                        HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID);
 
731
                        FplWaitingThread waiting = {threadID, blockPtrAddr};
 
732
                        fpl->waitingThreads.push_back(waiting);
 
733
 
 
734
                        __KernelSetFplTimeout(timeoutPtr);
 
735
                        __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited");
 
736
                }
 
737
 
 
738
                return 0;
 
739
        }
 
740
        else
 
741
        {
 
742
                DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFpl(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr);
 
743
                return error;
 
744
        }
 
745
}
 
746
 
 
747
int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr)
 
748
{
 
749
        u32 error;
 
750
        FPL *fpl = kernelObjects.Get<FPL>(uid, error);
 
751
        if (fpl)
 
752
        {
 
753
                DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFplCB(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr);
 
754
 
 
755
                int blockNum = fpl->allocateBlock();
 
756
                if (blockNum >= 0) {
 
757
                        u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
 
758
                        Memory::Write_U32(blockPtr, blockPtrAddr);
 
759
                } else {
 
760
                        SceUID threadID = __KernelGetCurThread();
 
761
                        HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID);
 
762
                        FplWaitingThread waiting = {threadID, blockPtrAddr};
 
763
                        fpl->waitingThreads.push_back(waiting);
 
764
 
 
765
                        __KernelSetFplTimeout(timeoutPtr);
 
766
                        __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited");
 
767
                }
 
768
 
 
769
                return 0;
 
770
        }
 
771
        else
 
772
        {
 
773
                DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFplCB(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr);
 
774
                return error;
 
775
        }
 
776
}
 
777
 
 
778
int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr)
 
779
{
 
780
        u32 error;
 
781
        FPL *fpl = kernelObjects.Get<FPL>(uid, error);
 
782
        if (fpl)
 
783
        {
 
784
                DEBUG_LOG(SCEKERNEL, "sceKernelTryAllocateFpl(%i, %08x)", uid, blockPtrAddr);
 
785
 
 
786
                int blockNum = fpl->allocateBlock();
 
787
                if (blockNum >= 0) {
 
788
                        u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
 
789
                        Memory::Write_U32(blockPtr, blockPtrAddr);
 
790
                        return 0;
 
791
                } else {
 
792
                        return SCE_KERNEL_ERROR_NO_MEMORY;
 
793
                }
 
794
        }
 
795
        else
 
796
        {
 
797
                DEBUG_LOG(SCEKERNEL, "sceKernelTryAllocateFpl(%i, %08x): invalid fpl", uid, blockPtrAddr);
 
798
                return error;
 
799
        }
 
800
}
 
801
 
 
802
int sceKernelFreeFpl(SceUID uid, u32 blockPtr)
 
803
{
 
804
        if (blockPtr > PSP_GetUserMemoryEnd()) {
 
805
                WARN_LOG(SCEKERNEL, "%08x=sceKernelFreeFpl(%i, %08x): invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, blockPtr);
 
806
                return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
 
807
        }
 
808
 
 
809
        u32 error;
 
810
        FPL *fpl = kernelObjects.Get<FPL>(uid, error);
 
811
        if (fpl) {
 
812
                int blockNum = (blockPtr - fpl->address) / fpl->alignedSize;
 
813
                if (blockNum < 0 || blockNum >= fpl->nf.numBlocks) {
 
814
                        DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x): bad block ptr", uid, blockPtr);
 
815
                        return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK;
 
816
                } else {
 
817
                        if (fpl->freeBlock(blockNum)) {
 
818
                                DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x)", uid, blockPtr);
 
819
                                __KernelSortFplThreads(fpl);
 
820
 
 
821
                                bool wokeThreads = false;
 
822
retry:
 
823
                                for (auto iter = fpl->waitingThreads.begin(), end = fpl->waitingThreads.end(); iter != end; ++iter)
 
824
                                {
 
825
                                        if (__KernelUnlockFplForThread(fpl, *iter, error, 0, wokeThreads))
 
826
                                        {
 
827
                                                fpl->waitingThreads.erase(iter);
 
828
                                                goto retry;
 
829
                                        }
 
830
                                }
 
831
 
 
832
                                if (wokeThreads)
 
833
                                        hleReSchedule("fpl freed");
 
834
                                return 0;
 
835
                        } else {
 
836
                                DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x): already free", uid, blockPtr);
 
837
                                return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK;
 
838
                        }
 
839
                }
 
840
        }
 
841
        else
 
842
        {
 
843
                DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x): invalid fpl", uid, blockPtr);
 
844
                return error;
 
845
        }
 
846
}
 
847
 
 
848
int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr)
 
849
{
 
850
        hleEatCycles(600);
 
851
 
 
852
        u32 error;
 
853
        FPL *fpl = kernelObjects.Get<FPL>(uid, error);
 
854
        if (fpl)
 
855
        {
 
856
                DEBUG_LOG(SCEKERNEL, "sceKernelCancelFpl(%i, %08x)", uid, numWaitThreadsPtr);
 
857
                fpl->nf.numWaitThreads = (int) fpl->waitingThreads.size();
 
858
                if (Memory::IsValidAddress(numWaitThreadsPtr))
 
859
                        Memory::Write_U32(fpl->nf.numWaitThreads, numWaitThreadsPtr);
 
860
 
 
861
                bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_CANCEL);
 
862
                if (wokeThreads)
 
863
                        hleReSchedule("fpl canceled");
 
864
                return 0;
 
865
        }
 
866
        else
 
867
        {
 
868
                DEBUG_LOG(SCEKERNEL, "sceKernelCancelFpl(%i, %08x): invalid fpl", uid, numWaitThreadsPtr);
 
869
                return error;
 
870
        }
 
871
}
 
872
 
 
873
int sceKernelReferFplStatus(SceUID uid, u32 statusPtr)
 
874
{
 
875
        u32 error;
 
876
        FPL *fpl = kernelObjects.Get<FPL>(uid, error);
 
877
        if (fpl)
 
878
        {
 
879
                DEBUG_LOG(SCEKERNEL, "sceKernelReferFplStatus(%i, %08x)", uid, statusPtr);
 
880
                // Refresh waiting threads and free block count.
 
881
                __KernelSortFplThreads(fpl);
 
882
                fpl->nf.numWaitThreads = (int) fpl->waitingThreads.size();
 
883
                fpl->nf.numFreeBlocks = 0;
 
884
                for (int i = 0; i < (int)fpl->nf.numBlocks; ++i)
 
885
                {
 
886
                        if (!fpl->blocks[i])
 
887
                                ++fpl->nf.numFreeBlocks;
 
888
                }
 
889
                if (Memory::Read_U32(statusPtr) != 0)
 
890
                        Memory::WriteStruct(statusPtr, &fpl->nf);
 
891
                return 0;
 
892
        }
 
893
        else
 
894
        {
 
895
                DEBUG_LOG(SCEKERNEL, "sceKernelReferFplStatus(%i, %08x): invalid fpl", uid, statusPtr);
 
896
                return error;
 
897
        }
 
898
}
 
899
 
 
900
 
 
901
 
 
902
//////////////////////////////////////////////////////////////////////////
 
903
// ALLOCATIONS
 
904
//////////////////////////////////////////////////////////////////////////
 
905
//00:49:12 <TyRaNiD> ector, well the partitions are 1 = kernel, 2 = user, 3 = me, 4 = kernel mirror :)
 
906
 
 
907
class PartitionMemoryBlock : public KernelObject
 
908
{
 
909
public:
 
910
        const char *GetName() override { return name; }
 
911
        const char *GetTypeName() override { return "MemoryPart"; }
 
912
        void GetQuickInfo(char *ptr, int size) override
 
913
        {
 
914
                int sz = alloc->GetBlockSizeFromAddress(address);
 
915
                snprintf(ptr, size, "MemPart: %08x - %08x       size: %08x", address, address + sz, sz);
 
916
        }
 
917
        static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_UID; }
 
918
        static int GetStaticIDType() { return PPSSPP_KERNEL_TMID_PMB; }
 
919
        int GetIDType() const override { return PPSSPP_KERNEL_TMID_PMB; }
 
920
 
 
921
        PartitionMemoryBlock(BlockAllocator *_alloc, const char *_name, u32 size, MemblockType type, u32 alignment)
 
922
        {
 
923
                alloc = _alloc;
 
924
                strncpy(name, _name, 32);
 
925
                name[31] = '\0';
 
926
 
 
927
                // 0 is used for save states to wake up.
 
928
                if (size != 0)
 
929
                {
 
930
                        if (type == PSP_SMEM_Addr)
 
931
                        {
 
932
                                alignment &= ~0xFF;
 
933
                                address = alloc->AllocAt(alignment, size, name);
 
934
                        }
 
935
                        else if (type == PSP_SMEM_LowAligned || type == PSP_SMEM_HighAligned)
 
936
                                address = alloc->AllocAligned(size, 0x100, alignment, type == PSP_SMEM_HighAligned, name);
 
937
                        else
 
938
                                address = alloc->Alloc(size, type == PSP_SMEM_High, name);
 
939
#ifdef _DEBUG
 
940
                        alloc->ListBlocks();
 
941
#endif
 
942
                }
 
943
        }
 
944
        ~PartitionMemoryBlock()
 
945
        {
 
946
                if (address != (u32)-1)
 
947
                        alloc->Free(address);
 
948
        }
 
949
        bool IsValid() {return address != (u32)-1;}
 
950
        BlockAllocator *alloc;
 
951
 
 
952
        void DoState(PointerWrap &p) override
 
953
        {
 
954
                auto s = p.Section("PMB", 1);
 
955
                if (!s)
 
956
                        return;
 
957
 
 
958
                p.Do(address);
 
959
                p.DoArray(name, sizeof(name));
 
960
        }
 
961
 
 
962
        u32 address;
 
963
        char name[32];
 
964
};
 
965
 
 
966
 
 
967
static u32 sceKernelMaxFreeMemSize()
 
968
{
 
969
        u32 retVal = userMemory.GetLargestFreeBlockSize();
 
970
        DEBUG_LOG(SCEKERNEL, "%08x (dec %i)=sceKernelMaxFreeMemSize()", retVal, retVal);
 
971
        return retVal;
 
972
}
 
973
 
 
974
static u32 sceKernelTotalFreeMemSize()
 
975
{
 
976
        u32 retVal = userMemory.GetTotalFreeBytes();
 
977
        DEBUG_LOG(SCEKERNEL, "%08x (dec %i)=sceKernelTotalFreeMemSize()", retVal, retVal);
 
978
        return retVal;
 
979
}
 
980
 
 
981
static int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 size, u32 addr)
 
982
{
 
983
        if (name == NULL)
 
984
        {
 
985
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelAllocPartitionMemory(): invalid name", SCE_KERNEL_ERROR_ERROR);
 
986
                return SCE_KERNEL_ERROR_ERROR;
 
987
        }
 
988
        if (size == 0)
 
989
        {
 
990
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelAllocPartitionMemory(): invalid size %x", SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED, size);
 
991
                return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
 
992
        }
 
993
        if (partition < 1 || partition > 9 || partition == 7)
 
994
        {
 
995
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelAllocPartitionMemory(): invalid partition %x", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, partition);
 
996
                return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
 
997
        }
 
998
        // We only support user right now.
 
999
        if (partition != 2 && partition != 5 && partition != 6)
 
1000
        {
 
1001
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelAllocPartitionMemory(): invalid partition %x", SCE_KERNEL_ERROR_ILLEGAL_PARTITION, partition);
 
1002
                return SCE_KERNEL_ERROR_ILLEGAL_PARTITION;
 
1003
        }
 
1004
        if (type < PSP_SMEM_Low || type > PSP_SMEM_HighAligned)
 
1005
        {
 
1006
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelAllocPartitionMemory(): invalid type %x", SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE, type);
 
1007
                return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE;
 
1008
        }
 
1009
        // Alignment is only allowed for powers of 2.
 
1010
        if ((type == PSP_SMEM_LowAligned || type == PSP_SMEM_HighAligned) && ((addr & (addr - 1)) != 0 || addr == 0))
 
1011
        {
 
1012
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelAllocPartitionMemory(): invalid alignment %x", SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE, addr);
 
1013
                return SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE;
 
1014
        }
 
1015
 
 
1016
        PartitionMemoryBlock *block = new PartitionMemoryBlock(&userMemory, name, size, (MemblockType)type, addr);
 
1017
        if (!block->IsValid())
 
1018
        {
 
1019
                delete block;
 
1020
                ERROR_LOG(SCEKERNEL, "sceKernelAllocPartitionMemory(partition = %i, %s, type= %i, size= %i, addr= %08x): allocation failed", partition, name, type, size, addr);
 
1021
                return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
 
1022
        }
 
1023
        SceUID uid = kernelObjects.Create(block);
 
1024
 
 
1025
        DEBUG_LOG(SCEKERNEL,"%i = sceKernelAllocPartitionMemory(partition = %i, %s, type= %i, size= %i, addr= %08x)",
 
1026
                uid, partition, name, type, size, addr);
 
1027
 
 
1028
        return uid;
 
1029
}
 
1030
 
 
1031
static int sceKernelFreePartitionMemory(SceUID id)
 
1032
{
 
1033
        DEBUG_LOG(SCEKERNEL,"sceKernelFreePartitionMemory(%d)",id);
 
1034
 
 
1035
        return kernelObjects.Destroy<PartitionMemoryBlock>(id);
 
1036
}
 
1037
 
 
1038
static u32 sceKernelGetBlockHeadAddr(SceUID id)
 
1039
{
 
1040
        u32 error;
 
1041
        PartitionMemoryBlock *block = kernelObjects.Get<PartitionMemoryBlock>(id, error);
 
1042
        if (block)
 
1043
        {
 
1044
                DEBUG_LOG(SCEKERNEL,"%08x = sceKernelGetBlockHeadAddr(%i)", block->address, id);
 
1045
                return block->address;
 
1046
        }
 
1047
        else
 
1048
        {
 
1049
                ERROR_LOG(SCEKERNEL,"sceKernelGetBlockHeadAddr failed(%i)", id);
 
1050
                return 0;
 
1051
        }
 
1052
}
 
1053
 
 
1054
 
 
1055
static int sceKernelPrintf(const char *formatString)
 
1056
{
 
1057
        if (formatString == NULL)
 
1058
                return -1;
 
1059
 
 
1060
        bool supported = true;
 
1061
        int param = 1;
 
1062
        char tempStr[24];
 
1063
        char tempFormat[24] = {'%'};
 
1064
        std::string result, format = formatString;
 
1065
 
 
1066
        // Each printf is a separate line already in the log, so don't double space.
 
1067
        // This does mean we break up strings, unfortunately.
 
1068
        if (!format.empty() && format[format.size() - 1] == '\n')
 
1069
                format.resize(format.size() - 1);
 
1070
 
 
1071
        for (size_t i = 0, n = format.size(); supported && i < n; )
 
1072
        {
 
1073
                size_t next = format.find('%', i);
 
1074
                if (next == format.npos)
 
1075
                {
 
1076
                        result += format.substr(i);
 
1077
                        break;
 
1078
                }
 
1079
                else if (next != i)
 
1080
                        result += format.substr(i, next - i);
 
1081
 
 
1082
                i = next + 1;
 
1083
                if (i >= n)
 
1084
                {
 
1085
                        supported = false;
 
1086
                        break;
 
1087
                }
 
1088
 
 
1089
                const char *s;
 
1090
                switch (format[i])
 
1091
                {
 
1092
                case '%':
 
1093
                        result += '%';
 
1094
                        ++i;
 
1095
                        break;
 
1096
 
 
1097
                case 's':
 
1098
                        s = Memory::GetCharPointer(PARAM(param++));
 
1099
                        result += s ? s : "(null)";
 
1100
                        ++i;
 
1101
                        break;
 
1102
 
 
1103
                case 'd':
 
1104
                case 'i':
 
1105
                case 'x':
 
1106
                case 'X':
 
1107
                case 'u':
 
1108
                        tempFormat[1] = format[i];
 
1109
                        tempFormat[2] = '\0';
 
1110
                        snprintf(tempStr, sizeof(tempStr), tempFormat, PARAM(param++));
 
1111
                        result += tempStr;
 
1112
                        ++i;
 
1113
                        break;
 
1114
 
 
1115
                case '0':
 
1116
                        if (i + 3 > n || format[i + 1] != '8' || (format[i + 2] != 'x' && format[i + 2] != 'X'))
 
1117
                                supported = false;
 
1118
                        else
 
1119
                        {
 
1120
                                // These are the '0', '8', and 'x' or 'X' respectively.
 
1121
                                tempFormat[1] = format[i];
 
1122
                                tempFormat[2] = format[i + 1];
 
1123
                                tempFormat[3] = format[i + 2];
 
1124
                                tempFormat[4] = '\0';
 
1125
                                snprintf(tempStr, sizeof(tempStr), tempFormat, PARAM(param++));
 
1126
                                result += tempStr;
 
1127
                                i += 3;
 
1128
                        }
 
1129
                        break;
 
1130
 
 
1131
                case 'p':
 
1132
                        snprintf(tempStr, sizeof(tempStr), "%08x", PARAM(param++));
 
1133
                        result += tempStr;
 
1134
                        ++i;
 
1135
                        break;
 
1136
 
 
1137
                default:
 
1138
                        supported = false;
 
1139
                        break;
 
1140
                }
 
1141
 
 
1142
                if (param > 6)
 
1143
                        supported = false;
 
1144
        }
 
1145
 
 
1146
        // Just in case there were embedded strings that had \n's.
 
1147
        if (!result.empty() && result[result.size() - 1] == '\n')
 
1148
                result.resize(result.size() - 1);
 
1149
 
 
1150
        if (supported)
 
1151
                INFO_LOG(SCEKERNEL, "sceKernelPrintf: %s", result.c_str());
 
1152
        else
 
1153
                ERROR_LOG(SCEKERNEL, "UNIMPL sceKernelPrintf(%s, %08x, %08x, %08x)", format.c_str(), PARAM(1), PARAM(2), PARAM(3));
 
1154
        return 0;
 
1155
}
 
1156
 
 
1157
static int sceKernelSetCompiledSdkVersion(int sdkVersion) {
 
1158
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1159
        bool validSDK = false;
 
1160
        switch (sdkMainVersion) {
 
1161
        case 0x01000000:
 
1162
        case 0x01050000:
 
1163
        case 0x02000000:
 
1164
        case 0x02050000:
 
1165
        case 0x02060000:
 
1166
        case 0x02070000:
 
1167
        case 0x02080000:
 
1168
        case 0x03000000:
 
1169
        case 0x03010000:
 
1170
        case 0x03030000:
 
1171
        case 0x03040000:
 
1172
        case 0x03050000:
 
1173
        case 0x03060000:
 
1174
                validSDK = true;
 
1175
                break;
 
1176
        default:
 
1177
                validSDK = false;
 
1178
                break;
 
1179
        }
 
1180
 
 
1181
        if (!validSDK) {
 
1182
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion unknown SDK: %x", sdkVersion);
 
1183
        }
 
1184
 
 
1185
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion(%08x)", sdkVersion);
 
1186
        sdkVersion_ = sdkVersion;
 
1187
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1188
        return 0;
 
1189
}
 
1190
 
 
1191
static int sceKernelSetCompiledSdkVersion370(int sdkVersion) {
 
1192
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1193
        if (sdkMainVersion != 0x03070000) {
 
1194
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion370 unknown SDK: %x", sdkVersion);
 
1195
        }
 
1196
 
 
1197
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion370(%08x)", sdkVersion);
 
1198
        sdkVersion_ = sdkVersion;
 
1199
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1200
        return 0;
 
1201
}
 
1202
 
 
1203
static int sceKernelSetCompiledSdkVersion380_390(int sdkVersion) {
 
1204
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1205
        if (sdkMainVersion != 0x03080000 && sdkMainVersion != 0x03090000) {
 
1206
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion380_390 unknown SDK: %x", sdkVersion);
 
1207
                sdkVersion_ = sdkVersion;
 
1208
                flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1209
        }
 
1210
 
 
1211
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion380_390(%08x)", sdkVersion);
 
1212
        sdkVersion_ = sdkVersion;
 
1213
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1214
        return 0;
 
1215
}
 
1216
 
 
1217
static int sceKernelSetCompiledSdkVersion395(int sdkVersion) {
 
1218
        int sdkMainVersion = sdkVersion & 0xFFFFFF00;
 
1219
        if (sdkMainVersion != 0x04000000
 
1220
                        && sdkMainVersion != 0x04000100
 
1221
                        && sdkMainVersion != 0x04000500
 
1222
                        && sdkMainVersion != 0x03090500
 
1223
                        && sdkMainVersion != 0x03090600) {
 
1224
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion395 unknown SDK: %x", sdkVersion);
 
1225
        }
 
1226
 
 
1227
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion395(%08x)", sdkVersion);
 
1228
        sdkVersion_ = sdkVersion;
 
1229
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1230
        return 0;
 
1231
}
 
1232
 
 
1233
static int sceKernelSetCompiledSdkVersion600_602(int sdkVersion) {
 
1234
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1235
        if (sdkMainVersion != 0x06010000
 
1236
                        && sdkMainVersion != 0x06000000
 
1237
                        && sdkMainVersion != 0x06020000) {
 
1238
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion600_602 unknown SDK: %x", sdkVersion);
 
1239
        }
 
1240
 
 
1241
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion600_602(%08x)", sdkVersion);
 
1242
        sdkVersion_ = sdkVersion;
 
1243
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1244
        return 0;
 
1245
}
 
1246
 
 
1247
static int sceKernelSetCompiledSdkVersion500_505(int sdkVersion)
 
1248
{
 
1249
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1250
        if (sdkMainVersion != 0x05000000
 
1251
                        && sdkMainVersion != 0x05050000) {
 
1252
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion500_505 unknown SDK: %x", sdkVersion);
 
1253
        }
 
1254
 
 
1255
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion500_505(%08x)", sdkVersion);
 
1256
        sdkVersion_ = sdkVersion;
 
1257
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1258
        return 0;
 
1259
}
 
1260
 
 
1261
static int sceKernelSetCompiledSdkVersion401_402(int sdkVersion) {
 
1262
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1263
        if (sdkMainVersion != 0x04010000
 
1264
                        && sdkMainVersion != 0x04020000) {
 
1265
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion401_402 unknown SDK: %x", sdkVersion);
 
1266
        }
 
1267
 
 
1268
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion401_402(%08x)", sdkVersion);
 
1269
        sdkVersion_ = sdkVersion;
 
1270
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1271
        return 0;
 
1272
}
 
1273
 
 
1274
static int sceKernelSetCompiledSdkVersion507(int sdkVersion) {
 
1275
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1276
        if (sdkMainVersion != 0x05070000) {
 
1277
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion507 unknown SDK: %x", sdkVersion);
 
1278
        }
 
1279
 
 
1280
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion507(%08x)", sdkVersion);
 
1281
        sdkVersion_ = sdkVersion;
 
1282
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1283
        return 0;
 
1284
}
 
1285
 
 
1286
static int sceKernelSetCompiledSdkVersion603_605(int sdkVersion) {
 
1287
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1288
        if (sdkMainVersion != 0x06040000
 
1289
                        && sdkMainVersion != 0x06030000
 
1290
                        && sdkMainVersion != 0x06050000) {
 
1291
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion603_605 unknown SDK: %x", sdkVersion);
 
1292
        }
 
1293
 
 
1294
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion603_605(%08x)", sdkVersion);
 
1295
        sdkVersion_ = sdkVersion;
 
1296
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1297
        return 0;
 
1298
}
 
1299
 
 
1300
static int sceKernelSetCompiledSdkVersion606(int sdkVersion) {
 
1301
        int sdkMainVersion = sdkVersion & 0xFFFF0000;
 
1302
        if (sdkMainVersion != 0x06060000) {
 
1303
                ERROR_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion606 unknown SDK: %x (would crash)", sdkVersion);
 
1304
        }
 
1305
 
 
1306
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion606(%08x)", sdkVersion);
 
1307
        sdkVersion_ = sdkVersion;
 
1308
        flags_ |=  SCE_KERNEL_HASCOMPILEDSDKVERSION;
 
1309
        return 0;
 
1310
}
 
1311
 
 
1312
int sceKernelGetCompiledSdkVersion() {
 
1313
        if (!(flags_ & SCE_KERNEL_HASCOMPILEDSDKVERSION))
 
1314
                return 0;
 
1315
        return sdkVersion_;
 
1316
}
 
1317
 
 
1318
static int sceKernelSetCompilerVersion(int version) {
 
1319
        DEBUG_LOG(SCEKERNEL, "sceKernelSetCompilerVersion(%08x)", version);
 
1320
        compilerVersion_ = version;
 
1321
        flags_ |= SCE_KERNEL_HASCOMPILERVERSION;
 
1322
        return 0;
 
1323
}
 
1324
 
 
1325
KernelObject *__KernelMemoryFPLObject()
 
1326
{
 
1327
        return new FPL;
 
1328
}
 
1329
 
 
1330
KernelObject *__KernelMemoryVPLObject()
 
1331
{
 
1332
        return new VPL;
 
1333
}
 
1334
 
 
1335
KernelObject *__KernelMemoryPMBObject()
 
1336
{
 
1337
        // TODO: We could theoretically handle kernelMemory too, but we don't support that now anyway.
 
1338
        return new PartitionMemoryBlock(&userMemory, "", 0, PSP_SMEM_Low, 0);
 
1339
}
 
1340
 
 
1341
// VPL = variable length memory pool
 
1342
 
 
1343
enum SceKernelVplAttr
 
1344
{
 
1345
        PSP_VPL_ATTR_FIFO       = 0x0000,
 
1346
        PSP_VPL_ATTR_PRIORITY   = 0x0100,
 
1347
        PSP_VPL_ATTR_SMALLEST   = 0x0200,
 
1348
        PSP_VPL_ATTR_MASK_ORDER = 0x0300,
 
1349
 
 
1350
        PSP_VPL_ATTR_HIGHMEM    = 0x4000,
 
1351
        PSP_VPL_ATTR_KNOWN      = PSP_VPL_ATTR_FIFO | PSP_VPL_ATTR_PRIORITY | PSP_VPL_ATTR_SMALLEST | PSP_VPL_ATTR_HIGHMEM,
 
1352
};
 
1353
 
 
1354
static bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u32 &error, int result, bool &wokeThreads) {
 
1355
        const SceUID threadID = threadInfo.threadID;
 
1356
        if (!HLEKernel::VerifyWait(threadID, WAITTYPE_VPL, vpl->GetUID())) {
 
1357
                return true;
 
1358
        }
 
1359
 
 
1360
        // If result is an error code, we're just letting it go.
 
1361
        if (result == 0) {
 
1362
                int size = (int) __KernelGetWaitValue(threadID, error);
 
1363
 
 
1364
                // An older savestate may have an invalid header, use the block allocator in that case.
 
1365
                u32 addr;
 
1366
                if (vpl->header.IsValid()) {
 
1367
                        addr = vpl->header->Allocate(size);
 
1368
                } else {
 
1369
                        // Padding (normally used to track the allocation.)
 
1370
                        u32 allocSize = size + 8;
 
1371
                        addr = vpl->alloc.Alloc(allocSize, true);
 
1372
                }
 
1373
                if (addr != (u32) -1) {
 
1374
                        Memory::Write_U32(addr, threadInfo.addrPtr);
 
1375
                } else {
 
1376
                        return false;
 
1377
                }
 
1378
        }
 
1379
 
 
1380
        u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
 
1381
        if (timeoutPtr != 0 && vplWaitTimer != -1) {
 
1382
                // Remove any event for this thread.
 
1383
                s64 cyclesLeft = CoreTiming::UnscheduleEvent(vplWaitTimer, threadID);
 
1384
                Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
 
1385
        }
 
1386
 
 
1387
        __KernelResumeThreadFromWait(threadID, result);
 
1388
        wokeThreads = true;
 
1389
        return true;
 
1390
}
 
1391
 
 
1392
void __KernelVplBeginCallback(SceUID threadID, SceUID prevCallbackId)
 
1393
{
 
1394
        auto result = HLEKernel::WaitBeginCallback<VPL, WAITTYPE_VPL, VplWaitingThread>(threadID, prevCallbackId, vplWaitTimer);
 
1395
        if (result == HLEKernel::WAIT_CB_SUCCESS)
 
1396
                DEBUG_LOG(SCEKERNEL, "sceKernelAllocateVplCB: Suspending vpl wait for callback");
 
1397
        else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
 
1398
                ERROR_LOG_REPORT(SCEKERNEL, "sceKernelAllocateVplCB: wait not found to pause for callback");
 
1399
        else
 
1400
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelAllocateVplCB: beginning callback with bad wait id?");
 
1401
}
 
1402
 
 
1403
void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId)
 
1404
{
 
1405
        auto result = HLEKernel::WaitEndCallback<VPL, WAITTYPE_VPL, VplWaitingThread>(threadID, prevCallbackId, vplWaitTimer, __KernelUnlockVplForThread);
 
1406
        if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
 
1407
                DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Resuming mbx wait from callback");
 
1408
}
 
1409
 
 
1410
static bool __VplThreadSortPriority(VplWaitingThread thread1, VplWaitingThread thread2)
 
1411
{
 
1412
        return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
 
1413
}
 
1414
 
 
1415
static bool __KernelClearVplThreads(VPL *vpl, int reason)
 
1416
{
 
1417
        u32 error;
 
1418
        bool wokeThreads = false;
 
1419
        for (auto iter = vpl->waitingThreads.begin(), end = vpl->waitingThreads.end(); iter != end; ++iter)
 
1420
                __KernelUnlockVplForThread(vpl, *iter, error, reason, wokeThreads);
 
1421
        vpl->waitingThreads.clear();
 
1422
 
 
1423
        return wokeThreads;
 
1424
}
 
1425
 
 
1426
static void __KernelSortVplThreads(VPL *vpl)
 
1427
{
 
1428
        // Remove any that are no longer waiting.
 
1429
        SceUID uid = vpl->GetUID();
 
1430
        HLEKernel::CleanupWaitingThreads(WAITTYPE_VPL, uid, vpl->waitingThreads);
 
1431
 
 
1432
        if ((vpl->nv.attr & PSP_VPL_ATTR_PRIORITY) != 0)
 
1433
                std::stable_sort(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), __VplThreadSortPriority);
 
1434
}
 
1435
 
 
1436
SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize, u32 optPtr)
 
1437
{
 
1438
        if (!name)
 
1439
        {
 
1440
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVpl(): invalid name", SCE_KERNEL_ERROR_ERROR);
 
1441
                return SCE_KERNEL_ERROR_ERROR;
 
1442
        }
 
1443
        if (partition < 1 || partition > 9 || partition == 7)
 
1444
        {
 
1445
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVpl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, partition);
 
1446
                return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
 
1447
        }
 
1448
        // We only support user right now.
 
1449
        if (partition != 2 && partition != 6)
 
1450
        {
 
1451
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVpl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_PERM, partition);
 
1452
                return SCE_KERNEL_ERROR_ILLEGAL_PERM;
 
1453
        }
 
1454
        if (((attr & ~PSP_VPL_ATTR_KNOWN) & ~0xFF) != 0)
 
1455
        {
 
1456
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVpl(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
 
1457
                return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
 
1458
        }
 
1459
        if (vplSize == 0)
 
1460
        {
 
1461
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVpl(): invalid size", SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE);
 
1462
                return SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE;
 
1463
        }
 
1464
        // Block Allocator seems to A-OK this, let's stop it here.
 
1465
        if (vplSize >= 0x80000000)
 
1466
        {
 
1467
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVpl(): way too big size", SCE_KERNEL_ERROR_NO_MEMORY);
 
1468
                return SCE_KERNEL_ERROR_NO_MEMORY;
 
1469
        }
 
1470
 
 
1471
        // Can't have that little space in a Vpl, sorry.
 
1472
        if (vplSize <= 0x30)
 
1473
                vplSize = 0x1000;
 
1474
        vplSize = (vplSize + 7) & ~7;
 
1475
 
 
1476
        // We ignore the upalign to 256 and do it ourselves by 8.
 
1477
        u32 allocSize = vplSize;
 
1478
        u32 memBlockPtr = userMemory.Alloc(allocSize, (attr & PSP_VPL_ATTR_HIGHMEM) != 0, "VPL");
 
1479
        if (memBlockPtr == (u32)-1)
 
1480
        {
 
1481
                ERROR_LOG(SCEKERNEL, "sceKernelCreateVpl(): Failed to allocate %i bytes of pool data", vplSize);
 
1482
                return SCE_KERNEL_ERROR_NO_MEMORY;
 
1483
        }
 
1484
 
 
1485
        VPL *vpl = new VPL;
 
1486
        SceUID id = kernelObjects.Create(vpl);
 
1487
 
 
1488
        strncpy(vpl->nv.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
 
1489
        vpl->nv.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
 
1490
        vpl->nv.attr = attr;
 
1491
        vpl->nv.size = sizeof(vpl->nv);
 
1492
        vpl->nv.poolSize = vplSize - 0x20;
 
1493
        vpl->nv.numWaitThreads = 0;
 
1494
        vpl->nv.freeSize = vpl->nv.poolSize;
 
1495
 
 
1496
        // A vpl normally has accounting stuff in the first 32 bytes.
 
1497
        vpl->address = memBlockPtr + 0x20;
 
1498
        vpl->alloc.Init(vpl->address, vpl->nv.poolSize);
 
1499
 
 
1500
        vpl->header = PSPPointer<SceKernelVplHeader>::Create(memBlockPtr);
 
1501
        vpl->header->Init(memBlockPtr, vplSize);
 
1502
 
 
1503
        DEBUG_LOG(SCEKERNEL, "%x=sceKernelCreateVpl(\"%s\", block=%i, attr=%i, size=%i)", 
 
1504
                id, name, partition, vpl->nv.attr, vpl->nv.poolSize);
 
1505
 
 
1506
        if (optPtr != 0)
 
1507
        {
 
1508
                u32 size = Memory::Read_U32(optPtr);
 
1509
                if (size > 4)
 
1510
                        WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateVpl(): unsupported options parameter, size = %d", size);
 
1511
        }
 
1512
 
 
1513
        return id;
 
1514
}
 
1515
 
 
1516
int sceKernelDeleteVpl(SceUID uid)
 
1517
{
 
1518
        DEBUG_LOG(SCEKERNEL, "sceKernelDeleteVpl(%i)", uid);
 
1519
        u32 error;
 
1520
        VPL *vpl = kernelObjects.Get<VPL>(uid, error);
 
1521
        if (vpl)
 
1522
        {
 
1523
                bool wokeThreads = __KernelClearVplThreads(vpl, SCE_KERNEL_ERROR_WAIT_DELETE);
 
1524
                if (wokeThreads)
 
1525
                        hleReSchedule("vpl deleted");
 
1526
 
 
1527
                userMemory.Free(vpl->address);
 
1528
                kernelObjects.Destroy<VPL>(uid);
 
1529
                return 0;
 
1530
        }
 
1531
        else
 
1532
                return error;
 
1533
}
 
1534
 
 
1535
// Returns false for invalid parameters (e.g. don't check callbacks, etc.)
 
1536
// Successful allocation is indicated by error == 0.
 
1537
static bool __KernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 &error, bool trying, const char *funcname) {
 
1538
        VPL *vpl = kernelObjects.Get<VPL>(uid, error);
 
1539
        if (vpl) {
 
1540
                if (size == 0 || size > (u32) vpl->nv.poolSize) {
 
1541
                        WARN_LOG(SCEKERNEL, "%s(vpl=%i, size=%i, ptrout=%08x): invalid size", funcname, uid, size, addrPtr);
 
1542
                        error = SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE;
 
1543
                        return false;
 
1544
                }
 
1545
 
 
1546
                VERBOSE_LOG(SCEKERNEL, "%s(vpl=%i, size=%i, ptrout=%08x)", funcname, uid, size, addrPtr);
 
1547
 
 
1548
                // For some reason, try doesn't follow the same rules...
 
1549
                if (!trying && (vpl->nv.attr & PSP_VPL_ATTR_MASK_ORDER) == PSP_VPL_ATTR_FIFO)
 
1550
                {
 
1551
                        __KernelSortVplThreads(vpl);
 
1552
                        if (!vpl->waitingThreads.empty())
 
1553
                        {
 
1554
                                // Can't allocate, blocked by FIFO queue.
 
1555
                                error = SCE_KERNEL_ERROR_NO_MEMORY;
 
1556
                                return true;
 
1557
                        }
 
1558
                }
 
1559
 
 
1560
                // Allocate using the header only for newer vpls (older come from savestates.)
 
1561
                u32 addr;
 
1562
                if (vpl->header.IsValid()) {
 
1563
                        addr = vpl->header->Allocate(size);
 
1564
                } else {
 
1565
                        // Padding (normally used to track the allocation.)
 
1566
                        u32 allocSize = size + 8;
 
1567
                        addr = vpl->alloc.Alloc(allocSize, true);
 
1568
                }
 
1569
                if (addr != (u32) -1) {
 
1570
                        Memory::Write_U32(addr, addrPtr);
 
1571
                        error =  0;
 
1572
                } else {
 
1573
                        error = SCE_KERNEL_ERROR_NO_MEMORY;
 
1574
                }
 
1575
 
 
1576
                return true;
 
1577
        }
 
1578
 
 
1579
        return false;
 
1580
}
 
1581
 
 
1582
void __KernelVplTimeout(u64 userdata, int cyclesLate) {
 
1583
        SceUID threadID = (SceUID) userdata;
 
1584
        u32 error;
 
1585
        SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_VPL, error);
 
1586
 
 
1587
        HLEKernel::WaitExecTimeout<VPL, WAITTYPE_VPL>(threadID);
 
1588
 
 
1589
        // If in FIFO mode, that may have cleared another thread to wake up.
 
1590
        VPL *vpl = kernelObjects.Get<VPL>(uid, error);
 
1591
        if (vpl && (vpl->nv.attr & PSP_VPL_ATTR_MASK_ORDER) == PSP_VPL_ATTR_FIFO) {
 
1592
                bool wokeThreads;
 
1593
                std::vector<VplWaitingThread>::iterator iter = vpl->waitingThreads.begin();
 
1594
                // Unlock every waiting thread until the first that must still wait.
 
1595
                while (iter != vpl->waitingThreads.end() && __KernelUnlockVplForThread(vpl, *iter, error, 0, wokeThreads)) {
 
1596
                        vpl->waitingThreads.erase(iter);
 
1597
                        iter = vpl->waitingThreads.begin();
 
1598
                }
 
1599
        }
 
1600
}
 
1601
 
 
1602
static void __KernelSetVplTimeout(u32 timeoutPtr)
 
1603
{
 
1604
        if (timeoutPtr == 0 || vplWaitTimer == -1)
 
1605
                return;
 
1606
 
 
1607
        int micro = (int) Memory::Read_U32(timeoutPtr);
 
1608
 
 
1609
        // This happens to be how the hardware seems to time things.
 
1610
        if (micro <= 5)
 
1611
                micro = 20;
 
1612
        // Yes, this 7 is reproducible.  6 is (a lot) longer than 7.
 
1613
        else if (micro == 7)
 
1614
                micro = 25;
 
1615
        else if (micro <= 215)
 
1616
                micro = 250;
 
1617
 
 
1618
        CoreTiming::ScheduleEvent(usToCycles(micro), vplWaitTimer, __KernelGetCurThread());
 
1619
}
 
1620
 
 
1621
int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
 
1622
{
 
1623
        u32 error, ignore;
 
1624
        if (__KernelAllocateVpl(uid, size, addrPtr, error, false, __FUNCTION__))
 
1625
        {
 
1626
                VPL *vpl = kernelObjects.Get<VPL>(uid, ignore);
 
1627
                if (error == SCE_KERNEL_ERROR_NO_MEMORY)
 
1628
                {
 
1629
                        if (timeoutPtr != 0 && Memory::Read_U32(timeoutPtr) == 0)
 
1630
                                return SCE_KERNEL_ERROR_WAIT_TIMEOUT;
 
1631
 
 
1632
                        if (vpl)
 
1633
                        {
 
1634
                                SceUID threadID = __KernelGetCurThread();
 
1635
                                HLEKernel::RemoveWaitingThread(vpl->waitingThreads, threadID);
 
1636
                                VplWaitingThread waiting = {threadID, addrPtr};
 
1637
                                vpl->waitingThreads.push_back(waiting);
 
1638
                        }
 
1639
 
 
1640
                        __KernelSetVplTimeout(timeoutPtr);
 
1641
                        __KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, false, "vpl waited");
 
1642
                }
 
1643
                // If anyone else was waiting, the allocation causes a delay.
 
1644
                else if (error == 0 && !vpl->waitingThreads.empty())
 
1645
                        return hleDelayResult(error, "vpl allocated", 50);
 
1646
        }
 
1647
        return error;
 
1648
}
 
1649
 
 
1650
int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
 
1651
{
 
1652
        u32 error, ignore;
 
1653
        if (__KernelAllocateVpl(uid, size, addrPtr, error, false, __FUNCTION__))
 
1654
        {
 
1655
                hleCheckCurrentCallbacks();
 
1656
 
 
1657
                VPL *vpl = kernelObjects.Get<VPL>(uid, ignore);
 
1658
                if (error == SCE_KERNEL_ERROR_NO_MEMORY)
 
1659
                {
 
1660
                        if (timeoutPtr != 0 && Memory::Read_U32(timeoutPtr) == 0)
 
1661
                                return SCE_KERNEL_ERROR_WAIT_TIMEOUT;
 
1662
 
 
1663
                        if (vpl)
 
1664
                        {
 
1665
                                SceUID threadID = __KernelGetCurThread();
 
1666
                                HLEKernel::RemoveWaitingThread(vpl->waitingThreads, threadID);
 
1667
                                VplWaitingThread waiting = {threadID, addrPtr};
 
1668
                                vpl->waitingThreads.push_back(waiting);
 
1669
                        }
 
1670
 
 
1671
                        __KernelSetVplTimeout(timeoutPtr);
 
1672
                        __KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, true, "vpl waited");
 
1673
                }
 
1674
                // If anyone else was waiting, the allocation causes a delay.
 
1675
                else if (error == 0 && !vpl->waitingThreads.empty())
 
1676
                        return hleDelayResult(error, "vpl allocated", 50);
 
1677
        }
 
1678
        return error;
 
1679
}
 
1680
 
 
1681
int sceKernelTryAllocateVpl(SceUID uid, u32 size, u32 addrPtr)
 
1682
{
 
1683
        u32 error;
 
1684
        __KernelAllocateVpl(uid, size, addrPtr, error, true, __FUNCTION__);
 
1685
        return error;
 
1686
}
 
1687
 
 
1688
int sceKernelFreeVpl(SceUID uid, u32 addr) {
 
1689
        if (addr && !Memory::IsValidAddress(addr)) {
 
1690
                WARN_LOG(SCEKERNEL, "%08x=sceKernelFreeVpl(%i, %08x): Invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, addr);
 
1691
                return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
 
1692
        }
 
1693
 
 
1694
        VERBOSE_LOG(SCEKERNEL, "sceKernelFreeVpl(%i, %08x)", uid, addr);
 
1695
        u32 error;
 
1696
        VPL *vpl = kernelObjects.Get<VPL>(uid, error);
 
1697
        if (vpl) {
 
1698
                bool freed;
 
1699
                // Free using the header for newer vpls (not old savestates.)
 
1700
                if (vpl->header.IsValid()) {
 
1701
                        freed = vpl->header->Free(addr);
 
1702
                } else {
 
1703
                        freed = vpl->alloc.FreeExact(addr);
 
1704
                }
 
1705
 
 
1706
                if (freed) {
 
1707
                        __KernelSortVplThreads(vpl);
 
1708
 
 
1709
                        bool wokeThreads = false;
 
1710
retry:
 
1711
                        for (auto iter = vpl->waitingThreads.begin(), end = vpl->waitingThreads.end(); iter != end; ++iter) {
 
1712
                                if (__KernelUnlockVplForThread(vpl, *iter, error, 0, wokeThreads)) {
 
1713
                                        vpl->waitingThreads.erase(iter);
 
1714
                                        goto retry;
 
1715
                                }
 
1716
                                // In FIFO, we stop at the first one that can't wake.
 
1717
                                else if ((vpl->nv.attr & PSP_VPL_ATTR_MASK_ORDER) == PSP_VPL_ATTR_FIFO)
 
1718
                                        break;
 
1719
                        }
 
1720
 
 
1721
                        if (wokeThreads) {
 
1722
                                hleReSchedule("vpl freed");
 
1723
                        }
 
1724
 
 
1725
                        return 0;
 
1726
                } else {
 
1727
                        WARN_LOG(SCEKERNEL, "%08x=sceKernelFreeVpl(%i, %08x): Unable to free", SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK, uid, addr);
 
1728
                        return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK;
 
1729
                }
 
1730
        } else {
 
1731
                return error;
 
1732
        }
 
1733
}
 
1734
 
 
1735
int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr)
 
1736
{
 
1737
        u32 error;
 
1738
        VPL *vpl = kernelObjects.Get<VPL>(uid, error);
 
1739
        if (vpl)
 
1740
        {
 
1741
                DEBUG_LOG(SCEKERNEL, "sceKernelCancelVpl(%i, %08x)", uid, numWaitThreadsPtr);
 
1742
                vpl->nv.numWaitThreads = (int) vpl->waitingThreads.size();
 
1743
                if (Memory::IsValidAddress(numWaitThreadsPtr))
 
1744
                        Memory::Write_U32(vpl->nv.numWaitThreads, numWaitThreadsPtr);
 
1745
 
 
1746
                bool wokeThreads = __KernelClearVplThreads(vpl, SCE_KERNEL_ERROR_WAIT_CANCEL);
 
1747
                if (wokeThreads)
 
1748
                        hleReSchedule("vpl canceled");
 
1749
 
 
1750
                return 0;
 
1751
        }
 
1752
        else
 
1753
        {
 
1754
                DEBUG_LOG(SCEKERNEL, "sceKernelCancelVpl(%i, %08x): invalid vpl", uid, numWaitThreadsPtr);
 
1755
                return error;
 
1756
        }
 
1757
}
 
1758
 
 
1759
int sceKernelReferVplStatus(SceUID uid, u32 infoPtr) {
 
1760
        u32 error;
 
1761
        VPL *vpl = kernelObjects.Get<VPL>(uid, error);
 
1762
        if (vpl) {
 
1763
                DEBUG_LOG(SCEKERNEL, "sceKernelReferVplStatus(%i, %08x)", uid, infoPtr);
 
1764
 
 
1765
                __KernelSortVplThreads(vpl);
 
1766
                vpl->nv.numWaitThreads = (int) vpl->waitingThreads.size();
 
1767
                if (vpl->header.IsValid()) {
 
1768
                        vpl->nv.freeSize = vpl->header->FreeSize();
 
1769
                } else {
 
1770
                        vpl->nv.freeSize = vpl->alloc.GetTotalFreeBytes();
 
1771
                }
 
1772
                if (Memory::IsValidAddress(infoPtr) && Memory::Read_U32(infoPtr) != 0) {
 
1773
                        Memory::WriteStruct(infoPtr, &vpl->nv);
 
1774
                }
 
1775
                return 0;
 
1776
        } else {
 
1777
                return error;
 
1778
        }
 
1779
}
 
1780
 
 
1781
static u32 AllocMemoryBlock(const char *pname, u32 type, u32 size, u32 paramsAddr) {
 
1782
        if (Memory::IsValidAddress(paramsAddr) && Memory::Read_U32(paramsAddr) != 4) {
 
1783
                ERROR_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(%s): unsupported params size %d", pname, Memory::Read_U32(paramsAddr));
 
1784
                return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
 
1785
        }
 
1786
        if (type != PSP_SMEM_High && type != PSP_SMEM_Low) {
 
1787
                ERROR_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(%s): unsupported type %d", pname, type);
 
1788
                return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE;
 
1789
        }
 
1790
        if (size == 0) {
 
1791
                WARN_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(%s): invalid size %x", pname, size);
 
1792
                return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
 
1793
        }
 
1794
        if (pname == NULL) {
 
1795
                ERROR_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(): NULL name");
 
1796
                return SCE_KERNEL_ERROR_ERROR;
 
1797
        }
 
1798
 
 
1799
        PartitionMemoryBlock *block = new PartitionMemoryBlock(&userMemory, pname, size, (MemblockType)type, 0);
 
1800
        if (!block->IsValid())
 
1801
        {
 
1802
                delete block;
 
1803
                ERROR_LOG(SCEKERNEL, "AllocMemoryBlock(%s, %i, %08x, %08x): allocation failed", pname, type, size, paramsAddr);
 
1804
                return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
 
1805
        }
 
1806
        SceUID uid = kernelObjects.Create(block);
 
1807
 
 
1808
        INFO_LOG(SCEKERNEL,"%08x=AllocMemoryBlock(SysMemUserForUser_FE707FDF)(%s, %i, %08x, %08x)", uid, pname, type, size, paramsAddr);
 
1809
        return uid;
 
1810
}
 
1811
 
 
1812
static u32 FreeMemoryBlock(u32 uid) {
 
1813
        INFO_LOG(SCEKERNEL, "FreeMemoryBlock(%08x)", uid);
 
1814
        return kernelObjects.Destroy<PartitionMemoryBlock>(uid);
 
1815
}
 
1816
 
 
1817
static u32 GetMemoryBlockPtr(u32 uid, u32 addr) {
 
1818
        u32 error;
 
1819
        PartitionMemoryBlock *block = kernelObjects.Get<PartitionMemoryBlock>(uid, error);
 
1820
        if (block)
 
1821
        {
 
1822
                INFO_LOG(SCEKERNEL, "GetMemoryBlockPtr(%08x, %08x) = %08x", uid, addr, block->address);
 
1823
                Memory::Write_U32(block->address, addr);
 
1824
                return 0;
 
1825
        }
 
1826
        else
 
1827
        {
 
1828
                ERROR_LOG(SCEKERNEL, "GetMemoryBlockPtr(%08x, %08x) failed", uid, addr);
 
1829
                return 0;
 
1830
        }
 
1831
}
 
1832
 
 
1833
static u32 SysMemUserForUser_D8DE5C1E() {
 
1834
        // Called by Evangelion Jo and return 0 here to go in-game.
 
1835
        ERROR_LOG(SCEKERNEL,"UNIMPL SysMemUserForUser_D8DE5C1E()");
 
1836
        return 0; 
 
1837
}
 
1838
 
 
1839
static u32 SysMemUserForUser_ACBD88CA() {
 
1840
        ERROR_LOG_REPORT_ONCE(SysMemUserForUser_ACBD88CA, SCEKERNEL, "UNIMPL SysMemUserForUser_ACBD88CA()");
 
1841
        return 0; 
 
1842
}
 
1843
 
 
1844
static u32 SysMemUserForUser_945E45DA() {
 
1845
        // Called by Evangelion Jo and expected return 0 here.
 
1846
        ERROR_LOG_REPORT_ONCE(SysMemUserForUser945E45DA, SCEKERNEL, "UNIMPL SysMemUserForUser_945E45DA()");
 
1847
        return 0; 
 
1848
}
 
1849
 
 
1850
enum
 
1851
{
 
1852
        PSP_ERROR_UNKNOWN_TLSPL_ID = 0x800201D0,
 
1853
        PSP_ERROR_TOO_MANY_TLSPL   = 0x800201D1,
 
1854
        PSP_ERROR_TLSPL_IN_USE     = 0x800201D2,
 
1855
};
 
1856
 
 
1857
enum
 
1858
{
 
1859
        // TODO: Complete untested guesses.
 
1860
        PSP_TLSPL_ATTR_FIFO     = 0,
 
1861
        PSP_TLSPL_ATTR_PRIORITY = 0x100,
 
1862
        PSP_TLSPL_ATTR_HIGHMEM  = 0x4000,
 
1863
        PSP_TLSPL_ATTR_KNOWN    = PSP_TLSPL_ATTR_HIGHMEM | PSP_TLSPL_ATTR_PRIORITY | PSP_TLSPL_ATTR_FIFO,
 
1864
};
 
1865
 
 
1866
struct NativeTlspl
 
1867
{
 
1868
        SceSize_le size;
 
1869
        char name[32];
 
1870
        SceUInt_le attr;
 
1871
        s32_le index;
 
1872
        u32_le blockSize;
 
1873
        u32_le totalBlocks;
 
1874
        u32_le freeBlocks;
 
1875
        u32_le numWaitThreads;
 
1876
};
 
1877
 
 
1878
struct TLSPL : public KernelObject
 
1879
{
 
1880
        const char *GetName() override { return ntls.name; }
 
1881
        const char *GetTypeName() override { return "TLS"; }
 
1882
        static u32 GetMissingErrorCode() { return PSP_ERROR_UNKNOWN_TLSPL_ID; }
 
1883
        static int GetStaticIDType() { return SCE_KERNEL_TMID_Tlspl; }
 
1884
        int GetIDType() const override { return SCE_KERNEL_TMID_Tlspl; }
 
1885
 
 
1886
        TLSPL() : next(0) {}
 
1887
 
 
1888
        void DoState(PointerWrap &p) override
 
1889
        {
 
1890
                auto s = p.Section("TLS", 1, 2);
 
1891
                if (!s)
 
1892
                        return;
 
1893
 
 
1894
                p.Do(ntls);
 
1895
                p.Do(address);
 
1896
                if (s >= 2)
 
1897
                        p.Do(alignment);
 
1898
                else
 
1899
                        alignment = 4;
 
1900
                p.Do(waitingThreads);
 
1901
                p.Do(next);
 
1902
                p.Do(usage);
 
1903
        }
 
1904
 
 
1905
        NativeTlspl ntls;
 
1906
        u32 address;
 
1907
        u32 alignment;
 
1908
        std::vector<SceUID> waitingThreads;
 
1909
        int next;
 
1910
        std::vector<SceUID> usage;
 
1911
};
 
1912
 
 
1913
KernelObject *__KernelTlsplObject()
 
1914
{
 
1915
        return new TLSPL;
 
1916
}
 
1917
 
 
1918
static void __KernelSortTlsplThreads(TLSPL *tls)
 
1919
{
 
1920
        // Remove any that are no longer waiting.
 
1921
        SceUID uid = tls->GetUID();
 
1922
        HLEKernel::CleanupWaitingThreads(WAITTYPE_TLSPL, uid, tls->waitingThreads);
 
1923
 
 
1924
        if ((tls->ntls.attr & PSP_FPL_ATTR_PRIORITY) != 0)
 
1925
                std::stable_sort(tls->waitingThreads.begin(), tls->waitingThreads.end(), __KernelThreadSortPriority);
 
1926
}
 
1927
 
 
1928
int __KernelFreeTls(TLSPL *tls, SceUID threadID)
 
1929
{
 
1930
        // Find the current thread's block.
 
1931
        int freeBlock = -1;
 
1932
        for (size_t i = 0; i < tls->ntls.totalBlocks; ++i)
 
1933
        {
 
1934
                if (tls->usage[i] == threadID)
 
1935
                {
 
1936
                        freeBlock = (int) i;
 
1937
                        break;
 
1938
                }
 
1939
        }
 
1940
 
 
1941
        if (freeBlock != -1)
 
1942
        {
 
1943
                SceUID uid = tls->GetUID();
 
1944
 
 
1945
                u32 alignedSize = (tls->ntls.blockSize + tls->alignment - 1) & ~(tls->alignment - 1);
 
1946
                u32 freedAddress = tls->address + freeBlock * alignedSize;
 
1947
 
 
1948
                // Whenever freeing a block, clear it (even if it's not going to wake anyone.)
 
1949
                Memory::Memset(freedAddress, 0, tls->ntls.blockSize);
 
1950
 
 
1951
                // First, let's remove the end check for the freeing thread.
 
1952
                auto freeingLocked = tlsplThreadEndChecks.equal_range(threadID);
 
1953
                for (TlsplMap::iterator iter = freeingLocked.first; iter != freeingLocked.second; ++iter)
 
1954
                {
 
1955
                        if (iter->second == uid)
 
1956
                        {
 
1957
                                tlsplThreadEndChecks.erase(iter);
 
1958
                                break;
 
1959
                        }
 
1960
                }
 
1961
 
 
1962
                __KernelSortTlsplThreads(tls);
 
1963
                while (!tls->waitingThreads.empty())
 
1964
                {
 
1965
                        SceUID waitingThreadID = tls->waitingThreads[0];
 
1966
                        tls->waitingThreads.erase(tls->waitingThreads.begin());
 
1967
 
 
1968
                        // This thread must've been woken up.
 
1969
                        if (!HLEKernel::VerifyWait(waitingThreadID, WAITTYPE_TLSPL, uid))
 
1970
                                continue;
 
1971
 
 
1972
                        // Otherwise, if there was a thread waiting, we were full, so this newly freed one is theirs.
 
1973
                        tls->usage[freeBlock] = waitingThreadID;
 
1974
                        __KernelResumeThreadFromWait(waitingThreadID, freedAddress);
 
1975
 
 
1976
                        // Gotta watch the thread to quit as well, since they've allocated now.
 
1977
                        tlsplThreadEndChecks.insert(std::make_pair(waitingThreadID, uid));
 
1978
 
 
1979
                        // No need to continue or free it, we're done.
 
1980
                        return 0;
 
1981
                }
 
1982
 
 
1983
                // No one was waiting, so now we can really free it.
 
1984
                tls->usage[freeBlock] = 0;
 
1985
                ++tls->ntls.freeBlocks;
 
1986
                return 0;
 
1987
        }
 
1988
        // We say "okay" even though nothing was freed.
 
1989
        else
 
1990
                return 0;
 
1991
}
 
1992
 
 
1993
void __KernelTlsplThreadEnd(SceUID threadID)
 
1994
{
 
1995
        u32 error;
 
1996
 
 
1997
        // It wasn't waiting, was it?
 
1998
        SceUID waitingTlsID = __KernelGetWaitID(threadID, WAITTYPE_TLSPL, error);
 
1999
        if (waitingTlsID)
 
2000
        {
 
2001
                TLSPL *tls = kernelObjects.Get<TLSPL>(waitingTlsID, error);
 
2002
                if (tls)
 
2003
                        tls->waitingThreads.erase(std::remove(tls->waitingThreads.begin(), tls->waitingThreads.end(), threadID), tls->waitingThreads.end());
 
2004
        }
 
2005
 
 
2006
        // Unlock all pools the thread had locked.
 
2007
        auto locked = tlsplThreadEndChecks.equal_range(threadID);
 
2008
        for (TlsplMap::iterator iter = locked.first; iter != locked.second; ++iter)
 
2009
        {
 
2010
                SceUID tlsID = iter->second;
 
2011
                TLSPL *tls = kernelObjects.Get<TLSPL>(tlsID, error);
 
2012
 
 
2013
                if (tls)
 
2014
                {
 
2015
                        __KernelFreeTls(tls, threadID);
 
2016
 
 
2017
                        // Restart the loop, freeing mutated it.
 
2018
                        locked = tlsplThreadEndChecks.equal_range(threadID);
 
2019
                        iter = locked.first;
 
2020
                        if (locked.first == locked.second)
 
2021
                                break;
 
2022
                }
 
2023
        }
 
2024
        tlsplThreadEndChecks.erase(locked.first, locked.second);
 
2025
}
 
2026
 
 
2027
SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 blockSize, u32 count, u32 optionsPtr)
 
2028
{
 
2029
        if (!name)
 
2030
        {
 
2031
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateTlspl(): invalid name", SCE_KERNEL_ERROR_NO_MEMORY);
 
2032
                return SCE_KERNEL_ERROR_NO_MEMORY;
 
2033
        }
 
2034
        if ((attr & ~PSP_TLSPL_ATTR_KNOWN) >= 0x100)
 
2035
        {
 
2036
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateTlspl(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
 
2037
                return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
 
2038
        }
 
2039
        if (partition < 1 || partition > 9 || partition == 7)
 
2040
        {
 
2041
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateTlspl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, partition);
 
2042
                return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
 
2043
        }
 
2044
        // We only support user right now.
 
2045
        if (partition != 2 && partition != 6)
 
2046
        {
 
2047
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateTlspl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_PERM, partition);
 
2048
                return SCE_KERNEL_ERROR_ILLEGAL_PERM;
 
2049
        }
 
2050
 
 
2051
        // There's probably a simpler way to get this same basic formula...
 
2052
        // This is based on results from a PSP.
 
2053
        bool illegalMemSize = blockSize == 0 || count == 0;
 
2054
        if (!illegalMemSize && (u64) blockSize > ((0x100000000ULL / (u64) count) - 4ULL))
 
2055
                illegalMemSize = true;
 
2056
        if (!illegalMemSize && (u64) count >= 0x100000000ULL / (((u64) blockSize + 3ULL) & ~3ULL))
 
2057
                illegalMemSize = true;
 
2058
        if (illegalMemSize)
 
2059
        {
 
2060
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateTlspl(): invalid blockSize/count", SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE);
 
2061
                return SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE;
 
2062
        }
 
2063
 
 
2064
        int index = -1;
 
2065
        for (int i = 0; i < TLSPL_NUM_INDEXES; ++i)
 
2066
                if (tlsplUsedIndexes[i] == false)
 
2067
                {
 
2068
                        index = i;
 
2069
                        break;
 
2070
                }
 
2071
 
 
2072
        if (index == -1)
 
2073
        {
 
2074
                WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateTlspl(): ran out of indexes for TLS pools", PSP_ERROR_TOO_MANY_TLSPL);
 
2075
                return PSP_ERROR_TOO_MANY_TLSPL;
 
2076
        }
 
2077
 
 
2078
        // Unless otherwise specified, we align to 4 bytes (a mips word.)
 
2079
        u32 alignment = 4;
 
2080
        if (optionsPtr != 0)
 
2081
        {
 
2082
                u32 size = Memory::Read_U32(optionsPtr);
 
2083
                if (size > 8)
 
2084
                        WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateTlspl(%s) unsupported options parameter, size = %d", name, size);
 
2085
                if (size >= 8)
 
2086
                        alignment = Memory::Read_U32(optionsPtr + 4);
 
2087
 
 
2088
                // Note that 0 intentionally is allowed.
 
2089
                if ((alignment & (alignment - 1)) != 0)
 
2090
                {
 
2091
                        ERROR_LOG_REPORT(SCEKERNEL, "sceKernelCreateTlspl(%s): alignment is not a power of 2: %d", name, alignment);
 
2092
                        return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
 
2093
                }
 
2094
                // This goes for 0, 1, and 2.  Can't have less than 4 byte alignment.
 
2095
                if (alignment < 4)
 
2096
                        alignment = 4;
 
2097
        }
 
2098
 
 
2099
        // Upalign.  Strangely, the sceKernelReferTlsplStatus value is the original.
 
2100
        u32 alignedSize = (blockSize + alignment - 1) & ~(alignment - 1);
 
2101
 
 
2102
        u32 totalSize = alignedSize * count;
 
2103
        u32 blockPtr = userMemory.Alloc(totalSize, (attr & PSP_TLSPL_ATTR_HIGHMEM) != 0, name);
 
2104
#ifdef _DEBUG
 
2105
        userMemory.ListBlocks();
 
2106
#endif
 
2107
 
 
2108
        if (blockPtr == (u32) -1)
 
2109
        {
 
2110
                ERROR_LOG(SCEKERNEL, "%08x=sceKernelCreateTlspl(%s, %d, %08x, %d, %d, %08x): failed to allocate memory", SCE_KERNEL_ERROR_NO_MEMORY, name, partition, attr, blockSize, count, optionsPtr);
 
2111
                return SCE_KERNEL_ERROR_NO_MEMORY;
 
2112
        }
 
2113
 
 
2114
        TLSPL *tls = new TLSPL();
 
2115
        SceUID id = kernelObjects.Create(tls);
 
2116
 
 
2117
        tls->ntls.size = sizeof(tls->ntls);
 
2118
        strncpy(tls->ntls.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
 
2119
        tls->ntls.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
 
2120
        tls->ntls.attr = attr;
 
2121
        tls->ntls.index = index;
 
2122
        tlsplUsedIndexes[index] = true;
 
2123
        tls->ntls.blockSize = blockSize;
 
2124
        tls->ntls.totalBlocks = count;
 
2125
        tls->ntls.freeBlocks = count;
 
2126
        tls->ntls.numWaitThreads = 0;
 
2127
        tls->address = blockPtr;
 
2128
        tls->alignment = alignment;
 
2129
        tls->usage.resize(count, 0);
 
2130
 
 
2131
        WARN_LOG(SCEKERNEL, "%08x=sceKernelCreateTlspl(%s, %d, %08x, %d, %d, %08x)", id, name, partition, attr, blockSize, count, optionsPtr);
 
2132
 
 
2133
        return id;
 
2134
}
 
2135
 
 
2136
int sceKernelDeleteTlspl(SceUID uid)
 
2137
{
 
2138
        u32 error;
 
2139
        TLSPL *tls = kernelObjects.Get<TLSPL>(uid, error);
 
2140
        if (tls)
 
2141
        {
 
2142
                bool inUse = false;
 
2143
                for (SceUID threadID : tls->usage)
 
2144
                {
 
2145
                        if (threadID != 0 && threadID != __KernelGetCurThread())
 
2146
                                inUse = true;
 
2147
                }
 
2148
                if (inUse)
 
2149
                {
 
2150
                        error = PSP_ERROR_TLSPL_IN_USE;
 
2151
                        WARN_LOG(SCEKERNEL, "%08x=sceKernelDeleteTlspl(%08x): in use", error, uid);
 
2152
                        return error;
 
2153
                }
 
2154
 
 
2155
                WARN_LOG(SCEKERNEL, "sceKernelDeleteTlspl(%08x)", uid);
 
2156
 
 
2157
                for (SceUID threadID : tls->waitingThreads)
 
2158
                        HLEKernel::ResumeFromWait(threadID, WAITTYPE_TLSPL, uid, 0);
 
2159
                hleReSchedule("deleted tlspl");
 
2160
 
 
2161
                userMemory.Free(tls->address);
 
2162
                tlsplUsedIndexes[tls->ntls.index] = false;
 
2163
                kernelObjects.Destroy<TLSPL>(uid);
 
2164
        }
 
2165
        else
 
2166
                ERROR_LOG(SCEKERNEL, "%08x=sceKernelDeleteTlspl(%08x): bad tlspl", error, uid);
 
2167
        return error;
 
2168
}
 
2169
 
 
2170
int sceKernelGetTlsAddr(SceUID uid)
 
2171
{
 
2172
        // TODO: Allocate downward if PSP_TLSPL_ATTR_HIGHMEM?
 
2173
        DEBUG_LOG(SCEKERNEL, "sceKernelGetTlsAddr(%08x)", uid);
 
2174
 
 
2175
        if (!__KernelIsDispatchEnabled() || __IsInInterrupt())
 
2176
                return 0;
 
2177
 
 
2178
        u32 error;
 
2179
        TLSPL *tls = kernelObjects.Get<TLSPL>(uid, error);
 
2180
        if (tls)
 
2181
        {
 
2182
                SceUID threadID = __KernelGetCurThread();
 
2183
                int allocBlock = -1;
 
2184
                bool needsClear = false;
 
2185
 
 
2186
                // If the thread already has one, return it.
 
2187
                for (size_t i = 0; i < tls->ntls.totalBlocks && allocBlock == -1; ++i)
 
2188
                {
 
2189
                        if (tls->usage[i] == threadID)
 
2190
                                allocBlock = (int) i;
 
2191
                }
 
2192
 
 
2193
                if (allocBlock == -1)
 
2194
                {
 
2195
                        for (size_t i = 0; i < tls->ntls.totalBlocks && allocBlock == -1; ++i)
 
2196
                        {
 
2197
                                // The PSP doesn't give the same block out twice in a row, even if freed.
 
2198
                                if (tls->usage[tls->next] == 0)
 
2199
                                        allocBlock = tls->next;
 
2200
                                tls->next = (tls->next + 1) % tls->ntls.totalBlocks;
 
2201
                        }
 
2202
 
 
2203
                        if (allocBlock != -1)
 
2204
                        {
 
2205
                                tls->usage[allocBlock] = threadID;
 
2206
                                tlsplThreadEndChecks.insert(std::make_pair(threadID, uid));
 
2207
                                --tls->ntls.freeBlocks;
 
2208
                                needsClear = true;
 
2209
                        }
 
2210
                }
 
2211
 
 
2212
                if (allocBlock == -1)
 
2213
                {
 
2214
                        tls->waitingThreads.push_back(threadID);
 
2215
                        __KernelWaitCurThread(WAITTYPE_TLSPL, uid, 1, 0, false, "allocate tls");
 
2216
                        return 0;
 
2217
                }
 
2218
 
 
2219
                u32 alignedSize = (tls->ntls.blockSize + tls->alignment - 1) & ~(tls->alignment - 1);
 
2220
                u32 allocAddress = tls->address + allocBlock * alignedSize;
 
2221
 
 
2222
                // We clear the blocks upon first allocation (and also when they are freed, both are necessary.)
 
2223
                if (needsClear)
 
2224
                        Memory::Memset(allocAddress, 0, tls->ntls.blockSize);
 
2225
 
 
2226
                return allocAddress;
 
2227
        }
 
2228
        else
 
2229
                return 0;
 
2230
}
 
2231
 
 
2232
// Parameters are an educated guess.
 
2233
int sceKernelFreeTlspl(SceUID uid)
 
2234
{
 
2235
        WARN_LOG(SCEKERNEL, "UNIMPL sceKernelFreeTlspl(%08x)", uid);
 
2236
        u32 error;
 
2237
        TLSPL *tls = kernelObjects.Get<TLSPL>(uid, error);
 
2238
        if (tls)
 
2239
        {
 
2240
                SceUID threadID = __KernelGetCurThread();
 
2241
                return __KernelFreeTls(tls, threadID);
 
2242
        }
 
2243
        else
 
2244
                return error;
 
2245
}
 
2246
 
 
2247
int sceKernelReferTlsplStatus(SceUID uid, u32 infoPtr)
 
2248
{
 
2249
        DEBUG_LOG(SCEKERNEL, "sceKernelReferTlsplStatus(%08x, %08x)", uid, infoPtr);
 
2250
        u32 error;
 
2251
        TLSPL *tls = kernelObjects.Get<TLSPL>(uid, error);
 
2252
        if (tls)
 
2253
        {
 
2254
                // Update the waiting threads in case of deletions, etc.
 
2255
                __KernelSortTlsplThreads(tls);
 
2256
                tls->ntls.numWaitThreads = (int) tls->waitingThreads.size();
 
2257
 
 
2258
                if (Memory::Read_U32(infoPtr) != 0)
 
2259
                        Memory::WriteStruct(infoPtr, &tls->ntls);
 
2260
                return 0;
 
2261
        }
 
2262
        else
 
2263
                return error;
 
2264
}
 
2265
 
 
2266
const HLEFunction SysMemUserForUser[] = {
 
2267
        {0XA291F107, &WrapU_V<sceKernelMaxFreeMemSize>,               "sceKernelMaxFreeMemSize",               'x', ""     },
 
2268
        {0XF919F628, &WrapU_V<sceKernelTotalFreeMemSize>,             "sceKernelTotalFreeMemSize",             'x', ""     },
 
2269
        {0X3FC9AE6A, &WrapU_V<sceKernelDevkitVersion>,                "sceKernelDevkitVersion",                'x', ""     },
 
2270
        {0X237DBD4F, &WrapI_ICIUU<sceKernelAllocPartitionMemory>,     "sceKernelAllocPartitionMemory",         'i', "isixx"},
 
2271
        {0XB6D61D02, &WrapI_I<sceKernelFreePartitionMemory>,          "sceKernelFreePartitionMemory",          'i', "i"    },
 
2272
        {0X9D9A5BA1, &WrapU_I<sceKernelGetBlockHeadAddr>,             "sceKernelGetBlockHeadAddr",             'x', "i"    },
 
2273
        {0X13A5ABEF, &WrapI_C<sceKernelPrintf>,                       "sceKernelPrintf",                       'i', "s"    },
 
2274
        {0X7591C7DB, &WrapI_I<sceKernelSetCompiledSdkVersion>,        "sceKernelSetCompiledSdkVersion",        'i', "i"    },
 
2275
        {0X342061E5, &WrapI_I<sceKernelSetCompiledSdkVersion370>,     "sceKernelSetCompiledSdkVersion370",     'i', "i"    },
 
2276
        {0X315AD3A0, &WrapI_I<sceKernelSetCompiledSdkVersion380_390>, "sceKernelSetCompiledSdkVersion380_390", 'i', "i"    },
 
2277
        {0XEBD5C3E6, &WrapI_I<sceKernelSetCompiledSdkVersion395>,     "sceKernelSetCompiledSdkVersion395",     'i', "i"    },
 
2278
        {0X057E7380, &WrapI_I<sceKernelSetCompiledSdkVersion401_402>, "sceKernelSetCompiledSdkVersion401_402", 'i', "i"    },
 
2279
        {0XF77D77CB, &WrapI_I<sceKernelSetCompilerVersion>,           "sceKernelSetCompilerVersion",           'i', "i"    },
 
2280
        {0X91DE343C, &WrapI_I<sceKernelSetCompiledSdkVersion500_505>, "sceKernelSetCompiledSdkVersion500_505", 'i', "i"    },
 
2281
        {0X7893F79A, &WrapI_I<sceKernelSetCompiledSdkVersion507>,     "sceKernelSetCompiledSdkVersion507",     'i', "i"    },
 
2282
        {0X35669D4C, &WrapI_I<sceKernelSetCompiledSdkVersion600_602>, "sceKernelSetCompiledSdkVersion600_602", 'i', "i"    },  //??
 
2283
        {0X1B4217BC, &WrapI_I<sceKernelSetCompiledSdkVersion603_605>, "sceKernelSetCompiledSdkVersion603_605", 'i', "i"    },
 
2284
        {0X358CA1BB, &WrapI_I<sceKernelSetCompiledSdkVersion606>,     "sceKernelSetCompiledSdkVersion606",     'i', "i"    },
 
2285
        {0XFC114573, &WrapI_V<sceKernelGetCompiledSdkVersion>,        "sceKernelGetCompiledSdkVersion",        'i', ""     },
 
2286
        {0X2A3E5280, nullptr,                                         "sceKernelQueryMemoryInfo",              '?', ""     },
 
2287
        {0XACBD88CA, &WrapU_V<SysMemUserForUser_ACBD88CA>,            "SysMemUserForUser_ACBD88CA",            'x', ""     },
 
2288
        {0X945E45DA, &WrapU_V<SysMemUserForUser_945E45DA>,            "SysMemUserForUser_945E45DA",            'x', ""     },
 
2289
        {0XA6848DF8, nullptr,                                         "sceKernelSetUsersystemLibWork",         '?', ""     },
 
2290
        {0X6231A71D, nullptr,                                         "sceKernelSetPTRIG",                     '?', ""     },
 
2291
        {0X39F49610, nullptr,                                         "sceKernelGetPTRIG",                     '?', ""     },
 
2292
        // Obscure raw block API
 
2293
        {0XDB83A952, &WrapU_UU<GetMemoryBlockPtr>,                    "SysMemUserForUser_DB83A952",            'x', "xx"   },  // GetMemoryBlockAddr
 
2294
        {0X50F61D8A, &WrapU_U<FreeMemoryBlock>,                       "SysMemUserForUser_50F61D8A",            'x', "x"    },  // FreeMemoryBlock
 
2295
        {0XFE707FDF, &WrapU_CUUU<AllocMemoryBlock>,                   "SysMemUserForUser_FE707FDF",            'x', "sxxx" },  // AllocMemoryBlock
 
2296
        {0XD8DE5C1E, &WrapU_V<SysMemUserForUser_D8DE5C1E>,            "SysMemUserForUser_D8DE5C1E",            'x', ""     },
 
2297
};
 
2298
 
 
2299
const HLEFunction SysMemForKernel[] = {
 
2300
        {0x636C953B, nullptr,                                         "SysMemForKernel_636c953b",              '?', ""        },
 
2301
        {0xC9805775, nullptr,                                         "SysMemForKernel_c9805775",              '?', ""        },
 
2302
        {0x1C1FBFE7, nullptr,                                         "SysMemForKernel_1c1fbfe7",              '?', ""        },
 
2303
};
 
2304
 
 
2305
void Register_SysMemForKernel() {
 
2306
        RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel);
 
2307
}
 
2308
 
 
2309
void Register_SysMemUserForUser() {
 
2310
        RegisterModule("SysMemUserForUser", ARRAY_SIZE(SysMemUserForUser), SysMemUserForUser);
 
2311
}