flycast/core/hw/sh4/modules/wince.h

409 lines
13 KiB
C++

/*
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 <https://www.gnu.org/licenses/>.
*/
#include "hw/sh4/sh4_sched.h"
#ifdef TRACE_WINCE_SYSCALLS
#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<false>(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<false>(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<false>(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)",
},
};
extern u32 unresolved_ascii_string;
extern u32 unresolved_unicode_string;
static inline std::string get_unicode_string(u32 addr)
{
std::string str;
while (true)
{
u16 c;
if (!read_mem16(addr, c))
{
unresolved_unicode_string = addr;
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))
{
unresolved_ascii_string = addr;
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;
}
#endif
#if defined(FAST_MMU) && defined(USE_WINCE_HACK)
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;
}
#endif