/* Copyright 2019 flyinghead This file is part of reicast. reicast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. reicast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with reicast. If not, see . */ #include "hw/sh4/sh4_sched.h" #define PUserKData 0x00005800 #define SYSHANDLE_OFFSET 0x004 #define SYS_HANDLE_BASE 64 #define SH_WIN32 0 #define SH_CURTHREAD 1 #define SH_CURPROC 2 static bool read_mem32(u32 addr, u32& data) { u32 pa; const TLB_Entry *entry; if (mmu_full_lookup(addr, &entry, pa) != MMU_ERROR_NONE) return false; data = ReadMem32_nommu(pa); return true; } static bool read_mem16(u32 addr, u16& data) { u32 pa; const TLB_Entry *entry; if (mmu_full_lookup(addr, &entry, pa) != MMU_ERROR_NONE) return false; data = ReadMem16_nommu(pa); return true; } static bool read_mem8(u32 addr, u8& data) { u32 pa; const TLB_Entry *entry; if (mmu_full_lookup(addr, &entry, pa) != MMU_ERROR_NONE) return false; data = ReadMem8_nommu(pa); return true; } static inline u32 getCurrentThreadId() { u32 addr = PUserKData + SYSHANDLE_OFFSET + SH_CURTHREAD * 4; u32 tid; if (read_mem32(addr, tid)) return tid; else return 0; } static inline u32 getCurrentProcessId() { u32 addr = PUserKData + SYSHANDLE_OFFSET + SH_CURPROC * 4; u32 pid; if (read_mem32(addr, pid)) return pid; else return 0; } #define FIRST_METHOD 0xFFFFFE01 #define APICALL_SCALE 2 static const char *wince_apis[] = { // SH_* "WIN32", "CURTHREAD", "CURPROC", "WDMAPI", // HT_* "EVENT", "MUTEX", "APISET", "FILE", "FIND", "DBFILE", "DBFIND", "SOCKET", "INTERFACE", "SEMAPHORE", "FSMAP", "WNETENUM", // SH_* "GDI", "WMGR", "INIT", "COMM", "FILESYS", "SHELL", "DEVMGR", "TAPI", "PATCHER", "IMM", "WNET", "?", "?", "?", "?", "USER" }; static const char *wince_methods[][256] = { // WIN32 { "Nop", "N/S", "CreateAPISet", "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", "VirtualCopy", "LoadLibraryW", "FreeLibrary", "GetProcAddressW", "ThreadAttachAllDLLs", "ThreadDetachAllDLLs", "GetTickCount", "OutputDebugStringW", "TlsCall", "GetSystemInfo", "(ropen)", "(rread)", "(rwrite)", "(rlseek)", "(rclose)", "RegisterDbgZones", "NKvDbgPrintfW", "ProfileSyscall", "FindResource", "LoadResource", "SizeofResource", "GetRealTime", "SetRealTime", "ProcessDetachAllDLLs", "ExtractResource", // 32 "GetRomFileInfo", "GetRomFileBytes", "CacheRangeFlush", "AddTrackedItem", "DeleteTrackedItem", "PrintTrackedItem", "GetKPhys", "GiveKPhys", "SetExceptionHandler", "RegisterTrackedItem", "FilterTrackedItem", "SetKernelAlarm", "RefreshKernelAlarm", "CeGetRandomSeed", "CloseProcOE", "SetGwesOOMEvent", "StringCompress", "StringDecompress", "BinaryCompress", "BinaryDecompress", "CreateEvent", "CreateProc", "CreateThread", "InputDebugCharW", "TakeCritSec", "LeaveCritSec", "WaitForMultiple", "MapPtrToProcess", "MapPtrUnsecure", "GetProcFromPtr", "IsBadPtr", "GetProcAddrBits", // 64 "GetFSHeapInfo", "OtherThreadsRunning", "KillAllOtherThreads", "GetOwnerProcess", "GetCallerProcess", "GetIdleTime", "SetLowestScheduledPriority", "IsPrimaryThread", "SetProcPermissions", "GetCurrentPermissions", "(74?)", "SetDaylightTime", "SetTimeZoneBias", "SetCleanRebootFlag", "CreateCrit", "PowerOffSystem", "CreateMutex", "SetDbgZone", "Sleep", "TurnOnProfiling", "TurnOffProfiling", "CeGetCurrentTrust", "CeGetCallerTrust", "NKTerminateThread", "SetLastError", "GetLastError", "GetProcName", "TerminateSelf", "CloseAllHandles", "SetHandleOwner", "LoadDriver", "CreateFileMapping", // 96 "UnmapViewOfFile", "FlushViewOfFile", "CreateFileForMappingW", "KernelIoControl", "GetThreadCallStack", "PPSHRestart", "(102?)", "UpdateNLSInfo", "ConnectDebugger", "InterruptInitialize", "InterruptDone", "InterruptDisable", "SetKMode", "SetPowerOffHandler", "SetGwesPowerHandler", "SetHardwareWatch", "QueryAPISetID", "PerformCallBack", "CaptureContext", "GetCallerProcessIndex", "WaitForDebugEvent", "ContinueDebugEvent", "DebugNotify", "OpenProcess", "THCreateSnapshot", "THGrow", "NotifyForceCleanboot", "DumpKCallProfile", "GetProcessVersion", "GetModuleFileNameW", "QueryPerformanceCounter", "QueryPerformanceFrequency", // 128 "KernExtractIcons", "ForcePageout", "GetThreadTimes", "GetModuleHandleW", "SetWDevicePowerHandler", "SetStdioPathW", "GetStdioPathW", "ReadRegistryFromOEM", "WriteRegistryToOEM", "WriteDebugLED", "LockPages", "UnlockPages", "VirtualSetAttributes", "SetRAMMode", "SetStoreQueueBase", "FlushViewOfFileMaybe", }, // CURTHREAD { "CloseHandle", "(AllHandle_Wait)", "Suspend", "Resume", "SetThreadPrio", "GetThreadPrio", "GetRetCode", "GetContext", "SetContext", "Terminate", "CeGetPrio", "CeSetPrio", "CeGetQuant", "CeSetQuant" }, // CURPROC { "CloseHandle", "(AllHandle_Wait)", "Terminate", "GetRetCode", "FlushICache", "ReadMemory", "WriteMemory", "DebugActive", "GetModInfo", "SetVer" }, // unused { }, // EVENT { "CloseHandle", "(AllHandle_Wait)", "Modify", "AddAccess", "GetData", "SetData" }, // MUTEX { "CloseHandle", "(AllHandle_Wait)", "ReleaseMutex" }, // APISET { "CloseHandle", "(AllHandle_Wait)", "Register", "CreateHandle", "Verify" }, // FILE { "CloseFileHandle", "(NULL)", "ReadFile", "WriteFile", "GetFileSize", "SetFilePointer", "GetFileInformationByHandle", "FlushFileBuffers", "GetFileTime", "SetFileTime", "SetEndOfFile", "DeviceIoControl", "ReadFileWithSeek", "WriteFileWithSeek" }, // FIND { "FindClose", "(NULL)", "FindNextFile" }, // DBFILE { }, // DBFIND { }, // SOCKET { }, // INTERFACE { }, // SEMAPHORE { }, // FSMAP { }, // WNETENUM { }, // GDI { }, // WMGR { }, // INIT { }, // COMM { }, // FILESYS { "ProcNotify", "(AllHandle_Wait)", "CreateDirectory", "RemoveDirectory", "MoveFile", "CopyFile", "DeleteFile", "GetFileAttibutes", "FindFirstFile", "CreateFile", "CeRegisterFileSystemNotification", "CeRegisterReplNotification", "CeOidGetInfoEx", "CeFindFirstDatabaseEx", "CeCreateDatabaseEx", "CeSetDatabaseInfoEx", "CeOpenDatabaseEx", "RegCloseKey", "RegCreateKeyExW", "RegDeleteKeyW", "RegDeleteValueW", "RegEnumValueW", "RegEnumKeyExW", "RegOpenKeyExW", "RegQueryInfoKeyW", "RegQueryValueExW", "RegSetValueExW", "GetTempPathW", "CeDeleteDatabaseEx", "CheckPassword", "SetPassword", "SetFileAttributesW", "GetStoreInformation", "CeGetReplChangeMask", "CeSetReplChangeMask", "CeGetReplChangeBitsEx", "CeClearReplChangeBitsEx", "CeGetReplOtherBitsEx", "CeSetReplOtherBitsEx", "GetSystemMemoryDivision", "SetSystemMemoryDivision", "RegCopyFile", "CloseAllFileHandles", "PrestoChangoFileName", "RegRestoreFile", "RegisterAFS", "DeregisterAFS", "GetPasswordActive", "SetPasswordActive", "RegFlushKey", "NotifyMountedFS", "CeSetReplChangeBitsEx", "RegisterAFSName", "DeregisterAFSName", "GetDiskFreeSpaceExW", "RegisterHiddenAFS", "CeChangeDatabaseLCID", "DumpHeap", "CeMountDBVol", "CeEnumDBVolumes", "CeUnmountDBVol", "CeFlushDBVol", "CeFreeNotification" }, // SHELL { }, // DEVMGR { }, // TAPI { }, // PATCHER { }, // IMM { }, // WNET { }, { }, { }, { }, { }, // USER { "NotifyCallback", "(unused)", "RegisterClass", "UnregisterClass", "CreateWindowEx", "PostMessage", "PostQuitMessage", "SendMessage", "GetMessage", "TranslateMessage", "DispatchMessage", "GetCapture", "SetCapture", "ReleaseCapture", "(ununsed)", "(ununsed)", "(ununsed)", "(ununsed)", "(ununsed)", "GetSystemMetrics", "ImageList_GetDragImage", "ImageList_GetIconSize", "ImageList_SetIconSize", "ImageList_GetImageInfo", "ImageList_Merge", "ShowCursor", "SetCursorPos", "ImageList_CopyDitherImage", "ImageList_DrawIndirect", "ImageList_DragShowNolock", "CWindowManager::WindowFromPoint(tagPOINT)", "(unused)", }, }; #ifdef TRACE_WINCE_SYSCALLS extern u32 unresolved_ascii_string; extern u32 unresolved_unicode_string; #endif static inline std::string get_unicode_string(u32 addr) { std::string str; while (true) { u16 c; if (!read_mem16(addr, c)) { #ifdef TRACE_WINCE_SYSCALLS unresolved_unicode_string = addr; #endif return "(page fault)"; } if (c == 0) break; str += (char)c; addr += 2; } return str; } static inline std::string get_ascii_string(u32 addr) { std::string str; while (true) { u8 c; if (!read_mem8(addr++, c)) { #ifdef TRACE_WINCE_SYSCALLS unresolved_ascii_string = addr; #endif return "(page fault)"; } if (c == 0) break; str += (char)c; } return str; } static bool print_wince_syscall(u32 address) { if (address & 1) { if (address == 0xfffffd5d || address == 0xfffffd05) // Sleep, QueryPerformanceCounter return true; if (address == 0xfffffde7) // GetTickCount { // This should make this syscall faster //r[0] = sh4_sched_now64() * 1000 / SH4_MAIN_CLOCK; //next_pc = pr; //skip_exception = true; return true; } u32 api_id; if (address <= FIRST_METHOD) api_id = (((FIRST_METHOD - address) / APICALL_SCALE) >> 8) & 0x3F; else api_id = 0; const char *api; char api_buf[128]; if (api_id < ARRAY_SIZE(wince_apis)) api = wince_apis[api_id]; else { sprintf(api_buf, "[%d]", api_id); api = api_buf; } u32 meth_id; if (address <= FIRST_METHOD) meth_id = ((FIRST_METHOD - address) / APICALL_SCALE) & 0xFF; else meth_id = ((address - FIRST_METHOD) / APICALL_SCALE) & 0xFF; const char *method = NULL; char method_buf[128]; if (api_id < ARRAY_SIZE(wince_methods) && meth_id < ARRAY_SIZE(wince_methods[api_id])) method = wince_methods[api_id][meth_id]; if (method == NULL) { sprintf(method_buf, "[%d]", meth_id); method = method_buf; } printf("WinCE %08x %04x.%04x %s: %s", address, getCurrentProcessId() & 0xffff, getCurrentThreadId() & 0xffff, api, method); if (address == 0xfffffd51) // SetLastError printf(" dwErrCode = %x\n", r[4]); else if (address == 0xffffd5ef) // CreateFile printf(" lpFileName = %s\n", get_unicode_string(r[4]).c_str()); else if (address == 0xfffffd97) // CreateProc printf(" imageName = %s, commandLine = %s\n", get_unicode_string(r[4]).c_str(), get_unicode_string(r[5]).c_str()); else if (!strcmp("DebugNotify", method)) printf(" %x, %x\n", r[4], r[5]); else if (address == 0xffffd5d3) // RegOpenKeyExW printf(" hKey = %x, lpSubKey = %s\n", r[4], get_unicode_string(r[5]).c_str()); else if (!strcmp("LoadLibraryW", method)) printf(" fileName = %s\n", get_unicode_string(r[4]).c_str()); else if (!strcmp("GetProcAddressW", method)) printf(" hModule = %x, procName = %s\n", r[4], get_unicode_string(r[5]).c_str()); else if (!strcmp("NKvDbgPrintfW", method)) printf(" fmt = %s\n", get_unicode_string(r[4]).c_str()); else if (!strcmp("OutputDebugStringW", method)) printf(" str = %s\n", get_unicode_string(r[4]).c_str()); else if (!strcmp("RegisterAFSName", method)) printf(" name = %s\n", get_unicode_string(r[4]).c_str()); else if (!strcmp("CreateAPISet", method)) printf(" name = %s\n", get_ascii_string(r[4]).c_str()); else if (!strcmp("Register", method) && !strcmp("APISET", api)) printf(" p = %x, id = %x\n", r[4], r[5]); else printf("\n"); // might be useful to detect errors? (hidden & dangerous) //if (!strcmp("GetProcName", method)) // os_DebugBreak(); return true; } else return false; } static bool wince_resolve_address(u32 va, TLB_Entry &entry) { // WinCE hack if ((va & 0x80000000) == 0) { const u32 ram_mask = RAM_MASK; u32 page_group = *(u32 *)&mem_b[(CCN_TTB + ((va >> 25) << 2)) & ram_mask]; u32 page = ((va >> 16) & 0x1ff) << 2; u32 paddr = *(u32 *)&mem_b[(page_group + page) & ram_mask]; if (paddr & 0x80000000) { u32 whatever = *(u32 *)&mem_b[(r_bank[4] + 0x14) & ram_mask]; if (whatever != *(u32 *)&mem_b[paddr & ram_mask]) { paddr += 12; u32 ptel = *(u32 *)&mem_b[(paddr + ((va >> 10) & 0x3c)) & ram_mask]; //FIXME CCN_PTEA = paddr >> 29; if (ptel != 0) { entry.Data.reg_data = ptel - 1; entry.Address.ASID = CCN_PTEH.ASID; entry.Assistance.reg_data = 0; u32 sz = entry.Data.SZ1 * 2 + entry.Data.SZ0; entry.Address.VPN = (va & mmu_mask[sz]) >> 10; return true; } } } } else { // SQ if (((va >> 26) & 0x3F) == 0x38) { u32 r1 = (va - 0xe0000000) & 0xfff00000; //r1 &= 0xfff00000; //u32 r0 = ReadMem32_nommu(0x8C01258C); // FIXME //u32 r0 = 0x8c138b14; //r0 = ReadMem32_nommu(r0); // 0xE0001F5 u32 r0 = 0xe0001f5; r0 += r1; entry.Data.reg_data = r0 - 1; entry.Assistance.reg_data = r0 >> 29; entry.Address.ASID = CCN_PTEH.ASID; u32 sz = entry.Data.SZ1 * 2 + entry.Data.SZ0; entry.Address.VPN = (va & mmu_mask[sz]) >> 10; return true; } } return false; }