void LightLock_Lock(LightLock* lock) { s32 val; _begin: do { val = __ldrex(lock); if (val < 0) { // Add ourselves to the list of threads blocked on this lock if (__strex(lock, val-1)) goto _begin; // strex failed, try to lock again _wait: // Wait for a thread to wake us up svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0); // Try to lock again do { val = __ldrex(lock); if (val < 0) { // Lock is still locked - keep waiting __clrex(); goto _wait; } } while (__strex(lock, -(val-1))); return; } } while (__strex(lock, -val)); }
//essentially : get commandIndex and totalCommands, calculate offset of new command, copy command and update totalCommands //use LDREX/STREX because this data may also be accessed by the GSP module and we don't want to break stuff //(mostly, we could overwrite the buffer header with wrong data and make the GSP module reexecute old commands) Result gspSubmitGxCommand(u32* sharedGspCmdBuf, u32 gxCommand[0x8]) { if(!sharedGspCmdBuf || !gxCommand)return -1; u32 cmdBufHeader = __ldrex((s32*)sharedGspCmdBuf); u8 commandIndex=cmdBufHeader&0xFF; u8 totalCommands=(cmdBufHeader>>8)&0xFF; if(totalCommands>=15)return -2; u8 nextCmd=(commandIndex+totalCommands)%15; //there are 15 command slots u32* dst=&sharedGspCmdBuf[8*(1+nextCmd)]; memcpy(dst, gxCommand, 0x20); __dsb(); totalCommands++; cmdBufHeader=((cmdBufHeader)&0xFFFF00FF)|(((u32)totalCommands)<<8); while(1) { if (!__strex((s32*)sharedGspCmdBuf, cmdBufHeader)) break; cmdBufHeader = __ldrex((s32*)sharedGspCmdBuf); totalCommands=((cmdBufHeader&0xFF00)>>8)+1; cmdBufHeader=((cmdBufHeader)&0xFFFF00FF)|((totalCommands<<8)&0xFF00); } if(totalCommands==1)return GSPGPU_TriggerCmdReqQueue(); return 0; }
int rt_free_box (void *box_mem, void *box) { /* Free a memory block, returns 0 if OK, 1 if box does not belong to box_mem */ #ifndef __USE_EXCLUSIVE_ACCESS int irq_dis; #endif if (box < box_mem || box >= ((P_BM) box_mem)->end) { return (1); } #ifndef __USE_EXCLUSIVE_ACCESS #if defined (__ICCARM__) irq_dis = __disable_irq_iar(); #else irq_dis = __disable_irq (); #endif /* __ICCARM__ */ *((void **)box) = ((P_BM) box_mem)->free; ((P_BM) box_mem)->free = box; if (!irq_dis) __enable_irq (); #else do { *((void **)box) = (void *)__ldrex(&((P_BM) box_mem)->free); } while (__strex ((U32)box, &((P_BM) box_mem)->free)); #endif return (0); }
void *rt_alloc_box (void *box_mem) { /* Allocate a memory block and return start address. */ void **free; #ifndef __USE_EXCLUSIVE_ACCESS int irq_dis; #if defined (__ICCARM__) irq_dis = __disable_irq_iar(); #else irq_dis = __disable_irq (); #endif /* __ICCARM__ */ free = ((P_BM) box_mem)->free; if (free) { ((P_BM) box_mem)->free = *free; } if (!irq_dis) __enable_irq (); #else do { if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0) { __clrex(); break; } } while (__strex((U32)*free, &((P_BM) box_mem)->free)); #endif return (free); }
void LightSemaphore_Acquire(LightSemaphore* semaphore, s32 count) { s32 old_count; s16 num_threads_acq; do { for (;;) { old_count = __ldrex(&semaphore->current_count); if (old_count > 0) break; __clrex(); do num_threads_acq = (s16)__ldrexh((u16 *)&semaphore->num_threads_acq); while (__strexh((u16 *)&semaphore->num_threads_acq, num_threads_acq + 1)); svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_WAIT_IF_LESS_THAN, count, 0); do num_threads_acq = (s16)__ldrexh((u16 *)&semaphore->num_threads_acq); while (__strexh((u16 *)&semaphore->num_threads_acq, num_threads_acq - 1)); } } while (__strex(&semaphore->current_count, old_count - count)); }
static int popInterrupt() { int curEvt; bool strexFailed; do { union { struct { u8 cur; u8 count; u8 err; u8 unused; }; u32 as_u32; } header; // Do a load on all header fields as an atomic unit header.as_u32 = __ldrex((s32*)gspEventData); if (__builtin_expect(header.count == 0, 0)) { __clrex(); return -1; } curEvt = gspEventData[0xC + header.cur]; header.cur += 1; if (header.cur >= 0x34) header.cur -= 0x34; header.count -= 1; header.err = 0; // Should this really be set? strexFailed = __strex((s32*)gspEventData, header.as_u32); } while (__builtin_expect(strexFailed, 0)); return curEvt; }
void gspEventThreadMain(void *arg) { while (gspRunEvents) { svcWaitSynchronization(gspEvent, U64_MAX); svcClearEvent(gspEvent); while (true) { int curEvt = popInterrupt(); if (curEvt == -1) break; if (curEvt < GSPGPU_EVENT_MAX) { if (gspEventCb[curEvt]) { ThreadFunc func = gspEventCb[curEvt]; if (gspEventCbOneShot[curEvt]) gspEventCb[curEvt] = NULL; func(gspEventCbData[curEvt]); } LightEvent_Signal(&gspEvents[curEvt]); do __ldrex(&gspLastEvent); while (__strex(&gspLastEvent, curEvt)); svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_SIGNAL, 1, 0); gspEventCounts[curEvt]++; } } } }
void LightLock_Unlock(LightLock* lock) { s32 val; do val = -__ldrex(lock); while (__strex(lock, val)); if (val > 1) // Wake up exactly one thread svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0); }
static inline int LightEvent_TryReset(LightEvent* event) { do { if (__ldrex(&event->state)) { __clrex(); return 0; } } while (__strex(&event->state, -1)); return 1; }
void __fastcall sub_1B6F2C(void *a1) { unsigned int *v1; // r3@1 unsigned int v2; // r2@2 __dmb(); v1 = (unsigned int *)((char *)a1 + 8); do v2 = __ldrex(v1); while ( __strex(v2 - 1, v1) ); __dmb(); if ( (signed int)v2 <= 0 ) operator delete(a1); }
int LightLock_TryLock(LightLock* lock) { s32 val; do { val = __ldrex(lock); if (val < 0) { __clrex(); return 1; // Failure } } while (__strex(lock, -val)); return 0; // Success }
void LightSemaphore_Release(LightSemaphore* semaphore, s32 count) { s32 old_count, new_count; do { old_count = __ldrex(&semaphore->current_count); new_count = old_count + count; if (new_count >= semaphore->max_count) new_count = semaphore->max_count; } while (__strex(&semaphore->current_count, new_count)); if(old_count <= 0 || semaphore->num_threads_acq > 0) svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_SIGNAL, count, 0); }
Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3) { Result res = 0; switch(type) { case 0x10000: { do { __ldrex((s32 *)&rosalinaState); } while(__strex((s32 *)&rosalinaState, (s32)(rosalinaState ^ varg1))); if(rosalinaState & 2) hasStartedRosalinaNetworkFuncsOnce = true; if(rosalinaState & 1) rosalinaLockAllThreads(); else if(varg1 & 1) rosalinaUnlockAllThreads(); break; } case 0x10001: { KRecursiveLock__Lock(criticalSectionLock); KRecursiveLock__Lock(&processLangemuLock); u32 i; for(i = 0; i < 0x40 && processLangemuAttributes[i].titleId != 0ULL; i++); if(i < 0x40) { processLangemuAttributes[i].titleId = ((u64)varg3 << 32) | (u32)varg2; processLangemuAttributes[i].state = (u8)(varg1 >> 24); processLangemuAttributes[i].country = (u8)(varg1 >> 16); processLangemuAttributes[i].language = (u8)(varg1 >> 8); processLangemuAttributes[i].region = (u8)((varg1 >> 4) & 0xf); processLangemuAttributes[i].mask = (u8)(varg1 & 0xf); } else res = 0xD8609013; KRecursiveLock__Unlock(&processLangemuLock); KRecursiveLock__Unlock(criticalSectionLock); break; }
GSPGPU_Event gspWaitForAnyEvent(void) { s32 x; do { do { x = __ldrex(&gspLastEvent); if (x < 0) { __clrex(); break; } } while (__strex(&gspLastEvent, -1)); if (x < 0) svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0); } while (x < 0); return (GSPGPU_Event)x; }
int __fastcall sub_1B85C0(int a1, int a2) { int v2; // r3@1 int v3; // r4@1 int v4; // r0@1 int result; // r0@3 void *v6; // r3@4 unsigned int *v7; // r2@5 unsigned int v8; // r1@6 char v9; // [sp+4h] [bp-Ch]@4 v2 = *(_DWORD *)a2; v3 = a1; v4 = *(_DWORD *)a2 - 12; if ( *(_DWORD *)(*(_DWORD *)a2 - 4) < 0 ) { v6 = sub_1B8200(v4, (int)&v9, 0); result = v3; *(_DWORD *)v3 = v6; } else { if ( (_UNKNOWN *)v4 != &unk_200B34 ) { v7 = (unsigned int *)(v2 - 4); __dmb(); do v8 = __ldrex(v7); while ( __strex(v8 + 1, v7) ); __dmb(); } result = v3; *(_DWORD *)v3 = v2; } return result; }
int __fastcall sub_110830(int a1, int a2, int a3, int a4) { int v4; // r5@1 int v5; // r4@1 int v6; // r6@1 void *v7; // r7@6 void *v8; // r0@6 char *v9; // r8@7 char v10; // r3@8 int *v11; // r4@8 int v12; // r0@11 int v13; // r0@11 int v14; // r0@11 int v15; // r0@11 int v16; // r0@11 int v17; // r0@11 int v18; // r0@11 int v19; // r0@11 void *v20; // r0@11 unsigned int *v22; // r3@15 signed int v23; // r2@16 unsigned int *v24; // r3@20 signed int v25; // r2@21 const char *v26; // [sp+4h] [bp-94h]@4 char v27; // [sp+Ch] [bp-8Ch]@11 int v28; // [sp+10h] [bp-88h]@5 char v29; // [sp+14h] [bp-84h]@7 int v30; // [sp+24h] [bp-74h]@5 char v31; // [sp+28h] [bp-70h]@8 char v32; // [sp+29h] [bp-6Fh]@8 char v33; // [sp+2Ah] [bp-6Eh]@8 char v34; // [sp+2Bh] [bp-6Dh]@8 char v35; // [sp+2Ch] [bp-6Ch]@8 char v36; // [sp+2Dh] [bp-6Bh]@8 char v37; // [sp+2Eh] [bp-6Ah]@8 char v38; // [sp+2Fh] [bp-69h]@8 char v39; // [sp+30h] [bp-68h]@8 char v40; // [sp+31h] [bp-67h]@8 char v41; // [sp+32h] [bp-66h]@8 char v42; // [sp+33h] [bp-65h]@8 char v43; // [sp+34h] [bp-64h]@8 char v44; // [sp+35h] [bp-63h]@8 char v45; // [sp+36h] [bp-62h]@8 char v46; // [sp+37h] [bp-61h]@8 char v47; // [sp+38h] [bp-60h]@8 char v48; // [sp+39h] [bp-5Fh]@8 char v49; // [sp+3Ah] [bp-5Eh]@8 char v50; // [sp+3Bh] [bp-5Dh]@8 char v51; // [sp+3Ch] [bp-5Ch]@8 char v52; // [sp+3Dh] [bp-5Bh]@8 char v53; // [sp+3Eh] [bp-5Ah]@8 char v54; // [sp+3Fh] [bp-59h]@8 char v55; // [sp+40h] [bp-58h]@8 char v56; // [sp+41h] [bp-57h]@8 char v57; // [sp+42h] [bp-56h]@8 char v58; // [sp+43h] [bp-55h]@8 char v59; // [sp+44h] [bp-54h]@8 char v60; // [sp+45h] [bp-53h]@8 char v61; // [sp+46h] [bp-52h]@8 char v62; // [sp+47h] [bp-51h]@8 char v63; // [sp+48h] [bp-50h]@8 char v64; // [sp+49h] [bp-4Fh]@8 char v65; // [sp+4Ah] [bp-4Eh]@8 char v66; // [sp+4Bh] [bp-4Dh]@8 char v67; // [sp+4Ch] [bp-4Ch]@8 char v68; // [sp+4Dh] [bp-4Bh]@8 char v69; // [sp+4Eh] [bp-4Ah]@8 char v70; // [sp+4Fh] [bp-49h]@8 char v71; // [sp+50h] [bp-48h]@8 char v72; // [sp+51h] [bp-47h]@8 char v73; // [sp+52h] [bp-46h]@8 char v74; // [sp+53h] [bp-45h]@8 char v75; // [sp+54h] [bp-44h]@8 char v76; // [sp+55h] [bp-43h]@8 char v77; // [sp+56h] [bp-42h]@8 char v78; // [sp+57h] [bp-41h]@8 char v79; // [sp+58h] [bp-40h]@8 char v80; // [sp+59h] [bp-3Fh]@8 char v81; // [sp+5Ah] [bp-3Eh]@8 char v82; // [sp+5Bh] [bp-3Dh]@8 char v83; // [sp+5Ch] [bp-3Ch]@8 char v84; // [sp+5Dh] [bp-3Bh]@8 char v85; // [sp+5Eh] [bp-3Ah]@8 char v86; // [sp+5Fh] [bp-39h]@8 char v87; // [sp+60h] [bp-38h]@8 char v88; // [sp+61h] [bp-37h]@8 char v89; // [sp+62h] [bp-36h]@8 char v90; // [sp+63h] [bp-35h]@8 char v91; // [sp+64h] [bp-34h]@8 char v92; // [sp+66h] [bp-32h]@8 char v93; // [sp+67h] [bp-31h]@8 char v94; // [sp+68h] [bp-30h]@8 char v95; // [sp+69h] [bp-2Fh]@8 char v96; // [sp+6Ah] [bp-2Eh]@8 char v97; // [sp+6Bh] [bp-2Dh]@8 char v98; // [sp+6Ch] [bp-2Ch]@11 v4 = a3; v5 = a4; v6 = sub_11D268(); if ( !v6 ) { if ( v4 ) { if ( v4 == 1 ) v26 = "serializing"; else v26 = 0; } else { v26 = "parsing"; } sub_1B8850(&v28, &unk_1D2476, &v30); if ( v5 ) { sub_11BBB4(&v30, " '%s'", v5); sub_1B7AAC(&v28, &v30); v7 = &unk_200B34; v8 = (void *)(v30 - 12); if ( (_UNKNOWN *)(v30 - 12) == &unk_200B34 ) { v9 = &v29; } else { v24 = (unsigned int *)(v30 - 4); __dmb(); do v25 = __ldrex(v24); while ( __strex(v25 - 1, v24) ); __dmb(); v9 = &v29; if ( v25 <= 0 ) operator delete(v8); } } else { v9 = &v29; v7 = &unk_200B34; } memset(&v30, 0, 0x49u); v30 = 16974380; v51 = 44; v58 = 44; v31 = 1; v10 = 44; v34 = 28; v32 = 30; v33 = 30; v35 = 29; v36 = 27; v37 = 65; v11 = &v30; v40 = 74; v46 = 74; v41 = 93; v44 = 93; v42 = 101; v43 = 75; v45 = 79; v47 = 70; v48 = 111; v49 = 49; v50 = 48; v52 = 48; v53 = 42; v54 = 36; v55 = 50; v56 = 46; v57 = 102; v38 = 94; v59 = 34; v39 = 94; v60 = 32; v85 = 3; v69 = 48; v72 = 42; v74 = 46; v90 = 30; v61 = 40; v77 = 40; v62 = 61; v66 = 61; v63 = 96; v64 = 55; v65 = 62; v76 = 62; v67 = 52; v75 = 52; v91 = 52; v68 = 56; v78 = 56; v70 = 121; v71 = 39; v73 = 54; v79 = 112; v80 = 23; v81 = 8; v89 = 8; v82 = 16; v83 = 6; v84 = 59; v86 = 9; v87 = 21; v88 = 5; v92 = 4; v93 = 26; v94 = 10; v95 = 94; v97 = 17; v96 = 18; while ( 1 ) { *((_BYTE *)v11 + 1) ^= v10 + (_BYTE)v11 - (unsigned int)&v30; v11 = (int *)((char *)v11 + 1); if ( (char *)v11 == &v97 ) break; v10 = v30; } v98 = 0; sub_11AC24(v9, 2, (char *)&v30 + 1, 532); v12 = sub_11ABD0(v9, "String field"); v13 = sub_11ABC0(v12, &v28); v14 = sub_11ABD0(v13, " contains invalid "); v15 = sub_11ABD0(v14, "UTF-8 data when "); v16 = sub_11ABD0(v15, v26); v17 = sub_11ABD0(v16, " a protocol "); v18 = sub_11ABD0(v17, "buffer. Use the 'bytes' type if you intend to send raw "); v19 = sub_11ABD0(v18, "bytes. "); sub_11B094(&v27, v19); sub_11AC40(v9); v20 = (void *)(v28 - 12); if ( (void *)(v28 - 12) != v7 ) { v22 = (unsigned int *)(v28 - 4); __dmb(); do v23 = __ldrex(v22); while ( __strex(v23 - 1, v22) ); __dmb(); if ( v23 <= 0 ) operator delete(v20); } } return v6; }
void __fastcall sub_1B7E44(const void **a1, size_t a2, int a3, int a4) { size_t v4; // r6@1 char *v5; // r4@1 int v6; // r10@1 const void **v7; // r9@1 int v8; // r8@1 int v9; // r5@1 int v10; // r7@1 unsigned int v11; // r5@1 size_t v12; // r7@1 int v13; // r0@3 int v14; // r4@3 void *v15; // r3@3 void *v16; // r0@4 const void *v17; // r1@4 int v18; // r2@7 int v19; // r6@7 int v20; // r10@7 char *v21; // r0@9 bool v22; // zf@14 int v23; // r10@17 int v24; // r6@17 char *v25; // r0@17 char *v26; // r1@17 void *v27; // ST04_4@22 unsigned int *v28; // r1@23 signed int v29; // r2@24 void *v30; // ST04_4@26 v4 = a2; v5 = (char *)*a1; v6 = a4; v7 = a1; v8 = a3; v9 = *((_DWORD *)*a1 - 3); v10 = v9 - a2; v11 = v9 + a4 - a3; v12 = v10 - a3; if ( v11 > *((_DWORD *)*a1 - 2) || *((_DWORD *)v5 - 1) > 0 ) { v13 = sub_1B7D04(v11); v14 = v13; v15 = (void *)(v13 + 12); if ( v4 ) { v16 = (void *)(v13 + 12); v17 = *v7; if ( v4 != 1 ) { v15 = memcpy(v16, v17, v4); if ( v12 ) { LABEL_7: v18 = v4 + 12; v19 = v4 + v8; v20 = v6 + v18; if ( v12 == 1 ) { *(_BYTE *)(v14 + v20) = *((_BYTE *)*v7 + v19); } else { v27 = v15; memcpy((void *)(v14 + v20), (char *)*v7 + v19, v12); v15 = v27; } } LABEL_9: v21 = (char *)*v7 - 12; if ( (_UNKNOWN *)v21 != &unk_200B34 ) { v28 = (unsigned int *)((char *)*v7 - 4); __dmb(); do v29 = __ldrex(v28); while ( __strex(v29 - 1, v28) ); __dmb(); if ( v29 <= 0 ) { v30 = v15; operator delete(v21); v15 = v30; } } v5 = (char *)v15; *v7 = v15; goto LABEL_11; } v15 = (void *)(v14 + 12); *(_BYTE *)(v14 + 12) = *(_BYTE *)v17; } if ( v12 ) goto LABEL_7; goto LABEL_9; } v22 = a3 == a4; if ( a3 != a4 ) v22 = v12 == 0; if ( !v22 ) { v23 = a4 + a2; v24 = a2 + a3; v25 = &v5[a4] + a2; v26 = &v5[a2] + a3; if ( v12 == 1 ) { v5[v23] = v5[v24]; v5 = (char *)*v7; } else { memmove(v25, v26, v12); v5 = (char *)*v7; } } LABEL_11: if ( (_UNKNOWN *)(v5 - 12) != &unk_200B34 ) { *((_DWORD *)v5 - 3) = v11; *((_DWORD *)v5 - 1) = 0; v5[v11] = 0; } }
void LightLock_Init(LightLock* lock) { do __ldrex(lock); while (__strex(lock, 1)); }
static inline void LightEvent_SetState(LightEvent* event, int state) { do __ldrex(&event->state); while (__strex(&event->state, state)); }