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 wrapWaitSynchronizationN(u32 nanoseconds1,u32 handles_ptr,u32 handles_count,u32 wait_all,u32 nanoseconds2,u32 out) // TODO: timeouts { bool all_unlocked = true; for (u32 i = 0; i < handles_count; i++) { u32 handle = mem_Read32(handles_ptr + i * 4); handleinfo* hi = handle_Get(handle); if (hi == NULL) { arm11_SetR(1, i); ERROR("handle %08x not found.\n", handle); PAUSE(); #ifdef EXIT_ON_ERROR exit(1); #endif return -1; } 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) { bool locked = false; handle_types[hi->type].fnWaitSynchronization(hi, &locked); if (!locked && !wait_all) { arm11_SetR(1, i); return 0; } else all_unlocked = false; } else { ERROR("WaitSynchronization undefined for handle-type \"%s\".\n", handle_types[hi->type].name); PAUSE(); arm11_SetR(1, i); //we just say this one is open return 0; } } if(wait_all && all_unlocked) { arm11_SetR(1, handles_count); return 0; } // Put thread in WAITING state if not all handles were unlocked. u32* wait_list = malloc(handles_count*4); mem_Read((u8 *) wait_list, handles_ptr, handles_count * 4); threads_SetCurrentThreadWaitList(wait_list, wait_all, handles_count); return 0; }
void mcu_GPU_init() { mcumutex = handle_New(HANDLE_TYPE_MUTEX, 0); handleinfo* h = handle_Get(mcumutex); if (h == NULL) { DEBUG("failed to get newly created semaphore\n"); PAUSE(); return; } h->locked = false; }
handleinfo* handle_Get(u32 handle) { u32 idx = handle - HANDLES_BASE; if (idx < handles_num) { if (handles[idx].type == HANDLE_TYPE_REDIR) return handle_Get(handles[idx].subtype); else return &handles[idx]; } return NULL; }
/* 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; } }
handleinfo* handle_Get(u32 handle) { u32 idx = handle - HANDLES_BASE; if (idx < handles_num) { if (!handles[idx].taken) { ERROR("handle_Get on free handle %08x", handle); return NULL; } if (handles[idx].type == HANDLE_TYPE_REDIR) return handle_Get(handles[idx].subtype); else return &handles[idx]; } return NULL; }
u32 svc_serverWaitSynchronization(handleinfo* h, bool *locked) { handleinfo* hi = handle_Get(h->misc[0]); if (hi == NULL) { *locked = 1; return 0; } if (hi->misc[0] & HANDLE_SERV_STAT_SYNCING) { mem_Write(hi->misc_ptr[0], arm11_ServiceBufferAddress() + 0x80, 0x80); //todo *locked = 0; return 0; } else { *locked = 1; 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 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 srv_InitHandle() { // Create a handle for srv: port. arm11_SetR(1, handle_New(HANDLE_TYPE_PORT, PORT_TYPE_SRV)); eventhandle = handle_New(HANDLE_TYPE_SEMAPHORE, 0); handleinfo* h = handle_Get(eventhandle); if (h == NULL) { DEBUG("failed to get newly created semaphore\n"); PAUSE(); return -1; } h->locked = true; h->misc[0] = 0x10; //there are 0x10 events we know 2 non of them are used here h->misc[1] = 0x10; 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 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; }
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 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 srv_SyncRequest() { u32 cid = mem_Read32(arm11_ServiceBufferAddress() + 0x80); // Read command-id. switch(cid) { case 0x10002: DEBUG("srv_Initialize\n"); // XXX: check +4, flags? mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); //no error PAUSE(); return 0; case 0x20000: DEBUG("srv_GetProcSemaphore"); mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); //no error mem_Write32(arm11_ServiceBufferAddress() + 0x88, 0); //done in sm 4.4 mem_Write32(arm11_ServiceBufferAddress() + 0x8C, eventhandle); return 0; char names[9]; case 0x000400C0: DEBUG("srv_UnRegisterService --todo--\n"); // Read rest of command header mem_Read((u8*)&req, arm11_ServiceBufferAddress() + 0x84, sizeof(req)); memcpy(names, req.name, 8); names[8] = '\0'; DEBUG("name=%s, namelen=%u\n", names, req.name_len); return 0; case 0x00030100: DEBUG("srv_registerService\n"); // Read rest of command header mem_Read((u8*)&req, arm11_ServiceBufferAddress() + 0x84, sizeof(req)); memcpy(names, req.name, 8); names[8] = '\0'; DEBUG("name=%s, namelen=%u, unk=0x%x\n", names, req.name_len, req.unk2); ownservice[ownservice_num].name = malloc(9); memcpy(ownservice[ownservice_num].name, req.name, 9); ownservice[ownservice_num].handle = handle_New(HANDLE_TYPE_SERVICE, SERVICE_DIRECT); handleinfo* hi = handle_Get(ownservice[ownservice_num].handle); if (hi == NULL) { ERROR("getting handle.\n"); return 0x0; } hi->misc[0] = HANDLE_SERV_STAT_TAKEN; //init hi->misc_ptr[0] = malloc(0x200); mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); //no error mem_Write32(arm11_ServiceBufferAddress() + 0x8C, ownservice[ownservice_num].handle); //return handle ownservice_num++; return 0; case 0x50100: DEBUG("srv_GetServiceHandle\n"); // Read rest of command header mem_Read((u8*)&req, arm11_ServiceBufferAddress() + 0x84, sizeof(req)); memcpy(names, req.name, 8); names[8] = '\0'; DEBUG("name=%s, namelen=%u, unk=0x%x\n", names, req.name_len, req.unk2); PAUSE(); u32 i; bool overdr = false; for (u32 i = 0; i < overdrivnum; i++) { if (memcmp(req.name, *(overdrivnames + i), strnlen(*(overdrivnames + i), 8)) == 0)overdr = true; } if (!overdr) { for (u32 i = 0; i < ownservice_num; i++) { if (memcmp(req.name, ownservice[i].name, strnlen(ownservice[i].name, 8)) == 0) { // Write result. mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); // Write handle_out. mem_Write32(arm11_ServiceBufferAddress() + 0x8C, ownservice[i].handle); return 0; } } } for(i=0; i<ARRAY_SIZE(services); i++) { // Find service in list. if(memcmp(req.name, services[i].name, strnlen(services[i].name, 8)) == 0) { // Write result. mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); // Write handle_out. mem_Write32(arm11_ServiceBufferAddress() + 0x8C, services[i].handle); return 0; } } ERROR("Unimplemented service: %s\n", req.name); arm11_Dump(); exit(1); case 0x90040: // EnableNotificationType DEBUG("srv_EnableNotificationType\n"); u32 type = mem_Read32(arm11_ServiceBufferAddress() + 0x84); DEBUG("STUBBED, type=%x\n", type); mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); return 0; case 0xa0040: // DisableNotificationType DEBUG("srv_DisableNotificationType\n"); type = mem_Read32(arm11_ServiceBufferAddress() + 0x84); DEBUG("STUBBED, type=%x\n", type); mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); //no error return 0; case 0xB0000: // GetNotificationType DEBUG("srv_GetNotificationType\n"); //mem_Dbugdump(); mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0); //worked mem_Write32(arm11_ServiceBufferAddress() + 0x88, 0); //type return 0; default: ERROR("Unimplemented command %08x in \"srv:\"\n", cid); arm11_Dump(); mem_Write32(arm11_ServiceBufferAddress() + 0x84, 0xFFFFFFFF); //worked return 0; //exit(1); } 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); 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; }
// Returns true if given thread is ready to execute. bool threads_IsThreadActive(u32 id) { u32 i; bool ret; switch(threads[id].state) { case RUNNING: return true; case STOPPED: return false; case WAITING_ARB: DEBUG("Thread is %d is stuck in arbitration.\n", id); return false; case WAITING_SYNC: DEBUG("Wait-list for thread %d:\n", id); if(threads[id].wait_all) { ret = true; for(i=0; i<threads[id].wait_list_size; i++) { u32 handle = threads[id].wait_list[i]; handleinfo* hi = handle_Get(handle); if(hi == NULL) continue; bool is_waiting = false; handle_types[hi->type].fnWaitSynchronization(hi, &is_waiting); DEBUG(" %08x, type=%s, waiting=%s\n", handle, handle_types[hi->type].name, is_waiting ? "true" : "false"); if(is_waiting) ret = false; } if (ret) { threads[id].r[1] = threads[id].wait_list_size; threads[id].state = RUNNING; } return ret; } else { ret = false; for(i=0; i<threads[id].wait_list_size; i++) { u32 handle = threads[id].wait_list[i]; handleinfo* hi = handle_Get(handle); if(hi == NULL) continue; bool is_waiting = false; handle_types[hi->type].fnWaitSynchronization(hi, &is_waiting); DEBUG(" %08x, type=%s, waiting=%s\n", handle, handle_types[hi->type].name, is_waiting ? "true" : "false"); if(!ret && !is_waiting) { threads[id].r[1] = i; threads[id].state = RUNNING; ret = true; } } return ret; } } return false; }
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; }