u32 svcCreateThread() { u32 prio = arm11_R(0); u32 ent_pc = arm11_R(1); u32 ent_r0 = arm11_R(2); u32 ent_sp = arm11_R(3); u32 cpu = arm11_R(4); DEBUG("entrypoint=%08x, r0=%08x, sp=%08x, prio=%x, cpu=%x\n", ent_pc, ent_r0, ent_sp, prio, cpu); u32 hand = handle_New(HANDLE_TYPE_THREAD, 0); u32 numthread = threads_New(hand); threads[numthread].priority = prio; threads[numthread].r[0] = ent_r0; threads[numthread].sp = ent_sp; threads[numthread].r15 = ent_pc &~0x1; if (ent_pc & 0x1) { threads[numthread].cpsr = 0x3F; //usermode } else { threads[numthread].cpsr = 0x1F; //usermode } threads[numthread].mode = RESUME; arm11_SetR(1, hand); // r1 = handle_out return 0; }
u32 svcAcceptSession() { u32 session = arm11_R(0); u32 old_port = arm11_R(1); handleinfo* newhi = handle_Get(old_port); if (newhi == NULL) { ERROR("getting handle.\n"); return 0x0; } u32 newhand = handle_New(HANDLE_TYPE_SERVICE_SERVER, SERVICE_DIRECT); handleinfo* newhi2 = handle_Get(newhand); if (newhi2 == NULL) { ERROR("getting handle.\n"); return 0x0; } newhi2->misc[0] = newhi->misc[1]; //unlock handleinfo* anewhi = handle_Get(newhi->misc[1]); if (anewhi == NULL) { ERROR("getting handle.\n"); return 0x0; } anewhi->misc[0] |= HANDLE_SERV_STAT_OPENING; DEBUG("AcceptSession %08x %08x\n", session, newhi->misc[1]); arm11_SetR(1, newhand); return 0; }
u32 svcAcceptSession() { s32 session = arm11_R(0); u32 port = arm11_R(1); arm11_SetR(1, handle_New(HANDLE_TYPE_SESSION, port)); DEBUG("AcceptSession %08x %08x\n", session, port); return 0; }
u32 svcCreateMemoryBlock() //todo ichfly { u32 memblock = arm11_R(0); u32 addr = arm11_R(1); u32 size = arm11_R(2); arm11_SetR(1, 0); //for tests //handle_New(HANDLE_TYPE_SHAREDMEM, 0)); // is this realy what it is I am not sure return 0; }
int main() { return 0; arm11_Init(); FILE* fd = fopen("tests/arm_instr.elf", "rb"); if(fd == NULL) { fprintf(stderr, "Failed to open file.\n"); return 1; } // Load file. if(loader_LoadFile(fd) != 0) { fprintf(stderr, "Failed to load file.\n"); fclose(fd); return 1; } arm11_Step(); ASSERT(arm11_R(0) == 0x31, "mov1 fail\n"); arm11_Step(); ASSERT(arm11_R(1) == 0x80000001, "mov2 fail\n"); arm11_Step(); arm11_Step(); ASSERT(arm11_R(3) == 0x33, "eor1 fail\n"); arm11_Step(); ASSERT(arm11_R(4) == 0x40000031, "eor2 fail\n"); arm11_Step(); ASSERT(arm11_R(5) == 0xC0000031, "eor3 fail\n"); arm11_Step(); ASSERT(arm11_R(6) == 0xC0000031, "eor4 fail\n"); arm11_Step(); ASSERT(arm11_R(7) == 0x100, "ldr1 fail\n"); arm11_Step(); ASSERT(arm11_R(8) == 0x123, "ldr2 fail\n"); arm11_Step(); arm11_Step(); ASSERT(arm11_R(2) == 0x1, "add pc1 fail\n"); arm11_Step(); ASSERT(arm11_R(2) == 0x0, "add pc2 fail\n"); return 0; }
u32 svcSetThreadPriority() { u32 hand = arm11_R(0); s32 prio = arm11_R(1); u32 threadid = threads_FindIdByHandle(hand); if (threadid != -1) { DEBUG("Thread Priority : %d -> %d\n", threads[threadid].priority, prio); threads[threadid].priority = prio; } return 0; }
u32 svcGetThreadPriority() { u32 out = arm11_R(0); u32 hand = arm11_R(1); s32 prio = 0; u32 threadid = threads_FindIdByHandle(hand); if (threadid != -1) { DEBUG("Thread Priority : %d\n", threads[threadid].priority); prio = threads[threadid].priority; } arm11_SetR(1, prio); // r1 = prio out return 0; }
s32 svcGetResourceLimitCurrentValues() { u32 values_ptr = arm11_R(0); u32 handleResourceLimit = arm11_R(1); u32 names_ptr = arm11_R(2); u32 nameCount = arm11_R(3); for (u32 i = 0; i < nameCount; i++) { u32 temp = mem_Read32(names_ptr + i*4); switch (temp) { case 1: //GetUsingMemorySize mem_Write32(values_ptr + i * 8, 0x0); mem_Write32(values_ptr + i * 8 + 4, 0x0); break; default: DEBUG("unknown ResourceLimitCurrentValues %08x",temp); break; } } return 0; }
u32 svcGetThreadId() { u32 handle = arm11_R(1); if (handle == 0xffff8000) return THREAD_ID_OFFSET + current_thread; else { DEBUG("svcGetThreadId not supported\n"); return 0; } }
u32 svcMapMemoryBlock() { u32 handle = arm11_R(0); u32 addr = arm11_R(1); u32 my_perm = arm11_R(2); u32 other_perm = arm11_R(3); handleinfo* h = handle_Get(handle); if(h == NULL) { DEBUG("Invalid handle.\n"); PAUSE(); return 0xFFFFFFFF; } if (h->type == HANDLE_TYPE_SERVICE) { switch (h->subtype) { default: DEBUG("Trying to map unknown mem\nhandle=%x, addr=%08x, my_perm=%x, other_perm=%x\n", handle, addr, my_perm, other_perm); PAUSE(); return 0xFFFFFFFF; } } else { switch (h->subtype) { case MEM_TYPE_GSP_0: mem_AddMappingShared(addr, GSPsharebuffsize, GSPsharedbuff); break; case MEM_TYPE_HID_0: mem_AddMappingShared(addr, 0x2000, HIDsharedbuff); break; default: DEBUG("Trying to map unknown mem\nhandle=%x, addr=%08x, my_perm=%x, other_perm=%x\n", handle, addr, my_perm, other_perm); PAUSE(); return 0xFFFFFFFF; } } return 0; }
u32 svcCreateMemoryBlock() // TODO { u32 memblock = arm11_R(0); u32 addr = arm11_R(1); u32 size = arm11_R(2); ERROR("CreateMemoryBlock addr=%08x size=%08x\n",addr,size); u32 handle = handle_New(HANDLE_TYPE_SHAREDMEM, MEM_TYPE_ALLOC); handleinfo* h = handle_Get(handle); if (h == NULL) { DEBUG("failed to get handle\n"); PAUSE(); return -1; } h->misc[0] = addr; h->misc[1] = size; h->misc_ptr[0] = malloc(size); arm11_SetR(1, handle); return 0; }
/* Generic SVC implementations. */ u32 svcSendSyncRequest() { u32 handle = arm11_R(0); handleinfo* hi = handle_Get(handle); if(hi == NULL) { ERROR("handle %08x not found.\n", handle); IPC_debugprint(arm11_ServiceBufferAddress() + 0x80); arm11_Dump(); PAUSE(); #ifdef EXIT_ON_ERROR exit(1); #else return 0; #endif } if(hi->type >= NUM_HANDLE_TYPES) { // This should never happen. ERROR("handle %08x has non-defined type.\n", handle); PAUSE(); exit(1); } // Lookup actual callback in table. if (handle_types[hi->type].fnSyncRequest != NULL) { u32 ret; bool locked = false; ret = handle_types[hi->type].fnSyncRequest(hi, &locked); // Handle is locked so we put thread into WAITING state. if (locked) { u32* wait_list = malloc(4); wait_list[0] = handle; threads_SetCurrentThreadWaitList(wait_list, true, 1); } return ret; } else { ERROR("svcSyncRequest undefined for handle-type \"%s\".\n", handle_types[hi->type].name); PAUSE(); exit(1); } }
u32 svcWaitSynchronization1() //todo timeout { u32 handle = arm11_R(0); handleinfo* hi = handle_Get(handle); if(hi == NULL) { ERROR("handle %08x not found.\n", handle); PAUSE(); #ifdef EXIT_ON_ERROR exit(1); #else return 0; #endif } if(hi->type >= NUM_HANDLE_TYPES) { // This should never happen. ERROR("handle %08x has non-defined type.\n", handle); PAUSE(); exit(1); } // Lookup actual callback in table. if (handle_types[hi->type].fnWaitSynchronization != NULL) { u32 ret; bool locked = false; ret = handle_types[hi->type].fnWaitSynchronization(hi, &locked); if (locked) { // If handle is locked we put thread in WAITING state. u32* wait_list = (u32*) malloc(4); wait_list[0] = handle; threads_SetCurrentThreadWaitList(wait_list, true, 1); } return ret; } else { ERROR("WaitSynchronization undefined for handle-type \"%s\".\n", handle_types[hi->type].name); PAUSE(); return 0; } }
u32 svcWaitSynchronizationN() // TODO: timeouts { u32 nanoseconds1 = arm11_R(0); u32 handles_ptr = arm11_R(1); u32 handles_count = arm11_R(2); u32 wait_all = arm11_R(3); u32 nanoseconds2 = arm11_R(4); u32 out = arm11_R(5); wrapWaitSynchronizationN(nanoseconds1, handles_ptr, handles_count, wait_all, nanoseconds2, out); return 0; }
u32 svcWaitSynchronization1() //todo timeout { u32 handle = arm11_R(0); handleinfo* hi = handle_Get(handle); if(hi == NULL) { ERROR("handle %08x not found.\n", handle); PAUSE(); #ifdef exitonerror exit(1); #else return 0; #endif } if(hi->type >= NUM_HANDLE_TYPES) { // This should never happen. ERROR("handle %08x has non-defined type.\n", handle); PAUSE(); exit(1); } u32 temp; bool locked = false; // Lookup actual callback in table. if (handle_types[hi->type].fnWaitSynchronization != NULL) { temp = handle_types[hi->type].fnWaitSynchronization(hi, &locked); if (locked) { u32* handelist = (u32*)malloc(4); *handelist = handle; lockcpu(handelist, 1,1); } return temp; } else { ERROR("svcCloseHandle undefined for handle-type \"%s\".\n", handle_types[hi->type].name); PAUSE(); return 0; } }
u32 svcCloseHandle() { u32 handle = arm11_R(0); if(handle == HANDLE_CURRENT_PROCESS) { printf("Program exited successfully.\n"); PAUSE(); exit(0); } handleinfo* hi = handle_Get(handle); if(hi == NULL) { ERROR("handle %08x not found.\n", handle); PAUSE(); #ifdef EXIT_ON_ERROR exit(1); #else return 0; #endif } if(hi->type >= NUM_HANDLE_TYPES) { // This should never happen. ERROR("handle %08x has non-defined type.\n", handle); PAUSE(); exit(1); } // Lookup actual callback in table. if(handle_types[hi->type].fnCloseHandle != NULL) return handle_types[hi->type].fnCloseHandle(&s, handle); ERROR("svcCloseHandle undefined for handle-type \"%s\".\n", handle_types[hi->type].name); PAUSE(); return 0; }
u32 svcControlMemory() { u32 op = arm11_R(0); u32 addr0 = arm11_R(1); u32 addr1 = arm11_R(2); u32 size = arm11_R(3); u32 perm = arm11_R(4); const char* ops; switch(op & 0xFF) { case 1: ops = "FREE"; break; case 2: ops = "RESERVE"; break; case 3: ops = "COMMIT"; break; case 4: ops = "MAP"; break; case 5: ops = "UNMAP"; break; case 6: ops = "PROTECT"; break; default: ops = "UNDEFINED"; break; } const char* perms; switch(perm) { case 0: perms = "--"; break; case 1: perms = "-R"; break; case 2: perms = "W-"; break; case 3: perms = "WR"; break; case 0x10000000: perms = "DONTCARE"; break; default: perms = "UNDEFINED"; } DEBUG("op=%s %s (%x), addr0=%x, addr1=%x, size=%x, perm=%s (%x)\n", ops, op & CONTROL_GSP_FLAG ? "GSP" : "", op, addr0, addr1, size, perms, perm); PAUSE(); if(addr0 & 0xFFF) return SVCERROR_ALIGN_ADDR; if(addr1 & 0xFFF) return SVCERROR_ALIGN_ADDR; if(size & 0xFFF) return SVCERROR_INVALID_SIZE; if(op == 0x10003) { // FFF680A4 if(addr0 == 0) { // FFF680C4 if(addr1 != 0) return SVCERROR_INVALID_PARAMS; } else if(size == 0) { // FFF680D0 if(addr0 < 0x14000000) return SVCERROR_INVALID_PARAMS; if((addr0+size) >= 0x1C000000) return SVCERROR_INVALID_PARAMS; if(addr1 != 0) return SVCERROR_INVALID_PARAMS; } else { if(addr0 < 0x14000000) return SVCERROR_INVALID_PARAMS; if(addr0 >= 0x1C000000) return SVCERROR_INVALID_PARAMS; if(addr1 != 0) return SVCERROR_INVALID_PARAMS; } } else if(op == 1) { if(size == 0) { // FFF68110 if(addr0 < 0x08000000) // FFF68130 return SVCERROR_INVALID_PARAMS; if(addr0 <= 0x1C000000) return SVCERROR_INVALID_PARAMS; } else { if(addr0 < 0x08000000) return SVCERROR_INVALID_PARAMS; if((addr0+size) <= 0x1C000000) return SVCERROR_INVALID_PARAMS; } } else { if(size == 0) { // FFF68148 if(addr0 < 0x08000000) return SVCERROR_INVALID_PARAMS; if(addr0 >= 0x14000000) return SVCERROR_INVALID_PARAMS; } else { if(addr0 < 0x08000000) return SVCERROR_INVALID_PARAMS; if((addr0+size) >= 0x14000000) return SVCERROR_INVALID_PARAMS; } if(op == 4 || op == 5) { // FFF680E8 if(size == 0) { if(addr1 < 0x100000) // FFF681CC return SVCERROR_INVALID_PARAMS; if(addr1 >= 0x14000000) return SVCERROR_INVALID_PARAMS; } if(addr1 < 0x100000) return SVCERROR_INVALID_PARAMS; if((addr1+size) >= 0x14000000) return SVCERROR_INVALID_PARAMS; } } // ???? switch(op & 0xff) { case 1: case 3: case 4: case 5: case 6: break; default: return SVCERROR_INVALID_OPERATION; } if(size == 0) return 0; //kprocess = *0xFFFF9004; //*(SP+0x10) = kprocess + 0x1c; // ??? /* u32 flags = outaddr & 0xff; if(flags != 1) { if(perms != 0 && perms != 1 && perms != 2 && perms != 3) return SVCERROR_INVALID_OPERATION; } */ /*if ((op&0xF) == 3) //COMMIT { arm11_SetR(1, addr0); // outaddr is in R1 return mem_AddSegment(addr0, size, NULL); }*/ /*if(op == 0x10003) { DEBUG("Mapping GSP heap..\n"); arm11_SetR(1, 0x08000000); // outaddr is in R1 return mem_AddSegment(0x08000000, size, NULL); }*/ if ((op & 0xF) == 0x3 || (op & 0xF) == 0x0) { //COMMIT if ((op & 0x10000) == 0x10000) { //LINEAR if (size > 0x08000000) { //Console.WriteLine("out of linear mem"); return 0xFFFFFFFF; } } if (addr0 != 0) { if ((op & 0x10000) == 0x10000) { //LINEAR addr0 = 0x08000000; } arm11_SetR(1, addr0); // outaddr is in R1 return mem_AddSegment(addr0, size, NULL); } else { if ((op & 0x10000) == 0x10000) { //LINEAR addr0 = 0x14000000 + linearalloced; linearalloced += size; arm11_SetR(1, addr0); // outaddr is in R1 return mem_AddMappingShared(addr0, size, LINEmembuffer); } /*else { addr0 = mallocarm11(0x20000000, 0xFFFFF000, size); }*/ arm11_SetR(1, addr0); // outaddr is in R1 return mem_AddSegment(addr0, size, NULL); } } if ((op & 0xF) == 0x4) { //MAP u8* buffer = mem_rawaddr(addr1, size); if (buffer == 0)return -1; return mem_AddMappingShared(addr0, size, buffer); } if ((op & 0xF) == 0x6) { //Protect we don't protect mem sorry DEBUG("STUBBED!\n"); return 0; } DEBUG("STUBBED!\n"); PAUSE(); /* // FFF6824C r11 = outaddr & 0xFFFFFF; is_ldr = GetKProcessID() == 1 ? 0xFFFFFFFF : 0; r2 = r2 & r11; if(r2 & 0xF00) { r2 = *(kprocess + 0xa0); r11 = (r11 & 0xFFFFF0FF) | (r2 & 0xF00); } if(flags == 3 && !is_ldr) { if(sub_FFF72828(*r10, 1, r5) == 0) return 0xC860180A; } s32 rc = sub_FFF741B4(*(SP+16), (returnval in r1) SP+12, r4, r6, r5, r11, r7); if(rc < 0) { //FFF682F8 if(flags == 1) sub_FFF7A0E8(*r10, 1, r5); } if(flags == 3) sub_FFF7A0E8(*r10, 1, r5); */ return -1; }
u32 svcMapMemoryBlock() { u32 handle = arm11_R(0); u32 addr = arm11_R(1); u32 my_perm = arm11_R(2); u32 other_perm = arm11_R(3); handleinfo* h = handle_Get(handle); DEBUG("handle=%x, addr=%08x, my_perm=%x, other_perm=%x\n", handle, addr, my_perm, other_perm); if(h == NULL) { DEBUG("Invalid handle.\n"); PAUSE(); return -1; } DEBUG("h->type=%x, h->subtype=%08x\n", h->type, (unsigned int)h->subtype); if(h->type == HANDLE_TYPE_SHAREDMEM) { switch (h->subtype) { case MEM_TYPE_GSP_0: mem_AddMappingShared(addr, GSPsharebuffsize, GSPsharedbuff); break; case MEM_TYPE_HID_0: mem_AddMappingShared(addr, 0x2000, HIDsharedbuff); break; case MEM_TYPE_HID_SPVR_0: mem_AddMappingShared(addr, 0x2000, HIDsharedbuffSPVR); break; case MEM_TYPE_CSND: mem_AddMappingShared(addr, CSND_sharedmemsize, CSND_sharedmem); break; case MEM_TYPE_APT_SHARED_FONT: // If user has supplied the shared font, map it. if(APTsharedfont == NULL) { ERROR("No shared font supplied\n"); return -1; } mem_AddMappingShared(0xDEAD0000, APTsharedfontsize, APTsharedfont); //todo ichfly break; case MEM_TYPE_APT_S_SHARED_FONT: // If user has supplied the shared font, map it. if (APTs_sharedfont == NULL) { ERROR("No shared font supplied\n"); return -1; } mem_AddMappingShared(0xDEAD0000, APTs_sharedfontsize, APTs_sharedfont); //todo ichfly break; case MEM_TYPE_ALLOC: if (h->misc[0] != 0) { DEBUG("meaning of addr unk %08x", h->misc[0]); } mem_AddMappingShared(addr,h->misc[1] ,h->misc_ptr[0] ); break; default: ERROR("Trying to map unknown memory\n"); return -1; } } else { ERROR("Handle has incorrect type\n"); return -1; } return 0; }
u32 svcWaitSynchronizationN() //todo timeout { u32 *handelist; u32 nanoseconds1 = arm11_R(0); u32 handles = arm11_R(1); u32 handlecount = arm11_R(2); u32 waitAll = arm11_R(3); u32 nanoseconds2 = arm11_R(4); bool allunlockde = true; for (u32 i = 0; i < handlecount; i++) { u32 curhandel = mem_Read32(handles + i * 4); handleinfo* hi = handle_Get(curhandel); if (hi == NULL) { ERROR("handle %08x not found.\n", curhandel); PAUSE(); #ifdef exitonerror exit(1); #else return 0; #endif } if (hi->type >= NUM_HANDLE_TYPES) { // This should never happen. ERROR("handle %08x has non-defined type.\n", curhandel); PAUSE(); exit(1); } u32 temp; bool locked = false; // Lookup actual callback in table. if (handle_types[hi->type].fnWaitSynchronization != NULL) { temp = handle_types[hi->type].fnWaitSynchronization(hi, &locked); if (!locked && waitAll == 0) { arm11_SetR(1,i); return 0; } else { allunlockde = false; } } else { ERROR("svcCloseHandle undefined for handle-type \"%s\".\n", handle_types[hi->type].name); PAUSE(); return 0; } } if (waitAll && allunlockde)return 0; handelist = malloc(handlecount*4); mem_Read((u8*)handelist, handles, handlecount * 4); lockcpu(handelist, waitAll, handlecount); return 0; }
u32 svcReplyAndReceive() { s32 index = arm11_R(0); u32 handles = arm11_R(1); u32 handleCount = arm11_R(2); u32 replyTarget = arm11_R(3); DEBUG("svcReplyAndReceive %08x %08x %08x %08x\n", index, handles, handleCount, replyTarget); if (replyTarget) //respond { IPC_debugprint(arm11_ServiceBufferAddress() + 0x80); handleinfo* h2 = handle_Get(replyTarget); if (h2 == NULL) { ERROR("handle not there"); } eventhandle = h2->misc[0]; h2 = handle_Get(eventhandle); if (h2 == NULL) { ERROR("handle not there"); } if (h2->misc[0] & HANDLE_SERV_STAT_SYNCING) { mem_Read(h2->misc_ptr[0], arm11_ServiceBufferAddress() + 0x80, 0x80); //todo h2->misc[0] |= HANDLE_SERV_STAT_ACKING; } } for (u32 i = 0; i < handleCount; i++) { DEBUG("%08x\n", mem_Read32(handles + i * 4)); } /*wrapWaitSynchronizationN(0xFFFFFFFF, handles, handleCount, 0, 0xFFFFFFFF,0); //feed module data here switch (times) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: RESP(0, 0x00160042); RESP(1, 0x0); RESP(2, 0x0); RESP(3, 0x12345); break; case 7: RESP(0, 0x00130042); RESP(1, 0x0); RESP(2, 0x0); RESP(3, handle_New(HANDLE_TYPE_EVENT, 0)); break; default: RESP(0, 0x000C0000); break; }*/ //RESP(0, 0x00010800); //feed end times++; arm11_SetR(1, 0); return 0; }
u32 svcReplyAndReceive() { s32 index = arm11_R(0); u32 handles = arm11_R(1); u32 handleCount = arm11_R(2); u32 replyTarget = arm11_R(3); DEBUG("svcReplyAndReceive %08x %08x %08x %08x\n", index, handles, handleCount, replyTarget); #ifdef MODULE_SUPPORT for (u32 i = 0; i < handleCount; i++) { DEBUG("%08x\n", mem_Read32(handles+i*4)); handleinfo* h = handle_Get(eventhandle); if (h == NULL) { PAUSE(); return -1; } if (h->type == HANDLE_TYPE_SERVICE) { h->misc[0] |= HANDLE_SERV_STAT_WAITING; h->misc[1] = curprocesshandle; h->misc[2] = threads_GetCurrentThreadHandle(); } } #endif for (u32 i = 0; i < handleCount; i++) { DEBUG("%08x\n", mem_Read32(handles + i * 4)); } /*wrapWaitSynchronizationN(0xFFFFFFFF, handles, handleCount, 0, 0xFFFFFFFF,0); //feed module data here switch (times) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: RESP(0, 0x00160042); RESP(1, 0x0); RESP(2, 0x0); RESP(3, 0x12345); break; case 7: RESP(0, 0x00130042); RESP(1, 0x0); RESP(2, 0x0); RESP(3, handle_New(HANDLE_TYPE_EVENT, 0)); break; default: RESP(0, 0x000C0000); break; } //feed end times++;*/ arm11_SetR(1, 0); return 1; }