From 60ccfbede6c1bb9c7ecb86629b86689c669ba1dc Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Sat, 21 Jan 2023 18:51:13 +0000 Subject: [PATCH] Insane amount of stuff including a bunch of amlib --- Makefile | 4 +- meson.build | 11 +- src/meson.build | 5 + src/micetools/amBackupStructs.h | 212 ++++ src/micetools/dll/comdevice.c | 64 +- src/micetools/dll/common.h | 3 + src/micetools/dll/devices/_devices.c | 15 + src/micetools/dll/devices/_devices.h | 14 +- src/micetools/dll/devices/meson.build | 13 +- .../dll/devices/{led_bd.c => ser_led_bd.c} | 458 +++---- .../devices/{touch_bd.c => ser_maitouch.c} | 194 +-- .../dll/devices/{aime_bd.c => ser_tn32msec.c} | 618 ++++----- src/micetools/dll/devices/smb_at24c64a.c | 173 +++ src/micetools/dll/devices/smb_ds.c | 85 ++ src/micetools/dll/devices/smb_exio.c | 53 + src/micetools/dll/devices/smb_n2.c | 421 ++++++ src/micetools/dll/devices/smb_pca9535.c | 126 ++ src/micetools/dll/dllmain.c | 108 +- src/micetools/dll/drivers/columba.c | 37 +- src/micetools/dll/drivers/mxhwreset.c | 2 +- src/micetools/dll/drivers/mxjvs.c | 565 ++++++--- src/micetools/dll/drivers/mxparallel.c | 6 +- src/micetools/dll/drivers/mxparallel.h | 4 +- src/micetools/dll/drivers/mxsmbus.c | 545 +------- src/micetools/dll/drivers/mxsram.c | 124 +- src/micetools/dll/drivers/mxsuperio.c | 2 +- src/micetools/dll/drivers/mxsuperio.h | 4 +- src/micetools/dll/gui/gui.c | 161 ++- src/micetools/dll/gui/imgui_memory_editor.c | 720 +++++++++++ src/micetools/dll/gui/imgui_memory_editor.h | 135 ++ src/micetools/dll/gui/meson.build | 1 + src/micetools/dll/hooks/com.c | 167 ++- src/micetools/dll/hooks/com.h | 44 +- src/micetools/dll/hooks/drive.c | 1014 ++++++++++----- src/micetools/dll/hooks/drive.h | 88 +- src/micetools/dll/hooks/files.c | 308 ++--- src/micetools/dll/hooks/files.h | 94 +- src/micetools/dll/hooks/gui.c | 160 ++- src/micetools/dll/hooks/gui.h | 4 + src/micetools/dll/hooks/network.c | 57 +- src/micetools/dll/hooks/processes.c | 4 +- src/micetools/dll/meson.build | 3 +- src/micetools/dll/smbus.h | 66 +- src/micetools/dll/util/_util.h | 11 + src/micetools/dll/util/hook.c | 1 + src/micetools/dll/util/log.c | 57 +- src/micetools/dll/util/log.h | 2 + src/micetools/dll/util/misc.c | 98 ++ src/micetools/launcher/locate.c | 5 + src/micetools/launcher/main.c | 4 +- src/micetools/lib/_am.h | 10 + src/micetools/lib/am/am.h | 6 + src/micetools/lib/am/amAime.h | 8 + src/micetools/lib/am/amAta.h | 4 + src/micetools/lib/am/amAuth.h | 11 + src/micetools/lib/am/amAuthDisk.h | 1 + src/micetools/lib/am/amBackup.h | 10 + src/micetools/lib/am/amCmos.h | 3 + src/micetools/lib/am/amCredit.h | 17 + src/micetools/lib/am/amDipsw.h | 23 + src/micetools/lib/am/amDongle.c | 1127 +++++++++++++++++ src/micetools/lib/am/amDongle.h | 211 +++ src/micetools/lib/am/amEeprom.c | 439 ++++++- src/micetools/lib/am/amEeprom.h | 56 +- src/micetools/lib/am/amGcatcher.h | 4 + src/micetools/lib/am/amGdeliver.h | 3 + src/micetools/lib/am/amGfetcher.h | 3 + src/micetools/lib/am/amHardware.h | 1 + src/micetools/lib/am/amHm.h | 23 + src/micetools/lib/am/amInstall.c | 580 +++++++++ src/micetools/lib/am/amInstall.h | 211 +++ src/micetools/lib/am/amJvs.h | 2 + src/micetools/lib/am/amJvsUpdate.h | 1 + src/micetools/lib/am/amJvsp.h | 3 + src/micetools/lib/am/amJvst.h | 0 src/micetools/lib/am/amJvstDriver.h | 3 + src/micetools/lib/am/amJvstThread.h | 1 + src/micetools/lib/am/amLib.h | 2 + src/micetools/lib/am/amLog.h | 2 + src/micetools/lib/am/amMacAddress.h | 0 src/micetools/lib/am/amMaster.h | 27 + src/micetools/lib/am/amNetwork.h | 15 + src/micetools/lib/am/amOemstring.c | 190 +++ src/micetools/lib/am/amOemstring.h | 41 + src/micetools/lib/am/amPlatform.c | 239 ++++ src/micetools/lib/am/amPlatform.h | 112 ++ src/micetools/lib/am/amRtc.h | 10 + src/micetools/lib/am/amSerialId.c | 37 + src/micetools/lib/am/amSerialId.h | 14 + src/micetools/lib/am/amSram.c | 298 +++++ src/micetools/lib/am/amSram.h | 56 + src/micetools/lib/am/amStorage.h | 25 + src/micetools/lib/am/amSysData.h | 12 + src/micetools/lib/am/amtimer.c | 19 - src/micetools/lib/am/meson.build | 68 +- src/micetools/lib/ami/ami.h | 5 + src/micetools/lib/ami/amiCrc.c | 30 + src/micetools/lib/ami/amiCrc.h | 24 + src/micetools/lib/ami/amiCri.h | 0 src/micetools/lib/ami/amiDebug.c | 54 + src/micetools/lib/ami/amiDebug.h | 28 + src/micetools/lib/ami/amiLog.h | 0 src/micetools/lib/ami/amiMd5.h | 0 src/micetools/lib/ami/amiTimer.c | 40 + .../lib/{am/amtimer.h => ami/amiTimer.h} | 17 +- src/micetools/lib/ami/meson.build | 20 + src/micetools/lib/ams/amsHttp.h | 11 + src/micetools/lib/dmi/dmi.c | 8 +- src/micetools/lib/dmi/dmi.h | 16 +- src/micetools/lib/json/LICESNSE | 25 - src/micetools/lib/json/README.txt | 1 - src/micetools/lib/json/json.c | 818 ------------ src/micetools/lib/json/json.h | 114 -- src/micetools/lib/json/meson.build | 7 - src/micetools/lib/libpcp/meson.build | 2 +- src/micetools/lib/libpcp/pcp.h | 6 +- src/micetools/lib/libpcp/pcpa.c | 256 +++- src/micetools/lib/libpcp/pcpa.h | 30 +- src/micetools/lib/libpcp/pcpp.c | 793 ++++++++---- src/micetools/lib/libpcp/pcpp.h | 65 +- src/micetools/lib/libpcp/pcpt.c | 152 ++- src/micetools/lib/libpcp/pcpt.h | 3 + src/micetools/lib/meson.build | 11 +- src/micetools/lib/mice/config.c | 58 +- src/micetools/lib/mice/config.def | 63 +- src/micetools/lib/mice/config.h | 1 + src/micetools/lib/mice/crc.c | 31 - src/micetools/lib/mice/crc.h | 2 - src/micetools/lib/mice/ioctl.h | 2 +- src/micetools/lib/mice/meson.build | 6 +- src/micetools/lib/mice/mice.h | 14 +- src/micetools/lib/mice/patch.c | 441 ++++--- src/micetools/lib/mice/patch.h | 49 +- src/micetools/lib/mice/version_fallback.h | 3 + src/micetools/lib/mxk/meson.build | 2 +- src/micetools/lib/mxk/mxk.c | 4 +- src/micetools/lib/mxk/mxk.h | 18 +- src/micetools/lib/mxk/mxkCrypt.c | 31 +- src/micetools/lib/mxk/mxkPacket.c | 1 - src/micetools/lib/mxk/mxkTransport.c | 15 +- src/micetools/lib/util/hex.c | 43 + src/micetools/lib/util/hex.h | 3 + src/micetools/maiBackupStructs.h | 181 +++ src/micetools/meson.build | 1 + src/micetools/micekeychip/callbacks/appboot.c | 16 +- src/micetools/micekeychip/callbacks/billing.c | 2 +- .../micekeychip/callbacks/callbacks.h | 2 +- src/micetools/micekeychip/mxk.c | 19 +- src/micetools/micemaster/appLauncher.c | 243 ++++ src/micetools/micemaster/appLauncher.h | 23 + .../micemaster/callbacks/callbacks.h | 36 + .../micemaster/callbacks/foreground.c | 306 +++++ src/micetools/micemaster/callbacks/logs.c | 214 ++++ src/micetools/micemaster/callbacks/misc.c | 14 + src/micetools/micemaster/config.c | 123 ++ src/micetools/micemaster/config.def | 47 + src/micetools/micemaster/config.h | 18 + src/micetools/micemaster/main.c | 521 ++++++++ src/micetools/micemaster/meson.build | 25 + src/micetools/micemaster/micemaster.rc | 3 + src/micetools/micemaster/mxm.c | 42 + src/micetools/micemaster/mxm.h | 74 ++ src/micetools/micemaster/mxmEventLog.c | 49 + src/micetools/micemaster/mxmEventLog.h | 25 + src/micetools/micepatch/meson.build | 30 +- src/micetools/util/meson.build | 29 +- src/micetools/util/micedump.c | 107 +- src/micetools/util/micedump/dmi.c | 45 + src/micetools/util/micedump/eeprom.c | 34 + src/micetools/util/micedump/kc_mxkeychip.c | 98 ++ src/micetools/util/micedump/kc_n2.c | 0 src/micetools/util/micedump/kc_pic.c | 0 src/micetools/util/micedump/main.c | 23 + src/micetools/util/micedump/micedump.h | 8 + src/micetools/util/micedump/platform.c | 16 + src/micetools/util/micedump/sram.c | 59 + src/micetools/util/micedump/superio.c | 0 src/micetools/util/micetinker.c | 30 +- src/micetools/util/proxy.c | 141 --- src/patches/ALLNetProc.patch | 13 + src/patches/ALLNetProc.patch.json | 93 -- src/patches/Game.patch | 16 + src/patches/Game.patch.json | 98 -- src/patches/InitialD8_GLW_RE_SBZZ.patch | 17 + src/patches/InitialD8_GLW_RE_SBZZ.patch.json | 121 -- src/patches/UnderNightInBirthExLate[st].patch | 14 + src/patches/maimai_dump_.patch | 21 + src/patches/maimai_dump_.patch.json | 149 --- src/patches/mxgfetcher.patch | 1 + src/patches/mxgfetcher.patch.json | 9 - src/patches/mxmaster.patch | 1 + src/patches/mxmaster.patch.json | 9 - src/patches/mxnetwork.patch | 2 + src/patches/mxnetwork.patch.json | 16 - src/patches/mxsegaboot.patch | 23 + src/patches/mxsegaboot.patch.json | 163 --- src/patches/patches.index | 12 + src/patches/patches.json | 79 -- 198 files changed, 12831 insertions(+), 4951 deletions(-) create mode 100644 src/micetools/amBackupStructs.h rename src/micetools/dll/devices/{led_bd.c => ser_led_bd.c} (96%) rename src/micetools/dll/devices/{touch_bd.c => ser_maitouch.c} (97%) rename src/micetools/dll/devices/{aime_bd.c => ser_tn32msec.c} (65%) create mode 100644 src/micetools/dll/devices/smb_at24c64a.c create mode 100644 src/micetools/dll/devices/smb_ds.c create mode 100644 src/micetools/dll/devices/smb_exio.c create mode 100644 src/micetools/dll/devices/smb_n2.c create mode 100644 src/micetools/dll/devices/smb_pca9535.c create mode 100644 src/micetools/dll/gui/imgui_memory_editor.c create mode 100644 src/micetools/dll/gui/imgui_memory_editor.h create mode 100644 src/micetools/dll/util/misc.c create mode 100644 src/micetools/lib/_am.h create mode 100644 src/micetools/lib/am/am.h create mode 100644 src/micetools/lib/am/amAime.h create mode 100644 src/micetools/lib/am/amAta.h create mode 100644 src/micetools/lib/am/amAuth.h create mode 100644 src/micetools/lib/am/amAuthDisk.h create mode 100644 src/micetools/lib/am/amBackup.h create mode 100644 src/micetools/lib/am/amCmos.h create mode 100644 src/micetools/lib/am/amCredit.h create mode 100644 src/micetools/lib/am/amDipsw.h create mode 100644 src/micetools/lib/am/amDongle.c create mode 100644 src/micetools/lib/am/amDongle.h create mode 100644 src/micetools/lib/am/amGcatcher.h create mode 100644 src/micetools/lib/am/amGdeliver.h create mode 100644 src/micetools/lib/am/amGfetcher.h create mode 100644 src/micetools/lib/am/amHardware.h create mode 100644 src/micetools/lib/am/amHm.h create mode 100644 src/micetools/lib/am/amInstall.c create mode 100644 src/micetools/lib/am/amInstall.h create mode 100644 src/micetools/lib/am/amJvs.h create mode 100644 src/micetools/lib/am/amJvsUpdate.h create mode 100644 src/micetools/lib/am/amJvsp.h create mode 100644 src/micetools/lib/am/amJvst.h create mode 100644 src/micetools/lib/am/amJvstDriver.h create mode 100644 src/micetools/lib/am/amJvstThread.h create mode 100644 src/micetools/lib/am/amLib.h create mode 100644 src/micetools/lib/am/amLog.h create mode 100644 src/micetools/lib/am/amMacAddress.h create mode 100644 src/micetools/lib/am/amMaster.h create mode 100644 src/micetools/lib/am/amNetwork.h create mode 100644 src/micetools/lib/am/amOemstring.c create mode 100644 src/micetools/lib/am/amOemstring.h create mode 100644 src/micetools/lib/am/amPlatform.c create mode 100644 src/micetools/lib/am/amPlatform.h create mode 100644 src/micetools/lib/am/amRtc.h create mode 100644 src/micetools/lib/am/amSerialId.c create mode 100644 src/micetools/lib/am/amSerialId.h create mode 100644 src/micetools/lib/am/amSram.c create mode 100644 src/micetools/lib/am/amSram.h create mode 100644 src/micetools/lib/am/amStorage.h create mode 100644 src/micetools/lib/am/amSysData.h delete mode 100644 src/micetools/lib/am/amtimer.c create mode 100644 src/micetools/lib/ami/ami.h create mode 100644 src/micetools/lib/ami/amiCrc.c create mode 100644 src/micetools/lib/ami/amiCrc.h create mode 100644 src/micetools/lib/ami/amiCri.h create mode 100644 src/micetools/lib/ami/amiDebug.c create mode 100644 src/micetools/lib/ami/amiDebug.h create mode 100644 src/micetools/lib/ami/amiLog.h create mode 100644 src/micetools/lib/ami/amiMd5.h create mode 100644 src/micetools/lib/ami/amiTimer.c rename src/micetools/lib/{am/amtimer.h => ami/amiTimer.h} (50%) create mode 100644 src/micetools/lib/ami/meson.build create mode 100644 src/micetools/lib/ams/amsHttp.h delete mode 100644 src/micetools/lib/json/LICESNSE delete mode 100644 src/micetools/lib/json/README.txt delete mode 100644 src/micetools/lib/json/json.c delete mode 100644 src/micetools/lib/json/json.h delete mode 100644 src/micetools/lib/json/meson.build delete mode 100644 src/micetools/lib/mice/crc.c delete mode 100644 src/micetools/lib/mice/crc.h create mode 100644 src/micetools/lib/mice/version_fallback.h create mode 100644 src/micetools/maiBackupStructs.h create mode 100644 src/micetools/micemaster/appLauncher.c create mode 100644 src/micetools/micemaster/appLauncher.h create mode 100644 src/micetools/micemaster/callbacks/callbacks.h create mode 100644 src/micetools/micemaster/callbacks/foreground.c create mode 100644 src/micetools/micemaster/callbacks/logs.c create mode 100644 src/micetools/micemaster/callbacks/misc.c create mode 100644 src/micetools/micemaster/config.c create mode 100644 src/micetools/micemaster/config.def create mode 100644 src/micetools/micemaster/config.h create mode 100644 src/micetools/micemaster/main.c create mode 100644 src/micetools/micemaster/meson.build create mode 100644 src/micetools/micemaster/micemaster.rc create mode 100644 src/micetools/micemaster/mxm.c create mode 100644 src/micetools/micemaster/mxm.h create mode 100644 src/micetools/micemaster/mxmEventLog.c create mode 100644 src/micetools/micemaster/mxmEventLog.h create mode 100644 src/micetools/util/micedump/dmi.c create mode 100644 src/micetools/util/micedump/eeprom.c create mode 100644 src/micetools/util/micedump/kc_mxkeychip.c create mode 100644 src/micetools/util/micedump/kc_n2.c create mode 100644 src/micetools/util/micedump/kc_pic.c create mode 100644 src/micetools/util/micedump/main.c create mode 100644 src/micetools/util/micedump/micedump.h create mode 100644 src/micetools/util/micedump/platform.c create mode 100644 src/micetools/util/micedump/sram.c create mode 100644 src/micetools/util/micedump/superio.c delete mode 100644 src/micetools/util/proxy.c create mode 100644 src/patches/ALLNetProc.patch delete mode 100644 src/patches/ALLNetProc.patch.json create mode 100644 src/patches/Game.patch delete mode 100644 src/patches/Game.patch.json create mode 100644 src/patches/InitialD8_GLW_RE_SBZZ.patch delete mode 100644 src/patches/InitialD8_GLW_RE_SBZZ.patch.json create mode 100644 src/patches/UnderNightInBirthExLate[st].patch create mode 100644 src/patches/maimai_dump_.patch delete mode 100644 src/patches/maimai_dump_.patch.json create mode 100644 src/patches/mxgfetcher.patch delete mode 100644 src/patches/mxgfetcher.patch.json create mode 100644 src/patches/mxmaster.patch delete mode 100644 src/patches/mxmaster.patch.json create mode 100644 src/patches/mxnetwork.patch delete mode 100644 src/patches/mxnetwork.patch.json create mode 100644 src/patches/mxsegaboot.patch delete mode 100644 src/patches/mxsegaboot.patch.json create mode 100644 src/patches/patches.index delete mode 100644 src/patches/patches.json diff --git a/Makefile b/Makefile index 20095ec..58d8db8 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ dist: @-mkdir $(DIST_DIR)\Execute\S > NUL 2>&1 @copy /Y "$(BUILD_DIR_32)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe" + @copy /Y "$(BUILD_DIR_32)/src/micetools/micemaster\micemaster.exe" "$(DIST_DIR)/micemaster.exe" @copy /Y "$(BUILD_DIR_32)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib" @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice86.exe" @@ -66,11 +67,10 @@ dist: @copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\TrueCrypt.exe" "$(DIST_DIR)/Execute/TrueCrypt.exe" @copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe" - @copy /Y "$(BUILD_DIR_32)/src/micetools/micepatch\micepatch.exe" "$(DIST_DIR)/util/micepatch.exe" +# @copy /Y "$(BUILD_DIR_32)/src/micetools/micepatch\micepatch.exe" "$(DIST_DIR)/util/micepatch.exe" @copy /Y "$(BUILD_DIR_32)/src/micetools/util\micedump.exe" "$(DIST_DIR)/util/micedump.exe" @copy /Y "$(BUILD_DIR_32)/src/micetools/util\micetinker.exe" "$(DIST_DIR)/util/micetinker.exe" @copy /Y "$(BUILD_DIR_32)/src/micetools/util\micemonitor.exe" "$(DIST_DIR)/util/micemonitor.exe" - @copy /Y "$(BUILD_DIR_32)/src/micetools/util\kcproxy.exe" "$(DIST_DIR)/util/kcproxy.exe" @copy /Y "src/micetools/miceboot\TrueCrypt.cmd" "$(DIST_DIR)/Execute/TrueCrypt.cmd" diff --git a/meson.build b/meson.build index ddf0ec3..eddceee 100644 --- a/meson.build +++ b/meson.build @@ -35,13 +35,14 @@ add_project_arguments( # Strip out as much crud as we can to keep XP builds small '/Os', '/EHc-', '/EHa-', '/EHs-', '/GL', '/GR-', - '/wd4706', # assignment within conditional expression - '/wd4214', # windns.h: nonstandard extension used: bit field types other than int - '/wd4201', # ewfapi.h: nameless struct/union - '/wd4200', # zero-sized arrays - '/wd4152', # hooks: function/data pointer conversion in expression '/wd4100', # basically every hook causes "unreferenced formal parameter" + '/wd4152', # hooks: function/data pointer conversion in expression + '/wd4200', # zero-sized arrays + '/wd4201', # ewfapi.h: nameless struct/union + '/wd4204', # non-constant aggregate initializer '/wd4206', # empty C files + '/wd4214', # windns.h: nonstandard extension used: bit field types other than int + '/wd4706', # assignment within conditional expression '/wd4189', # lots of keychip functions aren't 100% implemented yet diff --git a/src/meson.build b/src/meson.build index 6413e70..baad635 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,4 +2,9 @@ inih = subproject('inih_dep') cimgui = subproject('cimgui_dep', default_options: ['win32=enabled', 'dx9=enabled']) libs_dir = meson.current_source_dir() + +incdir = [ + include_directories('micetools'), +] + subdir('micetools') diff --git a/src/micetools/amBackupStructs.h b/src/micetools/amBackupStructs.h new file mode 100644 index 0000000..2045595 --- /dev/null +++ b/src/micetools/amBackupStructs.h @@ -0,0 +1,212 @@ +#include + +#pragma pack(push, 1) + +typedef struct { + uint32_t m_Flag; + uint32_t m_IpAddress; + uint32_t m_SubnetMask; + uint32_t m_Gateway; + uint32_t m_PrimaryDns; + uint32_t m_SecondaryDns; +} AM_SYSDATA_NETWORK_IF; + +typedef struct { + uint64_t m_TimeStamp; + char GameId[4]; + uint16_t m_Error; + uint8_t m_AppStartCount; + uint8_t Rsv0f[17]; +} ERROR_LOG_BODY; + +typedef struct { + uint8_t ChuteType; + uint8_t ServiceType; + uint8_t Operation; + uint8_t CoinRate[2]; + uint8_t BonusAdder; + uint8_t CreditRate; + uint8_t Cost[8]; + uint8_t Rsv0F; +} AM_CREDIT_CONFIG; + +typedef struct { + uint8_t Credit; + uint8_t Remain; +} AM_CREDIT_PDATA; + +typedef struct { + AM_CREDIT_PDATA Player[4]; + uint8_t Rsv08[8]; +} AM_CREDIT_DATA; + +typedef struct { + uint32_t CoinChute[4]; + uint32_t TotalCoin; + uint32_t CoinCredit; + uint32_t ServiceCredit; + uint32_t TotalCredit; +} AM_CREDIT_BOOKKEEPING; + +typedef struct { + uint8_t m_month; + uint8_t m_week; + uint8_t m_dayOfWeek; + uint8_t m_hour; + uint8_t m_minute; + uint8_t m_rsv5[3]; +} alpbSysdataDst_T; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + AM_SYSDATA_NETWORK_IF m_Eth; +} AM_SYSDATAwH_NETWORK; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[8]; + uint8_t m_Region; + uint8_t m_Rental; + uint8_t Rsv0F; + char m_strSerialId[17]; +} AM_SYSDATAwH_STATIC; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + AM_CREDIT_CONFIG m_Config; + uint8_t Rsv18[8]; +} AM_SYSDATAwH_CREDIT; + +typedef AM_SYSDATAwH_NETWORK AM_SYSDATAwH_NETWORK_ETH0; +typedef AM_SYSDATAwH_NETWORK AM_SYSDATAwH_NETWORK_ETH1; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + char m_GameId[4]; + uint8_t m_Region; + uint8_t Rsv0D[3]; +} AM_SYSDATAwH_HISTORY; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + uint8_t m_WritePointer; + uint8_t m_LogNum; + uint8_t Rsv0a[22]; + ERROR_LOG_BODY m_Body[15]; +} AM_SYSDATAwH_ERROR_LOG; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + AM_CREDIT_DATA m_CreditData; + AM_CREDIT_BOOKKEEPING m_Bookkeeping; + uint8_t Rsv38[456]; +} AM_SYSDATAwH_BACKUP; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + alpbSysdataDst_T m_Daylight; + alpbSysdataDst_T m_Standard; + uint32_t m_Bias; + uint32_t m_ServerBias; + uint8_t Rsv20[480]; +} AM_SYSDATAwH_TIMEZONE; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + uint32_t m_Caution; + uint32_t m_Peak; + uint8_t Rsv10[496]; +} AM_SYSDATAwH_HM_PEAK; + +typedef struct { + uint32_t m_Crc; + uint8_t Rsv04[4]; + uint8_t m_MountSleepS; + uint8_t Rsv09[55]; +} AM_SYSDATAwH_ALPB_DEV_CONFIG; + +typedef struct { + uint32_t m_Crc; + uint32_t m_Uk1; + uint32_t m_Uk2; + uint32_t m_Uk3; +} AM_SYSDATAwH_ALPB_CARD_ID; + +typedef struct { + uint32_t m_Crc; + uint32_t m_Uk1; + uint32_t m_Uk2; + uint32_t m_Uk3; + uint32_t m_Uk4; + uint32_t m_Uk5; + uint32_t m_Uk6; + uint32_t m_Uk7; +} AM_SYSDATAwH_ALPB_COMPUTER_NAME; + +#pragma pack(pop) + +#define AM_SYSDATAwH_STATIC_REG 0x000 +#define AM_SYSDATAwH_STATIC_DUP 0x200 +#define AM_SYSDATAwH_CREDIT_REG 0x020 +#define AM_SYSDATAwH_CREDIT_DUP 0x220 +#define AM_SYSDATAwH_NETWORK_ETH0_REG 0x040 +#define AM_SYSDATAwH_NETWORK_ETH0_DUP 0x240 +#define AM_SYSDATAwH_NETWORK_ETH1_REG 0x060 +#define AM_SYSDATAwH_NETWORK_ETH1_DUP 0x260 +#define AM_SYSDATAwH_HISTORY_REG 0x080 +#define AM_SYSDATAwH_HISTORY_DUP 0x280 +#define AM_SYSDATAwH_ALPB_CARD_ID_REG 0x090 +#define AM_SYSDATAwH_ALPB_CARD_ID_DUP 0x290 +#define AM_SYSDATAwH_ALPB_COMPUTER_NAME_REG 0x0a0 +#define AM_SYSDATAwH_ALPB_COMPUTER_NAME_DUP 0x2a0 +#define AM_SYSDATAwH_ALPB_DEV_CONFIG_REG 0x0c0 +#define AM_SYSDATAwH_ALPB_DEV_CONFIG_DUP 0x2c0 + +/** + * Storage locations: + * + * Static: (AM_SYSDATAwH_STATIC) + * 0x000 - 0x01f, eeprom + * 0x200 - 0x21f, eeprom + * Credit: (AM_SYSDATAwH_CREDIT) + * 0x020 - 0x03f, eeprom + * 0x220 - 0x23f, eeprom + * Network Eth0: (AM_SYSDATAwH_NETWORK_ETH0) + * 0x040 - 0x05f, eeprom + * 0x240 - 0x25f, eeprom + * Network Eth1: (AM_SYSDATAwH_NETWORK_ETH1) + * 0x060 - 0x07f, eeprom + * 0x260 - 0x27f, eeprom + * History: (AM_SYSDATAwH_HISTORY) + * 0x080 - 0x08f, eeprom + * 0x280 - 0x28f, eeprom + * Alpb Card Id: (AM_SYSDATAwH_ALPB_CARD_ID) + * 0x090 - 0x09f, eeprom + * 0x290 - 0x29f, eeprom + * Computer Name: (AM_SYSDATAwH_ALPB_COMPUTER_NAME) + * 0x0a0 - 0x0bf, eeprom + * 0x2a0 - 0x2bf, eeprom + * Dev Config (AM_SYSDATAwH_ALPB_DEV_CONFIG) + * 0x0c0 - 0x0ff, eeprom + * 0x2c0 - 0x2ff, eeprom + * + * Backup: (AM_SYSDATAwH_BACKUP) + * 0x0000 - 0x01ff, sram + * 0x1000 - 0x11ff, sram + * HM Peak: (AM_SYSDATAwH_HM_PEAK) + * 0x0200 - 0x03ff, sram + * 0x1200 - 0x13ff, sram + * Timezone: (AM_SYSDATAwH_TIMEZONE) + * 0x0400 - 0x05ff, sram + * 0x1400 - 0x15ff, sram + * Error Log: (AM_SYSDATAwH_ERROR_LOG) + * 0x0600 - 0x07ff, sram + * 0x1600 - 0x17ff, sram + */ diff --git a/src/micetools/dll/comdevice.c b/src/micetools/dll/comdevice.c index 567f001..cd411a8 100644 --- a/src/micetools/dll/comdevice.c +++ b/src/micetools/dll/comdevice.c @@ -1,25 +1,29 @@ #include "comdevice.h" -BOOL DevGetCommState(void* data, LPDCB lpDCB) { return TRUE; } -BOOL DevSetCommState(void* data, LPDCB lpDCB) { return TRUE; } -BOOL DevGetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; } -BOOL DevSetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; } -BOOL DevSetupComm(void* data, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; } -BOOL DevPurgeComm(void* data, DWORD dwFlags) { - if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&((com_device_t*)data)->out); +com_device_t* GetComDevice(HANDLE hFile) { + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + return pHData->hook->com_hook->com_device; +} +BOOL DevGetCommState(HANDLE hFile, LPDCB lpDCB) { return TRUE; } +BOOL DevSetCommState(HANDLE hFile, LPDCB lpDCB) { return TRUE; } +BOOL DevGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; } +BOOL DevSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; } +BOOL DevSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; } +BOOL DevPurgeComm(HANDLE hFile, DWORD dwFlags) { + if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&(GetComDevice(hFile)->out)); return TRUE; } -BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) { +BOOL DevGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) { // TODO: JVS SENSE return TRUE; } -BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) { - WaitForSingleObject(((com_device_t*)data)->event, INFINITE); +BOOL DevWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) { + WaitForSingleObject(GetComDevice(hFile)->event, INFINITE); if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent); return TRUE; } -BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) { +BOOL DevClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) { if (lpErrors != NULL) *lpErrors = 0; if (lpStat != NULL) { lpStat->fCtsHold = FALSE; @@ -30,30 +34,30 @@ BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) { lpStat->fEof = FALSE; lpStat->fTxim = FALSE; lpStat->fReserved = 0; - lpStat->cbInQue = ringbuf_available(&((com_device_t*)data)->out); - lpStat->cbOutQue = ringbuf_available(&((com_device_t*)data)->in); + lpStat->cbInQue = ringbuf_available(&(GetComDevice(hFile)->out)); + lpStat->cbOutQue = ringbuf_available(&(GetComDevice(hFile)->in)); } return TRUE; } -BOOL DevWriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, +BOOL DevWriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { if (nNumberOfBytesToWrite > 0xffff) return FALSE; // Ignore overflow - ringbuf_write(&((com_device_t*)file)->in, lpBuffer, nNumberOfBytesToWrite & 0xffff); + ringbuf_write(&(GetComDevice(ctx->m_Handle)->in), lpBuffer, nNumberOfBytesToWrite & 0xffff); if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nNumberOfBytesToWrite; return TRUE; } -BOOL DevReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, +BOOL DevReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { if (nNumberOfBytesToRead > 0xffff) return FALSE; - + com_device_t* comdev = GetComDevice(ctx->m_Handle); // Make sure we have at least one byte to return - // while (!ringbuf_available(&((com_device_t*)file)->out)) { - // WaitForSingleObject(((com_device_t*)file)->event, INFINITE); + // while (!ringbuf_available(&(comdev->out))) { + // WaitForSingleObject(comdev->event, INFINITE); // } - short read = ringbuf_read(&((com_device_t*)file)->out, lpBuffer, nNumberOfBytesToRead & 0xffff); + short read = ringbuf_read(&(comdev->out), lpBuffer, nNumberOfBytesToRead & 0xffff); if (lpNumberOfBytesRead) *lpNumberOfBytesRead = read; if (read != 0) { @@ -158,14 +162,15 @@ void com_device_thread(com_device_t* com, FnComDeviceThread* thread) { } com_device_t* new_com_device(BYTE port) { - com_device_t* hook = (com_device_t*)malloc(sizeof *hook); + com_device_t* com_device = (com_device_t*)malloc(sizeof *com_device); com_hook_t* com = new_com_hook(port); file_hook_t* file = new_file_hook(com->wName); + file->com_hook = com; + com->com_device = com_device; + file->altFilename = com->wDosName; - com->data = hook; - file->data = hook; - hook->com = com; - hook->file = file; + com_device->com = com; + com_device->file = file; com->GetCommState = DevGetCommState; com->SetCommState = DevSetCommState; @@ -180,12 +185,11 @@ com_device_t* new_com_device(BYTE port) { file->ReadFile = DevReadFile; file->WriteFile = DevWriteFile; - ringbuf_purge(&hook->in); - ringbuf_purge(&hook->out); - hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName); + ringbuf_purge(&com_device->in); + ringbuf_purge(&com_device->out); + com_device->event = CreateEventW(NULL, TRUE, FALSE, com_device->com->wName); hook_file(file); - hook_com(com); - return hook; + return com_device; } diff --git a/src/micetools/dll/common.h b/src/micetools/dll/common.h index f775843..e1b3c70 100644 --- a/src/micetools/dll/common.h +++ b/src/micetools/dll/common.h @@ -23,3 +23,6 @@ #include "../lib/mice/mice.h" #include "./util/_util.h" + +extern WCHAR exePath[MAX_PATH + 1]; +extern DWORD imageOffset; diff --git a/src/micetools/dll/devices/_devices.c b/src/micetools/dll/devices/_devices.c index b68d40f..930dae9 100644 --- a/src/micetools/dll/devices/_devices.c +++ b/src/micetools/dll/devices/_devices.c @@ -4,4 +4,19 @@ void install_devices() { install_led_bd(); install_touch_bd(); install_aime_bd(); + + smbus_install(0x20, &smbus_PCA9535_write, &smbus_PCA9535_read); + + // mxkN2CmdWriteData(byte addr,byte *data,ushort nbytes,ushort *nbytesOut) + // -> smbusWriteByte(addr, command:0xcc, byte:data[i]) + // -> smbusWriteI2C(addr, command:0xcc, data+i, n) + smbus_install(0x30, &smbus_N2_write, &smbus_N2_read); + + // mxkDsExioRequestComputeMac() -> smbusWriteByte(addr:0x54, command:0x5c, byte:0x94) + smbus_install(0x54, &smbus_EXIO_write, &smbus_EXIO_read); + + // mxkDsKeychipComputeMac + smbus_install(0x55, &smbus_DS_write, &smbus_DS_read); + + smbus_install(0x57, &smbus_AT24C64AN_write, &smbus_AT24C64AN_read); } diff --git a/src/micetools/dll/devices/_devices.h b/src/micetools/dll/devices/_devices.h index 5cda9f6..671e2b8 100644 --- a/src/micetools/dll/devices/_devices.h +++ b/src/micetools/dll/devices/_devices.h @@ -1,9 +1,21 @@ #pragma once #include "../comdevice.h" #include "../common.h" +#include "smbus.h" void install_led_bd(); void install_touch_bd(); void install_aime_bd(); -void install_devices(); \ No newline at end of file +smbus_callback_t smbus_PCA9535_write; +smbus_callback_t smbus_PCA9535_read; +smbus_callback_t smbus_DS_write; +smbus_callback_t smbus_DS_read; +smbus_callback_t smbus_N2_write; +smbus_callback_t smbus_N2_read; +smbus_callback_t smbus_AT24C64AN_write; +smbus_callback_t smbus_AT24C64AN_read; +smbus_callback_t smbus_EXIO_write; +smbus_callback_t smbus_EXIO_read; + +void install_devices(); diff --git a/src/micetools/dll/devices/meson.build b/src/micetools/dll/devices/meson.build index da3d9a7..c1812fc 100644 --- a/src/micetools/dll/devices/meson.build +++ b/src/micetools/dll/devices/meson.build @@ -1,6 +1,13 @@ devices_files = files( '_devices.c', - 'led_bd.c', - 'touch_bd.c', - 'aime_bd.c', + # Serial devices + 'ser_led_bd.c', + 'ser_maitouch.c', + 'ser_tn32msec.c', + # SMBus devices + 'smb_exio.c', + 'smb_pca9535.c', + 'smb_ds.c', + 'smb_n2.c', + 'smb_at24c64a.c', ) \ No newline at end of file diff --git a/src/micetools/dll/devices/led_bd.c b/src/micetools/dll/devices/ser_led_bd.c similarity index 96% rename from src/micetools/dll/devices/led_bd.c rename to src/micetools/dll/devices/ser_led_bd.c index b0de4ba..3848798 100644 --- a/src/micetools/dll/devices/led_bd.c +++ b/src/micetools/dll/devices/ser_led_bd.c @@ -1,229 +1,229 @@ -#include "../hooks/gui.h" -#include "_devices.h" - -/* -[0] = e0 -[1] = dest? -[2] = dst? -[3] = length -[4] = op code -[...] length-1 bytes -[.] = sum - -[0] = e0 -[2] = dst? -[1] = dest? -[3] = length -[4] = status -[5] = op -[6] = report -[...] -[.] = sum - -OP codes: - 3c: FUN_005735c0 (1) - - 10: FUN_00580c00 (1) - 7c: FUN_00580c00 (2) - 3c: FUN_00580c00 (1) - 39: FUN_00580c00 (4) - 3b: FUN_00580c00 (1) - - 31: FUN_00581350 (5) - 32: FUN_005813b0 (8) - 33: FUN_00581430 (8) -> something at [16]?? - 39: FUN_005814b0 (4) - 3f: FUN_00581220 (7) - - 7b: FUN_005812a0 (3) - 7c: FUN_00581310 (2) - -01: was this just an error? -10: - -31: Set button. [button] [r] [g] [b] - 0-7 = buttons - 8 = woofer - 9 = center -32: Set multiple. [00] [idx hi] [idx lo] [r] [g] [b] -33: Fade multiple?. [09] [?] [?] [r] [g] [b] -39: Set body light. [intensity] [-] [-] -3b: -3c: Commit? -3f: - -7c: -7b: - -initial setup: 7c 0-7, 32, 3c, 39, 3f, 3b -*/ - -unsigned char COLOURS[10][3]; -double positions[10][2] = { - { 0.337963, 0.470833 }, { 0.469444, 0.619792 }, { 0.469444, 0.828125 }, { 0.337037, 0.977083 }, - { 0.152778, 0.976042 }, { 0.020370, 0.828125 }, { 0.020370, 0.618750 }, { 0.151852, 0.472917 }, - { 0.5, 0.75 }, { 0.5, 0.5 }, -}; - -typedef struct rs232c_recv_head { - BYTE sync; - BYTE src; - BYTE dst; - BYTE length; - BYTE op; -} rs232c_recv_head_t; - -BYTE extra[0xff]; -static DWORD WINAPI led_bd_thread(com_device_t* dev) { - log_info("led_bd", "%ls woke up", dev->com->wName); - - while (1) { - rs232c_recv_head_t head; - if (comdev_available(dev) < sizeof head) { - // Sleep(100); - continue; - } - comdev_read(dev, (unsigned char*)&head, sizeof head); - comdev_read(dev, extra, head.length); - - // log_info("led_bd", "Bound %02x->%02x", head.src, head.dst); - - switch (head.op) { - case 0x01: - log_trace("led_bd", "01"); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x01\x01\x18", 8); - // syn dst src len sts op. rep chk - break; - - case 0x10: - log_trace("led_bd", "10"); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x10\x01\x27", 8); - // syn dst src len sts op. rep chk - break; - - case 0x31: - COLOURS[extra[0]][0] = extra[1]; - COLOURS[extra[0]][1] = extra[2]; - COLOURS[extra[0]][2] = extra[3]; - - log_trace("led_bd", "31: %02x = (%02x %02x %02x)", extra[0], extra[1], extra[2], - extra[3]); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x31\x01\x48", 8); - // syn dst src len sts op. rep chk - break; - case 0x32: - log_trace("led_bd", "32: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], - extra[2], extra[3], extra[4], extra[5], extra[6], extra[7]); - - for (unsigned char i = extra[2] - 1; i < extra[1]; i++) { - COLOURS[i][0] = extra[3]; - COLOURS[i][1] = extra[4]; - COLOURS[i][2] = extra[5]; - } - - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x32\x01\x49", 8); - // syn dst src len sts op. rep chk - break; - case 0x33: - log_trace("led_bd", "33: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], - extra[2], extra[3], extra[4], extra[5], extra[6], extra[7]); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x33\x01\x4a", 8); - // syn dst src len sts op. rep chk - COLOURS[extra[0]][0] = extra[extra[5]]; - COLOURS[extra[0]][1] = extra[extra[6]]; - COLOURS[extra[0]][2] = extra[extra[7]]; - break; - - case 0x39: - log_trace("led_bd", "39: %02x %02x %02x", extra[0], extra[1], extra[2]); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x39\x01\x50", 8); - // syn dst src len sts op. rep chk - - COLOURS[9][0] = extra[0]; - COLOURS[9][1] = extra[0]; - COLOURS[9][2] = extra[0]; - break; - case 0x3b: - log_trace("led_bd", "3b"); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3b\x01\x52", 8); - // syn dst src len sts op. rep chk - break; - case 0x3c: - log_trace("led_bd", "3c (I am %ls)", dev->com->wName); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3c\x01\x53", 8); - // syn dst src len sts op. rep chk - break; - case 0x3f: - log_trace("led_bd", "3f: %02x %02x %02x %02x %02x %02x", extra[0], extra[1], - extra[2], extra[3], extra[4], extra[5], extra[6]); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3f\x01\x56", 8); - // syn dst src len sts op. rep chk - break; - - case 0x7c: - // extra[0] goes from 0 to 7 - // Could this be some sort of calibration for the buttons? - log_trace("led_bd", "7c: %02x", extra[0]); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x04\x01\x7c\x01\x00\x94", 9); - // \/ causes 7b to be used - // comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x04\x01\x7c\x01\x10\xa4", 9); - // syn dst src len sts op. rep --- chk - break; - case 0x7b: - log_trace("led_bd", "7b: %02x %02x %02x", extra[0], extra[1], extra[2]); - comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x7b\x01\x92", 8); - // syn dst src len sts op. rep chk - break; - - default: - log_error("led_bd", "Unknown op %02x (%d)", head.op, head.length - 1); - break; - } - } -} - -static DWORD WINAPI led_null_thread(com_device_t* dev) { - while (1) Sleep(10000000); -} - -void led_overlay(IDirect3DDevice9* dev) { - ShowCursor(true); - D3DDEVICE_CREATION_PARAMETERS cparams; - RECT rect; - - dev->lpVtbl->GetCreationParameters(dev, &cparams); - GetClientRect(cparams.hFocusWindow, &rect); - - if (GetAsyncKeyState(VK_LBUTTON) & 1) { - POINT cursor; - GetCursorPos(&cursor); - - // log_info("led_overlay", "x: %d, y: %d", cursor.x, cursor.y); - // log_info("led_overlay", "x%: %f, y%: %f", (float)cursor.x / (float)rect.right, - // (float)(cursor.y - 26) / (float)rect.bottom); - } - - for (unsigned char i = 0; i < 10; i++) { - int x = (int)(rect.right * positions[i][0]); - int y = (int)(rect.bottom * positions[i][1]); - draw_rect(dev, x - 25, y - 25, 50, 50, COLOURS[i][0], COLOURS[i][1], COLOURS[i][2]); - } -} - -void install_led_bd() { - register_gui_hook(&led_overlay); - - char* text = MiceConfig.devices.led_bd; - char* copy = (char*)malloc(strlen(text) + 1); - memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); - - char* next_token; - char* token = strtok_s(copy, ",", &next_token); - while (token != NULL) { - BYTE com_port = atoi(token) & 0xFF; - if (com_port) com_device_thread(new_com_device(com_port), led_bd_thread); - token = strtok_s(NULL, ",", &next_token); - } - - free(copy); -} +#include "../hooks/gui.h" +#include "_devices.h" + +/* +[0] = e0 +[1] = dest? +[2] = dst? +[3] = length +[4] = op code +[...] length-1 bytes +[.] = sum + +[0] = e0 +[2] = dst? +[1] = dest? +[3] = length +[4] = status +[5] = op +[6] = report +[...] +[.] = sum + +OP codes: + 3c: FUN_005735c0 (1) + + 10: FUN_00580c00 (1) + 7c: FUN_00580c00 (2) + 3c: FUN_00580c00 (1) + 39: FUN_00580c00 (4) + 3b: FUN_00580c00 (1) + + 31: FUN_00581350 (5) + 32: FUN_005813b0 (8) + 33: FUN_00581430 (8) -> something at [16]?? + 39: FUN_005814b0 (4) + 3f: FUN_00581220 (7) + + 7b: FUN_005812a0 (3) + 7c: FUN_00581310 (2) + +01: was this just an error? +10: + +31: Set button. [button] [r] [g] [b] + 0-7 = buttons + 8 = woofer + 9 = center +32: Set multiple. [00] [idx hi] [idx lo] [r] [g] [b] +33: Fade multiple?. [09] [?] [?] [r] [g] [b] +39: Set body light. [intensity] [-] [-] +3b: +3c: Commit? +3f: + +7c: +7b: + +initial setup: 7c 0-7, 32, 3c, 39, 3f, 3b +*/ + +unsigned char COLOURS[10][3]; +double positions[10][2] = { + { 0.337963, 0.470833 }, { 0.469444, 0.619792 }, { 0.469444, 0.828125 }, { 0.337037, 0.977083 }, + { 0.152778, 0.976042 }, { 0.020370, 0.828125 }, { 0.020370, 0.618750 }, { 0.151852, 0.472917 }, + { 0.5, 0.75 }, { 0.5, 0.5 }, +}; + +typedef struct rs232c_recv_head { + BYTE sync; + BYTE src; + BYTE dst; + BYTE length; + BYTE op; +} rs232c_recv_head_t; + +BYTE extra[0xff]; +static DWORD WINAPI led_bd_thread(com_device_t* dev) { + log_info("led_bd", "%ls woke up", dev->com->wName); + + while (1) { + rs232c_recv_head_t head; + if (comdev_available(dev) < sizeof head) { + // Sleep(100); + continue; + } + comdev_read(dev, (unsigned char*)&head, sizeof head); + comdev_read(dev, extra, head.length); + + // log_info("led_bd", "Bound %02x->%02x", head.src, head.dst); + + switch (head.op) { + case 0x01: + log_trace("led_bd", "01"); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x01\x01\x18", 8); + // syn dst src len sts op. rep chk + break; + + case 0x10: + log_trace("led_bd", "10"); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x10\x01\x27", 8); + // syn dst src len sts op. rep chk + break; + + case 0x31: + COLOURS[extra[0]][0] = extra[1]; + COLOURS[extra[0]][1] = extra[2]; + COLOURS[extra[0]][2] = extra[3]; + + log_trace("led_bd", "31: %02x = (%02x %02x %02x)", extra[0], extra[1], extra[2], + extra[3]); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x31\x01\x48", 8); + // syn dst src len sts op. rep chk + break; + case 0x32: + log_trace("led_bd", "32: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], + extra[2], extra[3], extra[4], extra[5], extra[6], extra[7]); + + for (unsigned char i = extra[2] - 1; i < extra[1]; i++) { + COLOURS[i][0] = extra[3]; + COLOURS[i][1] = extra[4]; + COLOURS[i][2] = extra[5]; + } + + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x32\x01\x49", 8); + // syn dst src len sts op. rep chk + break; + case 0x33: + log_trace("led_bd", "33: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], + extra[2], extra[3], extra[4], extra[5], extra[6], extra[7]); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x33\x01\x4a", 8); + // syn dst src len sts op. rep chk + COLOURS[extra[0]][0] = extra[extra[5]]; + COLOURS[extra[0]][1] = extra[extra[6]]; + COLOURS[extra[0]][2] = extra[extra[7]]; + break; + + case 0x39: + log_trace("led_bd", "39: %02x %02x %02x", extra[0], extra[1], extra[2]); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x39\x01\x50", 8); + // syn dst src len sts op. rep chk + + COLOURS[9][0] = extra[0]; + COLOURS[9][1] = extra[0]; + COLOURS[9][2] = extra[0]; + break; + case 0x3b: + log_trace("led_bd", "3b"); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3b\x01\x52", 8); + // syn dst src len sts op. rep chk + break; + case 0x3c: + log_trace("led_bd", "3c (I am %ls)", dev->com->wName); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3c\x01\x53", 8); + // syn dst src len sts op. rep chk + break; + case 0x3f: + log_trace("led_bd", "3f: %02x %02x %02x %02x %02x %02x", extra[0], extra[1], + extra[2], extra[3], extra[4], extra[5], extra[6]); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3f\x01\x56", 8); + // syn dst src len sts op. rep chk + break; + + case 0x7c: + // extra[0] goes from 0 to 7 + // Could this be some sort of calibration for the buttons? + log_trace("led_bd", "7c: %02x", extra[0]); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x04\x01\x7c\x01\x00\x94", 9); + // \/ causes 7b to be used + // comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x04\x01\x7c\x01\x10\xa4", 9); + // syn dst src len sts op. rep --- chk + break; + case 0x7b: + log_trace("led_bd", "7b: %02x %02x %02x", extra[0], extra[1], extra[2]); + comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x7b\x01\x92", 8); + // syn dst src len sts op. rep chk + break; + + default: + log_error("led_bd", "Unknown op %02x (%d)", head.op, head.length - 1); + break; + } + } +} + +static DWORD WINAPI led_null_thread(com_device_t* dev) { + while (1) Sleep(10000000); +} + +void led_overlay(IDirect3DDevice9* dev) { + ShowCursor(true); + D3DDEVICE_CREATION_PARAMETERS cparams; + RECT rect; + + dev->lpVtbl->GetCreationParameters(dev, &cparams); + GetClientRect(cparams.hFocusWindow, &rect); + + if (GetAsyncKeyState(VK_LBUTTON) & 1) { + POINT cursor; + GetCursorPos(&cursor); + + // log_info("led_overlay", "x: %d, y: %d", cursor.x, cursor.y); + // log_info("led_overlay", "x%: %f, y%: %f", (float)cursor.x / (float)rect.right, + // (float)(cursor.y - 26) / (float)rect.bottom); + } + + for (unsigned char i = 0; i < 10; i++) { + int x = (int)(rect.right * positions[i][0]); + int y = (int)(rect.bottom * positions[i][1]); + draw_rect(dev, x - 25, y - 25, 50, 50, COLOURS[i][0], COLOURS[i][1], COLOURS[i][2]); + } +} + +void install_led_bd() { + // register_gui_hook(&led_overlay); + + char* text = MiceConfig.devices.led_bd; + char* copy = (char*)malloc(strlen(text) + 1); + memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); + + char* next_token; + char* token = strtok_s(copy, ",", &next_token); + while (token != NULL) { + BYTE com_port = atoi(token) & 0xFF; + if (com_port) com_device_thread(new_com_device(com_port), led_bd_thread); + token = strtok_s(NULL, ",", &next_token); + } + + free(copy); +} diff --git a/src/micetools/dll/devices/touch_bd.c b/src/micetools/dll/devices/ser_maitouch.c similarity index 97% rename from src/micetools/dll/devices/touch_bd.c rename to src/micetools/dll/devices/ser_maitouch.c index 67b3204..f30c946 100644 --- a/src/micetools/dll/devices/touch_bd.c +++ b/src/micetools/dll/devices/ser_maitouch.c @@ -1,97 +1,97 @@ -#include "_devices.h" - -static BYTE read_one(com_device_t* dev) { - while (!comdev_available(dev)) Sleep(50); - BYTE data; - comdev_read(dev, &data, 1); - return data; -} - -const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0"; -static BYTE get_touch_id(BYTE id) { - for (BYTE i = 0; i < sizeof(TOUCH_ID_LUT); i++) { - if (TOUCH_ID_LUT[i] == id) return i; - } - return 0xff; -} - -BOOL touch_is_enabled = false; -BYTE thresh = 0x00; // Lazy caching of single value -DWORD WINAPI touch_bd_thread(com_device_t* dev) { - log_info("touch_bd", "%ls woke up", dev->com->wName); - - while (1) { - if (touch_is_enabled && !comdev_available(dev)) { - // Active mode! - comdev_write(dev, (unsigned char*)"(@@@@@@@@@@@@)", 14); - Sleep(100); - continue; - } - - while (read_one(dev) != '{') continue; - while (comdev_available(dev) < 5) { - log_info("touch", "<. .>"); - Sleep(50); - } - BYTE command[5]; - comdev_read(dev, command, 5); - BYTE response[6]; - memcpy(response, "( )", 6); - - if (memcmp(command, "HALT}", 5) == 0) { - if (touch_is_enabled) - log_info("touch", "Touchscreen left active mode"); - else - log_misc("touch", "Touchscreen not in active mode"); - touch_is_enabled = false; - } else if (memcmp(command, "STAT}", 5) == 0) { - if (!touch_is_enabled) - log_info("touch", "Touchscreen entered active mode"); - else - log_misc("touch", "Touchscreen already in active mode"); - touch_is_enabled = true; - } else if (command[2] == 'k' && command[4] == '}') { - BYTE sensor = get_touch_id(command[1]); - - log_misc("touch", "k-command recieved: %d >=%d", sensor, command[3]); - // Sensor == '@': failed - // ( <> <> ) - response[1] = command[0]; - response[2] = command[1]; - thresh = command[3]; - - comdev_write(dev, response, 6); - } else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') { - BYTE sensor = get_touch_id(command[1]); - - // { t h } - log_misc("touch", "th-command recieved: %d", sensor); - - // Sensor == '@': failed - // ( <> ) - response[1] = command[0]; // 'L' or 'R' - response[2] = command[1]; // Sensor - response[4] = thresh; - - comdev_write(dev, response, 6); - } else { - log_error("touch", "Unhandled: {%.*s", 5, command); - } - } -} - -void install_touch_bd() { - char* text = MiceConfig.devices.touch_bd; - char* copy = (char*)malloc(strlen(text) + 1); - memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); - - char* next_token; - char* token = strtok_s(copy, ",", &next_token); - while (token != NULL) { - BYTE com_port = atoi(token) & 0xFF; - if (com_port) com_device_thread(new_com_device(com_port), touch_bd_thread); - token = strtok_s(NULL, ",", &next_token); - } - - free(copy); -} +#include "_devices.h" + +static BYTE read_one(com_device_t* dev) { + while (!comdev_available(dev)) Sleep(50); + BYTE data; + comdev_read(dev, &data, 1); + return data; +} + +const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0"; +static BYTE get_touch_id(BYTE id) { + for (BYTE i = 0; i < sizeof(TOUCH_ID_LUT); i++) { + if (TOUCH_ID_LUT[i] == id) return i; + } + return 0xff; +} + +BOOL touch_is_enabled = false; +BYTE thresh = 0x00; // Lazy caching of single value +DWORD WINAPI touch_bd_thread(com_device_t* dev) { + log_info("touch_bd", "%ls woke up", dev->com->wName); + + while (1) { + if (touch_is_enabled && !comdev_available(dev)) { + // Active mode! + comdev_write(dev, (unsigned char*)"(@@@@@@@@@@@@)", 14); + Sleep(100); + continue; + } + + while (read_one(dev) != '{') continue; + while (comdev_available(dev) < 5) { + log_info("touch", "<. .>"); + Sleep(50); + } + BYTE command[5]; + comdev_read(dev, command, 5); + BYTE response[6]; + memcpy(response, "( )", 6); + + if (memcmp(command, "HALT}", 5) == 0) { + if (touch_is_enabled) + log_info("touch", "Touchscreen left active mode"); + else + log_misc("touch", "Touchscreen not in active mode"); + touch_is_enabled = false; + } else if (memcmp(command, "STAT}", 5) == 0) { + if (!touch_is_enabled) + log_info("touch", "Touchscreen entered active mode"); + else + log_misc("touch", "Touchscreen already in active mode"); + touch_is_enabled = true; + } else if (command[2] == 'k' && command[4] == '}') { + BYTE sensor = get_touch_id(command[1]); + + log_misc("touch", "k-command recieved: %d >=%d", sensor, command[3]); + // Sensor == '@': failed + // ( <> <> ) + response[1] = command[0]; + response[2] = command[1]; + thresh = command[3]; + + comdev_write(dev, response, 6); + } else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') { + BYTE sensor = get_touch_id(command[1]); + + // { t h } + log_misc("touch", "th-command recieved: %d", sensor); + + // Sensor == '@': failed + // ( <> ) + response[1] = command[0]; // 'L' or 'R' + response[2] = command[1]; // Sensor + response[4] = thresh; + + comdev_write(dev, response, 6); + } else { + log_error("touch", "Unhandled: {%.*s", 5, command); + } + } +} + +void install_touch_bd() { + char* text = MiceConfig.devices.touch_bd; + char* copy = (char*)malloc(strlen(text) + 1); + memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); + + char* next_token; + char* token = strtok_s(copy, ",", &next_token); + while (token != NULL) { + BYTE com_port = atoi(token) & 0xFF; + if (com_port) com_device_thread(new_com_device(com_port), touch_bd_thread); + token = strtok_s(NULL, ",", &next_token); + } + + free(copy); +} diff --git a/src/micetools/dll/devices/aime_bd.c b/src/micetools/dll/devices/ser_tn32msec.c similarity index 65% rename from src/micetools/dll/devices/aime_bd.c rename to src/micetools/dll/devices/ser_tn32msec.c index ca123a1..56f6056 100644 --- a/src/micetools/dll/devices/aime_bd.c +++ b/src/micetools/dll/devices/ser_tn32msec.c @@ -1,290 +1,328 @@ -#include "_devices.h" - -static BYTE read_one(com_device_t* dev) { - while (!comdev_available(dev)) Sleep(50); - BYTE data; - comdev_read(dev, &data, 1); - return data; -} - -BYTE extra[0xff]; - -#define GetFWVersion 0x30 -#define GetHWVersion 0x32 -#define RadioOn 0x40 -#define RadioOff 0x41 -#define Poll 0x2 -#define MifareSelectTag 0x43 -#define Unknown1 0x44 // Present in code, not seen used -#define SetKeyBana 0x50 -#define Unknown2 0x51 // Present in code, not seen used -#define ReadBlock 0x52 -#define SetKeyAime 0x54 -#define Authenticate 0x55 -#define Unknown3 0x60 // Present in code, not seen used -#define Unknown4 0x61 // Present in code, not seen used -#define Reset 0x62 -#define Unknown5 0x70 // Present in code, not seen used -#define FelicaEncap 0x71 - -#define LedReset 0xf5 -#define LedGetInfo 0xf0 -#define LedSetColour 0x81 - -#define FWVer "TN32MSEC003S F/W Ver1.2" -#define HWVer "TN32MSEC003S H/W Ver3.0" - -#define CardType_Mifare 0x10 -#define CardType_FeliCa 0x20 - -#pragma pack(1) -typedef struct NFCMifare { - BYTE type; - BYTE id_len; - DWORD uid; -} NFCMifare_t; - -#pragma pack(1) -typedef struct NFCFelica { - BYTE type; - BYTE id_len; - uint64_t IDm; - uint64_t PMm; -} NFCFelica_t; - -#pragma pack(1) -typedef struct MifareBlock { - BYTE bytes[16]; -} MifareBlock_t; - -#pragma pack(1) -typedef struct MifareSector { - MifareBlock_t blocks[4]; -} MifareSector_t; - -#pragma pack(1) -typedef struct MifareMemory_t { - MifareSector_t sectors[16]; -} MifareMemory_t; - -#pragma pack(1) -typedef struct FelicaBlock { - BYTE bytes[16]; -} FelicaBlock_t; - -#pragma pack(1) -typedef struct FelicaMemory { - FelicaBlock_t dataBlocks[15]; - FelicaBlock_t systemBlocks[9]; -} FelicaMemory_t; - -MifareMemory_t mifareMemory; -FelicaMemory_t felicaMemory; -BYTE luid[10] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89 }; -#define PMm_VALUE 0x00F1000000014300ULL - -#define FelicaSystemBlock_RC 0x00 -#define FelicaSystemBlock_MAC 0x01 -#define FelicaSystemBlock_ID 0x02 -#define FelicaSystemBlock_D_ID 0x03 -#define FelicaSystemBlock_SER_C 0x04 -#define FelicaSystemBlock_SYS_C 0x05 -#define FelicaSystemBlock_CKV 0x06 -#define FelicaSystemBlock_CK 0x07 -#define FelicaSystemBlock_MC 0x08 - -void populate_felica(NFCFelica_t* card) { - card->type = CardType_FeliCa; - card->id_len = sizeof(card->IDm) + sizeof(card->PMm); - card->IDm = _byteswap_uint64(0x012E4CD8A30A39B3ULL); - card->PMm = _byteswap_uint64(PMm_VALUE); - - // Key name - felicaMemory.dataBlocks[0x0D].bytes[0] = 0x00; - felicaMemory.dataBlocks[0x0D].bytes[1] = 0x02; - felicaMemory.dataBlocks[0x0D].bytes[2] = 'N'; - felicaMemory.dataBlocks[0x0D].bytes[3] = 'B'; - felicaMemory.dataBlocks[0x0D].bytes[4] = 'G'; - felicaMemory.dataBlocks[0x0D].bytes[5] = 'I'; - felicaMemory.dataBlocks[0x0D].bytes[6] = 'C'; - felicaMemory.dataBlocks[0x0D].bytes[7] = '0'; - // Setup the fake blowfish data - felicaMemory.dataBlocks[0x0D].bytes[8] = 0x89; - felicaMemory.dataBlocks[0x0D].bytes[9] = 0x00; - felicaMemory.dataBlocks[0x0D].bytes[10] = 0x00; - felicaMemory.dataBlocks[0x0D].bytes[11] = 0x00; - felicaMemory.dataBlocks[0x0D].bytes[12] = 0x00; - felicaMemory.dataBlocks[0x0D].bytes[13] = 0x00; - felicaMemory.dataBlocks[0x0D].bytes[14] = 0x00; - felicaMemory.dataBlocks[0x0D].bytes[15] = 0x00; - - BYTE block0[16] = { - 0xC2, 0x1C, 0xCB, 0xC7, 0x58, 0xCA, 0x81, 0xB7, - 0xC0, 0x0B, 0x8E, 0x3A, 0x45, 0x43, 0xFE, 0xFC, - }; - memcpy(felicaMemory.dataBlocks[0].bytes, block0, 16); - memset(felicaMemory.dataBlocks[0x0e].bytes, 0xFF, 16); - BYTE blockID[16] = { - // IDd (=IDm) - 0x01, 0x2E, 0x4C, 0xD8, 0xA3, 0x0A, 0x39, 0xB3, - // ID - 0x00, 0x2a, 0x05, 0x73, 0x02, 0x01, 0x03, 0x00, - // ^DFC^ ^~~~~~ arbitary value - }; - memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_ID].bytes, blockID, 16); - BYTE blockDID[16] = { - // IDd (=IDm) - 0x01, - 0x2E, - 0x4C, - 0xD8, - 0xA3, - 0x0A, - 0x39, - 0xB3, - // PMm - 0x00, - 0xF1, - 0x00, - 0x00, - 0x00, - 0x01, - 0x43, - 0x00, - }; - memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_D_ID].bytes, blockDID, 16); -} -void populate_mifare(NFCMifare_t* card) { - card->type = CardType_Mifare; - card->id_len = sizeof(card->uid); - card->uid = _byteswap_ulong(0x01020304); - - // TODO: Better state haha - // Flash the card memory - for (BYTE i = 0; i < 10; i++) { - BYTE b = luid[i]; - mifareMemory.sectors[0].blocks[2].bytes[i + 6] = b; - mifareMemory.sectors[0].blocks[1].bytes[i + 6] = b; - } -} - -void nfc_poll(com_device_t* dev, comio_recv_head_t* req) { - BYTE data[256]; - BYTE nbytes = 1; - - // felica present - if (GetAsyncKeyState('L') < 0) { - NFCFelica_t card; - populate_felica(&card); - memcpy(data + nbytes, &card, sizeof card); - nbytes += sizeof card; - data[0]++; - } - // mifare (aime, bana) present - if (GetAsyncKeyState('P') < 0) { - NFCMifare_t card; - populate_mifare(&card); - memcpy(data + nbytes, &card, sizeof card); - nbytes += sizeof card; - data[0]++; - } - - comio_reply(dev, req, COMIO_STATUS_OK, nbytes, data); -} - -DWORD WINAPI aime_bd_thread(com_device_t* dev) { - log_info("aime_bd", "%ls woke up", dev->com->wName); - bool radio = false; - - while (1) { - comio_recv_head_t req; - comio_next_req(dev, &req, extra); - - log_info("aime_bd", "(%d) %02x", req.dst, req.op); - - if (req.dst == 0x00 || req.dst == 0x01) { - // Aime readers - switch (req.op) { - case Reset: - comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); - break; - case GetFWVersion: - comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1, (LPBYTE)FWVer); - break; - case GetHWVersion: - comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1, (LPBYTE)HWVer); - break; - case SetKeyAime: - log_info("aime_bd", "Aime key: %.*s", req.length, extra); - comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); - break; - case SetKeyBana: - log_info("aime_bd", "Bana key: %.*s", req.length, extra); - comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); - break; - case RadioOn: - radio = true; - comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); - break; - case RadioOff: - radio = false; - comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); - break; - case Poll: - nfc_poll(dev, &req); - break; - - case 0x44: - case 0x51: - case MifareSelectTag: - case Authenticate: - comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); - break; - - // TODO: These - case ReadBlock: - comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL); - break; - case FelicaEncap: - comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL); - break; - } - } else if (req.dst == 0x08 || req.dst == 0x09) { - // LED sub-boards - switch (req.op) { - case LedReset: - comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); - break; - case LedGetInfo: - // TODO: I'm not sure what this actually means. - // 838-15084 is probably a part number - comio_reply(dev, &req, COMIO_STATUS_OK, 9, (BYTE*)"15084\xff\x10\x00\x12"); - break; - case LedSetColour: - log_misc("nfc", "Set LED: #%02x%02x%02x", extra[0], extra[1], extra[2]); - printf("\033[48;2;%d;%d;%dm \033[0m", - extra[0], extra[1], extra[2]); - // No response expected here! - break; - } - } - - Sleep(50); - } -} - -void install_aime_bd() { - char* text = MiceConfig.devices.aime_bd; - char* copy = (char*)malloc(strlen(text) + 1); - memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); - - char* next_token; - char* token = strtok_s(copy, ",", &next_token); - while (token != NULL) { - BYTE com_port = atoi(token) & 0xFF; - if (com_port) com_device_thread(new_com_device(com_port), aime_bd_thread); - token = strtok_s(NULL, ",", &next_token); - } - - free(copy); -} +#include "_devices.h" + +static BYTE read_one(com_device_t* dev) { + while (!comdev_available(dev)) Sleep(50); + BYTE data; + comdev_read(dev, &data, 1); + return data; +} + +BYTE extra[0xff]; + +/** + * 51 and 55 are guesses based on the code. Makes sense given their opcodes + * too. + * TODO: Validate against a real board + */ +enum TN32_Opcode { + TN32Op_Unknown20 = 0x20, + TN32Op_GetFWVersion = 0x30, + TN32Op_GetHWVersion = 0x32, + TN32Op_RadioOn = 0x40, + TN32Op_RadioOff = 0x41, + TN32Op_Poll = 0x42, + TN32Op_MifareSelectTag = 0x43, + TN32Op_Unknown44 = 0x44, // Present in code, not seen used + TN32Op_SetKeyBana = 0x50, + TN32Op_GetKeyBana = 0x51, + TN32Op_ReadBlock = 0x52, + TN32Op_Unknown53 = 0x53, // Present in code, not seen used + TN32Op_SetKeyAime = 0x54, + TN32Op_GetKeyAime = 0x55, + TN32Op_Unknown60 = 0x60, // Present in code, not seen used + TN32Op_Unknown61 = 0x61, // Present in code, not seen used + TN32Op_Reset = 0x62, + TN32Op_Unknown70 = 0x70, // Present in code, not seen used + TN32Op_FelicaEncap = 0x71, +}; + +#define LedReset 0xf5 +#define LedGetInfo 0xf0 +#define LedSetColour 0x81 + +const char FWVer[] = "TN32MSEC003S F/W Ver1.2"; +const char HWVer[] = "TN32MSEC003S H/W Ver3.0"; + +#define CardType_Mifare 0x10 +#define CardType_FeliCa 0x20 + +#pragma pack(push, 1) +typedef struct NFCMifare { + BYTE type; + BYTE id_len; + DWORD uid; +} NFCMifare_t; + +typedef struct NFCFelica { + BYTE type; + BYTE id_len; + uint64_t IDm; + uint64_t PMm; +} NFCFelica_t; + +typedef struct MifareBlock { + BYTE bytes[16]; +} MifareBlock_t; + +typedef struct MifareSector { + MifareBlock_t blocks[4]; +} MifareSector_t; + +typedef struct MifareMemory_t { + MifareSector_t sectors[16]; +} MifareMemory_t; + +typedef struct FelicaBlock { + BYTE bytes[16]; +} FelicaBlock_t; + +typedef struct FelicaMemory { + FelicaBlock_t dataBlocks[15]; + FelicaBlock_t systemBlocks[9]; +} FelicaMemory_t; +#pragma pack(pop) + +MifareMemory_t mifareMemory; +FelicaMemory_t felicaMemory; +BYTE luid[10] = {0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89}; +#define PMm_VALUE 0x00F1000000014300ULL + +#define FelicaSystemBlock_RC 0x00 +#define FelicaSystemBlock_MAC 0x01 +#define FelicaSystemBlock_ID 0x02 +#define FelicaSystemBlock_D_ID 0x03 +#define FelicaSystemBlock_SER_C 0x04 +#define FelicaSystemBlock_SYS_C 0x05 +#define FelicaSystemBlock_CKV 0x06 +#define FelicaSystemBlock_CK 0x07 +#define FelicaSystemBlock_MC 0x08 + +void populate_felica(NFCFelica_t* card) { + card->type = CardType_FeliCa; + card->id_len = sizeof(card->IDm) + sizeof(card->PMm); + card->IDm = _byteswap_uint64(0x012E4CD8A30A39B3ULL); + card->PMm = _byteswap_uint64(PMm_VALUE); + + // Key name + felicaMemory.dataBlocks[0x0D].bytes[0] = 0x00; + felicaMemory.dataBlocks[0x0D].bytes[1] = 0x02; + felicaMemory.dataBlocks[0x0D].bytes[2] = 'N'; + felicaMemory.dataBlocks[0x0D].bytes[3] = 'B'; + felicaMemory.dataBlocks[0x0D].bytes[4] = 'G'; + felicaMemory.dataBlocks[0x0D].bytes[5] = 'I'; + felicaMemory.dataBlocks[0x0D].bytes[6] = 'C'; + felicaMemory.dataBlocks[0x0D].bytes[7] = '0'; + // Setup the fake blowfish data + felicaMemory.dataBlocks[0x0D].bytes[8] = 0x89; + felicaMemory.dataBlocks[0x0D].bytes[9] = 0x00; + felicaMemory.dataBlocks[0x0D].bytes[10] = 0x00; + felicaMemory.dataBlocks[0x0D].bytes[11] = 0x00; + felicaMemory.dataBlocks[0x0D].bytes[12] = 0x00; + felicaMemory.dataBlocks[0x0D].bytes[13] = 0x00; + felicaMemory.dataBlocks[0x0D].bytes[14] = 0x00; + felicaMemory.dataBlocks[0x0D].bytes[15] = 0x00; + + BYTE block0[16] = { + 0xC2, 0x1C, 0xCB, 0xC7, 0x58, 0xCA, 0x81, 0xB7, + 0xC0, 0x0B, 0x8E, 0x3A, 0x45, 0x43, 0xFE, 0xFC, + }; + memcpy(felicaMemory.dataBlocks[0].bytes, block0, 16); + memset(felicaMemory.dataBlocks[0x0e].bytes, 0xFF, 16); + BYTE blockID[16] = { + // IDd (=IDm) + 0x01, 0x2E, 0x4C, 0xD8, 0xA3, 0x0A, 0x39, 0xB3, + // ID + 0x00, 0x2a, 0x05, 0x73, 0x02, 0x01, 0x03, 0x00, + // ^DFC^ ^~~~~~ arbitary value + }; + memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_ID].bytes, blockID, + 16); + BYTE blockDID[16] = { + // IDd (=IDm) + 0x01, + 0x2E, + 0x4C, + 0xD8, + 0xA3, + 0x0A, + 0x39, + 0xB3, + // PMm + 0x00, + 0xF1, + 0x00, + 0x00, + 0x00, + 0x01, + 0x43, + 0x00, + }; + memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_D_ID].bytes, blockDID, + 16); +} +void populate_mifare(NFCMifare_t* card) { + card->type = CardType_Mifare; + card->id_len = sizeof(card->uid); + card->uid = _byteswap_ulong(0x01020304); + + // TODO: Better state haha + // Flash the card memory + for (BYTE i = 0; i < 10; i++) { + BYTE b = luid[i]; + mifareMemory.sectors[0].blocks[2].bytes[i + 6] = b; + mifareMemory.sectors[0].blocks[1].bytes[i + 6] = b; + } +} + +void nfc_poll(com_device_t* dev, comio_recv_head_t* req) { + BYTE data[256]; + BYTE nbytes = 1; + + // felica present + if (GetAsyncKeyState('L') < 0) { + NFCFelica_t card; + populate_felica(&card); + memcpy(data + nbytes, &card, sizeof card); + nbytes += sizeof card; + data[0]++; + } + // mifare (aime, bana) present + if (GetAsyncKeyState('P') < 0) { + NFCMifare_t card; + populate_mifare(&card); + memcpy(data + nbytes, &card, sizeof card); + nbytes += sizeof card; + data[0]++; + } + + comio_reply(dev, req, COMIO_STATUS_OK, nbytes, data); +} + +BYTE AIME_KEY[6]; +BYTE BANA_KEY[6]; + +DWORD WINAPI aime_bd_thread(com_device_t* dev) { + log_info("aime_bd", "%ls woke up", dev->com->wName); + bool radio = false; + + while (1) { + comio_recv_head_t req; + comio_next_req(dev, &req, extra); + + log_info("aime_bd", "(%d) %02x", req.dst, req.op); + + if (req.dst == 0x00 || req.dst == 0x01) { + // Aime readers + switch (req.op) { + case TN32Op_Reset: + comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); + break; + case TN32Op_GetFWVersion: + comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1, + (LPBYTE)FWVer); + break; + case TN32Op_GetHWVersion: + comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1, + (LPBYTE)HWVer); + break; + case TN32Op_SetKeyAime: + if (req.length != sizeof AIME_KEY) { + comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL); + } else { + memcpy(AIME_KEY, extra, sizeof AIME_KEY); + comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); + + log_info("aime_bd", + "Aime key: %02x %02x %02x %02x %02x %02x", + AIME_KEY[0], AIME_KEY[1], AIME_KEY[2], + AIME_KEY[3], AIME_KEY[4], AIME_KEY[5]); + } + break; + case TN32Op_SetKeyBana: + if (req.length != sizeof BANA_KEY) { + comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL); + } else { + memcpy(BANA_KEY, extra, sizeof BANA_KEY); + comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); + + log_info("aime_bd", + "Bana key: %02x %02x %02x %02x %02x %02x", + BANA_KEY[0], BANA_KEY[1], BANA_KEY[2], + BANA_KEY[3], BANA_KEY[4], BANA_KEY[5]); + } + break; + case TN32Op_RadioOn: + radio = true; + comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); + break; + case TN32Op_RadioOff: + radio = false; + comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); + break; + case TN32Op_Poll: + nfc_poll(dev, &req); + break; + + case TN32Op_GetKeyBana: + case TN32Op_GetKeyAime: + if (req.length != 5) { + // + } + + case TN32Op_Unknown44: + case TN32Op_MifareSelectTag: + comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); + break; + + // TODO: These + case TN32Op_ReadBlock: + comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL); + break; + case TN32Op_FelicaEncap: + comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL); + break; + } + } else if (req.dst == 0x08 || req.dst == 0x09) { + // LED sub-boards + switch (req.op) { + case LedReset: + comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL); + break; + case LedGetInfo: + // TODO: I'm not sure what this actually means. + // 838-15084 is probably a part number + comio_reply(dev, &req, COMIO_STATUS_OK, 9, + (BYTE*)"15084\xff\x10\x00\x12"); + break; + case LedSetColour: + log_misc("nfc", "Set LED: #%02x%02x%02x", extra[0], + extra[1], extra[2]); + printf( + "\033[48;2;%d;%d;%dm " + " \033[0m", + extra[0], extra[1], extra[2]); + // No response expected here! + break; + } + } + + Sleep(50); + } +} + +void install_aime_bd() { + char* text = MiceConfig.devices.aime_bd; + char* copy = (char*)malloc(strlen(text) + 1); + memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); + + char* next_token; + char* token = strtok_s(copy, ",", &next_token); + while (token != NULL) { + BYTE com_port = atoi(token) & 0xFF; + if (com_port) + com_device_thread(new_com_device(com_port), aime_bd_thread); + token = strtok_s(NULL, ",", &next_token); + } + + free(copy); +} diff --git a/src/micetools/dll/devices/smb_at24c64a.c b/src/micetools/dll/devices/smb_at24c64a.c new file mode 100644 index 0000000..15739fc --- /dev/null +++ b/src/micetools/dll/devices/smb_at24c64a.c @@ -0,0 +1,173 @@ +#include "../../amBackupStructs.h" +#include "../../maiBackupStructs.h" +#include "_devices.h" + +#define EEPROM_DUMP L"dev/eeprom.bin" + +// 8192 x 8 (64kbit) of eeprom +BYTE EEPROM_DATA[0x2000]; + +void eeprom_dump() { + HANDLE dump = + _CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); + if (dump == INVALID_HANDLE_VALUE) { + log_error("eeprom", "CreateFileA(EEPROM_DUMP) failed: %03x", GetLastError()); + return; + } else { + log_info("eeprom", "Wrote eeprom to %ls", EEPROM_DUMP); + } + _WriteFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, NULL, NULL); + FlushFileBuffers(dump); + _CloseHandle(dump); +} +void eeprom_restore() { + HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (dump == INVALID_HANDLE_VALUE) { + // Make the file, even though it'll probably be empty + eeprom_dump(); + return; + } + DWORD read; + if (!_ReadFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, &read, NULL)) + log_error("eeprom", "failed to restore (%d)", GetLastError()); + _CloseHandle(dump); +} + +#define SET_IP(val, a, b, c, d) \ + do { \ + *(uint32_t*)&val = (uint32_t)((a << 24) | (b << 16) | (c << 8) | d); \ + } while (0) + +#define fix_crc(block) \ + do { \ + (block).m_Crc = amCrc32RGet(sizeof(block) - 4, (BYTE*)(&(block)) + 4, 0); \ + } while (0) + +void set_eeprom_network_config() { + AM_SYSDATAwH_NETWORK_ETH0 NetEth0 = { 0 }; + NetEth0.m_Eth.m_Flag = 0; + NetEth0.m_Eth.m_IpAddress = MiceConfig.network.ip_address; + NetEth0.m_Eth.m_SubnetMask = MiceConfig.network.subnet_mask; + NetEth0.m_Eth.m_Gateway = MiceConfig.network.gateway; + NetEth0.m_Eth.m_PrimaryDns = MiceConfig.network.primary_dns; + NetEth0.m_Eth.m_SecondaryDns = MiceConfig.network.secondary_dns; + fix_crc(NetEth0); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_NETWORK_ETH0_REG], &NetEth0, sizeof NetEth0); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_NETWORK_ETH0_DUP], &NetEth0, sizeof NetEth0); + + AM_SYSDATAwH_NETWORK_ETH1 NetEth1 = { 0 }; + fix_crc(NetEth1); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_NETWORK_ETH1_REG], &NetEth1, sizeof NetEth1); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_NETWORK_ETH1_DUP], &NetEth1, sizeof NetEth1); +} + +int build_eeprom() { + static BOOL built = false; + if (built) return 0; + built = true; + + if (FileExists(EEPROM_DUMP)) { + eeprom_restore(); + // Our network config always gets priority + set_eeprom_network_config(); + return 0; + } + + log_info("eeprom", "Building default EEPROM file"); + + memset(EEPROM_DATA, 0xff, sizeof EEPROM_DATA); + + AM_SYSDATAwH_STATIC Static = { + .m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8), + .m_Rental = MiceConfig.sysconf.rental, + }; + strcpy_s(Static.m_strSerialId, sizeof Static.m_strSerialId, MiceConfig.sysconf.serial); + fix_crc(Static); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_STATIC_REG], &Static, sizeof Static); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_STATIC_DUP], &Static, sizeof Static); + + AM_SYSDATAwH_CREDIT Credit = { 0 }; + fix_crc(Credit); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_CREDIT_REG], &Credit, sizeof Credit); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_CREDIT_DUP], &Credit, sizeof Credit); + + set_eeprom_network_config(); + + AM_SYSDATAwH_HISTORY History = { 0 }; + // TODO: Game ID here should be configurable. + History.m_GameId[0] = 'S'; + History.m_GameId[1] = 'D'; + History.m_GameId[2] = 'E'; + History.m_GameId[3] = 'Y'; + History.m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8); + fix_crc(History); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_REG], &History, sizeof History); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_DUP], &History, sizeof History); + AM_SYSDATAwH_ALPB_CARD_ID CardInfo = { 0 }; + fix_crc(CardInfo); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_CARD_ID_REG] + (sizeof History), &CardInfo, + sizeof CardInfo); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_CARD_ID_DUP] + (sizeof History), &CardInfo, + sizeof CardInfo); + + AM_SYSDATAwH_ALPB_COMPUTER_NAME CompuerName = { 0 }; + fix_crc(CompuerName); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_COMPUTER_NAME_REG], &CompuerName, sizeof CompuerName); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_COMPUTER_NAME_DUP], &CompuerName, sizeof CompuerName); + + AM_SYSDATAwH_ALPB_DEV_CONFIG DevConfig = { 0 }; + fix_crc(DevConfig); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_DEV_CONFIG_REG], &DevConfig, sizeof DevConfig); + memcpy(&EEPROM_DATA[AM_SYSDATAwH_ALPB_DEV_CONFIG_DUP], &DevConfig, sizeof DevConfig); + + eeprom_dump(); + return 1; +} + +void eeprom_read(WORD addr, BYTE* data, BYTE length) { + if (!build_eeprom()) eeprom_restore(); + + if (addr >= sizeof EEPROM_DATA) return; + if (length + addr > sizeof EEPROM_DATA) length = (sizeof EEPROM_DATA - addr) & 0xff; + + memcpy(data, &EEPROM_DATA[addr], length); +} +void eeprom_write(WORD addr, BYTE* data, BYTE length) { + if (!build_eeprom()) eeprom_restore(); + + if (addr >= sizeof EEPROM_DATA) return; + if (length + addr > sizeof EEPROM_DATA) length = (sizeof EEPROM_DATA - addr) & 0xff; + + memcpy(&EEPROM_DATA[addr], data, length); + eeprom_dump(); +} + +BOOL smbus_AT24C64AN_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + switch (cmd) { + case ICH9_CMD_BLOCK: { + log_misc("eeprom", "write %d bytes at 0x%03x", dlen, code); + eeprom_write(code, data, dlen); + return TRUE; + } + default: + log_error("eeprom", "Unsupported write mode: %01x, %02x", cmd, code); + return FALSE; + } +} + +BOOL smbus_AT24C64AN_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + switch (cmd) { + case ICH9_CMD_BYTE: + data[0] = 0x00; + return TRUE; + case ICH9_CMD_BLOCK: { + log_misc("eeprom", "read %d bytes at 0x%03x", dlen, code); + eeprom_read(code, data, dlen); + return TRUE; + } + default: + log_error("eeprom", "Unsupported read mode: %01x, %02x", cmd, code); + return FALSE; + } +} diff --git a/src/micetools/dll/devices/smb_ds.c b/src/micetools/dll/devices/smb_ds.c new file mode 100644 index 0000000..4f0e823 --- /dev/null +++ b/src/micetools/dll/devices/smb_ds.c @@ -0,0 +1,85 @@ +#include "_devices.h" + +/** + * TODO: This whole device, properly + */ + +BOOL smbus_DS_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + static unsigned char challenge[7]; + + switch (cmd) { + case ICH9_CMD_BLOCK: { + switch (code) { + case 0xa9d0: + case 0xa9d1: + case 0xa9d2: + case 0xa9d3: { + if (dlen != 7) { + log_error("smb-ds", "Expected challenge length of 7 (saw %d)!", dlen); + return FALSE; + } + + memcpy(challenge, &(data[2]), 7); + + char* challenge_s = malloc(dlen * 3 + 1); + if (challenge_s == NULL) { + log_info("smb-ds", "Challenge: (buffer failed)"); + return TRUE; + } + + for (int i = 0; i < dlen; i++) { + sprintf_s(challenge_s + i * 3, 4, "%02x ", data[2 + i]); + } + challenge_s[dlen * 3 + 1] = '\0'; + log_info("smb-ds", "Challenge: %s", challenge_s); + free(challenge_s); + return TRUE; + } + default: + log_error("smb-ds", "Unknown write command: %04x", code); + } + } + case ICH9_CMD_I2C_READ: { + switch (code) { + case DS_I2C_CHALLENGE_RESPONSE: + // This just has to match EXIO! + for (int i = 0; i < dlen; i++) data[i] = 0x69; + return TRUE; + default: + log_error("smb-ds", "Unknown I2C read command: %04x", code); + } + } + default: + log_error("smb-ds", "Unsupported write mode: %01x (%04x)", cmd, code); + return FALSE; + } +} + +BOOL smbus_DS_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + static unsigned char DS_eeprom[3][0x20]; + + switch (cmd) { + case ICH9_CMD_BYTE_DATA: + if (code < 0x80) { + BYTE page = (code >> 5) & 0b11; + BYTE offset = code & 0x1f; + + data[0] = DS_eeprom[page][offset]; + + return TRUE; + } else if (code >= DS_GET_UNIQUE_NUMBER && code < DS_GET_UNIQUE_NUMBER + 0xf) { + data[0] = 0x04; // chosen by fair dice roll. + return TRUE; + } else if (code == DS_GET_STATUS) { + // Polled until DS_STATUS_FLAG_BUSY low + data[0] = 0x00; + return TRUE; + } else { + log_error("smb-ds", "Unknown read command: %04x", code); + return FALSE; + } + default: + log_error("smb-ds", "Unsupported read mode: %01x (%04x)", cmd, code); + return FALSE; + } +} diff --git a/src/micetools/dll/devices/smb_exio.c b/src/micetools/dll/devices/smb_exio.c new file mode 100644 index 0000000..c43a3d4 --- /dev/null +++ b/src/micetools/dll/devices/smb_exio.c @@ -0,0 +1,53 @@ +#include "_devices.h" + +BOOL smbus_EXIO_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + switch (cmd) { + case ICH9_CMD_BYTE_DATA: + switch (code) { + case 0x5c: + if (data[0] == 0x94) return TRUE; + default: + log_error("smb-exio", "Unknown write command: %02x", code); + return FALSE; + } + case ICH9_CMD_BLOCK: { + WORD reg = *(WORD*)(&data[-1]); + dlen = data[1]; + + // char* data_s = malloc(dlen * 3 + 1); + // for (int i = 0; i < dlen; i++) { + // sprintf_s(data_s + i * 3, 3, "%02x ", data[2 + i]); + // } + // data_s[dlen * 3 + 1] = '\0'; + + log_info("smb-exio", "Block write, %d @ %04x: ", dlen, reg); + // free(data_s); + return TRUE; + } + + default: + log_error("smb-exio", "Unsupported write mode: %01x (%02x)", cmd, code); + return FALSE; + } +} + +BOOL smbus_EXIO_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + switch (cmd) { + case ICH9_CMD_BYTE_DATA: + if (0x40 <= code < 0x40 + 0x14) { + // mxkDsExioReadMacOutputBuffer + // This just has to match N2_I2C_CHALLENGE_RESPONSE! + data[0] = 0x69; + return TRUE; + } else if (code == EXIO_GET_BUSY) { + data[0] = 0x00; // Anything non-zero = busy + return TRUE; + } else { + log_error("smx-exio", "Unknown read command: %02x", code); + return FALSE; + } + default: + log_error("smb-exio", "Unsupported read mode: %01x (%02x)", cmd, code); + return FALSE; + } +} diff --git a/src/micetools/dll/devices/smb_n2.c b/src/micetools/dll/devices/smb_n2.c new file mode 100644 index 0000000..824ed8d --- /dev/null +++ b/src/micetools/dll/devices/smb_n2.c @@ -0,0 +1,421 @@ +#include +#include +#include + +#include "../../lib/mxk/mxk.h" +#include "_devices.h" + +#define N2_TAG_OFFSET 0 +#define N2_PARAMSIZE_OFFSET 2 +#define N2_COMMAND_OFFSET 4 +#define N2_TAG_SIZE 2 +#define N2_PARAMSIZE_SIZE 2 +#define N2_COMMAND_SIZE 2 +#define N2_CHECKSUM_SIZE 20 +#define N2_AUTH_SIZE 20 +#define N2_HEADER_SIZE (N2_TAG_SIZE + N2_PARAMSIZE_SIZE + N2_COMMAND_SIZE) + +#define N2_TAG_RQU_COMMAND 0xC1 +#define N2_TAG_RQU_AUTH_COMMAND 0xC2 +#define N2_TAG_RSP_COMMAND 0xC3 +#define N2_TAG_RSP_AUTH_COMMAND 0xC4 +// TODO: Uncomment these if actually used, and adjust lazy +2 logic alongside +// #define N2_TAG_RQU_RSA_COMMAND 0xC5 +// #define N2_TAG_RSP_RSA_COMMAND 0xC6 + +#define N2_ORD_ENABLE_SESSION 1 +#define N2_ORD_DISABLE_SESSION 2 +#define N2_ORD_SET_AUTH_KEY 3 +#define N2_ORD_SET_ENC_KEY 4 +// GAP! +#define N2_ORD_GET_AUTH_LEVEL 9 +// GAP! +#define N2_ORD_GET_ERROR_CODE 11 +#define N2_ORD_GET_VERSION 12 +// GAP! (-> keychip info write?) +#define N2_ORD_READ_KEYCHIP_ID 14 +// GAP! (-> gkey write?) +#define N2_ORD_ENCRYPT_WITH_GKEY 16 // keychip.encrypt +#define N2_ORD_DECRYPT_WITH_GKEY 17 // keychip.decrypt +#define N2_ORD_ADD_PLAY_COUNT 18 +#define N2_ORD_READ_PLAY_COUNT 19 +// GAP! (-> storage? is that still on pic?) +#define N2_ORD_GET_RANDOM_VALUE 24 +#define N2_ORD_ENCRYPT_WITH_SKEY 25 // keychip.ssd.hostproof +#define N2_ORD_DECRYPT_WITH_SKEY 26 + +#define N2_SUCCESS 0 +#define N2_INVALID_AUTH 1 +#define N2_AUTHFAIL 2 +#define N2_LV_ERROR 3 +#define N2_BAD_PARAMETER 4 +#define N2_EEP_WRITEFAIL 5 +#define N2_BAD_TAG 6 +#define N2_BAD_ORDINAL 7 +#define N2_SUMFAIL 8 +#define N2_EEPWRITE_DISABLE 9 +#define N2_BAD_DATASIZE 10 +#define N2_FAIL 11 + +#define N2_IO_BUFFER 0x1000 + +BYTE n2_in_buffer[N2_IO_BUFFER]; +WORD n2_in_pointer = 0; +BYTE n2_out_buffer[N2_IO_BUFFER]; +WORD n2_out_pointer = 0; + +WORD n2_error_code = 0; + +BYTE n2_auth_key[20] = { 0x96, 0xed, 0x31, 0xb2, 0x28, 0x71, 0x05, 0xa5, 0xa3, 0x30, + 0x54, 0x0f, 0x25, 0xbe, 0xd8, 0x51, 0xa5, 0xc8, 0x36, 0x21 }; + +BYTE n2_session_nonce[20]; +struct { + BYTE key[16]; + BYTE iv[16]; +} n2_enc_key = { + .key = { 0x76, 0xec, 0x42, 0xb6, 0xae, 0x0c, 0xb0, 0x48, 0x10, 0x51, 0x71, 0xad, 0x8c, 0xb2, + 0xfb, 0x07 }, + .iv = { 0x8e, 0x30, 0x0b, 0xa4, 0x2e, 0x15, 0x4b, 0xaf, 0x65, 0x15, 0x32, 0xf5, 0x70, 0x04, + 0x1f, 0x5b }, +}; + +#define fix_endian(x) (((x & 0xff00) >> 8) | (((x)&0xff) << 8)) + +typedef struct { + WORD tag; + WORD paramSize; + WORD (*handler)(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut); +} n2_command; + +#pragma pack(push, 1) +typedef struct { + DWORD m_Crc; + BYTE Rsv04[12]; + char m_KeyId[16]; + struct { + DWORD m_Crc; + DWORD m_Format; + char m_GameId[4]; + BYTE m_Region; + BYTE m_ModelType; + BYTE m_SystemFlag; + BYTE Rsv0f; + // + char m_PlatformId[3]; + BYTE m_DvdFlag; + DWORD m_NetworkAddr; + BYTE Unk00[88]; + BYTE m_Seed[16]; + } m_Appboot; +} N2_KEYCHIP_INFO, *PN2_KEYCHIP_INFO; +#pragma pack(pop) + +N2_KEYCHIP_INFO n2_keychip_info = { + .m_KeyId = { 'A', '7', '2', 'E', '-', '0', '2', 'D', '1', '1', '2', '6', '1', '1', '1', '6' }, + .m_Appboot = { + .m_Format = 1, + .m_GameId = { 'S' , 'D', 'E', 'Y' }, + .m_Region = 0xff, + .m_ModelType = 2, + .m_SystemFlag = 0x24, + .m_PlatformId = {'A', 'A', 'S'}, + .m_DvdFlag = 1, + .m_NetworkAddr = (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24), + } +}; + +WORD n2_enable_session(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 20; + + RAND_bytes(n2_session_nonce, sizeof n2_session_nonce); + memcpy(dataOut, n2_session_nonce, sizeof n2_session_nonce); + + log_misc("smb-n2", "Session open"); + return N2_SUCCESS; +} +WORD n2_set_auth_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 0; + log_misc("smb-n2", "Auth key set"); + + BYTE pt[32]; + mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn, pt, sizeof pt); + memcpy(n2_auth_key, pt, sizeof n2_auth_key); + + return N2_SUCCESS; +} +WORD n2_set_enc_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 0; + log_misc("smb-n2", "Enc key set"); + + BYTE pt[32]; + mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn, pt, sizeof pt); + memcpy(n2_enc_key.key, pt, sizeof n2_enc_key.key); + memcpy(n2_enc_key.iv, pt + sizeof n2_enc_key.key, sizeof n2_enc_key.iv); + + return N2_SUCCESS; +} +WORD n2_get_auth_level(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 1; + dataOut[0] = 3; // TODO: ? + log_misc("smb-n2", "Auth level get"); + return N2_SUCCESS; +} +WORD n2_get_error_code(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 2; + ((PWORD)dataOut)[0] = fix_endian(n2_error_code); + log_misc("smb-n2", "Error get"); + return N2_SUCCESS; +} +WORD n2_read_keychip_id(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + DWORD nbytes = (dataIn[0] << 24) | (dataIn[1] << 16) | (dataIn[2] << 8) | dataIn[3]; + + *nOut = (nbytes & 0xff) + 2; + + n2_keychip_info.m_Appboot.m_Crc = amCrc32RGet(sizeof n2_keychip_info.m_Appboot - 4, (LPBYTE)&n2_keychip_info.m_Appboot + 4, 0); + n2_keychip_info.m_Crc = amCrc32RGet(sizeof n2_keychip_info - 4, (LPBYTE)&n2_keychip_info + 4, 0); + + mxkCryptEncryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataOut + 2, (LPBYTE)&n2_keychip_info, nbytes); + + log_misc("smb-n2", "Read keychip ID: %08x", nbytes); + return N2_SUCCESS; +} +WORD n2_get_version(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 2; + dataOut[0] = 0x01; + dataOut[1] = 0x04; + return N2_SUCCESS; +} + +WORD n2_encrypt_with_gkey(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 16; + BYTE temp[16]; + mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn + 1, temp, sizeof temp); + + for(size_t i=0;i<17;i++)printf(" %02x",dataIn[i]); + puts(""); + for(size_t i=0;i<17;i++)printf(" %02x",temp[i]); + puts(""); + + // Do Gkey encryption + + mxkCryptEncryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataOut, temp, sizeof temp); + return N2_SUCCESS; +} +WORD n2_decrypt_with_gkey(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 16; + BYTE temp[16]; + mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn + 1, temp, sizeof temp); + + // Do Gkey decryption + + mxkCryptEncryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataOut, temp, sizeof temp); + return N2_SUCCESS; +} +WORD n2_add_play_count(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 0; + return N2_SUCCESS; +} +WORD n2_read_play_count(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 4; + return N2_SUCCESS; +} +WORD n2_get_random_value(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 16; + RAND_bytes(dataOut, 16); + return N2_SUCCESS; +} +WORD n2_encrypt_with_skey(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 16; + BYTE temp[16]; + mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn + 1, temp, sizeof temp); + + // Do Skey encryption + + mxkCryptEncryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataOut, temp, sizeof temp); + return N2_SUCCESS; +} +WORD n2_decrypt_with_skey(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { + *nOut = 16; + BYTE temp[16]; + mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn + 1, temp, sizeof temp); + + // Do Skey decryption + + mxkCryptEncryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataOut, temp, sizeof temp); + return N2_SUCCESS; +} + + +n2_command N2_COMMANDS[0xff]; +#define N2_INSTALL_COMMAND(ord, tag_, paramSize_, handler_) \ + do { \ + N2_COMMANDS[ord].tag = (tag_); \ + N2_COMMANDS[ord].paramSize = (paramSize_); \ + N2_COMMANDS[ord].handler = &(handler_); \ + } while (0) + +void n2_install_commands() { + static bool installed = false; + if (installed) return; + installed = true; + + ZeroMemory(N2_COMMANDS, sizeof N2_COMMANDS); + N2_INSTALL_COMMAND(N2_ORD_ENABLE_SESSION, N2_TAG_RQU_COMMAND, 0, n2_enable_session); + + N2_INSTALL_COMMAND(N2_ORD_SET_AUTH_KEY, N2_TAG_RQU_AUTH_COMMAND, 32, n2_set_auth_key); + N2_INSTALL_COMMAND(N2_ORD_SET_ENC_KEY, N2_TAG_RQU_AUTH_COMMAND, 32, n2_set_enc_key); + + N2_INSTALL_COMMAND(N2_ORD_GET_AUTH_LEVEL, N2_TAG_RQU_COMMAND, 0, n2_get_auth_level); + + N2_INSTALL_COMMAND(N2_ORD_GET_ERROR_CODE, N2_TAG_RQU_COMMAND, 0, n2_get_error_code); + N2_INSTALL_COMMAND(N2_ORD_GET_VERSION, N2_TAG_RQU_COMMAND, 0, n2_get_version); + + N2_INSTALL_COMMAND(N2_ORD_READ_KEYCHIP_ID, N2_TAG_RQU_AUTH_COMMAND, 4, n2_read_keychip_id); + + N2_INSTALL_COMMAND(N2_ORD_ENCRYPT_WITH_GKEY, N2_TAG_RQU_AUTH_COMMAND, 17, n2_encrypt_with_gkey); + N2_INSTALL_COMMAND(N2_ORD_DECRYPT_WITH_GKEY, N2_TAG_RQU_AUTH_COMMAND, 17, n2_decrypt_with_gkey); + N2_INSTALL_COMMAND(N2_ORD_ADD_PLAY_COUNT, N2_TAG_RQU_AUTH_COMMAND, 1, n2_add_play_count); + N2_INSTALL_COMMAND(N2_ORD_READ_PLAY_COUNT, N2_TAG_RQU_AUTH_COMMAND, 0, n2_read_play_count); + + N2_INSTALL_COMMAND(N2_ORD_GET_RANDOM_VALUE, N2_TAG_RQU_AUTH_COMMAND, 0, n2_get_random_value); + N2_INSTALL_COMMAND(N2_ORD_ENCRYPT_WITH_SKEY, N2_TAG_RQU_AUTH_COMMAND, 17, n2_encrypt_with_skey); + N2_INSTALL_COMMAND(N2_ORD_DECRYPT_WITH_SKEY, N2_TAG_RQU_AUTH_COMMAND, 17, n2_decrypt_with_skey); +} + +void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) { + n2_install_commands(); + + log_info("smb-n2", "Processing command: %04x/%04x (%d bytes)", tag, command, paramSize); + + ZeroMemory(n2_out_buffer, sizeof n2_out_buffer); + + // We nede to sign with the old key, so need a copy + BYTE auth_key[20]; + memcpy(auth_key, n2_auth_key, sizeof auth_key); + + WORD result = N2_SUCCESS; + WORD bodyLength = 0; + + WORD expectedExtraData = N2_CHECKSUM_SIZE + N2_HEADER_SIZE; + if (tag == N2_TAG_RQU_AUTH_COMMAND) expectedExtraData += N2_AUTH_SIZE; + + n2_command handler = N2_COMMANDS[command & 0xff]; + if (handler.handler == NULL) { + result = N2_BAD_ORDINAL; + } else if (handler.tag != tag) { + result = N2_BAD_TAG; + } else if (handler.paramSize + expectedExtraData != paramSize) { + result = N2_BAD_DATASIZE; + } else { + result = (*handler.handler)(paramSize, n2_in_buffer + N2_HEADER_SIZE, + n2_out_buffer + N2_HEADER_SIZE, &bodyLength); + } + + WORD paramSizeOut = bodyLength + expectedExtraData; + ((PWORD)n2_out_buffer)[0] = fix_endian(tag + 2); + ((PWORD)n2_out_buffer)[1] = fix_endian(paramSizeOut); + ((PWORD)n2_out_buffer)[2] = fix_endian(result); + + EVP_MD_CTX* ctx; + unsigned int outlen; + + WORD fixed_command = fix_endian(command); + + // Calculate a SHA1 of the packet, and append it + ctx = EVP_MD_CTX_create(); + EVP_DigestInit(ctx, EVP_sha1()); + EVP_DigestUpdate(ctx, n2_out_buffer, N2_HEADER_SIZE); + EVP_DigestUpdate(ctx, &fixed_command, 2); + EVP_DigestUpdate(ctx, n2_out_buffer + N2_HEADER_SIZE, bodyLength); + EVP_DigestFinal_ex(ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength, &outlen); + EVP_MD_CTX_destroy(ctx); + + if (tag == N2_TAG_RQU_AUTH_COMMAND) { + BYTE crypto_buffer[N2_CHECKSUM_SIZE]; + + // Calculate a new SHA1 of the packet, including the SHA1 we just appeneded + ctx = EVP_MD_CTX_create(); + EVP_DigestInit(ctx, EVP_sha1()); + EVP_DigestUpdate(ctx, n2_out_buffer, N2_HEADER_SIZE); + EVP_DigestUpdate(ctx, &fixed_command, 2); + EVP_DigestUpdate(ctx, n2_out_buffer + N2_HEADER_SIZE, bodyLength); + EVP_DigestFinal_ex(ctx, crypto_buffer, &outlen); + EVP_MD_CTX_destroy(ctx); + + // Calculate an HMAC, and append it + HMAC_CTX hmac_ctx; + HMAC_CTX_init(&hmac_ctx); + HMAC_Init_ex(&hmac_ctx, auth_key, sizeof auth_key, EVP_sha1(), NULL); + + // SHA1(header | data) + HMAC_Update(&hmac_ctx, crypto_buffer, sizeof crypto_buffer); + // SHA1(header | auth | packet)) + HMAC_Update(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE); + // Request nonce + HMAC_Update(&hmac_ctx, n2_in_buffer + paramSize - N2_AUTH_SIZE - N2_CHECKSUM_SIZE, + N2_CHECKSUM_SIZE); + + HMAC_Final(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength + N2_CHECKSUM_SIZE, + &outlen); + HMAC_CTX_cleanup(&hmac_ctx); + } +} + +BOOL smbus_N2_write(ich9_cmd_t cmd, WORD code, BYTE nbytes, LPBYTE data) { + static WORD tag; + static WORD paramsize = 0xffff; + static WORD command; + + switch (cmd) { + case ICH9_CMD_BLOCK: { + switch (code >> 8) { + case 0xcc: { + // One extra byte of data is stuffed into the command code + n2_in_buffer[n2_in_pointer++] = code & 0xff; + memcpy(n2_in_buffer + n2_in_pointer, data, nbytes); + n2_in_pointer += nbytes; + + if (paramsize == 0xffff && + n2_in_pointer >= N2_PARAMSIZE_OFFSET + N2_PARAMSIZE_SIZE) { + paramsize = ((PWORD)(n2_in_buffer + N2_PARAMSIZE_OFFSET))[0]; + paramsize = fix_endian(paramsize); + } + + if (n2_in_pointer >= paramsize) { + tag = ((PWORD)(n2_in_buffer + N2_TAG_OFFSET))[0]; + tag = fix_endian(tag); + command = ((PWORD)(n2_in_buffer + N2_COMMAND_OFFSET))[0]; + command = fix_endian(command); + + do_n2_command(tag, paramsize, command, &n2_in_buffer[N2_HEADER_SIZE]); + paramsize = 0xffff; + n2_in_pointer = n2_out_pointer = 0; + } + + return TRUE; + } + } + log_error("smb-n2", "Unsupported command code: %04x (%d bytes)", code, nbytes); + return FALSE; + } + case ICH9_CMD_I2C_READ: { + switch (code) { + case 0xc3: { + memcpy(data, n2_out_buffer + n2_out_pointer, nbytes); + n2_out_pointer += nbytes; + return TRUE; + } + } + log_error("smb-n2", "Unsupported i2c command code: %04x (%d bytes)", code, nbytes); + return FALSE; + } + } + log_error("smb-n2", "Unsupported write mode: %01x (%02x)", cmd, code); + return FALSE; +} + +BOOL smbus_N2_read(ich9_cmd_t cmd, WORD code, BYTE nbytes, BYTE* data) { + log_error("smb-n2", "Unsupported read mode: %01x (%02x)", cmd, code); + return FALSE; +} diff --git a/src/micetools/dll/devices/smb_pca9535.c b/src/micetools/dll/devices/smb_pca9535.c new file mode 100644 index 0000000..3af1aa5 --- /dev/null +++ b/src/micetools/dll/devices/smb_pca9535.c @@ -0,0 +1,126 @@ +#include "_devices.h" + +uint16_t pca9535_config = 0xffff; + +BOOL smbus_PCA9535_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + switch (cmd) { + case ICH9_CMD_BYTE_DATA: + switch (code) { + case PCA9535_IN0: + log_error("pca9535", "Write PCA9535_IN0 unimplemented!"); + return FALSE; + case PCA9535_IN1: + log_error("pca9535", "Write PCA9535_IN1 unimplemented!"); + return FALSE; + case PCA9535_OUT0: + log_info("pca9535", "Out 0: %02x", data[0]); + return TRUE; + case PCA9535_OUT1: + log_info("pca9535", "Out 1: %02x", data[0]); + return TRUE; + case PCA9535_INV0: + log_info("pca9535", "Inv 0: %02x", data[0]); + return TRUE; + case PCA9535_INV1: + log_info("pca9535", "Inv 1: %02x", data[0]); + return TRUE; + case PCA9535_CONF0: + log_info("pca9535", "Conf 0: %02x", data[0]); + pca9535_config = (data[0] << 8) | (pca9535_config & 0xff); + return TRUE; + case PCA9535_CONF1: + log_info("pca9535", "Conf 1: %02x", data[0]); + pca9535_config = data[0] | (pca9535_config & 0xff00); + return TRUE; + default: + log_error("pca9535", "Unknown write command: %02x", code); + return FALSE; + } + default: + log_error("pca9535", "Unsupported write mode: %01x (%02x)", cmd, code); + return FALSE; + } +} + +#define DIPSW_PORTRAIT 0b0000'0'000 +#define DIPSW_LANDSCAPE 0b0000'1'000 + +#define DIPSW_RES_1920x1080 0b0'111'0000 +#define DIPSW_RES_1360x768 0b0'110'0000 +#define DIPSW_RES_1280x1024 0b0'101'0000 +#define DIPSW_RES_1280x720 0b0'100'0000 +#define DIPSW_RES_1024x768 0b0'011'0000 +#define DIPSW_RES_1024x600 0b0'010'0000 +#define DIPSW_RES_640x480 0b0'001'0000 +#define DIPSW_RES_DEFAULT 0b0'000'0000 + +BOOL smbus_PCA9535_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { + switch (cmd) { + case ICH9_CMD_BYTE_DATA: + switch (code) { + case PCA9535_IN0: // DIPSW + /* + 0: ? + 1: ? + 2: ? + 3: Orientation + 4: / \ + 5: | Resolution | + 6: \ / + 7: game specific + + 0b00001000 = landscape + */ + // data[0] = 0b00001000; + // data[0] = 0b0'111'0'000; + + data[0] = DIPSW_LANDSCAPE | DIPSW_RES_DEFAULT; + + return TRUE; + case PCA9535_IN1: // SW1/2 + extras + /* + 0: unk + 1: unk + 2: ¬test + 3: ¬service + 4: unk + 5: unk + 6: unk + 7: unk + */ + byte dip = 0x00; + if (GetAsyncKeyState('T') >= 0) { + dip |= 0x04; + } + if (GetAsyncKeyState('S') >= 0) { + dip |= 0x08; + } + data[0] = dip; + return TRUE; + case PCA9535_OUT0: + log_error("pca9535", "Read PCA9535_OUT0 unimplemented!"); + return FALSE; + case PCA9535_OUT1: + data[0] = 0x00; + return TRUE; + case PCA9535_INV0: + data[0] = 0x00; + return TRUE; + case PCA9535_INV1: + data[0] = 0x00; + return TRUE; + case PCA9535_CONF0: + data[0] = pca9535_config >> 8; + return TRUE; + case PCA9535_CONF1: + data[0] = pca9535_config & 0xff; + return TRUE; + default: + log_error("pca9535", "Unknown read command: %02x", code); + return FALSE; + } + default: + log_error("pca9535", "Unsupported read mode: %01x (%02x)", cmd, code); + return FALSE; + } +} diff --git a/src/micetools/dll/dllmain.c b/src/micetools/dll/dllmain.c index 04b2cc5..9c872dd 100644 --- a/src/micetools/dll/dllmain.c +++ b/src/micetools/dll/dllmain.c @@ -4,46 +4,85 @@ #include "hooks/_hooks.h" WCHAR exePath[MAX_PATH + 1]; +DWORD imageOffset; + +#define WIN32_EXE_BASE 0x00400000 + +DWORD GetImageBase(LPCWSTR sModulePath) { + HANDLE hObject = + _CreateFileW(sModulePath, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hObject == INVALID_HANDLE_VALUE) return 0; + + IMAGE_DOS_HEADER dosHeader = { 0 }; + DWORD nRead; + _SetFilePointer(hObject, 0, NULL, FILE_BEGIN); + _ReadFile(hObject, &dosHeader, sizeof dosHeader, &nRead, NULL); + if (nRead != sizeof dosHeader) { + log_error(BOOT_LOGGER, "Failed to read DOS header %03x", GetLastError()); + return 0; + } + if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) { + log_error(BOOT_LOGGER, "Invalid DOS magic number: %04x", dosHeader.e_magic); + return 0; + } + + IMAGE_NT_HEADERS32 ntHeaders32 = { 0 }; + _SetFilePointer(hObject, dosHeader.e_lfanew, NULL, FILE_BEGIN); + _ReadFile(hObject, &ntHeaders32, sizeof ntHeaders32, &nRead, NULL); + if (nRead != sizeof ntHeaders32) { + log_error(BOOT_LOGGER, "Failed to read NT header %03x", GetLastError()); + return 0; + } + if (ntHeaders32.Signature != IMAGE_NT_SIGNATURE) { + log_error(BOOT_LOGGER, "Invalid NT signature: %08x", ntHeaders32.Signature); + return 0; + } + + _CloseHandle(hObject); + return ntHeaders32.OptionalHeader.ImageBase; +} + +void apply_patches(HMODULE hModule) { + void* baseAddress = (void*)hModule; + + DWORD imageBase = GetImageBase(exePath); + if (imageBase == 0) { + log_error(BOOT_LOGGER, "Failed to locate image base. Patches will not be applied."); + return; + } + imageOffset = (DWORD)hModule - imageBase; -void apply_patches() { char exePathC[MAX_PATH + 1]; WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL); - patches_t patches; - char error[256]; - if (!load_patches(&patches, MiceConfig.mice.patches_file, error, exePathC)) { - log_error(BOOT_LOGGER, "Failed to load patches file: %s", error); + if (!load_patches(MiceConfig.mice.patches_file, exePathC)) { + log_error(BOOT_LOGGER, "Failed to load patches file %s", MiceConfig.mice.patches_file); return; } - for (size_t i = 0; i < patches.nopatchsets; i++) { - patchset_t* patchset = patches.patchsets[i]; + patch_t* patch = patch_list->next; + if (patch == NULL) { + log_warning(BOOT_LOGGER, "No patches to apply. Did you forgot an amiDebug patch file?"); + } + while (patch) { + DWORD oldProt; + VirtualProtect((void*)((DWORD)patch->address + imageOffset), patch->count, + PAGE_EXECUTE_READWRITE, &oldProt); - // Require the binary explicitly named - if (patchset->binary_name == NULL || strcmp(patchset->binary_name, exePathC) != 0) { + if (memcmp(patch->match, (void*)((DWORD)patch->address + imageOffset), patch->count) != 0) { + log_error(BOOT_LOGGER, "Patch %s failed! from-value missmatch", patch->name); + VirtualProtect((void*)((DWORD)patch->address + imageOffset), patch->count, oldProt, + &oldProt); + patch = patch->next; continue; } - if (!patchset->apply) continue; - for (size_t j = 0; j < patchset->nopatches; j++) { - patch_t patch = patchset->patches[j]; + memcpy((void*)((DWORD)patch->address + imageOffset), patch->replace, patch->count); + log_misc(BOOT_LOGGER, "Patched %d bytes at %08x (%s)", patch->count, patch->address, + patch->name); - DWORD oldProt; - VirtualProtect((void*)patch.offset, patch.count, PAGE_EXECUTE_READWRITE, &oldProt); - - if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) { - log_error(BOOT_LOGGER, "Patch %s[%d] failed! from-value missmatch", patchset->name, - j); - VirtualProtect((void*)patch.offset, patch.count, oldProt, &oldProt); - continue; - } - - memcpy((void*)patch.offset, patch.to, patch.count); - log_misc(BOOT_LOGGER, "Patched %d bytes at %08x", patch.count, patch.offset); - VirtualProtect((void*)patch.offset, patch.count, oldProt, &oldProt); - } + patch = patch->next; } - free_patches(&patches); } void prebind_hooks() { @@ -58,14 +97,17 @@ void prebind_hooks() { } } -void init_injection() { +void init_injection(HMODULE hModule) { + // Make sure our CRC32 tables are ready for anything that might want to use them + amCrc32RCreateTable(); + load_mice_config(); // We're in a new context now, so need to reconfigure setup_logging(); log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath); - if (MiceConfig.mice.apply_patches) apply_patches(); + if (MiceConfig.mice.apply_patches) apply_patches(hModule); // Columba: Driver-level memory access, used to read the DMI tables if (MiceConfig.drivers.columba) setup_columba(); @@ -106,12 +148,18 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv GetModuleFileNameW(NULL, exePath, MAX_PATH); wcscpy_s(exePath, MAX_PATH + 1, PathFindFileNameW(exePath)); - init_injection(); + HMODULE exeModule = GetModuleHandleA(NULL); + init_injection(exeModule); if (wcscmp(exePath, L"InitialD8_GLW_RE_SBZZ_dumped_.exe") == 0) { CreateHook((void*)(0x00407850), &tea_hook_test, 5); // *((DWORD*)(0x00407850)) = (DWORD)(&logcb); } + if (wcscmp(exePath, L"RingGame.exe") == 0) { + log_warning(BOOT_LOGGER, "Bodge hook goo!"); + CreateHook((void*)(0x005f2580), &tea_hook_test, 5); + } + return TRUE; } diff --git a/src/micetools/dll/drivers/columba.c b/src/micetools/dll/drivers/columba.c index 4d43b33..08e6a0b 100644 --- a/src/micetools/dll/drivers/columba.c +++ b/src/micetools/dll/drivers/columba.c @@ -1,36 +1,29 @@ +#include "../lib/am/amOemstring.h" #include "../lib/dmi/dmi.h" #include "mx.h" -// Much easier than pulling in winddk.h -typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; -typedef struct { - PHYSICAL_ADDRESS addr; - DWORD data_type; - DWORD bytes; -} columba_request; - #define DMI_HEADER_START 0x000f0000 #define DMI_TABLES_START 0x000f1000 -BOOL columba_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, - LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +BOOL WINAPI columba_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { case IOCTL_COLUMBA_READ: log_misc("columba", "DeviceIoControl(, , 0x%p, 0x%x, -, 0x%x, -, -)", lpInBuffer, nInBufferSize, nOutBufferSize); - columba_request* request = (columba_request*)lpInBuffer; - log_info("columba", "Physical read: 0x%04x %ss at %08X", request->bytes, - request->data_type == 1 ? "byte" - : request->data_type == 2 ? "short" - : request->data_type == 4 ? "long" - : "void", - request->addr); - DWORD requested_size = request->data_type * request->bytes; + AM_COLUMBA_REQUEST* request = (AM_COLUMBA_REQUEST*)lpInBuffer; + log_info("columba", "Physical read: 0x%04x %ss at %08X", request->m_elementCount, + request->m_elementSize == 1 ? "byte" + : request->m_elementSize == 2 ? "short" + : request->m_elementSize == 4 ? "long" + : "void", + request->m_physAddr.QuadPart); + DWORD requested_size = request->m_elementSize * request->m_elementCount; memset(lpOutBuffer, 0, nOutBufferSize); - if (request->addr.QuadPart == DMI_HEADER_START) { + if (request->m_physAddr.QuadPart == DMI_HEADER_START) { DMI_HEADER dmi = { .Signature = { '_', 'D', 'M', 'I', '_' }, .Checksum = 0, @@ -44,12 +37,12 @@ BOOL columba_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffe memcpy(lpOutBuffer, &dmi, sizeof(DMI_HEADER)); if (lpBytesReturned) *lpBytesReturned = requested_size; - } else if (request->addr.QuadPart == DMI_TABLES_START) { + } else if (request->m_physAddr.QuadPart == DMI_TABLES_START) { memcpy(lpOutBuffer, dmi_table, dmi_size); if (lpBytesReturned) *lpBytesReturned = 0x10000; } else { log_error("columba", "Request to unmapped memory location: %08x", - request->addr); + request->m_physAddr); return FALSE; } diff --git a/src/micetools/dll/drivers/mxhwreset.c b/src/micetools/dll/drivers/mxhwreset.c index bdc8e64..4de199b 100644 --- a/src/micetools/dll/drivers/mxhwreset.c +++ b/src/micetools/dll/drivers/mxhwreset.c @@ -1,6 +1,6 @@ #include "mx.h" -BOOL mxhwreset_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, +BOOL WINAPI mxhwreset_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { diff --git a/src/micetools/dll/drivers/mxjvs.c b/src/micetools/dll/drivers/mxjvs.c index 8e0c5c8..5b5c223 100644 --- a/src/micetools/dll/drivers/mxjvs.c +++ b/src/micetools/dll/drivers/mxjvs.c @@ -8,55 +8,44 @@ BOOL JVS_SENSE = false; BOOL coin_solenoid = false; BOOL test_btn = false; -// #define SCAN_COIN 0x70 -#define SCAN_TEST VK_OEM_4 // [{ -// 2 Players, 16 buttons each -int jvs_buttons[2][16] = { - { - 'C', // *1P3 - 'P', // NC - 'E', // *1P1 - 'D', // *1P2 - 'P', // NC - 'P', // NC - '1', // *1P Service - 'P', // NC - 'P', // -- - 'P', // -- - 'P', // -- - 'W', // *1P8 - 'Q', // *1P7 - 'A', // *1P6 - 'Z', // *1P5 - 'X', // *1P4 - }, - { - VK_OEM_PERIOD, // *2P3 - 'P', // NC - 'O', // *2P1 - 'L', // *2P2 - 'P', // NC - 'P', // NC - '2', // *2P Service - 'P', // NC - 'P', // -- - 'P', // -- - 'P', // -- - 'I', // *2P8 - 'U', // *2P7 - 'J', // *2P6 - 'M', // *2P5 - VK_OEM_COMMA, // *2P4 - }, -}; +#define PLAYER_COUNT 2 +#define COIN_COUNTERS 2 + +const char JVS_837_13551_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10"; + +typedef struct _jvs_board { + char test_keybind; + char coin_keybinds[COIN_COUNTERS]; + + char keybinds[PLAYER_COUNT][16]; + unsigned char flags[PLAYER_COUNT][16]; + + unsigned short coin_counts[COIN_COUNTERS]; + + unsigned char (*handler)(struct _jvs_board* board, unsigned char* inData, short inCount, + unsigned char* outData, unsigned char* outCount); + const char* id; + +} jvs_board_t; +#define JVS_FLAG_NONE 0 +#define JVS_FLAG_NC 1 +#define JVS_FLAG_INVERT 2 + +jvs_board_t (*jvs_config)[]; +size_t jvs_num_boards; + +// unsigned short coin_data[COIN_COUNTERS]; +// #define JVS_BUTTON_COIN_1 '1' +// #define JVS_BUTTON_COIN_2 '2' short jvs_unpad(unsigned char* paddedData, short length, unsigned char* unpaddedData) { short index = 0; bool escape = false; for (short i = 0; i < length; i++) { - if (escape) + if (escape) { unpaddedData[index++] = paddedData[i] + 1; - else if (paddedData[i] == JVS_MARK) + escape = false; + } else if (paddedData[i] == JVS_MARK) escape = true; else unpaddedData[index++] = paddedData[i]; @@ -80,80 +69,41 @@ short jvs_pad(unsigned char* unpaddedData, short length, unsigned char* paddedDa return index; } -const char JVS_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10"; +unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCount, + unsigned char* response, unsigned char* outCount) { + short jvsIndex = 0; + unsigned char respIndex = 0; -void mxjvs_exchange(unsigned char* paddedIn, short inCount, unsigned char* outData, short maxOut, - int* outCount) { - unsigned char* inData = malloc(inCount); - inCount = jvs_unpad(paddedIn, inCount, inData); - unsigned char* response = malloc(maxOut); - - unsigned char status = JVS_STATUS_OK; - - // JVS frame is 4 bytes in total - if (inCount < 4) { - log_error("mxjvs", "inCount impossibly small: %d", inCount); - status = JVS_STATUS_UNKNOWN; - goto jvs_exchange_error; - } - // This isn't a JVS packet - if (inData[0] != JVS_SYNC) { - log_error("mxjvs", "SYNC missing. Saw 0x%02x", inData[0]); - status = JVS_STATUS_UNKNOWN; - goto jvs_exchange_error; - } - - // Validate the checksum before proceeding - unsigned char sum = 0; - for (int i = 1; i < inCount - 1; i++) sum += inData[i]; - if (sum != inData[inCount - 1]) { - log_error("mxjvs", "Checksum failed. Computed 0x%02x, expected 0x%02x", sum, - inData[inCount - 1]); - status = JVS_STATUS_SUM; - goto jvs_exchange_error; - } - - unsigned char destination = inData[1]; - unsigned char length = inData[2]; - // length 0 is nonsensical because there's a checksum! - if (length == 0) { - status = JVS_STATUS_SUM; - goto jvs_exchange_error; - } - short jvsIndex = 3; // D0 - - response[0] = JVS_SYNC; - response[1] = JVS_NODE_MASTER; - short respIndex = 4; // D0 -#define jvs_read(x) \ - if (jvsIndex - 2 >= length) { \ - status = JVS_STATUS_OVERFLOW; \ - goto jvs_exchange_error; \ - } else { \ - (x) = inData[jvsIndex++]; \ +#define jvs_read(x) \ + if (jvsIndex >= inCount) { \ + return JVS_STATUS_OVERFLOW; \ + } else { \ + (x) = inData[jvsIndex++]; \ } #define jvs_write(x) response[respIndex++] = (x); - while (jvsIndex - 2 < length) { + static bool flipflop = false; + + while (jvsIndex < inCount) { unsigned char cmd; jvs_read(cmd); - // log_info("jvs", "jvs cmd: %02x", cmd); + + // log_info("mxjvs", "CMD: %02x", cmd); + switch (cmd) { case JVS_CMD_RESET: unsigned char reset_assert; jvs_read(reset_assert); - if (reset_assert != JVS_CMD_RESET_ASSERT) { - status = JVS_STATUS_UKCOM; - goto jvs_exchange_error; - } + if (reset_assert != JVS_CMD_RESET_ASSERT) return JVS_STATUS_UKCOM; + JVS_SENSE = true; // Special case *outCount = 0; - return; + return JVS_STATUS_OK; case JVS_CMD_CHANGE_COMMS: // Special case *outCount = 0; - return; + return JVS_STATUS_OK; case JVS_CMD_ASSIGN_ADDR: jvs_write(JVS_REPORT_OK); @@ -166,7 +116,7 @@ void mxjvs_exchange(unsigned char* paddedIn, short inCount, unsigned char* outDa case JVS_CMD_READ_ID: jvs_write(JVS_REPORT_OK); - for (int i = 0; i < sizeof JVS_ID; i++) jvs_write(JVS_ID[i]); + for (size_t i = 0; i < strlen(board->id); i++) jvs_write(board->id[i]); break; case JVS_CMD_GET_CMD_VERSION: jvs_write(JVS_REPORT_OK); @@ -185,11 +135,11 @@ void mxjvs_exchange(unsigned char* paddedIn, short inCount, unsigned char* outDa jvs_write(JVS_REPORT_OK); jvs_write(JVS_FEATURE_PLAYERS); - jvs_write(2); + jvs_write(PLAYER_COUNT); jvs_write(13); jvs_write(JVS_FEATURE_PAD); jvs_write(JVS_FEATURE_COINS); - jvs_write(2); + jvs_write(COIN_COUNTERS); jvs_write(JVS_FEATURE_PAD); jvs_write(JVS_FEATURE_PAD); jvs_write(JVS_FEATURE_ANALOG); @@ -215,43 +165,30 @@ void mxjvs_exchange(unsigned char* paddedIn, short inCount, unsigned char* outDa unsigned char switch_bytes; jvs_read(players); jvs_read(switch_bytes); - if (players > 2 || switch_bytes != 2) { + if (players > PLAYER_COUNT || switch_bytes != 2) { jvs_write(JVS_REPORT_PARAM_INVALID); break; } jvs_write(JVS_REPORT_OK); unsigned char buttons = 0x00; - if (GetAsyncKeyState(SCAN_TEST) < 0) buttons |= 0x80; + if (GetAsyncKeyState(board->test_keybind) < 0) buttons |= 0x80; jvs_write(buttons); - for (int i = 0; i < players; i++) { + for (int player = 0; player < players; player++) { for (int j = 0; j < switch_bytes; j++) { buttons = 0x00; for (int bit = 0; bit < 8; bit++) { - int scancode = jvs_buttons[i][j * 8 + bit]; + int scancode = + board->keybinds[player][(switch_bytes - j - 1) * 8 + bit]; + unsigned char flags = + board->flags[player][(switch_bytes - j - 1) * 8 + bit]; - // Buttons on maimai use beam interrupt sensors, so logical high = - // unpressed. - bool invert = ((j == 0 && (bit == 0 || bit == 2 || bit == 3)) || - (j == 1 && bit >= 3)); - - if (invert) + if (flags & JVS_FLAG_NC) continue; + if (flags & JVS_FLAG_INVERT) buttons |= (GetAsyncKeyState(scancode) >= 0) << bit; else buttons |= (GetAsyncKeyState(scancode) < 0) << bit; - - // JAMMA does **NOT** do any of this lol - // Service is pull-down for some reason - // bool pulse = (j == 0) && (bit == 6); - // // JAMMA uses the falling edge of a pull-up switch - // if (pulse) { - // buttons |= (GetAsyncKeyState(scancode) >= 0) << bit; - // buttons |= (!(GetAsyncKeyState(scancode) & 1)) << bit; - // } else { - // buttons |= (GetAsyncKeyState(scancode) < 0) << bit; - // buttons |= (GetAsyncKeyState(scancode) & 1) << bit; - // } } jvs_write(buttons); } @@ -263,9 +200,15 @@ void mxjvs_exchange(unsigned char* paddedIn, short inCount, unsigned char* outDa jvs_write(JVS_REPORT_OK); unsigned char coin_count; jvs_read(coin_count); - for (; coin_count; coin_count--) { - jvs_write(0x00); // coin MSB - jvs_write(0x00); // coin LSB + + if (board->coin_keybinds[0] && GetAsyncKeyState(board->coin_keybinds[0]) & 1) + board->coin_counts[0]++; + if (board->coin_keybinds[1] && GetAsyncKeyState(board->coin_keybinds[1]) & 1) + board->coin_counts[1]++; + + for (unsigned char slot = 0; slot < coin_count; slot++) { + jvs_write(board->coin_counts[slot] >> 8); + jvs_write(board->coin_counts[slot] & 0xff); } break; @@ -300,44 +243,117 @@ void mxjvs_exchange(unsigned char* paddedIn, short inCount, unsigned char* outDa } break; + case JVS_CMD_COIN_DECREASE: + jvs_write(JVS_REPORT_OK); + + unsigned char slot; + jvs_read(slot); + unsigned char cAmount[2]; + jvs_read(cAmount[0]); + jvs_read(cAmount[1]); + unsigned short sAmount = cAmount[0] << 8 | cAmount[1]; + board->coin_counts[slot] -= sAmount; + break; + default: log_error("mxjvs", "Unknown command: 0x%02x", cmd); - - status = JVS_STATUS_UKCOM; - goto jvs_exchange_error; + return JVS_STATUS_UKCOM; } } #undef jvs_read #undef jvs_write - goto jvs_exchange_complete; -jvs_exchange_error: - log_error("mxjvs", "JVS status: 0x%02x", status); - respIndex = 4; // As if we've just written status, but nothing else - -jvs_exchange_complete: - response[2] = (respIndex - 2) & 0xFF; // respIndex doesn't include SUM yet - response[3] = status; - - // Compute and set the checksum - sum = 0; - for (int i = 1; i < respIndex; i++) sum += response[i]; - response[respIndex++] = sum; - - short paddedLength = jvs_pad(response, respIndex, outData, maxOut); - // We failed hard. It's not worth sending an overflow response - if (paddedLength == -1) - *outCount = 0; - else - *outCount = 0x00000000 | paddedLength; - - free(response); - free(inData); + *outCount = respIndex; + return JVS_STATUS_OK; } -BOOL mxjvs_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, - LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +void jvs_send_status(unsigned char status, unsigned char* outData, LPDWORD outCount) { + short respIndex = 4; + + outData[0] = JVS_SYNC; + outData[1] = JVS_NODE_MASTER; + outData[2] = 2; + if (status == JVS_MARK || status == JVS_SYNC) { + outData[3] = JVS_MARK; + outData[4] = status - 1; + outData[5] = JVS_NODE_MASTER + 2 + status; + *outCount = 6; + } else { + outData[3] = status; + outData[4] = JVS_NODE_MASTER + 2 + status; + *outCount = 5; + } +} + +void mxjvs_handle(unsigned char* paddedIn, short inCount, unsigned char* outData, short maxOut, + LPDWORD outCount) { + *outCount = 0; + + unsigned char* inData = malloc(inCount); + inCount = jvs_unpad(paddedIn, inCount, inData); + + // JVS frame is 4 bytes in total + if (inCount < 4) { + log_error("mxjvs", "inCount impossibly small: %d", inCount); + jvs_send_status(JVS_STATUS_UNKNOWN, outData, outCount); + free(inData); + return; + } + // This isn't a JVS packet + if (inData[0] != JVS_SYNC) { + log_error("mxjvs", "SYNC missing. Saw 0x%02x", inData[0]); + jvs_send_status(JVS_STATUS_UNKNOWN, outData, outCount); + free(inData); + return; + } + + // Validate the checksum before proceeding + unsigned char sum = 0; + bool escape = false; + for (int i = 1; i < inCount - 1; i++) sum += inData[i]; + if (sum != inData[inCount - 1]) { + log_error("mxjvs", "Checksum failed. Computed 0x%02x, expected 0x%02x", sum, + inData[inCount - 1]); + jvs_send_status(JVS_STATUS_SUM, outData, outCount); + return; + } + + unsigned char destination = inData[1]; + if (destination == 0 || destination > jvs_num_boards) return; + + unsigned char* response = malloc(maxOut); + jvs_board_t* board = &(*jvs_config)[jvs_num_boards - destination]; + unsigned char packetSize; + unsigned char status = + board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize); + free(inData); + + if (status == JVS_STATUS_OK) { + if (packetSize == 0) return; + + response[0] = JVS_SYNC; + response[1] = JVS_NODE_MASTER; + response[2] = packetSize + 2; + response[3] = status; + + sum = 0; + for (int i = 1; i < packetSize + 4; i++) sum += response[i]; + response[packetSize + 4] = sum; + + short paddedLength = jvs_pad(response, packetSize + 5, outData, maxOut); + *outCount = (paddedLength == -1) ? 0 : paddedLength; + + free(response); + } else { + log_error("mxjvs", "JVS board %d returned status %d", destination, status); + free(response); + jvs_send_status(status, outData, outCount); + } +} + +BOOL WINAPI mxjvs_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { case IOCTL_MXJVS_EXCHANGE: log_trace("mxjvs", @@ -345,8 +361,8 @@ BOOL mxjvs_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, "0x%x, -, -)", lpInBuffer, nInBufferSize, nOutBufferSize); - mxjvs_exchange(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize & 0xFFFF, - (int*)lpBytesReturned); + mxjvs_handle(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize & 0xFFFF, + lpBytesReturned); break; default: @@ -375,11 +391,231 @@ BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) { return TRUE; } +jvs_board_t maimai_jvs_config[1] = { { + .test_keybind = VK_OEM_4, // [{ + .coin_keybinds = {'1', '2'}, + .keybinds = { + { + 0, + 0, + 0, + 'W', // *1P8 + 'Q', // *1P7 + 'A', // *1P6 + 'Z', // *1P5 + 'X', // *1P4 + 'C', // *1P3 + 0, + 'E', // *1P1 + 'D', // *1P2 + 0, + 0, + '1', // *1P Service + 0, + + }, + { + 0, + 0, + 0, + 'I', // *2P8 + 'U', // *2P7 + 'J', // *2P6 + 'M', // *2P5 + VK_OEM_COMMA, // *2P4 + VK_OEM_PERIOD, // *2P3 + 0, + 'O', // *2P1 + 'L', // *2P2 + 0, + 0, + '2', // *2P Service + 0, + + }, + }, + .flags = { + { + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_NC, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NONE, + JVS_FLAG_NC, + }, + { + + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_NC, + JVS_FLAG_INVERT, + JVS_FLAG_INVERT, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NONE, + JVS_FLAG_NC, + }, + }, + .coin_counts = {0, 0}, + .handler = &jvs_exchange, + .id = JVS_837_13551_ID, +} }; + +jvs_board_t under_night_jvs_config[2] = { + { + .test_keybind = VK_OEM_4, // [{ + .coin_keybinds = {'1', '2'}, + .keybinds = { + { + 0, 0, 0, 0, 0, 0, + 'A', // D (EXCs) + 'R', // C (Heavy) + 'E', // B (Middle) + 'W', // A (Light) + VK_RIGHT, // Right + VK_LEFT, // Left + VK_DOWN, // Down + VK_UP, // Up + VK_BACK, // Service + VK_RETURN, // Start + }, + { + 0 + }, + }, + .flags = { + { + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + }, + { + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + }, + }, + .coin_counts = {0, 0}, + .handler = &jvs_exchange, + .id = JVS_837_13551_ID, + }, + { + .test_keybind = VK_OEM_4, // [{ + .coin_keybinds = {0, 0}, + .keybinds = { + { + 0, 0, 0, 0, 0, 0, + 'J', // D (EXCs) + 'P', // C (Heavy) + 'O', // B (Middle) + 'I', // A (Light) + VK_NUMPAD6, // Right + VK_NUMPAD4, // Left + VK_NUMPAD2, // Down + VK_NUMPAD8, // Up + VK_BACK, // Service + VK_RETURN, // Start + }, + {0}, + }, + .flags = { + { + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + JVS_FLAG_NONE, + }, + { + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + JVS_FLAG_NC, + }, + }, + .coin_counts = {0, 0}, + .handler = &jvs_exchange, + .id = JVS_837_13551_ID, + }, +}; + +// jvs_board_t (*jvs_config)[] = &maimai_jvs_config; +// size_t jvs_num_boards = sizeof maimai_jvs_config / sizeof maimai_jvs_config[0]; +jvs_board_t (*jvs_config)[] = &under_night_jvs_config; +size_t jvs_num_boards = sizeof under_night_jvs_config / sizeof under_night_jvs_config[0]; + void setup_mxjvs() { file_hook_t* mxjvs = new_file_hook(L"\\\\.\\mxjvs"); mxjvs->DeviceIoControl = &mxjvs_DeviceIoControl; + hook_file(mxjvs); - com_hook_t* jvscom = new_com_hook(0); + com_hook_t* jvscom = new_com_hook(4); wcscpy_s(jvscom->wName, sizeof jvscom->wName, L"\\\\.\\mxjvs"); wcscpy_s(jvscom->wDosName, sizeof jvscom->wDosName, L"\\\\.\\mxjvs"); jvscom->GetCommState = mxjvs_GetCommState; @@ -389,6 +625,9 @@ void setup_mxjvs() { jvscom->PurgeComm = mxjvs_PurgeComm; jvscom->GetCommModemStatus = mxjvs_GetCommModemStatus; - hook_file(mxjvs); - hook_com(jvscom); + mxjvs->com_hook = jvscom; + + // TODO: Looks like some things might use JVS on COM4. We should setup a comdevice for this! + // file_hook_t* jvscom_file = new_file_hook(jvscom->wName); + // hook_file(jvscom_file); } diff --git a/src/micetools/dll/drivers/mxparallel.c b/src/micetools/dll/drivers/mxparallel.c index bc96bdf..8eecff8 100644 --- a/src/micetools/dll/drivers/mxparallel.c +++ b/src/micetools/dll/drivers/mxparallel.c @@ -45,7 +45,7 @@ uint32_t BILLING_PLAYCOUNT = 69420; overlappedComplete(len); \ } while (0) -BOOL mxparallel_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, +BOOL WINAPI mxparallel_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { log_trace("mxparallel", "DeviceIoControl(, 0x%08x, 0x%p, 0x%x, -, 0x%x, -, -)", @@ -155,7 +155,7 @@ void init_nv_storage() { billing_info.nearfull = 512; mxkSignValue(billing_info.nearfull, billing_info.nearfull_sig); mxkSignValue(billing_info.playlimit, billing_info.playlimit_sig); - billing_info.crc = crc32(sizeof billing_info - 4, (unsigned char*)&billing_info + 4, 0); + billing_info.crc = amCrc32RGet(sizeof billing_info - 4, (unsigned char*)&billing_info + 4, 0); memcpy(&flash[0x7a000], &billing_info, sizeof billing_info); memcpy(&flash[0x7b000], &billing_info, sizeof billing_info); @@ -263,7 +263,7 @@ void mxparallel_process_packet(BYTE* request) { log_warning("mxparallel", "GetAppBootInfo[%d] unexpected!", request[1]); } - APPBOOT.crc = crc32(sizeof APPBOOT - 4, (unsigned char*)&APPBOOT + 4, 0); + APPBOOT.crc = amCrc32RGet(sizeof APPBOOT - 4, (unsigned char*)&APPBOOT + 4, 0); for (int i = 0; i < sizeof APPBOOT; i += 16) { micexkSendPacket((unsigned char*)(&APPBOOT) + i); } diff --git a/src/micetools/dll/drivers/mxparallel.h b/src/micetools/dll/drivers/mxparallel.h index 0f7783b..980e331 100644 --- a/src/micetools/dll/drivers/mxparallel.h +++ b/src/micetools/dll/drivers/mxparallel.h @@ -3,7 +3,7 @@ #include "../../lib/mxk/mxk.h" #include "mx.h" -#pragma pack(1) +#pragma pack(push, 1) typedef struct { uint32_t crc; uint32_t playlimit; @@ -11,11 +11,11 @@ typedef struct { uint32_t nearfull; uint8_t nearfull_sig[128]; } billing_t; -#pragma pack(1) typedef struct { uint32_t length; uint8_t data[0x400 - 4]; } nvram_data_block_t; +#pragma pack(pop) void micexkTransportSend(unsigned char* send_data, int nbytes); diff --git a/src/micetools/dll/drivers/mxsmbus.c b/src/micetools/dll/drivers/mxsmbus.c index 29fcd2f..ffcf105 100644 --- a/src/micetools/dll/drivers/mxsmbus.c +++ b/src/micetools/dll/drivers/mxsmbus.c @@ -3,531 +3,70 @@ #include "mx.h" #include "smbus.h" -#define EEPROM_DUMP L"dev/eeprom.bin" -typedef struct eeprom_reg { - BYTE data[32]; -} eeprom_reg_t; -typedef struct eeprom_bank { - eeprom_reg_t reg[0x100]; -} eeprom_bank_t; +smbus_callback_t* smbus_devices[256] = { NULL }; -// 256 registers, 32 bytes each -eeprom_bank_t EEPROM_DATA; - -void eeprom_dump() { - HANDLE dump = - _CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); - if (dump == INVALID_HANDLE_VALUE) { - log_error("eeprom", "CreateFileA(EEPROM_DUMP) failed"); - return; - } else { - log_info("eeprom", "Wrote eeprom to %ls", EEPROM_DUMP); - } - _WriteFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, NULL, NULL); - FlushFileBuffers(dump); - _CloseHandle(dump); -} -void eeprom_restore() { - HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (dump == INVALID_HANDLE_VALUE) { - // Make the file, even though it'll probably be empty - eeprom_dump(); - return; - } - DWORD read; - if (!_ReadFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, &read, NULL)) - log_error("eeprom", "failed to restore (%d)", GetLastError()); - _CloseHandle(dump); +void smbus_install(BYTE v_addr, smbus_callback_t* write, smbus_callback_t* read) { + smbus_devices[v_addr << 1] = write; + smbus_devices[(v_addr << 1) + 1] = read; } -DWORD eeprom_crc(BYTE reg) { - if (reg == 0x04 || reg == 0x14 || reg == 0x80 || reg == 0x280) { - // Some registers are only treated as 16 byte values - return crc32(12, EEPROM_DATA.reg[reg].data + 4, 0); - } - - return crc32(28, EEPROM_DATA.reg[reg].data + 4, 0); -} - -#pragma pack(1) -typedef struct { - uint32_t checksum; - uint8_t pad1[8]; - uint8_t region; - uint8_t pad2[2]; - char mainId[17]; -} eeprom_block_1; -#pragma pack(1) -typedef struct { - uint32_t checksum; - uint32_t unk; - uint32_t dhcp_enabled; - uint32_t machine_ip; - uint32_t netmask; - uint32_t gateway; - uint32_t primary_dns; - uint32_t secondary_dns; -} eeprom_block_3; -#pragma pack(1) -typedef struct { - uint32_t checksum; - byte pad[4]; - char game_id[4]; - uint32_t unk; -} eeprom_block_5_1; -#pragma pack(1) -typedef struct { - uint32_t checksum; - uint32_t unk1; - uint32_t unk2; - uint32_t unk3; -} eeprom_block_5_2; - -#define SET_IP(val, a, b, c, d) \ - do { \ - *(uint32_t*)&val = (a << 24) | (b << 16) | (c << 8) | d; \ - } while (0) - -void eeprom_read(BYTE reg, BYTE index, BYTE* data, BYTE length) { - eeprom_restore(); - for (BYTE i = index; i < index + length; i++) { - if (i > 0x1f) break; - - BYTE byte = EEPROM_DATA.reg[reg].data[i]; - - // TODO: Reg 1 and 17 in the EEPROM are system info. We should fake these! - - if (reg == 0x00 || reg == 0x10) { - eeprom_block_1 block; - memset(&block, 0, sizeof block); - - block.region = 0b111; - strcpy(block.mainId, "AASE-01A65646203"); - - block.checksum = crc32(28, (BYTE*)(&block) + 4, 0); - - byte = ((BYTE*)(&block))[i]; - } - if (reg == 0x02) { - eeprom_block_3 block; - memset(&block, 0, sizeof block); - - // TODO: Load network config! - SET_IP(block.machine_ip, 192, 168, 103, 101); - SET_IP(block.netmask, 255, 255, 255, 0); - SET_IP(block.gateway, 192, 168, 103, 254); - SET_IP(block.primary_dns, 192, 168, 103, 254); - SET_IP(block.secondary_dns, 0, 0, 0, 0); - block.dhcp_enabled = 0; - - block.unk = 4835744; - - block.checksum = crc32(28, (BYTE*)(&block) + 4, 0); - - byte = ((BYTE*)(&block))[i]; - } - if (reg == 0x04) { - eeprom_block_5_1 block1; - eeprom_block_5_2 block2; - - memset(&block1, 0, sizeof block1); - memset(&block2, 0, sizeof block2); - block1.game_id[0] = 'S'; - block1.game_id[1] = 'D'; - block1.game_id[2] = 'E'; - block1.game_id[3] = 'Y'; - - block2.unk2 = 0xffffffff; - block2.unk3 = 0xffffffff; - - block1.checksum = crc32(12, (BYTE*)(&block1) + 4, 0); - block2.checksum = crc32(12, (BYTE*)(&block2) + 4, 0); - - if (i < 16) - byte = ((BYTE*)(&block1))[i]; - else - byte = ((BYTE*)(&block2))[i - 16]; - } - - // If register has a CRC - // if (reg == 0x00 || reg == 0x01 || reg == 0x02 || reg == 0x10 || reg - // == 0x11 || reg == 0x12 || reg == 0x200) { - if (false) { - // Intercept the read and inject a CRC instead - if (i == 0x00 || i == 0x01 || i == 0x02 || i == 0x03) { - DWORD crc = eeprom_crc(reg); - byte = crc >> 8 * i & 0xff; - } - } - - data[i - index] = byte; - } -} -void eeprom_write(BYTE reg, BYTE index, BYTE* data, BYTE length) { - log_misc("eeprom", "write reg=%d idx=%d len=%d", reg, index, length); - - for (BYTE i = index; i < index + length; i++) { - if (i > 0x1f) break; - EEPROM_DATA.reg[reg].data[i] = data[i - index]; - } - eeprom_dump(); -} - -typedef enum { - SMB_CMD_QUICK = 0b000, - SMB_CMD_BYTE = 0b001, - SMB_CMD_BYTE_DATA = 0b010, - SMB_CMD_WORD_DATA = 0b011, - SMB_CMD_PROCESS_CALL = 0b100, - SMB_CMD_BLOCK = 0b101, - SMB_CMD_I2C_READ = 0b110, - SMB_CMD_BLOCK_PROCESS = 0b111, -} smb_cmd_t; - -// EEPROM -BOOL smbus_AT24C64AN(BYTE addr, smb_cmd_t cmd, BYTE code, BYTE dlen, BYTE* data) { - BOOL read = addr & 1 == 1; - if (read) { - switch (cmd) { - case SMB_CMD_BYTE: - data[0] = 0x00; - break; - case SMB_CMD_BLOCK: { - WORD reg = *(WORD*)(&data[-1]); - dlen = data[1]; - log_info("eeprom", "Block read, %d @ %02x", dlen, reg); - - eeprom_read(reg >> 5, reg & 0x1f, &data[2], dlen); - return TRUE; - } - default: - log_error("eeprom", "Unsupported read mode: %01x, %02x", cmd, code); - return FALSE; - } - return TRUE; - } - - switch (cmd) { - case SMB_CMD_BLOCK: { - WORD reg = *(WORD*)(&data[-1]); - dlen = data[1]; - log_info("eeprom", "Block write, %d @ %02x", dlen, reg); - - eeprom_write(reg >> 5, reg & 0x1f, &data[2], dlen); - return TRUE; - } - default: - log_error("eeprom", "Unsupported write mode: %01x, %02x", cmd, code); - return FALSE; - } -} - -// dipsw -BOOL smbus_PCA9535(BYTE addr, smb_cmd_t cmd, BYTE code, BYTE dlen, BYTE* data) { - static uint16_t pca9535_config = 0xffff; - - BOOL read = addr & 1 == 1; - if (read) { - switch (cmd) { - case SMB_CMD_BYTE_DATA: - switch (code) { - case PCA9535_IN0: // DIPSW - /* - 0: ? - 1: ? - 2: ? - 3: Orientation - 4: / \ - 5: | Resolution | - 6: \ / - 7: game specific - - 0b00001000 = landscape - */ - data[0] = 0b00001000; - return TRUE; - case PCA9535_IN1: // SW1/2 + extras - /* - 0: unk - 1: unk - 2: ¬test - 3: ¬service - 4: unk - 5: unk - 6: unk - 7: unk - */ - byte dip = 0x00; - if (GetAsyncKeyState('T') >= 0) { - dip |= 0x04; - } - if (GetAsyncKeyState('S') >= 0) { - dip |= 0x08; - } - data[0] = dip; - return TRUE; - case PCA9535_OUT0: - log_error("pca9535", "Read PCA9535_OUT0 unimplemented!"); - return FALSE; - case PCA9535_OUT1: - data[0] = 0x00; - return TRUE; - case PCA9535_INV0: - data[0] = 0x00; - return TRUE; - case PCA9535_INV1: - data[0] = 0x00; - return TRUE; - case PCA9535_CONF0: - data[0] = pca9535_config >> 8; - return TRUE; - case PCA9535_CONF1: - data[0] = pca9535_config & 0xff; - return TRUE; - default: - log_error("pca9535", "Unknown read command: %02x", code); - return FALSE; - } - default: - log_error("pca9535", "Unsupported read mode: %01x (%02x)", cmd, code); - return FALSE; - } - } - - switch (cmd) { - case SMB_CMD_BYTE_DATA: - switch (code) { - case PCA9535_IN0: - log_error("pca9535", "Write PCA9535_IN0 unimplemented!"); - return FALSE; - case PCA9535_IN1: - log_error("pca9535", "Write PCA9535_IN1 unimplemented!"); - return FALSE; - case PCA9535_OUT0: - log_info("pca9535", "Out 0: %02x", data[0]); - return TRUE; - case PCA9535_OUT1: - log_info("pca9535", "Out 1: %02x", data[0]); - return TRUE; - case PCA9535_INV0: - log_info("pca9535", "Inv 0: %02x", data[0]); - return TRUE; - case PCA9535_INV1: - log_info("pca9535", "Inv 1: %02x", data[0]); - return TRUE; - case PCA9535_CONF0: - log_info("pca9535", "Conf 0: %02x", data[0]); - pca9535_config = (data[0] << 8) | (pca9535_config & 0xff); - return TRUE; - case PCA9535_CONF1: - log_info("pca9535", "Conf 1: %02x", data[0]); - pca9535_config = data[0] | (pca9535_config & 0xff00); - return TRUE; - default: - log_error("pca9535", "Unknown write command: %02x", code); - return FALSE; - } - default: - log_error("pca9535", "Unsupported write mode: %01x (%02x)", cmd, code); - return FALSE; - } -} - -// Very incomplete keychip -BOOL smbus_N2(BYTE addr, smb_cmd_t cmd, BYTE code, BYTE dlen, BYTE* data) { - static unsigned char challenge[7]; - static unsigned char n2_eeprom[3][0x20]; - - BOOL read = addr & 1 == 1; - if (read) { - switch (cmd) { - case SMB_CMD_BYTE_DATA: - if (code < 0x80) { - BYTE page = (code >> 5) & 0b11; - BYTE offset = code & 0x1f; - - data[0] = n2_eeprom[page][offset]; - - return TRUE; - } else if (code >= N2_GET_UNIQUE_NUMBER && code < N2_GET_UNIQUE_NUMBER + 0xf) { - data[0] = 0x04; // chosen by fair dice roll. - return TRUE; - } else if (code == N2_GET_STATUS) { - // Polled until N2_STATUS_FLAG_BUSY low - data[0] = 0x00; - return TRUE; - } else { - log_error("smb-keychip", "Unknown read command: %02x", code); - return FALSE; - } - default: - log_error("smb-keychip", "Unsupported read mode: %01x (%02x)", cmd, code); - return FALSE; - } - } - - switch (cmd) { - case SMB_CMD_BLOCK: { - WORD reg = *(WORD*)(&data[-1]); - dlen = data[1]; - - if (dlen != 7) { - log_error("smb-keychip", "Expected challenge length of 7 (saw %d)!", dlen); - return FALSE; - } - - memcpy(challenge, &(data[2]), 7); - - char* challenge_s = malloc(dlen * 3 + 1); - for (int i = 0; i < dlen; i++) { - sprintf(challenge_s + i * 3, "%02x ", data[2 + i]); - } - challenge_s[dlen * 3 + 1] = '\0'; - log_info("smb-keychip", "Challenge: %s", challenge_s); - free(challenge_s); - return TRUE; - } - case SMB_CMD_I2C_READ: { - switch (code) { - case N2_I2C_CHALLENGE_RESPONSE: - // This just has to match EXIO! - for (int i = 0; i < dlen; i++) data[i] = 0x69; - return TRUE; - default: - log_error("smb-keychip", "Unknown I2C command: %02x", code); - } - } - default: - log_error("smb-keychip", "Unsupported write mode: %01x (%02x)", cmd, code); - return FALSE; - } -} -BOOL smbus_EXIO(BYTE addr, smb_cmd_t cmd, BYTE code, BYTE dlen, BYTE* data) { - BOOL read = addr & 1 == 1; - if (read) { - switch (cmd) { - case SMB_CMD_BYTE_DATA: - if (0x40 <= code < 0x40 + 0x14) { - // mxkDsExioReadMacOutputBuffer - // This just has to match N2_I2C_CHALLENGE_RESPONSE! - data[0] = 0x69; - return TRUE; - } else if (code == EXIO_GET_BUSY) { - data[0] = 0x00; // Anything non-zero = busy - return TRUE; - } else { - log_error("smx-exio", "Unknown read command: %02x", code); - return FALSE; - } - default: - log_error("smb-exio", "Unsupported read mode: %01x (%02x)", cmd, code); - return FALSE; - } - } - - switch (cmd) { - case SMB_CMD_BYTE_DATA: - switch (code) { - case 0x5c: - if (data[0] == 0x94) return TRUE; - default: - log_error("smb-exio", "Unknown write command: %02x", code); - return FALSE; - } - case SMB_CMD_BLOCK: { - WORD reg = *(WORD*)(&data[-1]); - dlen = data[1]; - - char* data_s = malloc(dlen * 3 + 1); - for (int i = 0; i < dlen; i++) { - sprintf(data_s + i * 3, "%02x ", data[2 + i]); - } - data_s[dlen * 3 + 1] = '\0'; - - log_info("smb-exio", "Block write, %d @ %04x: %s", dlen, reg, data_s); - free(data_s); - return TRUE; - } - - default: - log_error("smb-exio", "Unsupported write mode: %01x (%02x)", cmd, code); - return FALSE; - } -} - -BOOL handle_smbus(BYTE* request) { - BYTE command = request[1]; - BYTE v_addr = request[2] & 0x7f; - BYTE command_code = request[3]; - - BYTE p_addr = request[2] << 1; - smb_cmd_t smb_cmd = SMB_CMD_QUICK; +BOOL handle_smbus(BYTE command, WORD v_addr, WORD command_code, BYTE nbytes, BYTE* data) { + WORD p_addr = (v_addr & 0x7fff) << 1; + ich9_cmd_t smb_cmd = ICH9_CMD_QUICK; switch (command) { - case 0: + case MXSMBUS_CMD_WRITE_QUICK: break; - case 1: + case MXSMBUS_CMD_READ_QUICK: p_addr++; break; - case 2: - smb_cmd = SMB_CMD_BYTE; + case MXSMBUS_CMD_WRITE_BYTE: + smb_cmd = ICH9_CMD_BYTE; break; - case 3: + case MXSMBUS_CMD_READ_BYTE: p_addr++; - smb_cmd = SMB_CMD_BYTE; + smb_cmd = ICH9_CMD_BYTE; break; - case 4: - smb_cmd = SMB_CMD_BYTE_DATA; + case MXSMBUS_CMD_WRITE_BYTE_DATA: + smb_cmd = ICH9_CMD_BYTE_DATA; break; - case 5: + case MXSMBUS_CMD_READ_BYTE_DATA: p_addr++; - smb_cmd = SMB_CMD_BYTE_DATA; + smb_cmd = ICH9_CMD_BYTE_DATA; break; - case 6: - smb_cmd = SMB_CMD_WORD_DATA; + case MXSMBUS_CMD_WRITE_WORD_DATA: + smb_cmd = ICH9_CMD_WORD_DATA; break; - case 7: + case MXSMBUS_CMD_READ_WORD_DATA: p_addr++; - smb_cmd = SMB_CMD_WORD_DATA; + smb_cmd = ICH9_CMD_WORD_DATA; break; - case 8: - smb_cmd = SMB_CMD_BLOCK; + case MXSMBUS_CMD_WRITE_BLOCK: + smb_cmd = ICH9_CMD_BLOCK; break; - case 9: + case MXSMBUS_CMD_READ_BLOCK: p_addr++; - smb_cmd = SMB_CMD_BLOCK; + smb_cmd = ICH9_CMD_BLOCK; break; - case 10: - smb_cmd = SMB_CMD_PROCESS_CALL; + case MXSMBUS_CMD_PROCESS_CALL: + smb_cmd = ICH9_CMD_PROCESS_CALL; break; - case 11: - smb_cmd = SMB_CMD_I2C_READ; + case MXSMBUS_CMD_I2C: + smb_cmd = ICH9_CMD_I2C_READ; break; } - log_trace("smbus", "Making request to %02X (virtual: %02X/%02x, cmd: %01X, code: %02X)", p_addr, + log_trace("smbus", "Making request to %02X (virtual: %04X/%04x, cmd: %01X, code: %04X)", p_addr, v_addr, command, smb_cmd, command_code); - switch (p_addr) { - case SMBUS_EEPROM: - case SMBUS_EEPROM + 1: - return smbus_AT24C64AN(p_addr, smb_cmd, command_code, request[4], &request[5]); - case SMBUS_PCA9535: - case SMBUS_PCA9535 + 1: - return smbus_PCA9535(p_addr, smb_cmd, command_code, request[4], &request[5]); - case SMBUS_N2: - case SMBUS_N2 + 1: - return smbus_N2(p_addr, smb_cmd, command_code, request[4], &request[5]); - case SMBUS_EXIO: - case SMBUS_EXIO + 1: - return smbus_EXIO(p_addr, smb_cmd, command_code, request[4], &request[5]); - default: - log_error("smbus", "Request to unregistered address: %02x", p_addr); - return FALSE; + smbus_callback_t* callback = smbus_devices[p_addr]; + if (callback == NULL) { + log_error("smbus", "Request to unregistered address: %02x", p_addr); + return FALSE; } + return (*callback)(smb_cmd, command_code, nbytes, data); } -BOOL mxsmbus_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, +BOOL WINAPI mxsmbus_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { mxsmbus_i2c_packet* i2c_packet = (mxsmbus_i2c_packet*)lpInBuffer; @@ -547,12 +86,14 @@ BOOL mxsmbus_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffe if (lpBytesReturned) *lpBytesReturned = 4; break; case IOCTL_MXSMBUS_I2C: { - BYTE command = ((BYTE*)lpInBuffer)[1]; + // BYTE command = ((BYTE*)lpInBuffer)[1]; + PMXSMBUS_I2C_PACKET packet = (PMXSMBUS_I2C_PACKET)lpInBuffer; + BYTE command = packet->command; if (command > 10) { ((BYTE*)lpOutBuffer)[0] = 0x19; return FALSE; } - if (handle_smbus(lpInBuffer)) { + if (handle_smbus(command, packet->v_addr & 0x7fff, packet->command_code, packet->nbytes, packet->data)) { ((BYTE*)lpOutBuffer)[0] = 0x00; return TRUE; } else { @@ -561,12 +102,14 @@ BOOL mxsmbus_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffe }; } case IOCTL_MXSMBUS_REQUEST: { - BYTE command = ((BYTE*)lpInBuffer)[1]; + // BYTE command = ((BYTE*)lpInBuffer)[1]; + PMXSMBUS_REQUEST_PACKET packet = (PMXSMBUS_REQUEST_PACKET)lpInBuffer; + BYTE command = packet->command; if (command > 11) { ((BYTE*)lpOutBuffer)[0] = 0x19; return FALSE; } - if (handle_smbus(lpInBuffer)) { + if (handle_smbus(command, packet->v_addr & 0x7f, packet->command_code, packet->nbytes, packet->data)) { ((BYTE*)lpOutBuffer)[0] = 0x00; return TRUE; } else { diff --git a/src/micetools/dll/drivers/mxsram.c b/src/micetools/dll/drivers/mxsram.c index 6bc0386..37432d4 100644 --- a/src/micetools/dll/drivers/mxsram.c +++ b/src/micetools/dll/drivers/mxsram.c @@ -1,12 +1,14 @@ +#include "../../amBackupStructs.h" +#include "../../maiBackupStructs.h" #include "mx.h" #define SRAM_DUMP L"dev/sram.bin" #define SRAM_SIZE 1024 * 2084 LPBYTE SRAM; -DWORD SRAM_POINTER = 0; void sram_dump() { - HANDLE dump = _CreateFileW(SRAM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); + HANDLE dump = + _CreateFileW(SRAM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (dump == INVALID_HANDLE_VALUE) { log_error("sram", "CreateFileA(SRAM_DUMP) failed"); return; @@ -16,18 +18,62 @@ void sram_dump() { } void sram_restore() { - HANDLE dump = - _CreateFileW(SRAM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE dump = _CreateFileW(SRAM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); if (dump == INVALID_HANDLE_VALUE) return; DWORD read; - if (!_ReadFile(dump, SRAM, SRAM_SIZE, &read, NULL)) log_error("sram", "failed to restore (%d)", GetLastError()); + if (!_ReadFile(dump, SRAM, SRAM_SIZE, &read, NULL)) + log_error("sram", "failed to restore (%d)", GetLastError()); _CloseHandle(dump); } -BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, - LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, - LPOVERLAPPED lpOverlapped) { - DWORD SRAM_VERSION = 0x0001; +#define ADDR_BACKUP 0x0000 +#define ADDR_HM_PEAK 0x0200 +#define ADDR_TIMEZONE 0x0400 +#define ADDR_ERROR_LOG 0x0600 +#define ADDR_DUP 0x1000 + +#define fix_crc(block) \ + do { \ + (block).m_Crc = amCrc32RGet(sizeof(block) - 4, (BYTE*)(&(block)) + 4, 0); \ + } while (0) + +int build_sram() { + static BOOL built = false; + if (built) return 0; + built = true; + + log_info("mxsram", "Building default SRAM file"); + + AM_SYSDATAwH_BACKUP Backup = { 0 }; + fix_crc(Backup); + memcpy(SRAM + ADDR_BACKUP, (unsigned char*)&Backup, sizeof Backup); + memcpy(SRAM + ADDR_BACKUP + ADDR_DUP, (unsigned char*)&Backup, sizeof Backup); + + AM_SYSDATAwH_HM_PEAK HmPeak = { 0 }; + fix_crc(HmPeak); + memcpy(SRAM + ADDR_HM_PEAK, (unsigned char*)&HmPeak, sizeof HmPeak); + memcpy(SRAM + ADDR_HM_PEAK + ADDR_DUP, (unsigned char*)&HmPeak, sizeof HmPeak); + + AM_SYSDATAwH_TIMEZONE Timezone = { 0 }; + fix_crc(Timezone); + memcpy(SRAM + ADDR_TIMEZONE, (unsigned char*)&Timezone, sizeof Timezone); + memcpy(SRAM + ADDR_TIMEZONE + ADDR_DUP, (unsigned char*)&Timezone, sizeof Timezone); + + AM_SYSDATAwH_ERROR_LOG ErrorLog = { 0 }; + fix_crc(ErrorLog); + memcpy(SRAM + ADDR_ERROR_LOG, (unsigned char*)&ErrorLog, sizeof ErrorLog); + memcpy(SRAM + ADDR_ERROR_LOG + ADDR_DUP, (unsigned char*)&ErrorLog, sizeof ErrorLog); + + sram_dump(); + + return 1; +} + +BOOL WINAPI mxsram_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { + DWORD SRAM_VERSION = 0x01000001; DWORD SRAM_SECTOR_SIZE = 4; // Max is 0x800 switch (dwIoControlCode) { @@ -46,15 +92,18 @@ BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer "0x%x, -, 0x%x, -, -)", lpInBuffer, nInBufferSize, nOutBufferSize); - DISK_GEOMETRY out = *(PDISK_GEOMETRY)lpOutBuffer; - memset(&out, 0, sizeof(out)); - out.Cylinders.QuadPart = 256; - out.MediaType = FixedMedia; - out.TracksPerCylinder = 24; - out.SectorsPerTrack = 8; - out.BytesPerSector = 512; + PDISK_GEOMETRY out = (PDISK_GEOMETRY)lpOutBuffer; + memset(out, 0, sizeof *out); + out->Cylinders.QuadPart = 256; + out->MediaType = FixedMedia; + out->TracksPerCylinder = 2; + out->SectorsPerTrack = 8; + out->BytesPerSector = 512; if (lpBytesReturned) *lpBytesReturned = sizeof(DISK_GEOMETRY); break; + case IOCTL_DISK_GET_LENGTH_INFO: + log_error("mxsram", "Unhandled IOCTL_DISK_GET_LENGTH_INFO"); + return FALSE; case IOCTL_MXSRAM_GET_SECTOR_SIZE: log_info("mxsram", "DeviceIoControl(, , 0x%p, " @@ -72,35 +121,28 @@ BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer return TRUE; } -DWORD mxsram_SetFilePointer(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { - if (dwMoveMethod == FILE_BEGIN) { - SRAM_POINTER = lDistanceToMove; - } else if (dwMoveMethod == FILE_CURRENT) { - SRAM_POINTER += lDistanceToMove; +BOOL mxsram_WriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { + log_misc("mxsram", "sram write 0x%04x bytes at 0x%04x", nNumberOfBytesToWrite, + ctx->m_Pointer.LowPart); + if (ctx->m_Pointer.LowPart + nNumberOfBytesToWrite >= SRAM_SIZE) { + nNumberOfBytesToWrite = SRAM_SIZE - ctx->m_Pointer.LowPart; } - return SRAM_POINTER; -} - -BOOL mxsram_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, - LPOVERLAPPED lpOverlapped) { - log_misc("mxsram", "sram write 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToWrite); - if (SRAM_POINTER + nNumberOfBytesToWrite >= SRAM_SIZE) { - nNumberOfBytesToWrite = SRAM_SIZE - SRAM_POINTER; - } - memcpy(SRAM + SRAM_POINTER, lpBuffer, nNumberOfBytesToWrite); + memcpy(SRAM + ctx->m_Pointer.LowPart, lpBuffer, nNumberOfBytesToWrite); sram_dump(); *lpNumberOfBytesWritten = nNumberOfBytesToWrite; return TRUE; } -BOOL mxsram_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, - LPOVERLAPPED lpOverlapped) { - log_misc("mxsram", "sram read 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToRead); - if (SRAM_POINTER + nNumberOfBytesToRead >= SRAM_SIZE) { - nNumberOfBytesToRead = SRAM_SIZE - SRAM_POINTER; +BOOL mxsram_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { + log_misc("mxsram", "sram read 0x%04x bytes at 0x%04x", nNumberOfBytesToRead, + ctx->m_Pointer.LowPart); + if (ctx->m_Pointer.LowPart + nNumberOfBytesToRead >= SRAM_SIZE) { + nNumberOfBytesToRead = SRAM_SIZE - ctx->m_Pointer.LowPart; } sram_restore(); - memcpy((LPVOID)lpBuffer, SRAM + SRAM_POINTER, nNumberOfBytesToRead); + memcpy((LPVOID)lpBuffer, SRAM + ctx->m_Pointer.LowPart, nNumberOfBytesToRead); *lpNumberOfBytesRead = nNumberOfBytesToRead; return TRUE; } @@ -112,12 +154,14 @@ void setup_mxsram() { log_error(BOOT_LOGGER, "unable to allocate 2MiB for SRAM"); exit(1); } - memset(SRAM, 0, SRAM_SIZE); - sram_restore(); + memset(SRAM, 0xff, SRAM_SIZE); + if (FileExists(SRAM_DUMP)) + sram_restore(); + else + build_sram(); file_hook_t* mxsram = new_file_hook(L"\\\\.\\mxsram"); mxsram->DeviceIoControl = &mxsram_DeviceIoControl; - mxsram->SetFilePointer = &mxsram_SetFilePointer; mxsram->ReadFile = &mxsram_ReadFile; mxsram->WriteFile = &mxsram_WriteFile; diff --git a/src/micetools/dll/drivers/mxsuperio.c b/src/micetools/dll/drivers/mxsuperio.c index a3b6d7f..ecdf616 100644 --- a/src/micetools/dll/drivers/mxsuperio.c +++ b/src/micetools/dll/drivers/mxsuperio.c @@ -256,7 +256,7 @@ void hwmon_write(superio_packet* packet) { } } -BOOL mxsuperio_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, +BOOL WINAPI mxsuperio_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { superio_packet* lpc_packet = (superio_packet*)lpInBuffer; diff --git a/src/micetools/dll/drivers/mxsuperio.h b/src/micetools/dll/drivers/mxsuperio.h index 72addf5..cc161e8 100644 --- a/src/micetools/dll/drivers/mxsuperio.h +++ b/src/micetools/dll/drivers/mxsuperio.h @@ -1,17 +1,17 @@ #pragma once #include "common.h" -#pragma pack(1) +#pragma pack(push, 1) typedef struct { BYTE index; BYTE reg; BYTE data; } superio_packet; -#pragma pack(1) typedef struct { BYTE chip; BYTE device; BYTE reg; BYTE data; } superio_lpc_packet; +#pragma pack(pop) diff --git a/src/micetools/dll/gui/gui.c b/src/micetools/dll/gui/gui.c index 7919940..1976857 100644 --- a/src/micetools/dll/gui/gui.c +++ b/src/micetools/dll/gui/gui.c @@ -1,12 +1,11 @@ #include "../hooks/gui.h" - #ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS #endif #include "cimgui.h" -BOOL initialized = false; -BOOL haveFirstFrame = false; +#include "imgui_memory_editor.h" + static HWND window; extern bool ImGui_ImplWin32_Init(void* hwnd); @@ -34,72 +33,104 @@ void InitImGui(IDirect3DDevice9* pDevice) { ImGui_ImplWin32_Init(window); ImGui_ImplDX9_Init(pDevice); - initialized = true; - return; } -extern int jvs_buttons[2][16]; extern BOOL JVS_SENSE; void jvs_tab() { int coin_count_1 = 0; int coin_count_2 = 0; - igText("Player 1 Coins: %d", coin_count_1); - igText("Player 2 Coins: %d", coin_count_2); - igSeparator(); - igText("Sense: %d", JVS_SENSE); - igSeparator(); - ImVec4 white = { 1.0, 1.0, 1.0, 1.0 }; - ImVec4 red = { 1.0, 0.0, 0.0, 1.0 }; + igText("Player 1 Coins: %d", coin_count_1); + igText("Player 2 Coins: %d", coin_count_2); + igSeparator(); + igText("Sense: %d", JVS_SENSE); + igSeparator(); + ImVec4 white = { 1.0, 1.0, 1.0, 1.0 }; + ImVec4 red = { 1.0, 0.0, 0.0, 1.0 }; - igColumns(5, NULL, true); - // for (auto s : scancodes) { - // igTextColored((GetKeyState(s.second) < 0) ? red : white, "%s: %x", s.first, s.second); - // igNextColumn(); - // } - igColumns(1, NULL, true); - igColumns(8, NULL, true); - for (int player = 0; player < 2; player++) { - for (int button = 0; button < 16; button++) { - int scan = jvs_buttons[player][button]; - igTextColored((GetKeyState(scan) < 0) ? red : white, "p%d_%02d: %02x", player, button, scan); - igNextColumn(); - } - } - igColumns(1, NULL, true); + igColumns(5, NULL, true); + // for (auto s : scancodes) { + // igTextColored((GetKeyState(s.second) < 0) ? red : white, "%s: %x", s.first, s.second); + // igNextColumn(); + // } + igColumns(1, NULL, true); + igColumns(8, NULL, true); + for (int player = 0; player < 2; player++) { + for (int button = 0; button < 16; button++) { + // int scan = jvs_buttons[player][button]; + // igTextColored((GetKeyState(scan) < 0) ? red : white, "p%d_%02d: %02x", player, button, + // scan); + igNextColumn(); + } + } + igColumns(1, NULL, true); - igSeparator(); - igText("JVS Count"); - // for (auto c : jvsCount) { - // igText("%x: %d", c.first, c.second); - // } - igSeparator(); - igText("Comio Count"); - // for (auto c : comioCount) { - // igText("%x: %d", c.first, c.second); - // } + igSeparator(); + igText("JVS Count"); + // for (auto c : jvsCount) { + // igText("%x: %d", c.first, c.second); + // } + igSeparator(); + igText("Comio Count"); + // for (auto c : comioCount) { + // igText("%x: %d", c.first, c.second); + // } } +void hud_fps() { + if (igBegin("FPS", NULL, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoNavInputs)) { + ImGuiIO* io = igGetIO(); -void hud_gui(IDirect3DDevice9* dev) { - static bool showMenu = false; + ImVec2 win_pos; + win_pos.x = io->DisplaySize.x - 120; + win_pos.y = 10; + igSetWindowPos_Vec2(win_pos, ImGuiCond_Once); - // if (GetAsyncKeyState(scancodes["openMenu"]) & 1) { - // showMenu = !showMenu; - // } - - if (!initialized) { - InitImGui(dev); - return; + igText("FPS: %.1f", io->Framerate); + igText(" dT: %.2fms", 1000 / io->Framerate); } - // if (!showMenu) return; - ImGui_ImplDX9_NewFrame(); - ImGui_ImplWin32_NewFrame(); + igEnd(); +} +void hud_eeprom(ImGuiKey open_key) { + static MemoryEditor editor; + static bool has_init = false; + if (!has_init) { + MemoryEditor_Init(&editor); + editor.Open = false; + has_init = true; + } + if (igIsKeyPressed_Bool(open_key, false)) editor.Open = !editor.Open; - igNewFrame(); + // TODO: Less hacky :) + extern BYTE EEPROM_DATA[0x2000]; + if (editor.Open) + MemoryEditor_DrawWindow(&editor, "EEPROM Editor", EEPROM_DATA, sizeof EEPROM_DATA, 0x000); +} +void hud_sram(ImGuiKey open_key) { + static MemoryEditor editor; + static bool has_init = false; + if (!has_init) { + MemoryEditor_Init(&editor); + editor.Open = false; + has_init = true; + } + if (igIsKeyPressed_Bool(open_key, false)) editor.Open = !editor.Open; + + // TODO: Less hacky :) + extern LPBYTE SRAM; + if (editor.Open) + MemoryEditor_DrawWindow(&editor, "SRAM Editor", SRAM, 1024 * 1024, 0x0000); +} + +void hud_control() { igBegin("maimai control", NULL, 0); + static bool haveFirstFrame = false; if (!haveFirstFrame) { ImVec2 size = { 600, 700 }; igSetWindowSize_Vec2(size, 0); @@ -123,6 +154,34 @@ void hud_gui(IDirect3DDevice9* dev) { LeaveCriticalSection(&logger_lock); igEnd(); +} + +void hud_gui(IDirect3DDevice9* dev) { + static bool showMenu = false; + + // if (GetAsyncKeyState(scancodes["openMenu"]) & 1) { + // showMenu = !showMenu; + // } + + static bool initialized = false; + if (!initialized) { + InitImGui(dev); + initialized = true; + } + // if (!showMenu) return; + + ImGui_ImplDX9_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + igNewFrame(); + + static bool showFps = false; + if (igIsKeyPressed_Bool(ImGuiKey_F12, false)) showFps = !showFps; + if (showFps) hud_fps(); + + hud_eeprom(ImGuiKey_F11); + hud_sram(ImGuiKey_F10); + // hud_control(); igEndFrame(); igRender(); diff --git a/src/micetools/dll/gui/imgui_memory_editor.c b/src/micetools/dll/gui/imgui_memory_editor.c new file mode 100644 index 0000000..ac99da2 --- /dev/null +++ b/src/micetools/dll/gui/imgui_memory_editor.c @@ -0,0 +1,720 @@ +#pragma once +// Ported to C from +// https://github.com/ocornut/imgui_club/blob/master/imgui_memory_editor/imgui_memory_editor.h + +#include "imgui_memory_editor.h" + +// FIXME: We should have a way to retrieve the text edit cursor position +// more easily in the API, this is rather tedious. This is such a ugly mess +// we may be better off not using InputText() at all here. +static int UserData_Callback(ImGuiInputTextCallbackData* data) { + UserData* user_data = (UserData*)data->UserData; + if (!ImGuiInputTextCallbackData_HasSelection(data)) user_data->CursorPos = data->CursorPos; + if (data->SelectionStart == 0 && data->SelectionEnd == data->BufTextLen) { + // When not editing a byte, always refresh its InputText content + // pulled from underlying memory data (this is a bit tricky, since + // InputText technically "owns" the master copy of the buffer we + // edit it in there) + ImGuiInputTextCallbackData_DeleteChars(data, 0, data->BufTextLen); + ImGuiInputTextCallbackData_InsertChars(data, 0, user_data->CurrentBufOverwrite, NULL); + data->SelectionStart = 0; + data->SelectionEnd = 2; + data->CursorPos = 0; + } + return 0; +} + +void MemoryEditor_Init(MemoryEditor* editor) { + // Settings + editor->Open = true; + editor->ReadOnly = false; + editor->Cols = 16; + editor->OptShowOptions = true; + editor->OptShowDataPreview = false; + editor->OptShowHexII = false; + editor->OptShowAscii = true; + editor->OptGreyOutZeroes = true; + editor->OptUpperCaseHex = true; + editor->OptMidColsCount = 8; + editor->OptAddrDigitsCount = 0; + editor->OptFooterExtraHeight = 0.0f; + editor->HighlightColor = IM_COL32(255, 255, 255, 50); + editor->ReadFn = NULL; + editor->WriteFn = NULL; + editor->HighlightFn = NULL; + + // State/Internals + editor->ContentsWidthChanged = false; + editor->DataPreviewAddr = editor->DataEditingAddr = (size_t)-1; + editor->DataEditingTakeFocus = false; + memset(editor->DataInputBuf, 0, sizeof(editor->DataInputBuf)); + memset(editor->AddrInputBuf, 0, sizeof(editor->AddrInputBuf)); + editor->GotoAddr = (size_t)-1; + editor->HighlightMin = editor->HighlightMax = (size_t)-1; + editor->PreviewEndianess = 0; + editor->PreviewDataType = ImGuiDataType_S32; +} + +void MemoryEditor_GotoAddrAndHighlight(MemoryEditor* editor, size_t addr_min, size_t addr_max) { + editor->GotoAddr = addr_min; + editor->HighlightMin = addr_min; + editor->HighlightMax = addr_max; +} + +void MemoryEditor_CalcSizes(MemoryEditor* editor, Sizes* s, size_t mem_size, + size_t base_display_addr) { + ImGuiStyle* style = igGetStyle(); + s->AddrDigitsCount = editor->OptAddrDigitsCount; + if (s->AddrDigitsCount == 0) + for (size_t n = base_display_addr + mem_size - 1; n > 0; n >>= 4) s->AddrDigitsCount++; + s->LineHeight = igGetTextLineHeight(); + ImVec2 textSize; + igCalcTextSize(&textSize, "F", NULL, false, -1.0f); + s->GlyphWidth = textSize.x + 1; // We assume the font is mono-space + s->HexCellWidth = + (float)(int)(s->GlyphWidth * 2.5f); // "FF " we include trailing space in the + // width to easily catch clicks everywhere + s->SpacingBetweenMidCols = + (float)(int)(s->HexCellWidth * + 0.25f); // Every OptMidColsCount columns we add a bit of extra spacing + s->PosHexStart = (s->AddrDigitsCount + 2) * s->GlyphWidth; + s->PosHexEnd = s->PosHexStart + (s->HexCellWidth * editor->Cols); + s->PosAsciiStart = s->PosAsciiEnd = s->PosHexEnd; + if (editor->OptShowAscii) { + s->PosAsciiStart = s->PosHexEnd + s->GlyphWidth * 1; + if (editor->OptMidColsCount > 0) + s->PosAsciiStart += + (float)((editor->Cols + editor->OptMidColsCount - 1) / editor->OptMidColsCount) * + s->SpacingBetweenMidCols; + s->PosAsciiEnd = s->PosAsciiStart + editor->Cols * s->GlyphWidth; + } + s->WindowWidth = + s->PosAsciiEnd + style->ScrollbarSize + style->WindowPadding.x * 2 + s->GlyphWidth; +} + +// Standalone Memory Editor window +void MemoryEditor_DrawWindow(MemoryEditor* editor, const char* title, void* mem_data, + size_t mem_size, size_t base_display_addr) { + Sizes s; + MemoryEditor_CalcSizes(editor, &s, mem_size, base_display_addr); + + ImVec2 vec1, vec2; + vec1.x = s.WindowWidth; + vec1.y = s.WindowWidth * 0.60f; + igSetNextWindowSize(vec1, ImGuiCond_FirstUseEver); + vec1.x = 0.0f; + vec1.y = 0.0f; + vec2.x = s.WindowWidth; + vec2.y = FLT_MAX; + igSetNextWindowSizeConstraints(vec1, vec2, NULL, NULL); + + editor->Open = true; + if (igBegin(title, &editor->Open, ImGuiWindowFlags_NoScrollbar)) { + if (igIsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) && + igIsMouseReleased_Nil(ImGuiMouseButton_Right)) + igOpenPopup_Str("context", 0); + MemoryEditor_DrawContents(editor, mem_data, mem_size, base_display_addr); + if (editor->ContentsWidthChanged) { + MemoryEditor_CalcSizes(editor, &s, mem_size, base_display_addr); + igGetWindowSize(&vec1); + vec1.x = s.WindowWidth; + igSetWindowSize_Vec2(vec1, 0); + } + } + igEnd(); +} + +// Memory Editor contents only +void MemoryEditor_DrawContents(MemoryEditor* editor, void* mem_data_void, size_t mem_size, + size_t base_display_addr) { + if (editor->Cols < 1) editor->Cols = 1; + + ImU8* mem_data = (ImU8*)mem_data_void; + Sizes s; + MemoryEditor_CalcSizes(editor, &s, mem_size, base_display_addr); + ImGuiStyle* style = igGetStyle(); + + // We begin into our scrolling region with the 'ImGuiWindowFlags_NoMove' in order to prevent + // click from moving the window. This is used as a facility since our main click detection code + // doesn't assign an ActiveId so the click would normally be caught as a window-move. + const float height_separator = style->ItemSpacing.y; + float footer_height = editor->OptFooterExtraHeight; + if (editor->OptShowOptions) + footer_height += height_separator + igGetFrameHeightWithSpacing() * 1; + if (editor->OptShowDataPreview) + footer_height += height_separator + igGetFrameHeightWithSpacing() * 1 + + igGetTextLineHeightWithSpacing() * 3; + + ImVec2 vec1, vec2; + vec1.x = 0; + vec1.y = -footer_height; + igBeginChild_Str("##scrolling", vec1, false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav); + ImDrawList* draw_list = igGetWindowDrawList(); + + vec1.y = 0; + igPushStyleVar_Vec2(ImGuiStyleVar_FramePadding, vec1); + igPushStyleVar_Vec2(ImGuiStyleVar_ItemSpacing, vec1); + + // We are not really using the clipper API correctly here, because we rely on + // visible_start_addr/visible_end_addr for our scrolling function. + const int line_total_count = (int)((mem_size + editor->Cols - 1) / editor->Cols); + ImGuiListClipper clipper; + ImGuiListClipper_Begin(&clipper, line_total_count, s.LineHeight); + + bool data_next = false; + + if (editor->ReadOnly || editor->DataEditingAddr >= mem_size) + editor->DataEditingAddr = (size_t)-1; + if (editor->DataPreviewAddr >= mem_size) editor->DataPreviewAddr = (size_t)-1; + + size_t preview_data_type_size = + editor->OptShowDataPreview ? MemoryEditor_DataTypeGetSize(editor->PreviewDataType) : 0; + + size_t data_editing_addr_next = (size_t)-1; + if (editor->DataEditingAddr != (size_t)-1) { + // Move cursor but only apply on next frame so scrolling with be synchronized (because + // currently we can't change the scrolling while the window is being rendered) + if (igIsKeyPressed_Bool(igGetKeyIndex(ImGuiKey_UpArrow), true) && + (ptrdiff_t)editor->DataEditingAddr >= (ptrdiff_t)editor->Cols) { + data_editing_addr_next = editor->DataEditingAddr - editor->Cols; + } else if (igIsKeyPressed_Bool(igGetKeyIndex(ImGuiKey_DownArrow), true) && + (ptrdiff_t)editor->DataEditingAddr < (ptrdiff_t)mem_size - editor->Cols) { + data_editing_addr_next = editor->DataEditingAddr + editor->Cols; + } else if (igIsKeyPressed_Bool(igGetKeyIndex(ImGuiKey_LeftArrow), true) && + (ptrdiff_t)editor->DataEditingAddr > (ptrdiff_t)0) { + data_editing_addr_next = editor->DataEditingAddr - 1; + } else if (igIsKeyPressed_Bool(igGetKeyIndex(ImGuiKey_RightArrow), true) && + (ptrdiff_t)editor->DataEditingAddr < (ptrdiff_t)mem_size - 1) { + data_editing_addr_next = editor->DataEditingAddr + 1; + } + } + + // Draw vertical separator + ImVec2 window_pos; + igGetWindowPos(&window_pos); + if (editor->OptShowAscii) { + vec1.x = window_pos.x + s.PosAsciiStart - s.GlyphWidth; + vec1.y = window_pos.y; + vec2.x = window_pos.x + s.PosAsciiStart - s.GlyphWidth; + vec2.y = window_pos.y + 9999; + ImDrawList_AddLine(draw_list, vec1, vec2, igGetColorU32_Col(ImGuiCol_Border, 1.0f), 1); + } + + const ImU32 color_text = igGetColorU32_Col(ImGuiCol_Text, 1.0f); + const ImU32 color_disabled = + editor->OptGreyOutZeroes ? igGetColorU32_Col(ImGuiCol_TextDisabled, 1.0f) : color_text; + + const char* format_address = + editor->OptUpperCaseHex ? "%0*" _PRISizeT "X: " : "%0*" _PRISizeT "x: "; + const char* format_data = editor->OptUpperCaseHex ? "%0*" _PRISizeT "X" : "%0*" _PRISizeT "x"; + const char* format_byte = editor->OptUpperCaseHex ? "%02X" : "%02x"; + const char* format_byte_space = editor->OptUpperCaseHex ? "%02X " : "%02x "; + + while (ImGuiListClipper_Step(&clipper)) + for (int line_i = clipper.DisplayStart; line_i < clipper.DisplayEnd; + line_i++) // display only visible lines + { + size_t addr = (size_t)(line_i * editor->Cols); + igText(format_address, s.AddrDigitsCount, base_display_addr + addr); + + // Draw Hexadecimal + for (int n = 0; n < editor->Cols && addr < mem_size; n++, addr++) { + float byte_pos_x = s.PosHexStart + s.HexCellWidth * n; + if (editor->OptMidColsCount > 0) + byte_pos_x += (float)(n / editor->OptMidColsCount) * s.SpacingBetweenMidCols; + igSameLine(byte_pos_x, -1.0f); + + // Draw highlight + bool is_highlight_from_user_range = + (addr >= editor->HighlightMin && addr < editor->HighlightMax); + bool is_highlight_from_user_func = + (editor->HighlightFn && editor->HighlightFn(mem_data, addr)); + bool is_highlight_from_preview = + (addr >= editor->DataPreviewAddr && + addr < editor->DataPreviewAddr + preview_data_type_size); + if (is_highlight_from_user_range || is_highlight_from_user_func || + is_highlight_from_preview) { + ImVec2 pos; + igGetCursorScreenPos(&pos); + float highlight_width = s.GlyphWidth * 2; + bool is_next_byte_highlighted = + (addr + 1 < mem_size) && + ((editor->HighlightMax != (size_t)-1 && addr + 1 < editor->HighlightMax) || + (editor->HighlightFn && editor->HighlightFn(mem_data, addr + 1))); + if (is_next_byte_highlighted || (n + 1 == editor->Cols)) { + highlight_width = s.HexCellWidth; + if (editor->OptMidColsCount > 0 && n > 0 && (n + 1) < editor->Cols && + ((n + 1) % editor->OptMidColsCount) == 0) + highlight_width += s.SpacingBetweenMidCols; + } + + vec1.x = pos.x = highlight_width; + vec1.y = pos.y + s.LineHeight; + ImDrawList_AddRectFilled(draw_list, pos, vec1, editor->HighlightColor, 0, 0); + } + + if (editor->DataEditingAddr == addr) { + // Display text input on current byte + bool data_write = false; + igPushID_Ptr((void*)addr); + if (editor->DataEditingTakeFocus) { + igSetKeyboardFocusHere(0); + sprintf(editor->AddrInputBuf, format_data, s.AddrDigitsCount, + base_display_addr + addr); + sprintf(editor->DataInputBuf, format_byte, + editor->ReadFn ? editor->ReadFn(mem_data, addr) : mem_data[addr]); + } + UserData user_data; + user_data.CursorPos = -1; + sprintf(user_data.CurrentBufOverwrite, format_byte, + editor->ReadFn ? editor->ReadFn(mem_data, addr) : mem_data[addr]); + ImGuiInputTextFlags flags = + ImGuiInputTextFlags_CharsHexadecimal | + ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll | + ImGuiInputTextFlags_NoHorizontalScroll | + ImGuiInputTextFlags_CallbackAlways | ImGuiInputTextFlags_AlwaysOverwrite; + igSetNextItemWidth(s.GlyphWidth * 2); + if (igInputText("##data", editor->DataInputBuf, + IM_ARRAYSIZE(editor->DataInputBuf), flags, UserData_Callback, + &user_data)) + data_write = data_next = true; + else if (!editor->DataEditingTakeFocus && !igIsItemActive()) + editor->DataEditingAddr = data_editing_addr_next = (size_t)-1; + editor->DataEditingTakeFocus = false; + if (user_data.CursorPos >= 2) data_write = data_next = true; + if (data_editing_addr_next != (size_t)-1) data_write = data_next = false; + unsigned int data_input_value = 0; + if (data_write && sscanf(editor->DataInputBuf, "%X", &data_input_value) == 1) { + if (editor->WriteFn) + editor->WriteFn(mem_data, addr, (ImU8)data_input_value); + else + mem_data[addr] = (ImU8)data_input_value; + } + igPopID(); + } else { + // NB: The trailing space is not visible but ensure there's no gap that the + // mouse cannot click on. + ImU8 b = editor->ReadFn ? editor->ReadFn(mem_data, addr) : mem_data[addr]; + + if (editor->OptShowHexII) { + if ((b >= 32 && b < 128)) + igText(".%c ", b); + else if (b == 0xFF && editor->OptGreyOutZeroes) + igTextDisabled("## "); + else if (b == 0x00) + igText(" "); + else + igText(format_byte_space, b); + } else { + if (b == 0 && editor->OptGreyOutZeroes) + igTextDisabled("00 "); + else + igText(format_byte_space, b); + } + if (!editor->ReadOnly && igIsItemHovered(0) && igIsMouseClicked_Bool(0, false)) { + editor->DataEditingTakeFocus = true; + data_editing_addr_next = addr; + } + } + } + + if (editor->OptShowAscii) { + // Draw ASCII values + igSameLine(s.PosAsciiStart, -1.0f); + ImVec2 pos; + igGetCursorScreenPos(&pos); + addr = line_i * editor->Cols; + igPushID_Int(line_i); + vec1.x = s.PosAsciiEnd - s.PosAsciiStart; + vec1.y = s.LineHeight; + if (igInvisibleButton("igInvisibleButtonascii", vec1, 0)) { + editor->DataEditingAddr = editor->DataPreviewAddr = + addr + (size_t)((igGetIO()->MousePos.x - pos.x) / s.GlyphWidth); + editor->DataEditingTakeFocus = true; + } + igPopID(); + for (int n = 0; n < editor->Cols && addr < mem_size; n++, addr++) { + if (addr == editor->DataEditingAddr) { + vec1.x = pos.x + s.GlyphWidth; + vec1.y = pos.y + s.LineHeight; + ImDrawList_AddRectFilled(draw_list, pos, vec1, + igGetColorU32_Col(ImGuiCol_FrameBg, 1.0f), 0, 0); + ImDrawList_AddRectFilled(draw_list, pos, vec1, + igGetColorU32_Col(ImGuiCol_TextSelectedBg, 1.0f), 0, 0); + } + unsigned char c = + editor->ReadFn ? editor->ReadFn(mem_data, addr) : mem_data[addr]; + char display_c = (c < 32 || c >= 128) ? '.' : c; + + ImDrawList_AddText_Vec2(draw_list, pos, + (display_c == c) ? color_text : color_disabled, + &display_c, &display_c + 1); + pos.x += s.GlyphWidth; + } + } + } + igPopStyleVar(2); + igEndChild(); + + // Notify the main window of our ideal child content size (FIXME: we are missing an API to get + // the contents size from the child) + igSetCursorPosX(s.WindowWidth); + + if (data_next && editor->DataEditingAddr + 1 < mem_size) { + editor->DataEditingAddr = editor->DataPreviewAddr = editor->DataEditingAddr + 1; + editor->DataEditingTakeFocus = true; + } else if (data_editing_addr_next != (size_t)-1) { + editor->DataEditingAddr = editor->DataPreviewAddr = data_editing_addr_next; + editor->DataEditingTakeFocus = true; + } + + const bool lock_show_data_preview = editor->OptShowDataPreview; + if (editor->OptShowOptions) { + igSeparator(); + MemoryEditor_DrawOptionsLine(editor, &s, mem_data, mem_size, base_display_addr); + } + + if (lock_show_data_preview) { + igSeparator(); + MemoryEditor_DrawPreviewLine(editor, &s, mem_data, mem_size, base_display_addr); + } +} + +void MemoryEditor_DrawOptionsLine(MemoryEditor* editor, const Sizes* s, void* mem_data, + size_t mem_size, size_t base_display_addr) { + IM_UNUSED(mem_data); + ImGuiStyle* style = igGetStyle(); + const char* format_range = editor->OptUpperCaseHex + ? "Range %0*" _PRISizeT "X..%0*" _PRISizeT "X" + : "Range %0*" _PRISizeT "x..%0*" _PRISizeT "x"; + + ImVec2 vec1 = { 0 }; + // Options menu + if (igButton("Options", vec1)) igOpenPopup_Str("context", 0); + if (igBeginPopup("context", 0)) { + igSetNextItemWidth(s->GlyphWidth * 7 + style->FramePadding.x * 2.0f); + if (igDragInt("##cols", &editor->Cols, 0.2f, 4, 32, "%d cols", 0)) { + editor->ContentsWidthChanged = true; + if (editor->Cols < 1) editor->Cols = 1; + } + igCheckbox("Show Data Preview", &editor->OptShowDataPreview); + igCheckbox("Show HexII", &editor->OptShowHexII); + if (igCheckbox("Show Ascii", &editor->OptShowAscii)) { + editor->ContentsWidthChanged = true; + } + igCheckbox("Grey out zeroes", &editor->OptGreyOutZeroes); + igCheckbox("Uppercase Hex", &editor->OptUpperCaseHex); + + igEndPopup(); + } + + igSameLine(0, -1); + igText(format_range, s->AddrDigitsCount, base_display_addr, s->AddrDigitsCount, + base_display_addr + mem_size - 1); + igSameLine(0, -1); + igSetNextItemWidth((s->AddrDigitsCount + 1) * s->GlyphWidth + style->FramePadding.x * 2.0f); + if (igInputText("##addr", editor->AddrInputBuf, IM_ARRAYSIZE(editor->AddrInputBuf), + ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue, + NULL, NULL)) { + size_t goto_addr; + if (sscanf(editor->AddrInputBuf, "%" _PRISizeT "X", &goto_addr) == 1) { + editor->GotoAddr = goto_addr - base_display_addr; + editor->HighlightMin = editor->HighlightMax = (size_t)-1; + } + } + + if (editor->GotoAddr != (size_t)-1) { + if (editor->GotoAddr < mem_size) { + vec1.x = 0; + vec1.y = 0; + igBeginChild_Str("##scrolling", vec1, false, 0); + igGetCursorStartPos(&vec1); + igSetScrollFromPosY_Float( + vec1.y + (editor->GotoAddr / editor->Cols) * igGetTextLineHeight(), 0.5f); + igEndChild(); + editor->DataEditingAddr = editor->DataPreviewAddr = editor->GotoAddr; + editor->DataEditingTakeFocus = true; + } + editor->GotoAddr = (size_t)-1; + } +} + +void MemoryEditor_DrawPreviewLine(MemoryEditor* editor, const Sizes* s, void* mem_data_void, + size_t mem_size, size_t base_display_addr) { + IM_UNUSED(base_display_addr); + ImVec2 vec1 = { 0 }; + ImU8* mem_data = (ImU8*)mem_data_void; + ImGuiStyle* style = igGetStyle(); + igAlignTextToFramePadding(); + igText("Preview as:"); + igSameLine(0, -1); + igSetNextItemWidth((s->GlyphWidth * 10.0f) + style->FramePadding.x * 2.0f + + style->ItemInnerSpacing.x); + if (igBeginCombo("##combo_type", MemoryEditor_DataTypeGetDesc(editor->PreviewDataType), + ImGuiComboFlags_HeightLargest)) { + for (int n = 0; n < ImGuiDataType_COUNT; n++) + if (igSelectable_Bool(MemoryEditor_DataTypeGetDesc((ImGuiDataType)n), + editor->PreviewDataType == n, 0, vec1)) + editor->PreviewDataType = (ImGuiDataType)n; + igEndCombo(); + } + igSameLine(0, -1); + igSetNextItemWidth((s->GlyphWidth * 6.0f) + style->FramePadding.x * 2.0f + + style->ItemInnerSpacing.x); + igCombo_Str("##combo_endianess", &editor->PreviewEndianess, "LE\0BE\0\0", -1); + + char buf[128] = ""; + float x = s->GlyphWidth * 6.0f; + bool has_value = editor->DataPreviewAddr != (size_t)-1; + if (has_value) + MemoryEditor_DrawPreviewData(editor, editor->DataPreviewAddr, mem_data, mem_size, + editor->PreviewDataType, DataFormat_Dec, buf, + (size_t)IM_ARRAYSIZE(buf)); + igText("Dec"); + igSameLine(x, -1); + igTextUnformatted(has_value ? buf : "N/A", NULL); + if (has_value) + MemoryEditor_DrawPreviewData(editor, editor->DataPreviewAddr, mem_data, mem_size, + editor->PreviewDataType, DataFormat_Hex, buf, + (size_t)IM_ARRAYSIZE(buf)); + igText("Hex"); + igSameLine(x, -1); + igTextUnformatted(has_value ? buf : "N/A", NULL); + if (has_value) + MemoryEditor_DrawPreviewData(editor, editor->DataPreviewAddr, mem_data, mem_size, + editor->PreviewDataType, DataFormat_Bin, buf, + (size_t)IM_ARRAYSIZE(buf)); + buf[IM_ARRAYSIZE(buf) - 1] = 0; + igText("Bin"); + igSameLine(x, -1); + igTextUnformatted(has_value ? buf : "N/A", NULL); +} + +// Utilities for Data Preview +const char* MemoryEditor_DataTypeGetDesc(ImGuiDataType data_type) { + const char* descs[] = { "Int8", "Uint8", "Int16", "Uint16", "Int32", + "Uint32", "Int64", "Uint64", "Float", "Double" }; + // IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + return descs[data_type]; +} + +size_t MemoryEditor_DataTypeGetSize(ImGuiDataType data_type) { + const size_t sizes[] = { 1, 1, 2, 2, 4, 4, 8, 8, sizeof(float), sizeof(double) }; + // IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + return sizes[data_type]; +} + +const char* MemoryEditor_DataFormatGetDesc(DataFormat data_format) { + const char* descs[] = { "Bin", "Dec", "Hex" }; + // IM_ASSERT(data_format >= 0 && data_format < DataFormat_COUNT); + return descs[data_format]; +} + +bool MemoryEditor_IsBigEndian() { + uint16_t x = 1; + char c[2]; + memcpy(c, &x, 2); + return c[0] != 0; +} + +static void* MemoryEditor_EndianessCopyBigEndian(void* _dst, void* _src, size_t s, + int is_little_endian) { + if (is_little_endian) { + uint8_t* dst = (uint8_t*)_dst; + uint8_t* src = (uint8_t*)_src + s - 1; + for (int i = 0, n = (int)s; i < n; ++i) memcpy(dst++, src--, 1); + return _dst; + } else { + return memcpy(_dst, _src, s); + } +} + +static void* MemoryEditor_EndianessCopyLittleEndian(void* _dst, void* _src, size_t s, + int is_little_endian) { + if (is_little_endian) { + return memcpy(_dst, _src, s); + } else { + uint8_t* dst = (uint8_t*)_dst; + uint8_t* src = (uint8_t*)_src + s - 1; + for (int i = 0, n = (int)s; i < n; ++i) memcpy(dst++, src--, 1); + return _dst; + } +} + +void* MemoryEditor_EndianessCopy(MemoryEditor* editor, void* dst, void* src, size_t size) { + static void* (*fp)(void*, void*, size_t, int) = NULL; + if (fp == NULL) + fp = MemoryEditor_IsBigEndian() ? MemoryEditor_EndianessCopyBigEndian + : MemoryEditor_EndianessCopyLittleEndian; + return fp(dst, src, size, editor->PreviewEndianess); +} + +const char* MemoryEditor_FormatBinary(const uint8_t* buf, int width) { + // IM_ASSERT(width <= 64); + size_t out_n = 0; + static char out_buf[64 + 8 + 1]; + int n = width / 8; + for (int j = n - 1; j >= 0; --j) { + for (int i = 0; i < 8; ++i) out_buf[out_n++] = (buf[j] & (1 << (7 - i))) ? '1' : '0'; + out_buf[out_n++] = ' '; + } + // IM_ASSERT(out_n < IM_ARRAYSIZE(out_buf)); + out_buf[out_n] = 0; + return out_buf; +} + +// [Internal] +void MemoryEditor_DrawPreviewData(MemoryEditor* editor, size_t addr, const ImU8* mem_data, + size_t mem_size, ImGuiDataType data_type, DataFormat data_format, + char* out_buf, size_t out_buf_size) { + uint8_t buf[8]; + size_t elem_size = MemoryEditor_DataTypeGetSize(data_type); + size_t size = addr + elem_size > mem_size ? mem_size - addr : elem_size; + if (editor->ReadFn) + for (int i = 0, n = (int)size; i < n; ++i) buf[i] = editor->ReadFn(mem_data, addr + i); + else + memcpy(buf, mem_data + addr, size); + + if (data_format == DataFormat_Bin) { + uint8_t binbuf[8]; + MemoryEditor_EndianessCopy(editor, binbuf, buf, size); + ImSnprintf(out_buf, out_buf_size, "%s", MemoryEditor_FormatBinary(binbuf, (int)size * 8)); + return; + } + + out_buf[0] = 0; + switch (data_type) { + case ImGuiDataType_S8: { + int8_t int8 = 0; + MemoryEditor_EndianessCopy(editor, &int8, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%hhd", int8); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%02x", int8 & 0xFF); + return; + } + break; + } + case ImGuiDataType_U8: { + uint8_t uint8 = 0; + MemoryEditor_EndianessCopy(editor, &uint8, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%hhu", uint8); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%02x", uint8 & 0XFF); + return; + } + break; + } + case ImGuiDataType_S16: { + int16_t int16 = 0; + MemoryEditor_EndianessCopy(editor, &int16, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%hd", int16); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%04x", int16 & 0xFFFF); + return; + } + break; + } + case ImGuiDataType_U16: { + uint16_t uint16 = 0; + MemoryEditor_EndianessCopy(editor, &uint16, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%hu", uint16); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%04x", uint16 & 0xFFFF); + return; + } + break; + } + case ImGuiDataType_S32: { + int32_t int32 = 0; + MemoryEditor_EndianessCopy(editor, &int32, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%d", int32); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%08x", int32); + return; + } + break; + } + case ImGuiDataType_U32: { + uint32_t uint32 = 0; + MemoryEditor_EndianessCopy(editor, &uint32, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%u", uint32); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%08x", uint32); + return; + } + break; + } + case ImGuiDataType_S64: { + int64_t int64 = 0; + MemoryEditor_EndianessCopy(editor, &int64, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%lld", (long long)int64); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)int64); + return; + } + break; + } + case ImGuiDataType_U64: { + uint64_t uint64 = 0; + MemoryEditor_EndianessCopy(editor, &uint64, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%llu", (long long)uint64); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)uint64); + return; + } + break; + } + case ImGuiDataType_Float: { + float float32 = 0.0f; + MemoryEditor_EndianessCopy(editor, &float32, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%f", float32); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "%a", float32); + return; + } + break; + } + case ImGuiDataType_Double: { + double float64 = 0.0; + MemoryEditor_EndianessCopy(editor, &float64, buf, size); + if (data_format == DataFormat_Dec) { + ImSnprintf(out_buf, out_buf_size, "%f", float64); + return; + } + if (data_format == DataFormat_Hex) { + ImSnprintf(out_buf, out_buf_size, "%a", float64); + return; + } + break; + } + case ImGuiDataType_COUNT: + break; + } +} \ No newline at end of file diff --git a/src/micetools/dll/gui/imgui_memory_editor.h b/src/micetools/dll/gui/imgui_memory_editor.h new file mode 100644 index 0000000..a523927 --- /dev/null +++ b/src/micetools/dll/gui/imgui_memory_editor.h @@ -0,0 +1,135 @@ +#pragma once +// Ported to C from +// https://github.com/ocornut/imgui_club/blob/master/imgui_memory_editor/imgui_memory_editor.h + +#include +#include +#include +#include +#include + +#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS +#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS +#endif +#include "cimgui.h" + +#ifdef _MSC_VER +#define _PRISizeT "I" +#define ImSnprintf _snprintf +#else +#define _PRISizeT "z" +#define ImSnprintf snprintf +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning( \ + disable : 4996) // warning C4996: 'sprintf': This function or variable may be unsafe. +#endif + +typedef enum DataFormat_ { + DataFormat_Bin = 0, + DataFormat_Dec = 1, + DataFormat_Hex = 2, + DataFormat_COUNT +} DataFormat; + +typedef struct UserData_ { + char CurrentBufOverwrite[3]; // Input + int CursorPos; // Output +} UserData; +// FIXME: We should have a way to retrieve the text edit cursor position +// more easily in the API, this is rather tedious. This is such a ugly mess +// we may be better off not using InputText() at all here. +static int UserData_Callback(ImGuiInputTextCallbackData* data); + +typedef struct MemoryEditor_ { + // Settings + bool Open; // = true // set to false when DrawWindow() was closed. ignore if not using + // DrawWindow(). + bool ReadOnly; // = false // disable any editing. + int Cols; // = 16 // number of columns to display. + bool OptShowOptions; // = true // display options button/context menu. when disabled, options + // will be locked unless you provide your own UI for them. + bool + OptShowDataPreview; // = false // display a footer previewing the decimal/binary/hex/float + // representation of the currently selected bytes. + bool OptShowHexII; // = false // display values in HexII representation instead of regular + // hexadecimal: hide null/zero bytes, ascii values as ".X". + bool OptShowAscii; // = true // display ASCII representation on the right side. + bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color. + bool OptUpperCaseHex; // = true // display hexadecimal values as "FF" instead of "ff". + int OptMidColsCount; // = 8 // set to 0 to disable extra spacing between every mid-cols. + int OptAddrDigitsCount; // = 0 // number of addr digits to display (default calculated + // based on maximum displayed addr). + float OptFooterExtraHeight; // = 0 // space to reserve at the bottom of the widget to add + // custom widgets + ImU32 HighlightColor; // // background color of highlighted bytes. + ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes. + void (*WriteFn)(ImU8* data, size_t off, + ImU8 d); // = 0 // optional handler to write bytes. + bool (*HighlightFn)(const ImU8* data, + size_t off); //= 0 // optional handler to return Highlight property + //(to support non-contiguous highlighting). + + // [Internal State] + bool ContentsWidthChanged; + size_t DataPreviewAddr; + size_t DataEditingAddr; + bool DataEditingTakeFocus; + char DataInputBuf[32]; + char AddrInputBuf[32]; + size_t GotoAddr; + size_t HighlightMin, HighlightMax; + int PreviewEndianess; + ImGuiDataType PreviewDataType; +} MemoryEditor; + +void MemoryEditor_Init(MemoryEditor* editor); + +void MemoryEditor_GotoAddrAndHighlight(MemoryEditor* editor, size_t addr_min, size_t addr_max); + +typedef struct Sizes_ { + int AddrDigitsCount; + float LineHeight; + float GlyphWidth; + float HexCellWidth; + float SpacingBetweenMidCols; + float PosHexStart; + float PosHexEnd; + float PosAsciiStart; + float PosAsciiEnd; + float WindowWidth; +} Sizes; + +void MemoryEditor_CalcSizes(MemoryEditor* editor, Sizes* s, size_t mem_size, + size_t base_display_addr); + +// Standalone Memory Editor window +void MemoryEditor_DrawWindow(MemoryEditor* editor, const char* title, void* mem_data, + size_t mem_size, size_t base_display_addr); + +// Memory Editor contents only +void MemoryEditor_DrawContents(MemoryEditor* editor, void* mem_data_void, size_t mem_size, + size_t base_display_addr); +void MemoryEditor_DrawOptionsLine(MemoryEditor* editor, const Sizes* s, void* mem_data, + size_t mem_size, size_t base_display_addr); +void MemoryEditor_DrawPreviewLine(MemoryEditor* editor, const Sizes* s, void* mem_data_void, + size_t mem_size, size_t base_display_addr); + +// Utilities for Data Preview +const char* MemoryEditor_DataTypeGetDesc(ImGuiDataType data_type); +size_t MemoryEditor_DataTypeGetSize(ImGuiDataType data_type); +const char* MemoryEditor_DataFormatGetDesc(DataFormat data_format); +bool MemoryEditor_IsBigEndian(void); + +static void* MemoryEditor_EndianessCopyBigEndian(void* _dst, void* _src, size_t s, + int is_little_endian); +static void* MemoryEditor_EndianessCopyLittleEndian(void* _dst, void* _src, size_t s, + int is_little_endian); +void* MemoryEditor_EndianessCopy(MemoryEditor* editor, void* dst, void* src, size_t size); +const char* MemoryEditor_FormatBinary(const uint8_t* buf, int width); +// [Internal] +void MemoryEditor_DrawPreviewData(MemoryEditor* editor, size_t addr, const ImU8* mem_data, + size_t mem_size, ImGuiDataType data_type, DataFormat data_format, + char* out_buf, size_t out_buf_size); \ No newline at end of file diff --git a/src/micetools/dll/gui/meson.build b/src/micetools/dll/gui/meson.build index aae5d3b..e173183 100644 --- a/src/micetools/dll/gui/meson.build +++ b/src/micetools/dll/gui/meson.build @@ -1,3 +1,4 @@ gui_files = files( + 'imgui_memory_editor.c', 'gui.c', ) diff --git a/src/micetools/dll/hooks/com.c b/src/micetools/dll/hooks/com.c index b70f1c1..e65674f 100644 --- a/src/micetools/dll/hooks/com.c +++ b/src/micetools/dll/hooks/com.c @@ -1,8 +1,8 @@ +#define _MICE_COM #include "com.h" #include "files.h" -com_hook_t* com_hook_list = NULL; com_hook_t* new_com_hook(BYTE port) { com_hook_t* hook = (com_hook_t*)malloc(sizeof *hook); @@ -26,145 +26,136 @@ com_hook_t* new_com_hook(BYTE port) { return hook; } -void hook_com(com_hook_t* hook) { - hook->next = NULL; - hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE)); - *hook->virtual_handle = NULL; - if (com_hook_list == NULL) { - com_hook_list = hook; - return; - } - - com_hook_t* hl = com_hook_list; - while (hl->next != NULL) hl = hl->next; - hl->next = hook; -} - BOOL WINAPI FakeGetCommState(HANDLE hFile, LPDCB lpDCB) { - com_hook_t* hook = get_handle_com_hook(hFile); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); log_misc(COMM_LOGGER, "GetCommState(0x%p, 0x%p) (%08x)", hFile, lpDCB, hook); - if (hook != NULL) { - if (hook->GetCommState == NULL) { - log_error(COMM_LOGGER, "GetCommState(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->GetCommState(hook->data, lpDCB); + if (pHData == NULL || pHData->hook->com_hook == NULL) return TrueGetCommState(hFile, lpDCB); + com_hook_t* com_hook = pHData->hook->com_hook; + + if (com_hook->GetCommState == NULL) { + log_error(COMM_LOGGER, "GetCommState(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TrueGetCommState(hFile, lpDCB); + return com_hook->GetCommState(hFile, lpDCB); } BOOL WINAPI FakeSetCommState(HANDLE hFile, LPDCB lpDCB) { log_misc(COMM_LOGGER, "SetCommState(0x%p, 0x%p)", hFile, lpDCB); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->SetCommState == NULL) { - log_error(COMM_LOGGER, "SetCommState(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->SetCommState(hook->data, lpDCB); - } + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) return TrueSetCommState(hFile, lpDCB); - return TrueSetCommState(hFile, lpDCB); + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->SetCommState == NULL) { + log_error(COMM_LOGGER, "SetCommState(%ls) unimplemented", com_hook->wName); + return FALSE; + } + return com_hook->SetCommState(hFile, lpDCB); } BOOL WINAPI FakeGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { log_misc(COMM_LOGGER, "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->GetCommTimeouts == NULL) { - log_error(COMM_LOGGER, "GetCommTimeouts(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->GetCommTimeouts(hook->data, lpCommTimeouts); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) + return TrueGetCommTimeouts(hFile, lpCommTimeouts); + + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->GetCommTimeouts == NULL) { + log_error(COMM_LOGGER, "GetCommTimeouts(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TrueGetCommTimeouts(hFile, lpCommTimeouts); + return com_hook->GetCommTimeouts(hFile, lpCommTimeouts); } BOOL WINAPI FakeSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { log_misc(COMM_LOGGER, "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->SetCommTimeouts == NULL) { - log_error(COMM_LOGGER, "SetCommTimeouts(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->SetCommTimeouts(hook->data, lpCommTimeouts); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) + return TrueSetCommTimeouts(hFile, lpCommTimeouts); + + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->SetCommTimeouts == NULL) { + log_error(COMM_LOGGER, "SetCommTimeouts(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TrueSetCommTimeouts(hFile, lpCommTimeouts); + return com_hook->SetCommTimeouts(hFile, lpCommTimeouts); } BOOL WINAPI FakeSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) { log_misc(COMM_LOGGER, "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->SetupComm == NULL) { - log_error(COMM_LOGGER, "SetupComm(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->SetupComm(hook->data, dwInQueue, dwOutQueue); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) + return TrueSetupComm(hFile, dwInQueue, dwOutQueue); + + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->SetupComm == NULL) { + log_error(COMM_LOGGER, "SetupComm(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TrueSetupComm(hFile, dwInQueue, dwOutQueue); + return com_hook->SetupComm(hFile, dwInQueue, dwOutQueue); } BOOL WINAPI FakePurgeComm(HANDLE hFile, DWORD dwFlags) { log_misc(COMM_LOGGER, "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->PurgeComm == NULL) { - log_error(COMM_LOGGER, "PurgeComm(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->PurgeComm(hook->data, dwFlags); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) return TruePurgeComm(hFile, dwFlags); + + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->PurgeComm == NULL) { + log_error(COMM_LOGGER, "PurgeComm(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TruePurgeComm(hFile, dwFlags); + return com_hook->PurgeComm(hFile, dwFlags); } BOOL WINAPI FakeGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) { log_misc(COMM_LOGGER, "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->GetCommModemStatus == NULL) { - log_error(COMM_LOGGER, "GetCommModemStatus(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->GetCommModemStatus(hook->data, lpModelStat); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) + return TrueGetCommModemStatus(hFile, lpModelStat); + + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->GetCommModemStatus == NULL) { + log_error(COMM_LOGGER, "GetCommModemStatus(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TrueGetCommModemStatus(hFile, lpModelStat); + return com_hook->GetCommModemStatus(hFile, lpModelStat); } BOOL WINAPI FakeWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) { log_misc(COMM_LOGGER, "WaitCommEvent(0x%p)", hFile); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->WaitCommEvent == NULL) { - log_error(COMM_LOGGER, "WaitCommEvent(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->WaitCommEvent(hook->data, lpEvtMask, lpOverlapped); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) + return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped); + + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->WaitCommEvent == NULL) { + log_error(COMM_LOGGER, "WaitCommEvent(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped); + return com_hook->WaitCommEvent(hFile, lpEvtMask, lpOverlapped); } BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) { log_trace(COMM_LOGGER, "ClearCommError(0x%p)", hFile); - com_hook_t* hook = get_handle_com_hook(hFile); - if (hook != NULL) { - if (hook->ClearCommError == NULL) { - log_error(COMM_LOGGER, "ClearCommError(%ls) unimplemented", hook->wName); - return FALSE; - } - return hook->ClearCommError(hook->data, lpErrors, lpStat); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL || pHData->hook->com_hook == NULL) + return TrueClearCommError(hFile, lpErrors, lpStat); + + com_hook_t* com_hook = pHData->hook->com_hook; + if (com_hook->ClearCommError == NULL) { + log_error(COMM_LOGGER, "ClearCommError(%ls) unimplemented", com_hook->wName); + return FALSE; } - return TrueClearCommError(hFile, lpErrors, lpStat); + return com_hook->ClearCommError(hFile, lpErrors, lpStat); } void hook_commio() { diff --git a/src/micetools/dll/hooks/com.h b/src/micetools/dll/hooks/com.h index 9ced280..d9cf36a 100644 --- a/src/micetools/dll/hooks/com.h +++ b/src/micetools/dll/hooks/com.h @@ -1,26 +1,30 @@ #pragma once +#ifndef _MICE_COM +#define _MICE_COM extern +#endif + #include "../common.h" -static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB); -static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB); -static BOOL(WINAPI* TrueGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); -static BOOL(WINAPI* TrueSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); -static BOOL(WINAPI* TrueSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue); -static BOOL(WINAPI* TruePurgeComm)(HANDLE hFile, DWORD dwFlags); -static BOOL(WINAPI* TrueGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat); -static BOOL(WINAPI* TrueWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped); -static BOOL(WINAPI* TrueClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat); +_MICE_COM BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB); +_MICE_COM BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB); +_MICE_COM BOOL(WINAPI* TrueGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); +_MICE_COM BOOL(WINAPI* TrueSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); +_MICE_COM BOOL(WINAPI* TrueSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue); +_MICE_COM BOOL(WINAPI* TruePurgeComm)(HANDLE hFile, DWORD dwFlags); +_MICE_COM BOOL(WINAPI* TrueGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat); +_MICE_COM BOOL(WINAPI* TrueWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped); +_MICE_COM BOOL(WINAPI* TrueClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat); -typedef BOOL(FnGetCommState)(void* com, LPDCB lpDCB); -typedef BOOL(FnSetCommState)(void* com, LPDCB lpDCB); -typedef BOOL(FnGetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts); -typedef BOOL(FnSetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts); -typedef BOOL(FnSetupComm)(void* com, DWORD dwInQueue, DWORD dwOutQueue); -typedef BOOL(FnPurgeComm)(void* com, DWORD dwFlags); -typedef BOOL(FnGetCommModemStatus)(void* com, LPDWORD lpModelStat); -typedef BOOL(FnWaitCommEvent)(void* com, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped); -typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat); +typedef BOOL(FnGetCommState)(HANDLE hFile, LPDCB lpDCB); +typedef BOOL(FnSetCommState)(HANDLE hFile, LPDCB lpDCB); +typedef BOOL(FnGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); +typedef BOOL(FnSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); +typedef BOOL(FnSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue); +typedef BOOL(FnPurgeComm)(HANDLE hFile, DWORD dwFlags); +typedef BOOL(FnGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat); +typedef BOOL(FnWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped); +typedef BOOL(FnClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat); typedef struct com_hook { LPHANDLE virtual_handle; @@ -38,13 +42,11 @@ typedef struct com_hook { FnWaitCommEvent* WaitCommEvent; FnClearCommError* ClearCommError; - void* data; + void* com_device; struct com_hook* next; } com_hook_t; -extern com_hook_t* com_hook_list; - com_hook_t* new_com_hook(BYTE port); void hook_com(com_hook_t* hook); diff --git a/src/micetools/dll/hooks/drive.c b/src/micetools/dll/hooks/drive.c index 5c4c5d7..4ca0aa1 100644 --- a/src/micetools/dll/hooks/drive.c +++ b/src/micetools/dll/hooks/drive.c @@ -1,12 +1,145 @@ #include "drive.h" +#include +#include + #include "./files.h" -BOOL c_drive_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, - LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +typedef struct _physical_disk physical_disk_t; +typedef struct _disk_partition disk_partition_t; +typedef struct _disk_volume disk_volume_t; + +struct _disk_volume { + wchar_t m_FilenameW[MAX_PATH + 1]; + char m_FilenameA[MAX_PATH + 1]; + LPSTR m_Name; + char m_MountPoint; + + // Back-references + physical_disk_t* m_pDrive; + disk_partition_t* m_pPartition; + BOOL m_NameIsOnHeap; +}; +struct _disk_partition { + DWORD m_Size; + UCHAR m_Filesystem; + spd_slot_t m_SPDContent; + UCHAR* m_Content; + LONGLONG m_ContentSize; + + disk_volume_t m_Volume; + + DWORD m_PhysicalLBA; + DWORD m_SlotLBA; + DWORD m_PartitionNumber; +}; +struct _physical_disk { + DWORD m_DriveNumber; + STORAGE_BUS_TYPE m_BusType; + LPSTR m_VID; + LPSTR m_PID; + DWORD m_BootPartition; + BOOL m_HasSegaboot; + + disk_partition_t m_Partitions[4]; + disk_partition_t m_Extended[]; +}; + +/* + First 512 bytes of SPD_Original0: + LOADER::LoadBootIDHeader +*/ +BYTE Original0BootIDHeader[512] = { + 0x4B, 0xDF, 0xB4, 0x43, 0x27, 0x3C, 0xFE, 0xD6, 0xA2, 0xA8, 0xF8, 0xFD, 0xB4, 0x55, 0xE6, 0xBA, + 0x5A, 0x0F, 0xBF, 0x14, 0xA4, 0x37, 0xB6, 0x42, 0xB3, 0xAD, 0x11, 0x4A, 0xCA, 0x1A, 0x4C, 0xD9, + 0x11, 0xF1, 0x60, 0x4B, 0x37, 0x58, 0x9C, 0x9A, 0x89, 0x8F, 0x07, 0x9C, 0xE7, 0xF2, 0x64, 0xCC, + 0x6E, 0x84, 0x87, 0xAA, 0x20, 0xA0, 0xB8, 0x55, 0x9B, 0xE7, 0x79, 0x4F, 0x51, 0x25, 0xC3, 0x7E, + 0xEF, 0xD9, 0x25, 0xA9, 0x94, 0xF1, 0x7F, 0xEF, 0xE1, 0xD9, 0xAE, 0x4F, 0xC2, 0xEE, 0xB6, 0xA8, + 0xD9, 0x54, 0x0F, 0x33, 0xA8, 0xA9, 0x22, 0x72, 0x81, 0xD0, 0xA3, 0x04, 0x5C, 0x45, 0x3E, 0xBE, + 0xF7, 0x2A, 0xED, 0x55, 0xAB, 0x16, 0xC1, 0xA8, 0x61, 0x70, 0xEE, 0x55, 0xCB, 0xE6, 0x68, 0xA5, + 0xB4, 0xDC, 0x30, 0x6D, 0x32, 0xD6, 0x69, 0x8D, 0xFC, 0x90, 0x71, 0x7E, 0xDB, 0x6B, 0x17, 0xFA, + 0xAB, 0xE0, 0x11, 0x14, 0xBA, 0xD9, 0x33, 0xB7, 0x7C, 0x54, 0x9E, 0x21, 0xA1, 0x43, 0xFD, 0x8F, + 0x14, 0xF4, 0xBE, 0x5F, 0x0B, 0x02, 0x8E, 0x87, 0xCA, 0x85, 0xE9, 0xC1, 0x60, 0xF7, 0x7E, 0x44, + 0x55, 0x3A, 0x5E, 0x94, 0x65, 0x95, 0xFD, 0x02, 0xF9, 0xFF, 0xBF, 0x07, 0x80, 0xC5, 0x26, 0x58, + 0x6F, 0x37, 0xFA, 0x59, 0x2F, 0x02, 0xF3, 0x9D, 0x24, 0x7D, 0x42, 0x6B, 0xF3, 0x49, 0x63, 0xC9, + 0x2A, 0xCB, 0xFC, 0x71, 0x69, 0x44, 0xB5, 0xAC, 0xD3, 0x37, 0xA0, 0x01, 0x65, 0x3D, 0x49, 0xC4, + 0x7D, 0xE5, 0xF8, 0x6E, 0x09, 0xC7, 0x3E, 0xD1, 0x96, 0x09, 0x23, 0xA4, 0xE8, 0xA5, 0x6A, 0xA2, + 0x5B, 0x5B, 0xA5, 0x9C, 0xF8, 0x8D, 0x84, 0x55, 0x3F, 0x19, 0x8F, 0xDC, 0xFA, 0x7B, 0xF1, 0xC9, + 0xB6, 0xBF, 0xE8, 0x73, 0xB9, 0xC9, 0xC3, 0x17, 0x14, 0xAB, 0xA3, 0x60, 0x13, 0xED, 0x6D, 0xCC, + 0x10, 0x7B, 0x1D, 0xC6, 0xBC, 0xEC, 0x56, 0xFA, 0x52, 0xC5, 0x4E, 0xAC, 0x8F, 0x36, 0x8B, 0x92, + 0x6C, 0xB5, 0x9A, 0x57, 0x7D, 0xFA, 0x97, 0x72, 0xFC, 0xFA, 0xB8, 0xFE, 0x20, 0x71, 0xFB, 0x63, + 0x00, 0x96, 0x29, 0xCE, 0xE2, 0x06, 0xFF, 0x64, 0x48, 0xB5, 0x1F, 0xD6, 0x88, 0x48, 0x7A, 0x62, + 0x2B, 0xBE, 0xE6, 0xC4, 0xFD, 0xF6, 0x85, 0x45, 0x0A, 0x8C, 0x6C, 0x20, 0x64, 0x05, 0x81, 0x13, + 0xB5, 0x59, 0xAE, 0x34, 0x41, 0x0B, 0xB5, 0x65, 0x57, 0x59, 0x9C, 0xE8, 0xD0, 0xAE, 0x81, 0xD8, + 0x6D, 0xC9, 0xFD, 0xF8, 0xC9, 0x15, 0xB6, 0xDC, 0xC9, 0x13, 0xF2, 0x6E, 0xD9, 0xA5, 0x77, 0x62, + 0xB7, 0x15, 0x61, 0x21, 0x73, 0xFE, 0x0A, 0x57, 0x3B, 0x2C, 0x2F, 0x23, 0xC3, 0x33, 0xB8, 0x77, + 0xCE, 0xCE, 0x76, 0x98, 0xDB, 0xE5, 0x9A, 0x00, 0xE1, 0xC3, 0x6F, 0x7D, 0x42, 0xC4, 0xDE, 0xB7, + 0x1D, 0xA0, 0xC1, 0x1C, 0xB9, 0x09, 0x28, 0xD9, 0x59, 0x9D, 0x3F, 0xEA, 0xF1, 0xB6, 0xA0, 0x1C, + 0x5E, 0x4A, 0xE4, 0x1A, 0xE7, 0xA7, 0x1C, 0xAD, 0xF6, 0xF1, 0xCB, 0x9C, 0x06, 0xE6, 0x4C, 0xF4, + 0xD6, 0xEE, 0x5F, 0x18, 0xF5, 0x00, 0x4A, 0x76, 0x5E, 0x7D, 0x96, 0x20, 0x57, 0x68, 0x23, 0x69, + 0x8F, 0x60, 0x91, 0xBF, 0x00, 0x08, 0xFE, 0x4F, 0x36, 0x45, 0x86, 0x14, 0x48, 0xC5, 0x8B, 0xEA, + 0xE3, 0x64, 0x27, 0x1E, 0x49, 0xDF, 0x98, 0xAD, 0xE2, 0x66, 0x09, 0x07, 0xDD, 0x24, 0xB0, 0x4D, + 0x52, 0xA6, 0xD1, 0x3D, 0xB9, 0x52, 0x0B, 0x88, 0x97, 0x97, 0x0F, 0x83, 0x85, 0xD5, 0x3F, 0x0E, + 0x1A, 0xF2, 0x26, 0xBA, 0x14, 0x53, 0xDD, 0xF4, 0x7D, 0xAF, 0xB6, 0xEE, 0x36, 0x3A, 0xB5, 0xDA, + 0x2F, 0x99, 0xC8, 0x54, 0xD2, 0xDB, 0x52, 0x49, 0xD6, 0xB6, 0x07, 0x1A, 0xBA, 0x9A, 0x85, 0xBB, +}; + +physical_disk_t SSD = { + .m_DriveNumber = 0, + .m_BusType = BusTypeAta, + .m_BootPartition = 1, + .m_HasSegaboot = TRUE, + .m_Partitions = { + // 1.5GB boot partitions + { + .m_Size = 0x300B85, + .m_Filesystem = MBR_FS_NTFS, + }, + // 1.5GB recovery partitions + { + .m_Size = 0x300BC4, + .m_Filesystem = MBR_FS_NTFS, + }, + }, + .m_Extended = { + { 0x102d83, MBR_FS_FAT16, SPD_OS }, // 512MB OS update + { 0x403947, MBR_FS_FAT16, SPD_Patch0 }, // 2GB patch0 + { 0x403947, MBR_FS_FAT16, SPD_Patch1 }, // 2GB patch1 + { 0x48ed459, MBR_FS_NTFS, SPD_AppData }, // 40GB something + { + 0x20014aa, + MBR_FS_FAT16, + SPD_Original0, + .m_Content = Original0BootIDHeader, + .m_ContentSize = sizeof Original0BootIDHeader, + }, // 16GB game + { 0 }, + }, +}; +physical_disk_t UPDATE_USB = { + .m_DriveNumber = 1, + .m_BusType = BusTypeUsb, + .m_VID = "13FE", + .m_PID = "4200", + .m_Partitions = { + // 59050 MB update partitions + { + .m_Size = 0x735a080, + .m_Filesystem = MBR_FS_NTFS, + .m_Volume = { + .m_Name = "SEGA_INS", + }, + }, + }, + .m_Extended = {{0}}, +}; +physical_disk_t* PHYSICAL_DISKS[] = { &SSD, &UPDATE_USB }; + +BOOL WINAPI c_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { log_trace("C", "DeviceIOControl %08x", dwIoControlCode); - memset(lpOutBuffer, 0, nInBufferSize); + ZeroMemory(lpOutBuffer, nOutBufferSize); switch (dwIoControlCode) { case IOCTL_STORAGE_GET_DEVICE_NUMBER: ((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK; @@ -21,11 +154,11 @@ BOOL c_drive_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffe } } -BOOL x_drive_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, - LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +BOOL WINAPI x_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { log_trace("X", "DeviceIOControl %08x", dwIoControlCode); - memset(lpOutBuffer, 0, nInBufferSize); + ZeroMemory(lpOutBuffer, nOutBufferSize); switch (dwIoControlCode) { case IOCTL_STORAGE_GET_DEVICE_NUMBER: ((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK; @@ -37,126 +170,57 @@ BOOL x_drive_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffe } } -LARGE_INTEGER pd0_file_pointer; -BOOL pd0_SetFilePointerEx(void* file, LARGE_INTEGER liDistanceToMove, - PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) { - log_trace("pd0", "Seek 0x%08x", liDistanceToMove.QuadPart); - if (dwMoveMethod == FILE_BEGIN) - pd0_file_pointer = liDistanceToMove; - else - pd0_file_pointer.QuadPart += liDistanceToMove.QuadPart; - if (lpNewFilePointer) lpNewFilePointer->QuadPart = pd0_file_pointer.QuadPart; - return TRUE; -} -DWORD pd0_SetFilePointer(void* file, LONG liDistanceToMove, PLONG lpDistanceToMoveHigh, - DWORD dwMoveMethod) { - if (lpDistanceToMoveHigh && *lpDistanceToMoveHigh) - log_trace("pd0", "Seek 0x%x%08x", *lpDistanceToMoveHigh, liDistanceToMove); - else - log_trace("pd0", "Seek 0x%08x", liDistanceToMove); - - if (dwMoveMethod == FILE_BEGIN) { - if (lpDistanceToMoveHigh) - pd0_file_pointer.HighPart = *lpDistanceToMoveHigh; - else - pd0_file_pointer.HighPart = 0; - pd0_file_pointer.LowPart = liDistanceToMove; - } else { - pd0_file_pointer.QuadPart += liDistanceToMove; - if (lpDistanceToMoveHigh) pd0_file_pointer.HighPart += *lpDistanceToMoveHigh; +BOOL WINAPI pd_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { + physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData; + if (pd == NULL) { + log_error("drive", "ioctl:ctx->m_HookData NULL; expected a physical drive!"); + return FALSE; } - return pd0_file_pointer.LowPart; + + log_trace("drive", "DeviceIOControl %08x", dwIoControlCode); + ZeroMemory(lpOutBuffer, nOutBufferSize); + switch (dwIoControlCode) { + case IOCTL_ATA_PASS_THROUGH: + if (pd->m_BusType != BusTypeAta) return FALSE; + + PATA_PASS_THROUGH_EX ata = (PATA_PASS_THROUGH_EX)lpInBuffer; + + BYTE command = ata->CurrentTaskFile[6]; + if (command != 0xC1) { + log_error("pd0", "Unimplemented ATA command: %02x", command); + return FALSE; + } + + BYTE data = ata->CurrentTaskFile[0]; + switch (data) { + // These are used un UnlockSection1, 2, and 3 in mxstorage! + + case 0x11: // mxkSsdHostProofSet (step == 0) + // Game -> ATA | 128 bytes: random from N2 + case 0x12: // mxkSsdHostProofGet (step == 0) + // ATA -> GAME | 128 bytes: (guess) readback of 0x11 + case 0x21: // mxkSsdHostProofSet (step == 1) + // Game -> ATA | 128 bytes: random from N2 + case 0x22: // mxkSsdHostProofGet (step == 1) + // ATA -> GAME | 128 bytes: (guess) readback of 0x21 + case 0x31: // mxkSsdHostProofSeed + // ATA -> Game | 80 bytes: seed + case 0x32: // mxkSsdHostProofChallenge + // Game -> ATA | 80 bytes: the seed, encrypted by N2 with S-Key + + // It looks like mxkeychip never actually checks the response buffer, + // as long as the ioctl succeeds! Saves us a lot of work here! + return TRUE; + } + log_error("drive", "Unimeplemented ATA C1 command: %02x", data); + return FALSE; + } + log_error("drive", "Unimplemented ioctl: %08x", dwIoControlCode); + return FALSE; } -void write_chs(BYTE* chs, WORD cylinder, BYTE head, BYTE sector) { - chs[0] = head; - chs[1] = sector | ((cylinder >> 8) << 6); - chs[2] = cylinder & 0xff; -} - -#pragma pack(1) -typedef struct spd { - uint32_t crc; - uint8_t version; - uint8_t _[11]; -#pragma pack(1) - struct { - /* - (BCD) - 1.0 = original0 - 1.1 = original1 - 2.0 = patch0 - 2.1 = patch1 - 3.0 = os - 4.0 = app_data - */ - spd_slot_t slot_content; - /* - Guess: Filesystem type - 0: Encrypted FAT16 - 1: Decrypted NTFS - */ - uint8_t uk1; - uint16_t block_size; - uint32_t block_count; - uint8_t __[8]; - } slots[31]; -} spd_t; - -#pragma pack(1) -typedef struct { - uint16_t year; - uint8_t mon; - uint8_t day; - uint8_t hour; - uint8_t min; - uint8_t sec; - uint8_t _; -} slot_time_t; -#pragma pack(1) -typedef struct { - char id[4]; - slot_time_t time; - uint32_t version; - uint32_t _[2]; - uint32_t segcount; - uint32_t segsize; - - char hw[3]; - uint8_t instant; - slot_time_t orgtime; - uint32_t orgversion; - uint32_t osver; - uint32_t ossegcount; - - uint8_t __[8]; -} sbr_slot_t; -#pragma pack(1) -enum { - Slot_Check = 0x00, // status=error - Slot_Install = 0x01, // status=install -> FAILED TO READ PREMADE BLOCK!! - Slot_Complete = 0x02, // status=complete - Slot_Empty = 0x03, // status=error - Slot_Error = 0x04, // status=error - Slot_Invalid = 0xff, -}; -typedef uint8_t slot_status_t; -#pragma pack(1) -typedef struct { - uint32_t crc; - uint8_t version; - uint8_t _[11 + 16 + 32]; - uint8_t bootslot; - uint8_t __[2]; - slot_status_t slot_status[5]; - uint8_t ___[8 + 16 + 32 + 64]; - sbr_slot_t slot_os; - sbr_slot_t slot_original0; - sbr_slot_t slot_appdata; - sbr_slot_t slot_patch0; - sbr_slot_t slot_patch1; -} sbr_t; - sbr_t SegaBootRecord = { .version = SBR_VERSION, .bootslot = 0x02, @@ -233,74 +297,50 @@ sbr_t SegaBootRecord = { }, }; +// Partitions #define BOOT_PARITION_SIZE 0x300B85 // 1.5GB #define RECOVER_PARTITION_SIZE 0x300BC4 // 1.5GB typedef struct { uint32_t size; uint8_t type; spd_slot_t content; + uint32_t offset; + LONGLONG slot_offset; } partition_t; #define PARITION_OS 0 #define PARITION_PATCH0 1 #define PARITION_PATCH1 2 #define PARITION_APP_DATA 3 #define PARITION_ORIGINAL0 4 -partition_t partitions[] = { - { 0x102d83, MBR_FS_FAT16, SPD_OS }, // 512MB OS update - { 0x403947, MBR_FS_FAT16, SPD_Patch0 }, // 2GB patch0 - { 0x403947, MBR_FS_FAT16, SPD_Patch1 }, // 2GB patch1 - { 0x48ed459, MBR_FS_NTFS, SPD_AppData }, // 40GB something - { 0x20014aa, MBR_FS_FAT16, SPD_Original0 }, // 16GB game -}; -#define NUM_PARITIONS (sizeof partitions / sizeof partitions[0]) #define MBR_LBA_GAP 0x3f // 1 track worth of sectors is claimed for the MBR +#define EXT_HEADER_GAP 0x3f #define BLOCKSIZE 512ll -#define SPD_OFFSET ((extended_base * BLOCKSIZE) + sizeof(mbr_t)) -#define SBR0_OFFSET (SPD_OFFSET + sizeof(spd_t)) -#define SBR1_OFFSET (SBR0_OFFSET + sizeof SegaBootRecord) +#define SPD_OFFSET 1 +#define SBR0_OFFSET 2 +#define SBR1_OFFSET 3 -/* - First 512 bytes of SPD_Original0: - LOADER::LoadBootIDHeader -*/ +// Drives +/** + * VID_0CA3 = SEGA CORPROATION + * VID_0928 = PLX / Oxford Semiconductor + * VID/PID pairs for B: + * 0CA3/000E + * 0928/0007 + * 0CA3/000C + * + * Mountpoints based on drive name: + * Z: DEV + * L: SEGA_AM_LOG + */ -BYTE Original0BootIDHeader[512] = { - 0x4B, 0xDF, 0xB4, 0x43, 0x27, 0x3C, 0xFE, 0xD6, 0xA2, 0xA8, 0xF8, 0xFD, 0xB4, 0x55, 0xE6, 0xBA, - 0x5A, 0x0F, 0xBF, 0x14, 0xA4, 0x37, 0xB6, 0x42, 0xB3, 0xAD, 0x11, 0x4A, 0xCA, 0x1A, 0x4C, 0xD9, - 0x11, 0xF1, 0x60, 0x4B, 0x37, 0x58, 0x9C, 0x9A, 0x89, 0x8F, 0x07, 0x9C, 0xE7, 0xF2, 0x64, 0xCC, - 0x6E, 0x84, 0x87, 0xAA, 0x20, 0xA0, 0xB8, 0x55, 0x9B, 0xE7, 0x79, 0x4F, 0x51, 0x25, 0xC3, 0x7E, - 0xEF, 0xD9, 0x25, 0xA9, 0x94, 0xF1, 0x7F, 0xEF, 0xE1, 0xD9, 0xAE, 0x4F, 0xC2, 0xEE, 0xB6, 0xA8, - 0xD9, 0x54, 0x0F, 0x33, 0xA8, 0xA9, 0x22, 0x72, 0x81, 0xD0, 0xA3, 0x04, 0x5C, 0x45, 0x3E, 0xBE, - 0xF7, 0x2A, 0xED, 0x55, 0xAB, 0x16, 0xC1, 0xA8, 0x61, 0x70, 0xEE, 0x55, 0xCB, 0xE6, 0x68, 0xA5, - 0xB4, 0xDC, 0x30, 0x6D, 0x32, 0xD6, 0x69, 0x8D, 0xFC, 0x90, 0x71, 0x7E, 0xDB, 0x6B, 0x17, 0xFA, - 0xAB, 0xE0, 0x11, 0x14, 0xBA, 0xD9, 0x33, 0xB7, 0x7C, 0x54, 0x9E, 0x21, 0xA1, 0x43, 0xFD, 0x8F, - 0x14, 0xF4, 0xBE, 0x5F, 0x0B, 0x02, 0x8E, 0x87, 0xCA, 0x85, 0xE9, 0xC1, 0x60, 0xF7, 0x7E, 0x44, - 0x55, 0x3A, 0x5E, 0x94, 0x65, 0x95, 0xFD, 0x02, 0xF9, 0xFF, 0xBF, 0x07, 0x80, 0xC5, 0x26, 0x58, - 0x6F, 0x37, 0xFA, 0x59, 0x2F, 0x02, 0xF3, 0x9D, 0x24, 0x7D, 0x42, 0x6B, 0xF3, 0x49, 0x63, 0xC9, - 0x2A, 0xCB, 0xFC, 0x71, 0x69, 0x44, 0xB5, 0xAC, 0xD3, 0x37, 0xA0, 0x01, 0x65, 0x3D, 0x49, 0xC4, - 0x7D, 0xE5, 0xF8, 0x6E, 0x09, 0xC7, 0x3E, 0xD1, 0x96, 0x09, 0x23, 0xA4, 0xE8, 0xA5, 0x6A, 0xA2, - 0x5B, 0x5B, 0xA5, 0x9C, 0xF8, 0x8D, 0x84, 0x55, 0x3F, 0x19, 0x8F, 0xDC, 0xFA, 0x7B, 0xF1, 0xC9, - 0xB6, 0xBF, 0xE8, 0x73, 0xB9, 0xC9, 0xC3, 0x17, 0x14, 0xAB, 0xA3, 0x60, 0x13, 0xED, 0x6D, 0xCC, - 0x10, 0x7B, 0x1D, 0xC6, 0xBC, 0xEC, 0x56, 0xFA, 0x52, 0xC5, 0x4E, 0xAC, 0x8F, 0x36, 0x8B, 0x92, - 0x6C, 0xB5, 0x9A, 0x57, 0x7D, 0xFA, 0x97, 0x72, 0xFC, 0xFA, 0xB8, 0xFE, 0x20, 0x71, 0xFB, 0x63, - 0x00, 0x96, 0x29, 0xCE, 0xE2, 0x06, 0xFF, 0x64, 0x48, 0xB5, 0x1F, 0xD6, 0x88, 0x48, 0x7A, 0x62, - 0x2B, 0xBE, 0xE6, 0xC4, 0xFD, 0xF6, 0x85, 0x45, 0x0A, 0x8C, 0x6C, 0x20, 0x64, 0x05, 0x81, 0x13, - 0xB5, 0x59, 0xAE, 0x34, 0x41, 0x0B, 0xB5, 0x65, 0x57, 0x59, 0x9C, 0xE8, 0xD0, 0xAE, 0x81, 0xD8, - 0x6D, 0xC9, 0xFD, 0xF8, 0xC9, 0x15, 0xB6, 0xDC, 0xC9, 0x13, 0xF2, 0x6E, 0xD9, 0xA5, 0x77, 0x62, - 0xB7, 0x15, 0x61, 0x21, 0x73, 0xFE, 0x0A, 0x57, 0x3B, 0x2C, 0x2F, 0x23, 0xC3, 0x33, 0xB8, 0x77, - 0xCE, 0xCE, 0x76, 0x98, 0xDB, 0xE5, 0x9A, 0x00, 0xE1, 0xC3, 0x6F, 0x7D, 0x42, 0xC4, 0xDE, 0xB7, - 0x1D, 0xA0, 0xC1, 0x1C, 0xB9, 0x09, 0x28, 0xD9, 0x59, 0x9D, 0x3F, 0xEA, 0xF1, 0xB6, 0xA0, 0x1C, - 0x5E, 0x4A, 0xE4, 0x1A, 0xE7, 0xA7, 0x1C, 0xAD, 0xF6, 0xF1, 0xCB, 0x9C, 0x06, 0xE6, 0x4C, 0xF4, - 0xD6, 0xEE, 0x5F, 0x18, 0xF5, 0x00, 0x4A, 0x76, 0x5E, 0x7D, 0x96, 0x20, 0x57, 0x68, 0x23, 0x69, - 0x8F, 0x60, 0x91, 0xBF, 0x00, 0x08, 0xFE, 0x4F, 0x36, 0x45, 0x86, 0x14, 0x48, 0xC5, 0x8B, 0xEA, - 0xE3, 0x64, 0x27, 0x1E, 0x49, 0xDF, 0x98, 0xAD, 0xE2, 0x66, 0x09, 0x07, 0xDD, 0x24, 0xB0, 0x4D, - 0x52, 0xA6, 0xD1, 0x3D, 0xB9, 0x52, 0x0B, 0x88, 0x97, 0x97, 0x0F, 0x83, 0x85, 0xD5, 0x3F, 0x0E, - 0x1A, 0xF2, 0x26, 0xBA, 0x14, 0x53, 0xDD, 0xF4, 0x7D, 0xAF, 0xB6, 0xEE, 0x36, 0x3A, 0xB5, 0xDA, - 0x2F, 0x99, 0xC8, 0x54, 0xD2, 0xDB, 0x52, 0x49, 0xD6, 0xB6, 0x07, 0x1A, 0xBA, 0x9A, 0x85, 0xBB, -}; +// Volumes +typedef struct { + size_t disk; + size_t partition; +} find_index_t; sbr_slot_t* get_sbr_slot(spd_slot_t slot) { switch (slot) { @@ -321,163 +361,186 @@ sbr_slot_t* get_sbr_slot(spd_slot_t slot) { } } -BOOL pd0_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { - log_info("pd0", "Read %d @ %llx", nNumberOfBytesToRead, pd0_file_pointer.QuadPart); - - uint32_t ext_offset = 0; - uint32_t offsets[NUM_PARITIONS]; - LONGLONG slot_offsets[NUM_PARITIONS]; - uint32_t extended_base = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE; - for (int i = 0; i < NUM_PARITIONS; i++) { - offsets[i] = ext_offset; - ext_offset += partitions[i].size + MBR_LBA_GAP; - - sbr_slot_t* pslot = get_sbr_slot(partitions[i].content); - if (pslot == NULL) - slot_offsets[i] = offsets[i]; - else { - LONGLONG partition_start = (offsets[i] + extended_base + MBR_LBA_GAP) * BLOCKSIZE; - LONGLONG slot_size = (LONGLONG)pslot->segcount * (LONGLONG)pslot->segsize; - LONGLONG slot_start = partitions[i].size * BLOCKSIZE - slot_size; - slot_offsets[i] = partition_start + slot_start; - } +BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { + physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData; + if (pd == NULL) { + log_error("drive", "read:ctx->m_HookData NULL; expected a physical drive!"); + return FALSE; } - printf("Offsets0: %08x\n", offsets[0]); - printf("ExtendBase: %08x\n", extended_base); + log_info("drive", "PhysicalDrive%d: Read %d @ %llx", pd->m_DriveNumber, nNumberOfBytesToRead, + ctx->m_Pointer.QuadPart); - // MBR (C+Recover+Extend) - if (pd0_file_pointer.QuadPart == 0) { + // ! WARNING: This ReadFile implementation is currently limited to aligned + // ! reads. Given the main purpose of this function is to allow reading + // ! the partition information, this doesn't currently pose an issue. + + DWORD ptrLBA = (ctx->m_Pointer.QuadPart / BLOCKSIZE) & 0xffffffff; + + // MBR header + if (ptrLBA == 0) { mbr_t* mbr = (mbr_t*)lpBuffer; + if (nNumberOfBytesToRead < sizeof *mbr) { + log_error("drive", "Buffer too small for master boot record!"); + return FALSE; + } + memset(mbr, 0, sizeof *mbr); mbr->sig[0] = 0x55; mbr->sig[1] = 0xAA; - // 1.5GB C parition - mbr->partitions[0].status = MBR_FLAG_BOOTABLE; - mbr->partitions[0].type = MBR_FS_NTFS; - mbr->partitions[0].lba = MBR_LBA_GAP; - mbr->partitions[0].sectors = BOOT_PARITION_SIZE; + for (size_t i = 0; i < 4; i++) { + if (pd->m_Partitions[i].m_Size == 0) break; - // 1.5GB Recovery - mbr->partitions[1].status = MBR_FLAG_NONE; - mbr->partitions[1].type = MBR_FS_NTFS; - mbr->partitions[1].lba = MBR_LBA_GAP + BOOT_PARITION_SIZE; - mbr->partitions[1].sectors = RECOVER_PARTITION_SIZE; - - // Everything else is in an extended - mbr->partitions[2].status = MBR_FLAG_NONE; - mbr->partitions[2].type = MBR_FS_EXT_LBA; - mbr->partitions[2].lba = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE; - mbr->partitions[2].sectors = ext_offset; + mbr->partitions[i].status = + (pd->m_BootPartition == i + 1) ? MBR_FLAG_BOOTABLE : MBR_FLAG_NONE; + mbr->partitions[i].type = pd->m_Partitions[i].m_Filesystem; + mbr->partitions[i].lba = pd->m_Partitions[i].m_PhysicalLBA; + mbr->partitions[i].sectors = pd->m_Partitions[i].m_Size; + } *lpNumberOfBytesRead = sizeof *mbr; + return TRUE; } + if (ptrLBA <= MBR_LBA_GAP) { + // Read within the 63 extra tracks + log_error("drive", "Read failed"); + return FALSE; + } + + // MBR partitions + for (size_t i = 0; i < 4; i++) { + if (pd->m_Partitions[i].m_PartitionNumber == 0) break; + + if (ptrLBA >= pd->m_Partitions[i].m_PhysicalLBA && + ptrLBA < pd->m_Partitions[i].m_PhysicalLBA + pd->m_Partitions[i].m_Size) { + DWORD readOffset = ptrLBA - pd->m_Partitions[i].m_PhysicalLBA; + int willRead = pd->m_Partitions[i].m_ContentSize - (readOffset * BLOCKSIZE); + if (willRead > nNumberOfBytesToRead) willRead = nNumberOfBytesToRead; + + if (willRead < 0) { + log_error("disk", "Attempted read in %d/%d at block offset %08x; No data to read!", + pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, readOffset); + return FALSE; + } + + memcpy(lpBuffer, pd->m_Partitions[i].m_Content, willRead); + *lpNumberOfBytesRead = willRead; + + log_info("drive", "Read at %d/%d+%d", pd->m_DriveNumber, + pd->m_Partitions[i].m_PartitionNumber, readOffset); + return TRUE; + } + } // Extended partitions - for (int i = 0; i < NUM_PARITIONS; i++) { - if (pd0_file_pointer.QuadPart != ((extended_base + offsets[i]) * BLOCKSIZE)) continue; + for (size_t i = 0; pd->m_Extended[i].m_Size; i++) { + // Extended header + DWORD headerLBA = pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP; + if (ptrLBA == headerLBA) { + mbr_t* mbr = (mbr_t*)lpBuffer; + if (nNumberOfBytesToRead < sizeof *mbr) { + log_error("drive", "Buffer too small for an extended boot record!"); + return FALSE; + } - mbr_t* mbr = (mbr_t*)lpBuffer; - memset(mbr, 0, sizeof *mbr); - mbr->sig[0] = 0x55; - mbr->sig[1] = 0xAA; + memset(mbr, 0, sizeof *mbr); + mbr->sig[0] = 0x55; + mbr->sig[1] = 0xAA; - mbr->partitions[0].status = MBR_FLAG_NONE; - mbr->partitions[0].type = partitions[i].type; - mbr->partitions[0].lba = MBR_LBA_GAP; - mbr->partitions[0].sectors = partitions[i].size; + mbr->partitions[0].status = MBR_FLAG_NONE; + mbr->partitions[0].type = pd->m_Extended[i].m_Filesystem; + mbr->partitions[0].lba = EXT_HEADER_GAP; + mbr->partitions[0].sectors = pd->m_Extended[i].m_Size; - if (i != NUM_PARITIONS - 1) { - mbr->partitions[1].status = MBR_FLAG_NONE; - mbr->partitions[1].type = MBR_FS_EXT_CHS; - mbr->partitions[1].lba = offsets[i + 1]; - mbr->partitions[1].sectors = partitions[i + 1].size + MBR_LBA_GAP; + if (pd->m_Extended[i + 1].m_Size) { + mbr->partitions[1].status = MBR_FLAG_NONE; + // ! mxinstaller expects to see CHS here, then uses the LBA values + mbr->partitions[1].type = MBR_FS_EXT_CHS; + mbr->partitions[1].lba = + pd->m_Extended[i + 1].m_PhysicalLBA - pd->m_Extended[0].m_PhysicalLBA; + mbr->partitions[1].sectors = pd->m_Extended[i + 1].m_Size + EXT_HEADER_GAP; + } + + *lpNumberOfBytesRead = sizeof *mbr; + return TRUE; } - *lpNumberOfBytesRead = sizeof *mbr; - return TRUE; - } - - SegaBootRecord.crc = crc32(sizeof SegaBootRecord - 4, &SegaBootRecord.version, 0); - - // SEGA Partition Description - if (pd0_file_pointer.QuadPart == SPD_OFFSET) { - spd_t* spd = (spd_t*)lpBuffer; - spd->version = SPD_VERSION; - for (uint8_t i = 0; i < NUM_PARITIONS; i++) { - spd->slots[i].block_size = BLOCKSIZE; - spd->slots[i].block_count = partitions[i].size; - spd->slots[i].slot_content = partitions[i].content; - spd->slots[i].uk1 = partitions[i].type == MBR_FS_FAT16 ? 0 : 1; - } - spd->crc = crc32(sizeof *spd - 4, &(spd->version), 0); - - *lpNumberOfBytesRead = sizeof *spd; - return TRUE; - } - - // SEGA Boot Record 0 and 1. The two are a redundant copy of each other - if (pd0_file_pointer.QuadPart == SBR0_OFFSET || pd0_file_pointer.QuadPart == SBR1_OFFSET) { - memcpy(lpBuffer, &SegaBootRecord, sizeof SegaBootRecord); - *lpNumberOfBytesRead = sizeof SegaBootRecord; - return TRUE; - } - - // Read within a partition - if (pd0_file_pointer.QuadPart < MBR_LBA_GAP * BLOCKSIZE) { - log_error("pd0", "Read performed within the first track of disk!"); - } else if (pd0_file_pointer.QuadPart < (MBR_LBA_GAP + BOOT_PARITION_SIZE) * BLOCKSIZE) { - log_warning("pd0", "Game attempting to read windows partition!"); - } else if (pd0_file_pointer.QuadPart < - (MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE) * BLOCKSIZE) { - log_warning("pd0", "Game attempting to read recovery partition!"); - } else if (pd0_file_pointer.QuadPart == slot_offsets[PARITION_ORIGINAL0]) { - log_info("pd0", "Original0 BootID Header read"); - memcpy(lpBuffer, Original0BootIDHeader, sizeof Original0BootIDHeader); - *lpNumberOfBytesRead = sizeof Original0BootIDHeader; - return TRUE; - } else { - for (int i = 0; i < NUM_PARITIONS; i++) { - if (pd0_file_pointer.QuadPart < - (offsets[i] + MBR_LBA_GAP + extended_base) * BLOCKSIZE) { - log_error("pd0", "Read performed within the first track of partition %d!", i + 5); - goto warned; - } else if (pd0_file_pointer.QuadPart < - (offsets[i] + MBR_LBA_GAP + partitions[i].size + extended_base) * - BLOCKSIZE) { - LONGLONG partition_start = (offsets[i] + extended_base + MBR_LBA_GAP) * BLOCKSIZE; - LONGLONG delta = pd0_file_pointer.QuadPart - partition_start; - - sbr_slot_t* slot = get_sbr_slot(partitions[i].content); - if (slot == NULL) { - log_warning("pd0", - "Read performed within empty partition %d (partition +%09llx)", - i + 5, delta); - } else { - LONGLONG slot_size = slot->segcount * slot->segsize; - LONGLONG slot_start = partitions[i].size * BLOCKSIZE - slot_size; - log_warning("pd0", - "Read performed within slot %d (partition +%09llx/slot +%09llx)", i, - delta, delta - slot_start); + if (i == 0 && pd->m_HasSegaboot) { + // SEGA Partition Description + if (ptrLBA == headerLBA + SPD_OFFSET) { + spd_t* spd = (spd_t*)lpBuffer; + if (nNumberOfBytesToRead < sizeof *spd) { + log_error("drive", "Buffer too small for SPD!"); + return FALSE; } - goto warned; + spd->version = SPD_VERSION; + for (size_t j = 0; pd->m_Extended[j].m_Size; j++) { + spd->slots[j].block_size = BLOCKSIZE; + spd->slots[j].block_count = pd->m_Extended[j].m_Size; + spd->slots[j].slot_content = pd->m_Extended[j].m_SPDContent; + spd->slots[j].uk1 = pd->m_Extended[j].m_Filesystem == MBR_FS_FAT16 ? 0 : 1; + } + + spd->crc = amCrc32RGet(sizeof *spd - 4, &(spd->version), 0); + *lpNumberOfBytesRead = sizeof *spd; + return TRUE; + } + // SEGA Boot Record 0 and 1. The two are a redundant copy of each other + if (ptrLBA == headerLBA + SBR0_OFFSET || ptrLBA == headerLBA + SBR1_OFFSET) { + SegaBootRecord.crc = amCrc32RGet(sizeof SegaBootRecord - 4, &SegaBootRecord.version, 0); + + memcpy(lpBuffer, &SegaBootRecord, sizeof SegaBootRecord); + *lpNumberOfBytesRead = sizeof SegaBootRecord; + return TRUE; } } - log_error("pd0", "Read to unmapped address: %llx (%d bytes)", pd0_file_pointer.QuadPart, - nNumberOfBytesToRead); - warned:; + + if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP && + ptrLBA < pd->m_Extended[i].m_PhysicalLBA) { + // Read within the 63 extra tracks + log_error("drive", "Read failed"); + return FALSE; + } + + if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA && + ptrLBA < pd->m_Extended[i].m_PhysicalLBA + pd->m_Extended[i].m_Size) { + DWORD readOffset = ptrLBA - pd->m_Extended[i].m_PhysicalLBA; + int willRead = pd->m_Extended[i].m_ContentSize - (readOffset * BLOCKSIZE); + if (willRead > nNumberOfBytesToRead) willRead = nNumberOfBytesToRead; + + if (willRead < 0) { + log_error("disk", "Attempted read in %d/%d at block offset %08x; No data to read!", + pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, readOffset); + return FALSE; + } + + memcpy(lpBuffer, pd->m_Extended[i].m_Content, willRead); + *lpNumberOfBytesRead = willRead; + + log_info("drive", "Read at %d/%d+%d", pd->m_DriveNumber, + pd->m_Partitions[i].m_PartitionNumber, readOffset); + return TRUE; + } } + log_error("drive", "Read failed"); return FALSE; } -BOOL pd0_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { - log_warning("pd0", "Write %d @ %llx", nNumberOfBytesToWrite, pd0_file_pointer.QuadPart); +BOOL pd_WriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { + physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData; + if (pd == NULL) { + log_error("drive", "write:ctx->m_HookData NULL; expected a physical drive!"); + return FALSE; + } + + log_warning("drive", "PhysicalDrive%d: Write %d @ %llx", pd->m_DriveNumber, + nNumberOfBytesToWrite, ctx->m_Pointer.QuadPart); for (DWORD i = 0; i < nNumberOfBytesToWrite; i += 32) { for (int j = 0; j < 32; j++) { @@ -490,7 +553,317 @@ BOOL pd0_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, return TRUE; } +disk_volume_t* incrementFindIndex(HANDLE hFindVolume) { + find_index_t* find_index = GetDataForHandle(hFindVolume, HDATA_FIND_VOLUME); + if (find_index == NULL) return NULL; + + while (1) { + if (find_index->disk >= sizeof PHYSICAL_DISKS / sizeof PHYSICAL_DISKS[0]) { + return NULL; + } + + if (find_index->partition > 3) { + if (PHYSICAL_DISKS[find_index->disk] + ->m_Extended[find_index->partition - 4] + .m_PartitionNumber == 0) { + find_index->disk++; + find_index->partition = 0; + continue; + } + + return &(PHYSICAL_DISKS[find_index->disk] + ->m_Extended[(find_index->partition++) - 4] + .m_Volume); + } + if (PHYSICAL_DISKS[find_index->disk] + ->m_Partitions[find_index->partition] + .m_PartitionNumber == 0) { + find_index->partition = 4; + continue; + } + + return &(PHYSICAL_DISKS[find_index->disk]->m_Partitions[find_index->partition++].m_Volume); + } +} +BOOL WINAPI FakeFindNextVolumeW(HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength) { + disk_volume_t* volume = incrementFindIndex(hFindVolume); + if (volume == NULL) { + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; + } + + wcscpy_s(lpszVolumeName, cchBufferLength, volume->m_FilenameW); + wcscat_s(lpszVolumeName, cchBufferLength, L"\\"); + return TRUE; +} +BOOL WINAPI FakeFindNextVolumeA(HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength) { + disk_volume_t* volume = incrementFindIndex(hFindVolume); + if (volume == NULL) { + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; + } + + strcpy_s(lpszVolumeName, cchBufferLength, volume->m_FilenameA); + strcat_s(lpszVolumeName, cchBufferLength, "\\"); + return TRUE; +} +HANDLE WINAPI FakeFindFirstVolumeW(LPWSTR lpszVolumeName, DWORD cchBufferLength) { + find_index_t* find_index = malloc(sizeof(find_index_t)); + find_index->disk = 0; + find_index->partition = 0; + HANDLE handle = GetDummyHandle(); + SetDataForHandle(handle, HDATA_FIND_VOLUME, find_index, TRUE); + + FakeFindNextVolumeW(handle, lpszVolumeName, cchBufferLength); + return handle; +} +HANDLE WINAPI FakeFindFirstVolumeA(LPSTR lpszVolumeName, DWORD cchBufferLength) { + find_index_t* find_index = malloc(sizeof(find_index_t)); + find_index->disk = 0; + find_index->partition = 0; + HANDLE handle = GetDummyHandle(); + SetDataForHandle(handle, HDATA_FIND_VOLUME, find_index, TRUE); + + FakeFindNextVolumeA(handle, lpszVolumeName, cchBufferLength); + return handle; +} +BOOL WINAPI FakeFindVolumeClose(HANDLE hFindVolume) { + if (RemoveDataForHandle(hFindVolume, HDATA_FIND_VOLUME)) return _CloseHandle(hFindVolume); + return FALSE; +} + +disk_volume_t* getVolumeByPath(LPCSTR lpRootPathName) { + // Unimplemented + if (lpRootPathName == NULL) return FALSE; + + char filename[MAX_PATH + 1]; + + for (size_t disk = 0; disk < sizeof PHYSICAL_DISKS / sizeof PHYSICAL_DISKS[0]; disk++) { + for (size_t part = 0; part < 4; part++) { + strcpy_s(filename, sizeof filename, + PHYSICAL_DISKS[disk]->m_Partitions[part].m_Volume.m_FilenameA); + strcat_s(filename, sizeof filename, "\\"); + if (strcmp(filename, lpRootPathName)) continue; + + return &(PHYSICAL_DISKS[disk]->m_Partitions[part].m_Volume); + } + + for (size_t part = 0; PHYSICAL_DISKS[disk]->m_Extended[part].m_PartitionNumber; part++) { + strcpy_s(filename, sizeof filename, + PHYSICAL_DISKS[disk]->m_Extended[part].m_Volume.m_FilenameA); + strcat_s(filename, sizeof filename, "\\"); + if (strcmp(filename, lpRootPathName)) continue; + + return &(PHYSICAL_DISKS[disk]->m_Extended[part].m_Volume); + } + } + return NULL; +} + +BOOL WINAPI FakeGetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, + DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, + LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, + LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize) { + if (nVolumeNameSize) lpVolumeNameBuffer[0] = '\0'; + if (lpVolumeSerialNumber) lpVolumeSerialNumber[0] = 0; + if (lpMaximumComponentLength) *lpMaximumComponentLength = MAX_PATH; + if (lpFileSystemFlags) *lpFileSystemFlags = 0; + if (nFileSystemNameSize) lpFileSystemNameBuffer[0] = '\0'; + + disk_volume_t* volume = getVolumeByPath(lpRootPathName); + if (volume == NULL) return FALSE; + + if (volume->m_Name && lpVolumeNameBuffer) + strcpy_s(lpVolumeNameBuffer, nVolumeNameSize, volume->m_Name); + return TRUE; +} +BOOL WINAPI FakeSetVolumeLabelA(LPCSTR lpRootPathName, LPCSTR lpVolumeName) { + disk_volume_t* volume = getVolumeByPath(lpRootPathName); + if (volume == NULL) return FALSE; + + if (lpVolumeName) { + size_t len = strlen(lpVolumeName); + // By default volume names are pointers to constants! + if (volume->m_NameIsOnHeap) + realloc(volume->m_Name, len + 1); + else { + volume->m_Name = malloc(len + 1); + volume->m_NameIsOnHeap = TRUE; + } + memcpy(volume->m_Name, lpVolumeName, len); + } else { + volume->m_Name = NULL; + } + return TRUE; +}; + +BOOL WINAPI volume_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { + disk_volume_t* volume = (disk_volume_t*)ctx->m_HookData; + if (volume == NULL) { + log_error("drive", "ctx->m_HookData NULL; expected a volume!"); + return FALSE; + } + + memset(lpOutBuffer, 0, nInBufferSize); + switch (dwIoControlCode) { + case IOCTL_STORAGE_GET_DEVICE_NUMBER: + ((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK; + ((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->DeviceNumber = volume->m_pDrive->m_DriveNumber; + ((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->PartitionNumber = + volume->m_pPartition->m_PartitionNumber; + return TRUE; + case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: + PVOLUME_DISK_EXTENTS vde = (PVOLUME_DISK_EXTENTS)lpOutBuffer; + + vde->NumberOfDiskExtents = 1; + vde->Extents[0].DiskNumber = volume->m_pDrive->m_DriveNumber; + + vde->Extents[0].StartingOffset.QuadPart = + volume->m_pPartition->m_PhysicalLBA * BLOCKSIZE; + vde->Extents[0].ExtentLength.QuadPart = volume->m_pPartition->m_Size * BLOCKSIZE; + + return TRUE; + case IOCTL_STORAGE_QUERY_PROPERTY: + PSTORAGE_PROPERTY_QUERY queryIn = (PSTORAGE_PROPERTY_QUERY)lpInBuffer; + + if (queryIn->PropertyId != StorageDeviceProperty || + queryIn->QueryType != PropertyStandardQuery) { + log_error("drive", "Unimplemented storage query: %d/%d", queryIn->PropertyId, + queryIn->QueryType); + return FALSE; + } + PSTORAGE_DEVICE_DESCRIPTOR descriptor = (PSTORAGE_DEVICE_DESCRIPTOR)(lpOutBuffer); + + descriptor->BusType = volume->m_pDrive->m_BusType; + + size_t rdpOffset = offsetof(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties); + if (volume->m_pDrive->m_VID) { + descriptor->VendorIdOffset = rdpOffset; + rdpOffset += sprintf_s((char*)descriptor + rdpOffset, nOutBufferSize - rdpOffset, + "%s", volume->m_pDrive->m_VID) + + 1; + } + if (volume->m_pDrive->m_PID) { + descriptor->ProductIdOffset = rdpOffset; + rdpOffset += sprintf_s((char*)descriptor + rdpOffset, nOutBufferSize - rdpOffset, + "%s", volume->m_pDrive->m_PID) + + 1; + } + descriptor->RawPropertiesLength = + rdpOffset - offsetof(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties); + return TRUE; + case IOCTL_DISK_GET_LENGTH_INFO: + PGET_LENGTH_INFORMATION length = (PGET_LENGTH_INFORMATION)lpOutBuffer; + if (volume->m_pPartition) { + length->Length.QuadPart = volume->m_pPartition->m_Size; + } + return TRUE; + default: + log_error("drive", "Unimplemented IOCTL: %08x", dwIoControlCode); + return FALSE; + } +} + +void init_volume(disk_volume_t* vol) { + wchar_t* volume_name = vol->m_FilenameW; + wcscpy_s(volume_name, MAX_PATH + 1, L"\\\\?\\Volume"); + + GUID guid; + CoCreateGuid(&guid); + StringFromGUID2(&guid, volume_name + 10, MAX_PATH + 1 - 10); + + file_hook_t* volume_hook = new_file_hook(volume_name); + log_misc("disk", "Creating fake volume: %ls", volume_name); + + volume_hook->DeviceIoControl = &volume_DeviceIoControl; + volume_hook->hook_data = (void*)vol; + + hook_file(volume_hook); + + // This is a pretty nasty way to convert from W to A, but all values + // are always going to be within ASCII range so it's.. okay. + for (size_t i = 0; i < sizeof vol->m_FilenameA; i++) { + vol->m_FilenameA[i] = vol->m_FilenameW[i] & 0xff; + } +} +void init_pd(physical_disk_t* pd) { + DWORD partitionNumber = 1; + DWORD currentLBA = MBR_LBA_GAP; + + // Init MBR + for (int i = 0; i < 4; i++) { + if (pd->m_Partitions[i].m_Size == 0) break; + + pd->m_Partitions[i].m_PartitionNumber = partitionNumber++; + pd->m_Partitions[i].m_PhysicalLBA = currentLBA; + + init_volume(&(pd->m_Partitions[i].m_Volume)); + pd->m_Partitions[i].m_Volume.m_pDrive = pd; + pd->m_Partitions[i].m_Volume.m_pPartition = &(pd->m_Partitions[i]); + + currentLBA += pd->m_Partitions[i].m_Size; + } + + // If we have any extended partitions + DWORD extendedPartNo = 0; + if (pd->m_Extended[0].m_Size) { + if (partitionNumber == 5) { + log_error("drive", "Fatal: Too many paritions in drive %d!", pd->m_DriveNumber); + exit(1); + } + pd->m_Partitions[partitionNumber - 1].m_Filesystem = MBR_FS_EXT_LBA; + pd->m_Partitions[partitionNumber - 1].m_PhysicalLBA = currentLBA; + extendedPartNo = partitionNumber; + + // Note: We don't increment partitionNumber, to keep the presence of this partition + // transparent elsewhere. + } + DWORD extendedStart = currentLBA; + + // Init extended partitions + for (int i = 0; pd->m_Extended[i].m_Size; i++) { + pd->m_Extended[i].m_PartitionNumber = partitionNumber++; + + currentLBA += EXT_HEADER_GAP; + pd->m_Extended[i].m_PhysicalLBA = currentLBA; + pd->m_Extended[i].m_SlotLBA = currentLBA; + currentLBA += pd->m_Extended[i].m_Size; + + init_volume(&(pd->m_Extended[i].m_Volume)); + pd->m_Extended[i].m_Volume.m_pDrive = pd; + pd->m_Extended[i].m_Volume.m_pPartition = &(pd->m_Extended[i]); + + sbr_slot_t* pslot = get_sbr_slot(pd->m_Extended[i].m_SPDContent); + if (pslot != NULL) { + DWORD slot_size = ((LONGLONG)pslot->segcount * (LONGLONG)pslot->segsize) / BLOCKSIZE; + DWORD slot_offset = pd->m_Extended[i].m_Size - slot_size; + pd->m_Extended[i].m_SlotLBA += slot_offset; + } + } + + // Back-fill, if needed + if (extendedPartNo) { + pd->m_Partitions[extendedPartNo - 1].m_Size = currentLBA - extendedStart; + } + + // Install hooks + // strlen(\\.\PhysicalDrive255) = 20, then +1 for null + wchar_t* hookPath = malloc(21 * sizeof(wchar_t)); + swprintf_s(hookPath, 21, L"\\\\.\\PhysicalDrive%d", pd->m_DriveNumber); + file_hook_t* hook = new_file_hook(hookPath); + hook->DeviceIoControl = pd_DeviceIoControl; + hook->ReadFile = pd_ReadFile; + hook->WriteFile = pd_WriteFile; + hook->hook_data = (void*)pd; + hook_file(hook); +} + void hook_drives() { + init_pd(&SSD); + init_pd(&UPDATE_USB); + file_hook_t* c_drive = new_file_hook(L"\\\\.\\C:"); c_drive->DeviceIoControl = &c_drive_DeviceIoControl; hook_file(c_drive); @@ -499,12 +872,33 @@ void hook_drives() { x_drive->DeviceIoControl = &x_drive_DeviceIoControl; hook_file(x_drive); - file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive0"); - // file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive2063598201"); - // file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive1811939950"); - physical_drive_0->SetFilePointerEx = pd0_SetFilePointerEx; - physical_drive_0->SetFilePointer = pd0_SetFilePointer; - physical_drive_0->ReadFile = pd0_ReadFile; - physical_drive_0->WriteFile = pd0_WriteFile; - hook_file(physical_drive_0); + hook("Kernel32.dll", "FindFirstVolumeW", &FakeFindFirstVolumeW, NULL, 5); + hook("Kernel32.dll", "FindNextVolumeW", &FakeFindNextVolumeW, NULL, 5); + hook("Kernel32.dll", "FindFirstVolumeA", &FakeFindFirstVolumeA, NULL, 5); + hook("Kernel32.dll", "FindNextVolumeA", &FakeFindNextVolumeA, NULL, 5); + hook("Kernel32.dll", "FindVolumeClose", &FakeFindVolumeClose, NULL, 5); + hook("Kernel32.dll", "SetVolumeLabelA", &FakeSetVolumeLabelA, NULL, 5); + hook("Kernel32.dll", "GetVolumeInformationA", &FakeGetVolumeInformationA, NULL, 5); + + /** + * mxinstaller iterates all volumes to find those that match the slot metadata. + * It uses: + * - FindFirstVolumeW + * - FindNextVolumeW + * - FindVolumeClose + * to iterate volumes. + * For each volume, it: + * - opens it with CreateFileW + * - calls IOCTL_STORAGE_GET_DEVICE_NUMBER + * - asserts that DeviceType == FILE_DEVICE_DISK + * - calls IOCTL_VOLUME_GET_VOLUME_DISK_EXTENT + * - checks that NumberOfDiskExtents < 128 + * - this is not fatal, however an error will be shown and only the first 128 will be checked + * - for each extent (!! sizeof DISK_EXTENT == 24; it's 8-byte aligned): + * - asserts that [].DiskNumber == state_->DiskNumber + * - finds a slot that matches: + * - slot->offset == [].StartingOffset + * - slot->segments == ([].ExtentLength.LowPart >> 9) | ([].ExtentLength.HighPart << 23) + * == [].ExtentLength / 512 + */ } diff --git a/src/micetools/dll/hooks/drive.h b/src/micetools/dll/hooks/drive.h index 0148746..fa0144a 100644 --- a/src/micetools/dll/hooks/drive.h +++ b/src/micetools/dll/hooks/drive.h @@ -13,10 +13,9 @@ void hook_drives(); #define MBR_FS_NTFS 0x07 #define MBR_FS_EXT_LBA 0x0F -#pragma pack(1) +#pragma pack(push, 1) typedef struct mbr { BYTE bootstrap_code[446]; -#pragma pack(1) struct { BYTE status; BYTE start_chs[3]; @@ -32,6 +31,7 @@ typedef struct mbr { #define SPD_VERSION 1 #define SBR_VERSION 1 +// Sega Partition Descriptor enum spd_slot { SPD_Original0 = 0x10, SPD_Original1 = 0x11, @@ -40,4 +40,86 @@ enum spd_slot { SPD_OS = 0x30, SPD_AppData = 0x40, }; -typedef uint8_t spd_slot_t; \ No newline at end of file +typedef uint8_t spd_slot_t; + +typedef struct spd { + uint32_t crc; + uint8_t version; + uint8_t _[11]; + struct { + /* + (BCD) + 1.0 = original0 + 1.1 = original1 + 2.0 = patch0 + 2.1 = patch1 + 3.0 = os + 4.0 = app_data + */ + spd_slot_t slot_content; + /* + Guess: Filesystem type + 0: Encrypted FAT16 + 1: Decrypted NTFS + */ + uint8_t uk1; + uint16_t block_size; + uint32_t block_count; + uint8_t __[8]; + } slots[31]; +} spd_t; + +// Sega Boot Record +typedef struct { + uint16_t year; + uint8_t mon; + uint8_t day; + uint8_t hour; + uint8_t min; + uint8_t sec; + uint8_t _; +} slot_time_t; + +typedef struct { + char id[4]; + slot_time_t time; + uint32_t version; + uint32_t _[2]; + uint32_t segcount; + uint32_t segsize; + + char hw[3]; + uint8_t instant; + slot_time_t orgtime; + uint32_t orgversion; + uint32_t osver; + uint32_t ossegcount; + + uint8_t __[8]; +} sbr_slot_t; + +enum { + Slot_Check = 0x00, // status=error + Slot_Install = 0x01, // status=install -> FAILED TO READ PREMADE BLOCK!! + Slot_Complete = 0x02, // status=complete + Slot_Empty = 0x03, // status=error + Slot_Error = 0x04, // status=error + Slot_Invalid = 0xff, +}; + +typedef uint8_t slot_status_t; +typedef struct { + uint32_t crc; + uint8_t version; + uint8_t _[11 + 16 + 32]; + uint8_t bootslot; + uint8_t __[2]; + slot_status_t slot_status[5]; + uint8_t ___[8 + 16 + 32 + 64]; + sbr_slot_t slot_os; + sbr_slot_t slot_original0; + sbr_slot_t slot_appdata; + sbr_slot_t slot_patch0; + sbr_slot_t slot_patch1; +} sbr_t; +#pragma pack(pop) diff --git a/src/micetools/dll/hooks/files.c b/src/micetools/dll/hooks/files.c index 712f3b7..4b1a034 100644 --- a/src/micetools/dll/hooks/files.c +++ b/src/micetools/dll/hooks/files.c @@ -1,67 +1,20 @@ +#define _MICE_FILES #include "files.h" -open_hook_t* open_hooks_list = NULL; -HANDLE open_hook(file_hook_t* file_hook, com_hook_t* com_hook) { +HANDLE open_hook(file_hook_t* file_hook) { open_hook_t* opened = (open_hook_t*)malloc(sizeof(open_hook_t)); - memset(opened, 0, sizeof *opened); + ZeroMemory(opened, sizeof *opened); - opened->file_hook = file_hook; - opened->com_hook = com_hook; + opened->hook = file_hook; - CHAR path[MAX_PATH]; - GetModuleFileNameA(NULL, path, MAX_PATH); - HANDLE handle = - _CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (handle == INVALID_HANDLE_VALUE) { - log_error(HOOKS_LOGGER, "Failed to create dummy handle: %03x", GetLastError()); - return INVALID_HANDLE_VALUE; - } - opened->handle = handle; - opened->next = open_hooks_list; - open_hooks_list = opened; + HANDLE handle = GetDummyHandle(); + opened->ctx.m_Handle = handle; + opened->ctx.m_HookData = file_hook->hook_data; + + SetDataForHandle(handle, HDATA_FILE, opened, TRUE); return handle; } -void close_hook(HANDLE handle) { - if (handle == INVALID_HANDLE_VALUE) return; - - _CloseHandle(handle); - - open_hook_t* opened = NULL; - open_hook_t* root = open_hooks_list; - if (open_hooks_list->handle == handle) { - open_hook_t* next = open_hooks_list->next; - free(open_hooks_list); - open_hooks_list = next; - return; - } - - while (root != NULL) { - if (root->next && root->next->handle == handle) { - opened = root->next; - root->next = opened->next; - free(opened); - return; - } - root = root->next; - } -} -file_hook_t* get_handle_file_hook(HANDLE handle) { - open_hook_t* root = open_hooks_list; - while (root != NULL) { - if (root->handle == handle) return root->file_hook; - root = root->next; - } - return NULL; -} -com_hook_t* get_handle_com_hook(HANDLE handle) { - open_hook_t* root = open_hooks_list; - while (root != NULL) { - if (root->handle == handle) return root->com_hook; - root = root->next; - } - return NULL; -} file_hook_t* file_hook_list = NULL; file_hook_t* new_file_hook(LPCWSTR filename) { @@ -92,26 +45,16 @@ drive_redirect_t DRIVE_REDIRECT_TABLE[] = { char _redirected_path[MAX_PATH]; -void find_hooks(LPCWSTR lpFileName, file_hook_t** found_fh, com_hook_t** found_ch) { +file_hook_t* find_hook(LPCWSTR lpFileName) { file_hook_t* file_hook = file_hook_list; while (file_hook != NULL) { if (wcscmp(lpFileName, file_hook->filename) == 0 || (file_hook->altFilename != NULL && wcscmp(lpFileName, file_hook->altFilename) == 0)) { - *found_fh = file_hook; - break; + return file_hook; } file_hook = file_hook->next; } - - com_hook_t* com_hook = com_hook_list; - while (com_hook != NULL) { - if (wcscmp(lpFileName, com_hook->wName) == 0 || - wcscmp(lpFileName, com_hook->wDosName) == 0) { - *found_ch = com_hook; - break; - } - com_hook = com_hook->next; - } + return NULL; }; void make_dirs(char* path) { @@ -135,8 +78,20 @@ void make_dirs(char* path) { } } +char WORKING_DIR[MAX_PATH + 1] = { 0 }; +char get_gamedata_drive() { + if (WORKING_DIR[0] == 0x00) { + GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR); + } + return WORKING_DIR[0]; +} + +inline char char_lower(char value) { + if ('A' <= value <= 'Z') return value - 'A' + 'a'; + return value; +} + BOOL redirect_path(LPCSTR path, LPCSTR* redirected) { - return FALSE; for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) { drive_redirect_t row = DRIVE_REDIRECT_TABLE[i]; if (strncmp(path, row.drive, strlen(row.drive)) == 0) { @@ -161,14 +116,14 @@ BOOL redirect_path(LPCSTR path, LPCSTR* redirected) { if ((('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) { - char drive; - if ('A' <= path[0] && path[0] <= 'Z') { - drive = path[0] - 'A' + 'a'; - } else { - drive = path[0]; + // TODO: Ca + if (char_lower(path[0]) == char_lower(get_gamedata_drive())) { + return FALSE; } + ZeroMemory(_redirected_path, sizeof _redirected_path); - snprintf(_redirected_path, sizeof _redirected_path, "dev\\%c\\%s", drive, path + 3); + snprintf(_redirected_path, sizeof _redirected_path, "dev\\%c\\%s", char_lower(path[0]), + path + 3); make_dirs(_redirected_path); *redirected = _redirected_path; @@ -189,11 +144,9 @@ HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD d LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - file_hook_t* found_fh = NULL; - com_hook_t* found_ch = NULL; - find_hooks(lpFileName, &found_fh, &found_ch); - if (found_fh != NULL || found_ch != NULL) { - HANDLE handle = open_hook(found_fh, found_ch); + file_hook_t* found_fh = find_hook(lpFileName); + if (found_fh != NULL) { + HANDLE handle = open_hook(found_fh); log_info(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle); return handle; } @@ -220,11 +173,9 @@ HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw WCHAR wideFileName[MAX_PATH + 1]; MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1); - file_hook_t* found_fh = NULL; - com_hook_t* found_ch = NULL; - find_hooks(wideFileName, &found_fh, &found_ch); - if (found_fh != NULL || found_ch != NULL) { - HANDLE handle = open_hook(found_fh, found_ch); + file_hook_t* found_fh = find_hook(wideFileName); + if (found_fh != NULL) { + HANDLE handle = open_hook(found_fh); log_info(HOOKS_LOGGER, "CreateFileA(%s) -> 0x%p", lpFileName, handle); return handle; } @@ -240,149 +191,162 @@ BOOL WINAPI FakePathFileExistsA(LPCSTR pszPath) { redirect_path(pszPath, &pszPath); return TruePathFileExistsA(pszPath); } -BOOL WINAPI FakePathFileExistsW(LPCSTR pszPath) { +BOOL WINAPI FakePathFileExistsW(LPCWSTR pszPath) { LPCSTR redirected; - if (redirect_path(pszPath, &redirected)) { + if (redirect_path_w(pszPath, &redirected)) { return TruePathFileExistsA(redirected); } return TruePathFileExistsW(pszPath); } BOOL WINAPI FakeDeleteFileA(LPCSTR pszPath) { - redirect_path(pszPath, &pszPath); - return TrueDeleteFileA(pszPath); -} -BOOL WINAPI FakeDeleteFileW(LPCSTR pszPath) { LPCSTR redirected; if (redirect_path(pszPath, &redirected)) { return TrueDeleteFileA(redirected); } + return TrueDeleteFileA(pszPath); +} +BOOL WINAPI FakeDeleteFileW(LPCWSTR pszPath) { + LPCSTR redirected; + if (redirect_path_w(pszPath, &redirected)) { + return TrueDeleteFileA(redirected); + } return TrueDeleteFileW(pszPath); } BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { - file_hook_t* hook = get_handle_file_hook(hDevice); - if (hook != NULL) { - if (hook->DeviceIoControl) { - // TODO: Less jank - if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent); + open_hook_t* pHData = GetDataForHandle(hDevice, HDATA_FILE); + if (pHData == NULL) { + log_trace(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice, + dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize); - BOOL ret = - hook->DeviceIoControl(hook->data, dwIoControlCode, lpInBuffer, nInBufferSize, - lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); - if (ret && lpOverlapped && lpBytesReturned) { - lpOverlapped->InternalHigh = *lpBytesReturned; - } - return ret; - } else { - log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", hook->filename); - return FALSE; - } + return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, + nOutBufferSize, lpBytesReturned, lpOverlapped); } - log_trace(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice, - dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize); + file_hook_t* file_hook = pHData->hook; + if (!file_hook->DeviceIoControl) { + log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", file_hook->filename); + return FALSE; + } - return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, - nOutBufferSize, lpBytesReturned, lpOverlapped); + BOOL ret = + file_hook->DeviceIoControl(&(pHData->ctx), dwIoControlCode, lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + if (lpOverlapped) { + SetEvent(lpOverlapped->hEvent); + if (ret && lpBytesReturned) { + lpOverlapped->InternalHigh = *lpBytesReturned; + } + } + return ret; } DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { - file_hook_t* hook = get_handle_file_hook(hFile); - if (hook != NULL) { - if (hook->SetFilePointer) { - return hook->SetFilePointer(hook->data, lDistanceToMove, lpDistanceToMoveHigh, - dwMoveMethod); - } else { - log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename); - return FALSE; - } + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL) + return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod); + + if (dwMoveMethod == FILE_BEGIN) { + if (*lpDistanceToMoveHigh) + pHData->ctx.m_Pointer.HighPart = *lpDistanceToMoveHigh; + else + pHData->ctx.m_Pointer.HighPart = 0; + pHData->ctx.m_Pointer.LowPart = lDistanceToMove; + } else if (dwMoveMethod == FILE_END) { + log_error("files", "FILE_END unimplemented"); + return 0xFFFFFFFF; + } else { + if (lpDistanceToMoveHigh) pHData->ctx.m_Pointer.HighPart += *lpDistanceToMoveHigh; + pHData->ctx.m_Pointer.LowPart += lDistanceToMove; } - return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod); + return pHData->ctx.m_Pointer.LowPart; } BOOL WINAPI FakeSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) { - file_hook_t* hook = get_handle_file_hook(hFile); - if (hook != NULL) { - if (hook->SetFilePointerEx) { - return hook->SetFilePointerEx(hook->data, liDistanceToMove, lpNewFilePointer, - dwMoveMethod); - } else { - log_error(HOOKS_LOGGER, "SetFilePointerEx(%ls) unimplemented", hook->filename); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData != NULL) { + if (dwMoveMethod == FILE_BEGIN) { + pHData->ctx.m_Pointer = liDistanceToMove; + } else if (dwMoveMethod == FILE_END) { + log_error("files", "FILE_END unimplemented"); return FALSE; + } else { + pHData->ctx.m_Pointer.QuadPart += liDistanceToMove.QuadPart; } + if (lpNewFilePointer) lpNewFilePointer->QuadPart = pHData->ctx.m_Pointer.QuadPart; + + return TRUE; } return TrueSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod); } DWORD WINAPI FakeGetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) { - file_hook_t* hook = get_handle_file_hook(hFile); - if (hook != NULL) { - if (hook->GetFileSizeEx) { - return hook->GetFileSizeEx(hook->data, lpFileSize); - } else { - log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", hook->filename); - return FALSE; - } + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL) { + return TrueGetFileSizeEx(hFile, lpFileSize); } - - return TrueGetFileSizeEx(hFile, lpFileSize); + file_hook_t* file_hook = pHData->hook; + if (!file_hook->GetFileSizeEx) { + log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", file_hook->filename); + return FALSE; + } + return file_hook->GetFileSizeEx(&(pHData->ctx), lpFileSize); } DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { - if (hFile == GetStdHandle(STD_INPUT_HANDLE) || hFile == GetStdHandle(STD_OUTPUT_HANDLE) || - hFile == GetStdHandle(STD_ERROR_HANDLE)) { + if (hFile == GetStdHandle(STD_OUTPUT_HANDLE) || hFile == GetStdHandle(STD_ERROR_HANDLE)) { return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); } - log_trace("file", "WriteFile(%08x)", hFile); - file_hook_t* hook = get_handle_file_hook(hFile); - if (hook != NULL) { - if (hook->WriteFile) { - return hook->WriteFile(hook->data, lpBuffer, nNumberOfBytesToWrite, - lpNumberOfBytesWritten, lpOverlapped); - } else { - log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename); - return FALSE; - } + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL) { + return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, + lpOverlapped); } - // return FALSE; - return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, - lpOverlapped); + file_hook_t* file_hook = pHData->hook; + if (!file_hook->WriteFile) { + log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", file_hook->filename); + return FALSE; + } + return file_hook->WriteFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToWrite, + lpNumberOfBytesWritten, lpOverlapped); } BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { - file_hook_t* hook = get_handle_file_hook(hFile); - if (hook != NULL) { - if (hook->ReadFile) { - return hook->ReadFile(hook->data, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, - lpOverlapped); - } else { - log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename); - return FALSE; - } + if (hFile == GetStdHandle(STD_INPUT_HANDLE)) { + return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, + lpOverlapped); } - return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); + open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); + if (pHData == NULL) { + return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, + lpOverlapped); + } + + file_hook_t* file_hook = pHData->hook; + + if (!file_hook->ReadFile) { + log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", file_hook->filename); + return FALSE; + } + return file_hook->ReadFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, + lpOverlapped); } BOOL WINAPI FakeCloseHandle(HANDLE hObject) { - file_hook_t* hook = get_handle_file_hook(hObject); - if (hook != NULL) { - log_misc("file", "close %08x", hObject); - close_hook(hObject); - return TRUE; - } + RemoveDataForHandle(hObject, HDATA_ANY); return TrueCloseHandle(hObject); } @@ -407,8 +371,8 @@ void hook_io() { hook("Shlwapi.dll", "PathFileExistsA", FakePathFileExistsA, (void**)&TruePathFileExistsA, 5); hook("Shlwapi.dll", "PathFileExistsW", FakePathFileExistsW, (void**)&TruePathFileExistsW, 5); - hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA, 5); - hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW, 5); + hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA, 7); + hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW, 7); hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5); } diff --git a/src/micetools/dll/hooks/files.h b/src/micetools/dll/hooks/files.h index c746e1a..7ad5d58 100644 --- a/src/micetools/dll/hooks/files.h +++ b/src/micetools/dll/hooks/files.h @@ -2,51 +2,64 @@ #include "../common.h" #include "com.h" -static HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile); -static HANDLE(WINAPI* TrueCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile); +#ifndef _MICE_FILES +#define _MICE_FILES extern +#endif -static BOOL(WINAPI* TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, - LPOVERLAPPED lpOverlapped); +_MICE_FILES HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile); +_MICE_FILES HANDLE(WINAPI* TrueCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile); -static DWORD(WINAPI* TrueSetFilePointer)(HANDLE hFile, LONG lDistanceToMove, - PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); -static BOOL(WINAPI* TrueSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, - PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod); +_MICE_FILES BOOL(WINAPI* TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, + LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + +_MICE_FILES DWORD(WINAPI* TrueSetFilePointer)(HANDLE hFile, LONG lDistanceToMove, + PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); +_MICE_FILES BOOL(WINAPI* TrueSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, + PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod); // logging needs access to WriteFile, so we can't static it! BOOL(WINAPI* TrueWriteFile) (HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); -static BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); -static BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize); -static BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject); -static BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath); -static BOOL(WINAPI* TruePathFileExistsW)(LPCWSTR pszPath); -static BOOL(WINAPI* TrueDeleteFileA)(LPCSTR lpFileName); -static BOOL(WINAPI* TrueDeleteFileW)(LPCWSTR lpFileName); +_MICE_FILES BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); +_MICE_FILES BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize); +_MICE_FILES BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject); +_MICE_FILES BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath); +_MICE_FILES BOOL(WINAPI* TruePathFileExistsW)(LPCWSTR pszPath); +_MICE_FILES BOOL(WINAPI* TrueDeleteFileA)(LPCSTR lpFileName); +_MICE_FILES BOOL(WINAPI* TrueDeleteFileW)(LPCWSTR lpFileName); -typedef BOOL(FnDeviceIoControl)(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, - LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); +typedef struct { + HANDLE m_Handle; + LARGE_INTEGER m_Pointer; + void* m_HookData; +} file_context_t; -typedef DWORD(FnSetFilePointer)(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, - DWORD dwMoveMethod); -typedef BOOL(FnSetFilePointerEx)(void* file, LARGE_INTEGER liDistanceToMove, +typedef BOOL(WINAPI FnDeviceIoControl)(file_context_t* ctx, DWORD dwIoControlCode, + LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, + DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped); + +typedef DWORD(FnSetFilePointer)(file_context_t* ctx, LONG lDistanceToMove, + PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); +typedef BOOL(FnSetFilePointerEx)(file_context_t* ctx, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod); -typedef BOOL(FnWriteFile)(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, +typedef BOOL(FnWriteFile)(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); -typedef BOOL(FnReadFile)(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, +typedef BOOL(FnReadFile)(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); -typedef BOOL(FnGetFileSizeEx)(void* file, PLARGE_INTEGER lpFileSize); +typedef BOOL(FnGetFileSizeEx)(file_context_t* ctx, PLARGE_INTEGER lpFileSize); typedef struct _stat64i32 _stat64i32_t; static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer); @@ -56,6 +69,7 @@ static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer); #define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle) #define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW) #define _CreateFileA (TrueCreateFileA ? TrueCreateFileA : CreateFileA) +#define _SetFilePointer (TrueSetFilePointer ? TrueSetFilePointer : SetFilePointer) typedef struct drive_redirect { const CHAR* drive; @@ -72,22 +86,20 @@ typedef struct file_hook { LPCWSTR altFilename; FnDeviceIoControl* DeviceIoControl; - FnSetFilePointer* SetFilePointer; - FnSetFilePointerEx* SetFilePointerEx; FnWriteFile* WriteFile; FnReadFile* ReadFile; FnGetFileSizeEx* GetFileSizeEx; - void* data; + com_hook_t* com_hook; + void* hook_data; LPHANDLE virtual_handle; struct file_hook* next; } file_hook_t; typedef struct open_hook { - HANDLE handle; - file_hook_t* file_hook; - com_hook_t* com_hook; + file_context_t ctx; + file_hook_t* hook; struct open_hook* next; } open_hook_t; @@ -96,7 +108,3 @@ extern file_hook_t* file_hook_list; file_hook_t* new_file_hook(LPCWSTR filename); void hook_file(file_hook_t* hook); void hook_io(); - -void close_hook(HANDLE handle); -file_hook_t* get_handle_file_hook(HANDLE handle); -com_hook_t* get_handle_com_hook(HANDLE handle); diff --git a/src/micetools/dll/hooks/gui.c b/src/micetools/dll/hooks/gui.c index 011158d..bd253fd 100644 --- a/src/micetools/dll/hooks/gui.c +++ b/src/micetools/dll/hooks/gui.c @@ -17,10 +17,49 @@ HWND GetProcessWindow() { EnumWindows(EnumWindowsCallback, 0); return window; } + +BOOL UnFrameWindow(HWND hwnd) { + SetLastError(ERROR_SUCCESS); + LONG style = GetWindowLongW(hwnd, GWL_STYLE); + if (GetLastError() != ERROR_SUCCESS) return FALSE; + + RECT rect; + if (!GetClientRect(hwnd, &rect)) return FALSE; + + style &= ~(WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU); + if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE; + + SetWindowLongW(hwnd, GWL_STYLE, style); + if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE)) + return FALSE; + return TRUE; +} + +BOOL FrameWindow(HWND hwnd) { + SetLastError(ERROR_SUCCESS); + LONG style = GetWindowLongW(hwnd, GWL_STYLE); + if (GetLastError() != ERROR_SUCCESS) return FALSE; + + RECT rect; + if (!GetClientRect(hwnd, &rect)) return FALSE; + + style |= WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; + if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE; + + SetWindowLongW(hwnd, GWL_STYLE, style); + + if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE)) + return FALSE; + return TRUE; +} + BOOL GetD3D9Device(void** pTable, size_t Size) { if (!pTable) return false; - IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION); + IDirect3D9* pD3D = + (TrueDirect3DCreate9 ? TrueDirect3DCreate9 : Direct3DCreate9)(D3D_SDK_VERSION); if (!pD3D) return false; IDirect3DDevice9* pDummyDevice = NULL; @@ -92,8 +131,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UIN } void post_win_create(HWND hWnd) { - void* d3d9Device[119]; + // Don't double-hook! + if (TrueEndScene != NULL) return; + void* d3d9Device[119]; if (GetD3D9Device(d3d9Device, sizeof(d3d9Device))) { *((PVOID*)&TrueEndScene) = CreateHook((PVOID)d3d9Device[42], (PVOID)hkEndScene, 7); } @@ -103,10 +144,46 @@ void post_win_create(HWND hWnd) { } } +RECT monitorRect = { 0 }; +int monitorIndex = 0; +BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, + LPARAM dwData) { + if (monitorIndex == MiceConfig.window.adaptor) + memcpy(&monitorRect, lprcMonitor, sizeof monitorRect); + monitorIndex++; + return TRUE; +} + +void SetupWindowPosition(int* X, int* Y, int* nWidth, int* nHeight) { + monitorIndex = 0; + EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)NULL); + + if (MiceConfig.window.w) *nWidth = MiceConfig.window.w; + if (MiceConfig.window.h) *nHeight = MiceConfig.window.h; + + if (MiceConfig.window.centre) { + *X = ((monitorRect.right - monitorRect.left) - *nWidth) / 2; + *Y = ((monitorRect.bottom - monitorRect.top) - *nHeight) / 2; + } else { + *X = MiceConfig.window.x; + *Y = MiceConfig.window.y; + } + *X += monitorRect.left; + *Y += monitorRect.top; +} + HWND WINAPI FakeCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) { - HWND hWnd = TrueCreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, + // Pass-through for system stuff + if (lpWindowName == NULL || strcmp(lpWindowName, "OleMainThreadWndName") == 0 || + strcmp(lpWindowName, "CicMarshalWnd") == 0) { + return TrueCreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, + nHeight, hWndParent, hMenu, hInstance, lpParam); + } + + SetupWindowPosition(&X, &Y, &nWidth, &nHeight); + HWND hWnd = TrueCreateWindowExA(dwExStyle, lpClassName, "Micetools", dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); post_win_create(hWnd); return hWnd; @@ -114,14 +191,87 @@ HWND WINAPI FakeCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWi HWND WINAPI FakeCreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) { - HWND hWnd = TrueCreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, + // Pass-through for system stuff + if (lpWindowName == NULL || wcscmp(lpWindowName, L"OleMainThreadWndName") == 0 || + wcscmp(lpWindowName, L"CicMarshalWnd") == 0) { + return TrueCreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, + nHeight, hWndParent, hMenu, hInstance, lpParam); + } + + SetupWindowPosition(&X, &Y, &nWidth, &nHeight); + HWND hWnd = TrueCreateWindowExW(dwExStyle, lpClassName, L"Micetools", dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); post_win_create(hWnd); return hWnd; } +static HRESULT(STDMETHODCALLTYPE* TrueCreateDevice)(IDirect3D9* this, UINT Adapter, + D3DDEVTYPE DeviceType, HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS* pPresentationParameters, + IDirect3DDevice9** ppReturnedDeviceInterface); + +extern RECT monitorRect; +HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDEVTYPE DeviceType, + HWND hFocusWindow, DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS* pPresentationParameters, + IDirect3DDevice9** ppReturnedDeviceInterface) { + if (MiceConfig.window.windowed) { + pPresentationParameters->Windowed = TRUE; + pPresentationParameters->FullScreen_RefreshRateInHz = 0; + } else if (pPresentationParameters->Windowed) { + D3DDISPLAYMODE d3ddm; + this->lpVtbl->GetAdapterDisplayMode(this, Adapter, &d3ddm); + + pPresentationParameters->Windowed = FALSE; + pPresentationParameters->FullScreen_RefreshRateInHz = d3ddm.RefreshRate; + } + if (MiceConfig.window.borderless) + UnFrameWindow(hFocusWindow); + else + FrameWindow(hFocusWindow); + Adapter = MiceConfig.window.adaptor; + + RECT winRect; + GetWindowRect(hFocusWindow, &winRect); + int w = MiceConfig.window.w ? MiceConfig.window.w : (winRect.right - winRect.left); + int h = MiceConfig.window.h ? MiceConfig.window.h : (winRect.bottom - winRect.top); + int x = MiceConfig.window.x; + int y = MiceConfig.window.y; + if (MiceConfig.window.centre) { + x = ((monitorRect.right - monitorRect.left) - w) / 2; + y = ((monitorRect.bottom - monitorRect.top) - h) / 2; + } + + x += monitorRect.left; + y += monitorRect.top; + + SetWindowPos(hFocusWindow, HWND_TOP, x, y, w, h, 0); + + return TrueCreateDevice(this, Adapter, DeviceType, hFocusWindow, BehaviorFlags, + pPresentationParameters, ppReturnedDeviceInterface); +} + +IDirect3D9* WINAPI FakeDirect3DCreate9(UINT SDKVersion) { + IDirect3D9* pD3D = TrueDirect3DCreate9(D3D_SDK_VERSION); + + TrueCreateDevice = pD3D->lpVtbl->CreateDevice; + DWORD patch = (DWORD)&FakeCreateDevice; + patch_at(&pD3D->lpVtbl->CreateDevice, (char*)&patch, 4); + + return pD3D; +}; + +int WINAPI FakeGetSystemMetrics(int nIndex) { + int real = TrueGetSystemMetrics(nIndex); + if (nIndex == SM_CXSCREEN && MiceConfig.window.w) return MiceConfig.window.w; + if (nIndex == SM_CYSCREEN && MiceConfig.window.h) return MiceConfig.window.h; + return nIndex; +} + void hook_gui() { - // hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA, 7); hook("User32.dll", "CreateWindowExW", FakeCreateWindowExW, (void**)&TrueCreateWindowExW, 7); + hook("User32.dll", "GetSystemMetrics", FakeGetSystemMetrics, (void**)&TrueGetSystemMetrics, 7); + hook("D3d9.dll", "Direct3DCreate9", FakeDirect3DCreate9, (void**)&TrueDirect3DCreate9, 5); } diff --git a/src/micetools/dll/hooks/gui.h b/src/micetools/dll/hooks/gui.h index dbec24e..80da499 100644 --- a/src/micetools/dll/hooks/gui.h +++ b/src/micetools/dll/hooks/gui.h @@ -10,6 +10,10 @@ static HWND(WINAPI* TrueCreateWindowExW)(DWORD dwExStyle, LPCWSTR lpClassName, L HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); static BOOL(WINAPI* TrueSetSystemCursor)(HCURSOR hcur, DWORD id); +static IDirect3D9*(WINAPI* TrueDirect3DCreate9)(UINT SDKVersion); +static int(WINAPI* TrueGetSystemMetrics)(int nIndex); + +#define _GetSystemMetrics (TrueGetSystemMetrics ? TrueGetSystemMetrics : GetSystemMetrics) void draw_rect(IDirect3DDevice9* dev, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b); diff --git a/src/micetools/dll/hooks/network.c b/src/micetools/dll/hooks/network.c index b2c32b2..4a137aa 100644 --- a/src/micetools/dll/hooks/network.c +++ b/src/micetools/dll/hooks/network.c @@ -3,13 +3,18 @@ int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) { ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr); USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port); - log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff, port); + // Poorly exclude pcps. TODO: better + if (port < 40100 || port > 40120) { + log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff, port); + } return True_connect(s, name, namelen); } -static uint8_t spoof_mac[6] = { 0xD8, 0xBB, 0xC1, 0x0A, 0x2F, 0x1D }; #define IF_INDEX 1 +#define MAC_PREFIX_0 0xD8 +#define MAC_PREFIX_1 0xBB +#define MAC_PREFIX_2 0xC1 DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) { log_info("network", "Injecting fake IfTable"); @@ -35,8 +40,13 @@ DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) row->dwType = IF_TYPE_ETHERNET_CSMACD; row->dwMtu = 4200; row->dwSpeed = 1000000000; - row->dwPhysAddrLen = sizeof(spoof_mac); - memcpy(row->bPhysAddr, spoof_mac, sizeof(spoof_mac)); + row->dwPhysAddrLen = 6; + row->bPhysAddr[0] = MAC_PREFIX_0; + row->bPhysAddr[1] = MAC_PREFIX_1; + row->bPhysAddr[2] = MAC_PREFIX_2; + row->bPhysAddr[3] = (MiceConfig.network.mac >> 16) & 0xff; + row->bPhysAddr[4] = (MiceConfig.network.mac >> 8) & 0xff; + row->bPhysAddr[5] = MiceConfig.network.mac & 0xff; row->dwAdminStatus = 1; row->dwOperStatus = IF_OPER_STATUS_OPERATIONAL; @@ -55,20 +65,21 @@ DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) typedef struct { char* name; - unsigned char address[4]; + unsigned int* address; } dns; + dns INTERCEPT_DNS[] = { // Startup - { "naominet.jp", { 10, 79, 140, 238 } }, + { "naominet.jp", &(MiceConfig.network.naominet_jp) }, // Billing - { "ib.naominet.jp", { 10, 79, 140, 238 } }, + { "ib.naominet.jp", &(MiceConfig.network.ib_naominet_jp) }, // Aime - { "aime.naominet.jp", { 10, 79, 140, 238 } }, + { "aime.naominet.jp", &(MiceConfig.network.aime_naominet_jp) }, // Routers (ping targets) - { "tenporouter.loc", { 10, 79, 140, 238 } }, - { "bbrouter.loc", { 10, 79, 140, 238 } }, // Must match tenporouter - { "mobirouter.loc", { 10, 79, 140, 238 } }, - { "dslrouter.loc", { 10, 79, 140, 238 } }, + { "tenporouter.loc", &(MiceConfig.network.tenporouter_loc) }, + { "bbrouter.loc", &(MiceConfig.network.bbrouter_loc) }, // Must match tenporouter + { "mobirouter.loc", &(MiceConfig.network.mobirouter_loc) }, + { "dslrouter.loc", &(MiceConfig.network.dslrouter_loc) }, }; DNS_RECORDA dummy_record; @@ -78,19 +89,15 @@ DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID if (ppQueryResults) { for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) { if (strcmp(pszName, INTERCEPT_DNS[i].name) == 0) { -#define spoof (INTERCEPT_DNS[i].address) - log_info("dns", "Replacing %s with %hhu.%hhu.%hhu.%hhu", pszName, spoof[0], - spoof[1], spoof[2], spoof[3]); + log_info("dns", "Replacing %s with %08x", pszName, *INTERCEPT_DNS[i].address); // We only support replacing at most one address, but that's all we'll ever need to! (*ppQueryResults) = &dummy_record; (*ppQueryResults)->pNext = NULL; (*ppQueryResults)->wType = DNS_TYPE_A; - (*ppQueryResults)->Data.A.IpAddress = - (spoof[0]) | (spoof[1] << 8) | (spoof[2] << 16) | (spoof[3] << 24); + (*ppQueryResults)->Data.A.IpAddress = _byteswap_ulong(*INTERCEPT_DNS[i].address); return ERROR_SUCCESS; -#undef spoof } } } @@ -104,19 +111,11 @@ INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily, log_misc("dns", "(WSA)DNS lookup for %s", AddressString); for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) { if (strcmp(AddressString, INTERCEPT_DNS[i].name) == 0) { -#define spoof (INTERCEPT_DNS[i].address) - log_info("dns", "(WSA)Replacing %s with %hhu.%hhu.%hhu.%hhu", AddressString, spoof[0], - spoof[1], spoof[2], spoof[3]); + log_info("dns", "(WSA)Replacing %s with %08x", AddressString, INTERCEPT_DNS[i].address); lpAddress->sa_family = AF_INET; - // ... :) - lpAddress->sa_data[2] = spoof[0]; - lpAddress->sa_data[3] = spoof[1]; - lpAddress->sa_data[4] = spoof[2]; - lpAddress->sa_data[5] = spoof[3]; - + memcpy(&lpAddress->sa_data, INTERCEPT_DNS[i].address, 4); return ERROR_SUCCESS; -#undef spoof } } log_warning("dns", "(WSA)DNS passthrough for %s", AddressString); diff --git a/src/micetools/dll/hooks/processes.c b/src/micetools/dll/hooks/processes.c index 6ac2372..8560cf0 100644 --- a/src/micetools/dll/hooks/processes.c +++ b/src/micetools/dll/hooks/processes.c @@ -22,7 +22,7 @@ BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, if (lpProcessInformation) { lpProcessInformation->hProcess = fake_evt; } - return TRUE; + return FALSE; } BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, @@ -36,6 +36,8 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, // #else // log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine); log_info("spawn", "CreateProcessW %ls", lpApplicationName); + + lpProcessInformation->hThread = GetDummyHandle(); return TRUE; CHAR applicationName[MAX_PATH + 1]; diff --git a/src/micetools/dll/meson.build b/src/micetools/dll/meson.build index 9d1e05b..bf45e64 100644 --- a/src/micetools/dll/meson.build +++ b/src/micetools/dll/meson.build @@ -8,6 +8,7 @@ shared_library( name_prefix: '', vs_module_defs: 'mice.def', sources: [ + 'util/misc.c', 'util/log.c', 'util/hook.c', @@ -23,7 +24,7 @@ shared_library( link_with: [ dmi_lib, mice_lib, - amlib, + amiTimer, mxklib, ], include_directories: [ diff --git a/src/micetools/dll/smbus.h b/src/micetools/dll/smbus.h index 9a02f42..8de2e30 100644 --- a/src/micetools/dll/smbus.h +++ b/src/micetools/dll/smbus.h @@ -120,15 +120,17 @@ IOCTL_MXSUPERIO_READ: #define SMBUS_EEPROM 0xAE // Keychip -#define N2_GET_EEPROM 0x40 -#define N2_GET_UNIQUE_NUMBER 0xA0 -#define N2_GET_STATUS 0xA8 -#define N2_STATUS_FLAG_BUSY 2 -#define N2_I2C_CHALLENGE_RESPONSE 0xB0 +#define DS_GET_EEPROM 0x40 +#define DS_GET_UNIQUE_NUMBER 0xA0 +#define DS_GET_STATUS 0xA8 +#define DS_STATUS_FLAG_BUSY 2 +#define DS_I2C_CHALLENGE_RESPONSE 0xB0 #define EXIO_GET_BUSY 0x00 -#pragma pack(1) +// Old +// TODO: Check for uses, then delete +#pragma pack(push, 1) typedef struct mxsmbus_request_packet_ { BYTE status; BYTE prt; @@ -137,8 +139,6 @@ typedef struct mxsmbus_request_packet_ { BYTE dlen; BYTE data[32]; } mxsmbus_request_packet; - -#pragma pack(1) typedef struct mxsmbus_i2c_packet_ { BYTE status; BYTE prt; @@ -147,3 +147,53 @@ typedef struct mxsmbus_i2c_packet_ { BYTE dlen; BYTE data[32]; } mxsmbus_i2c_packet; + +typedef struct _MXSMBUS_REQUEST_PACKET { + BYTE status; + BYTE command; + BYTE v_addr; + BYTE command_code; + BYTE nbytes; + BYTE data[32]; +} MXSMBUS_REQUEST_PACKET, *PMXSMBUS_REQUEST_PACKET; + +typedef struct _MXSMBUS_I2C_PACKET { + BYTE status; + BYTE command; + WORD v_addr; + WORD command_code; + BYTE nbytes; + BYTE data[32]; +} MXSMBUS_I2C_PACKET, *PMXSMBUS_I2C_PACKET; +#pragma pack(pop) + + +typedef enum { + ICH9_CMD_QUICK = 0b000, + ICH9_CMD_BYTE = 0b001, + ICH9_CMD_BYTE_DATA = 0b010, + ICH9_CMD_WORD_DATA = 0b011, + ICH9_CMD_PROCESS_CALL = 0b100, + ICH9_CMD_BLOCK = 0b101, + ICH9_CMD_I2C_READ = 0b110, + ICH9_CMD_BLOCK_PROCESS = 0b111, +} ich9_cmd_t; + +typedef enum { + MXSMBUS_CMD_WRITE_QUICK = 0, + MXSMBUS_CMD_READ_QUICK = 1, + MXSMBUS_CMD_WRITE_BYTE = 2, + MXSMBUS_CMD_READ_BYTE = 3, + MXSMBUS_CMD_WRITE_BYTE_DATA = 4, + MXSMBUS_CMD_READ_BYTE_DATA = 5, + MXSMBUS_CMD_WRITE_WORD_DATA = 6, + MXSMBUS_CMD_READ_WORD_DATA = 7, + MXSMBUS_CMD_WRITE_BLOCK = 8, + MXSMBUS_CMD_READ_BLOCK = 9, + MXSMBUS_CMD_PROCESS_CALL = 10, + MXSMBUS_CMD_I2C = 11, +} mxsmbus_cmd_t; + +typedef BOOL smbus_callback_t(ich9_cmd_t cmd, WORD code, BYTE nbytes, BYTE* data); + +void smbus_install(BYTE v_addr, smbus_callback_t* write, smbus_callback_t* read); diff --git a/src/micetools/dll/util/_util.h b/src/micetools/dll/util/_util.h index 04dfbc1..9aaebe2 100644 --- a/src/micetools/dll/util/_util.h +++ b/src/micetools/dll/util/_util.h @@ -2,3 +2,14 @@ #include "log.h" #include "hook.h" + +#define HDATA_FILE 0 +#define HDATA_FIND_VOLUME 1 +#define HDATA_ANY 0xFFFFFFFF + +BOOL FileExists(wchar_t* szPath); +PVOID GetDataForHandle(HANDLE hObject, DWORD type); +void SetDataForHandle(HANDLE hObject, DWORD type, PVOID pData, BOOL isHeap); +BOOL RemoveDataForHandle(HANDLE hObject, DWORD type); +HANDLE GetDummyHandle(); +void BytesToHex(char* hex_buffer, BYTE* bytes, DWORD nbytes); diff --git a/src/micetools/dll/util/hook.c b/src/micetools/dll/util/hook.c index 4918920..7b3ad85 100644 --- a/src/micetools/dll/util/hook.c +++ b/src/micetools/dll/util/hook.c @@ -1,6 +1,7 @@ #include "hook.h" #include +#include #include #include "log.h" diff --git a/src/micetools/dll/util/log.c b/src/micetools/dll/util/log.c index 3e1931f..1285cce 100644 --- a/src/micetools/dll/util/log.c +++ b/src/micetools/dll/util/log.c @@ -1,13 +1,18 @@ #include "log.h" +#include #include #include #include #include +#pragma comment(lib, "DbgHelp.lib") #include "../../lib/mice/config.h" #include "../hooks/logging.h" +extern WCHAR exePath[MAX_PATH + 1]; +extern DWORD imageOffset; + extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); @@ -72,19 +77,18 @@ void __stdcall amLogCallback(DWORD level, char* format) { DWORD pLogcb; DWORD* ppLogcb; -extern WCHAR exePath[MAX_PATH + 1]; int _do_log(BYTE log_level, const char* caller, const char* format, va_list args) { // TODO: These are all horrible bodges if (wcscmp(exePath, L"mxnetwork.exe") == 0) { - // *((DWORD*)(0x004438e8)) = (DWORD)(&logcb); - *((DWORD*)(0x004438e8)) = 0x00000000; + // *((DWORD*)(imageOffset + 0x004438e8)) = (DWORD)(&logcb); + *((DWORD*)(imageOffset + 0x004438e8)) = 0x00000000; } if (wcscmp(exePath, L"maimai_dump_.exe") == 0) { - *((DWORD*)(0x00c820ec)) = 0x00000001; + *((DWORD*)(imageOffset + 0x00c820ec)) = 0x00000001; pLogcb = (DWORD)(&amLogCallback); ppLogcb = &pLogcb; - *((DWORD***)(0x00c820F4)) = &ppLogcb; - // *((DWORD*)(0x004438e8)) = (DWORD)(&logcb); + *((DWORD***)(imageOffset + 0x00c820F4)) = &ppLogcb; + // *((DWORD*)(imageOffset + 0x004438e8)) = (DWORD)(&logcb); } force_console_bind(); @@ -214,3 +218,44 @@ void setup_logging() { CREATE_ALWAYS, 0, NULL); } } + +void log_stack(const char* caller) { + char name[MAX_PATH * sizeof(TCHAR)]; + char Storage[sizeof(IMAGEHLP_SYMBOL64) + sizeof(name)]; + + IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)Storage; + CONTEXT context; + RtlCaptureContext(&context); + + STACKFRAME64 stack = { 0 }; + stack.AddrPC.Offset = context.Eip; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrStack.Offset = context.Esp; + stack.AddrStack.Mode = AddrModeFlat; + stack.AddrFrame.Offset = context.Ebp; + stack.AddrFrame.Mode = AddrModeFlat; + + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + BOOL initres = SymInitialize(process, NULL, true); + for (ULONG frame = 0;; frame++) { + BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, process, thread, &stack, &context, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL); + + symbol->SizeOfStruct = sizeof(Storage); + symbol->MaxNameLength = sizeof(name); + + DWORD64 displacement; + SymGetSymFromAddr64(process, (ULONG64)stack.AddrPC.Offset, &displacement, symbol); + UnDecorateSymbolName(symbol->Name, (PSTR)name, sizeof(name), UNDNAME_COMPLETE); + + log_error(caller, "%02u called from 0x%08X STACK=0x%08X FRAME=0x%08X %s\n", frame, + (ULONG64)stack.AddrPC.Offset, (ULONG64)stack.AddrStack.Offset, + (ULONG64)stack.AddrFrame.Offset, symbol->Name); + + if (result == FALSE) { + DWORD frameError = GetLastError(); + break; + } + } +} diff --git a/src/micetools/dll/util/log.h b/src/micetools/dll/util/log.h index 0ebd8f2..064a9e3 100644 --- a/src/micetools/dll/util/log.h +++ b/src/micetools/dll/util/log.h @@ -30,4 +30,6 @@ int vlog_warning(const char* caller, const char* format, va_list args); int vlog_error(const char* caller, const char* format, va_list args); int vlog_game(const char* caller, const char* format, va_list args); +void log_stack(const char* caller); + void setup_logging(); diff --git a/src/micetools/dll/util/misc.c b/src/micetools/dll/util/misc.c new file mode 100644 index 0000000..cafc1fe --- /dev/null +++ b/src/micetools/dll/util/misc.c @@ -0,0 +1,98 @@ +#include + +#include "../hooks/files.h" + +BOOL FileExists(wchar_t* szPath) { + DWORD dwAttrib = GetFileAttributesW(szPath); + return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +} + +typedef struct _handle_list { + HANDLE m_Handle; + PVOID m_pData; + DWORD m_Type; + BOOL m_IsOnHeap; + struct _handle_list* m_Next; +} handle_list_t; +handle_list_t handle_list_root = { + .m_Handle = INVALID_HANDLE_VALUE, + .m_pData = NULL, + .m_Type = 0xffffffff, + .m_IsOnHeap = FALSE, + .m_Next = NULL, +}; + +PVOID GetDataForHandle(HANDLE hObject, DWORD type) { + if (hObject == INVALID_HANDLE_VALUE) return NULL; + + handle_list_t* head = &handle_list_root; + while (head) { + if (head->m_Handle == hObject && (type == HDATA_ANY || head->m_Type == type)) + return head->m_pData; + head = head->m_Next; + } + return NULL; +} +void SetDataForHandle(HANDLE hObject, DWORD type, PVOID pData, BOOL isHeap) { + if (hObject == INVALID_HANDLE_VALUE) return; + + handle_list_t* head = &handle_list_root; + while (1) { + if (head->m_Handle == hObject && (type == HDATA_ANY || head->m_Type == type)) { + if (head->m_IsOnHeap) free(head->m_pData); + head->m_pData = pData; + head->m_IsOnHeap = isHeap; + return; + } + if (head->m_Next == NULL) break; + head = head->m_Next; + } + head->m_Next = malloc(sizeof *head); + head->m_Next->m_Handle = hObject; + head->m_Next->m_pData = pData; + head->m_Next->m_Next = NULL; + head->m_Next->m_IsOnHeap = isHeap; + head->m_Next->m_Type = type; +} +BOOL RemoveDataForHandle(HANDLE hObject, DWORD type) { + if (hObject == INVALID_HANDLE_VALUE) return FALSE; + + handle_list_t* head = &handle_list_root; + handle_list_t* previous = &handle_list_root; + BOOL ret = FALSE; + while (head) { + if (head->m_Handle == hObject && (type == HDATA_ANY || head->m_Type == type)) { + previous->m_Next = head->m_Next; + if (head->m_IsOnHeap) free(head->m_pData); + handle_list_t* next = head->m_Next; + free(head); + head = next; + if (type != HDATA_ANY) return TRUE; + ret = TRUE; + } else { + previous = head; + head = head->m_Next; + } + } + return ret; +} + +HANDLE GetDummyHandle() { + CHAR path[MAX_PATH]; + GetModuleFileNameA(NULL, path, MAX_PATH); + HANDLE hObject = + _CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + + if (hObject == INVALID_HANDLE_VALUE) { + log_error(HOOKS_LOGGER, "Failed to create dummy handle: %03x", GetLastError()); + } + + return hObject; +} + +void BytesToHex(char* hex_buffer, BYTE* bytes, DWORD nbytes) { + for (size_t i = 0; i < nbytes; i++) { + sprintf(hex_buffer + i * 3, "%02x ", bytes[i]); + } + hex_buffer[nbytes * 3] = '\0'; +} diff --git a/src/micetools/launcher/locate.c b/src/micetools/launcher/locate.c index 92db8eb..b02b5e6 100644 --- a/src/micetools/launcher/locate.c +++ b/src/micetools/launcher/locate.c @@ -5,6 +5,11 @@ const char* KNOWN_GAMES[] = { // Preferentially use a decrypted dump if present "maimai_dump_.exe", + + // Generic + "RingGame.exe", + + // We currently have no hope of running undumped maimai but whatever "maimai.exe", }; diff --git a/src/micetools/launcher/main.c b/src/micetools/launcher/main.c index b43c0f9..4d18ce1 100644 --- a/src/micetools/launcher/main.c +++ b/src/micetools/launcher/main.c @@ -4,8 +4,6 @@ #include "../lib/mice/mice.h" #include "locate.h" -const char* VERSION = "0.0-pre"; - bool debug_wait = false; int boot_delay = 0; bool gametest = false; @@ -57,7 +55,7 @@ void parse_cmdline(int argc, char* argv[]) { int main(int argc, char* argv[]) { load_mice_config(); - fprintf(stderr, "Micetools version: %s\n", VERSION); + fprintf(stderr, "Micetools version: %s\n", MICE_VERSION); parse_cmdline(argc, argv); diff --git a/src/micetools/lib/_am.h b/src/micetools/lib/_am.h new file mode 100644 index 0000000..3dafe6b --- /dev/null +++ b/src/micetools/lib/_am.h @@ -0,0 +1,10 @@ +#include "../mice/version_fallback.h" + +#define AM_LIB_C_HEADER(name, storage_type) \ + int name##DebugLevel = 0; \ + struct _##storage_type name; \ + char* name##Version = #name " Ver.mice" MICE_VERSION " Build:" __DATE__ " " __TIME__; +#define AM_LIB_H_HEADER(name, storage_type) \ + extern int name##DebugLevel; \ + extern struct _##storage_type name; \ + extern char* name##Version; diff --git a/src/micetools/lib/am/am.h b/src/micetools/lib/am/am.h new file mode 100644 index 0000000..dcc0805 --- /dev/null +++ b/src/micetools/lib/am/am.h @@ -0,0 +1,6 @@ +#pragma once + +#include "amEeprom.h" +#include "amOemstring.h" +#include "amPlatform.h" +#include "amSram.h" diff --git a/src/micetools/lib/am/amAime.h b/src/micetools/lib/am/amAime.h new file mode 100644 index 0000000..9b1821f --- /dev/null +++ b/src/micetools/lib/am/amAime.h @@ -0,0 +1,8 @@ +void amAimeInit(void); +void amAimeExit(void); +void amAimeGetResult(void); +void amAimeCancelToGetCardInfo(void); +void amAimeUpdate(void); +void amAimeGetCardInfo(void); +void amAimeGetAimeId(void); +void amAimeRegistCard(void); diff --git a/src/micetools/lib/am/amAta.h b/src/micetools/lib/am/amAta.h new file mode 100644 index 0000000..ba1df08 --- /dev/null +++ b/src/micetools/lib/am/amAta.h @@ -0,0 +1,4 @@ +void amAtaOpenDevice(void); +void amAtaCloseDevice(void); +void amAtaPioInCommand(void); +void amAtaPioOutCommand(void); diff --git a/src/micetools/lib/am/amAuth.h b/src/micetools/lib/am/amAuth.h new file mode 100644 index 0000000..55be5fa --- /dev/null +++ b/src/micetools/lib/am/amAuth.h @@ -0,0 +1,11 @@ +void amAuthInit(void); +void amAuthExit(void); +void amAuthGetSerialId(void); +void amAuthGetCurrentStatus(void); +void amAuthAccount(void); +void amAuthCancelAccount(void); +void amAuthGetCurrentTime(void); +void amAuthGetPlaceInfo(void); +void amAuthGetCloseTime(void); +void amAuthDiffTime(void); +void amAuthGetTitleServerAddress(void); diff --git a/src/micetools/lib/am/amAuthDisk.h b/src/micetools/lib/am/amAuthDisk.h new file mode 100644 index 0000000..4ab94b1 --- /dev/null +++ b/src/micetools/lib/am/amAuthDisk.h @@ -0,0 +1 @@ +void amAuthDiscRead(void); diff --git a/src/micetools/lib/am/amBackup.h b/src/micetools/lib/am/amBackup.h new file mode 100644 index 0000000..cc18b5a --- /dev/null +++ b/src/micetools/lib/am/amBackup.h @@ -0,0 +1,10 @@ +void amBackupInit(void); +void amBackupExit(void); +void amBackupRead(void); +void amBackupRecordCheckValid(void); +void amBackupRecordReadDup(void); +void amBackupRecordWriteDup(void); +void amBackupRecordValidate(void); +void amBackupRecordWrite(void); +void amBackupRecordWriteDup(void); +void amBackupWrite(void); diff --git a/src/micetools/lib/am/amCmos.h b/src/micetools/lib/am/amCmos.h new file mode 100644 index 0000000..def3bb4 --- /dev/null +++ b/src/micetools/lib/am/amCmos.h @@ -0,0 +1,3 @@ +void amCmosReadByteInRearpart(void); +void amCmosSetPartition(void); +void amCmosWriteByteInRearpart(void); diff --git a/src/micetools/lib/am/amCredit.h b/src/micetools/lib/am/amCredit.h new file mode 100644 index 0000000..dde497d --- /dev/null +++ b/src/micetools/lib/am/amCredit.h @@ -0,0 +1,17 @@ +void amCreditClear(void); +void amCreditExit(void); +void amCreditGetEvent(void); +void amCreditGetMaxCredit(void); +void amCreditGetStatus(void); +void amCreditInit(void); +void amCreditIsEnough(void); +void amCreditIsModifiedBookkeeping(void); +void amCreditIsModifiedData(void); +void amCreditIsValidConfig(void); +void amCreditIsValidCustomBonusAdder(void); +void amCreditLoadBookkeeping(void); +void amCreditLoadConfig(void); +void amCreditLoadData(void); +void amCreditSetCustomBonusAdder(void); +void amCreditSetDistribution(void); +void amCreditUpdateJVS(void); diff --git a/src/micetools/lib/am/amDipsw.h b/src/micetools/lib/am/amDipsw.h new file mode 100644 index 0000000..611df61 --- /dev/null +++ b/src/micetools/lib/am/amDipsw.h @@ -0,0 +1,23 @@ +void amDipswCreateDeviceFile(void); +void amDipswCreateMutex(void); +void amDipswExit(void); +void amDipswGetDriverVerision(void); +void amDipswInit(void); +void amDipswModifyByte(void); +void amDipswModifyByteEx(void); +void amDipswModifyByteInternal(void); +void amDipswModifyByteInternalEx(void); +void amDipswMxsmbusStatusCheck(void); +void amDipswReadByte(void); +void amDipswReadByteInternal(void); +void amDipswReadByteInternalEx(void); +void amDipswRequestGetDipsw(void); +void amDipswRequestGetPushsw(void); +void amDipswRequestReadByte(void); +void amDipswRequestSetJvsIoctl(void); +void amDipswRequestSetLed(void); +void amDipswResponse(void); +void amDipswResponseInternalEx(void); +void amDipswWriteByte(void); +void amDipswWriteByteInternal(void); +void amDipswWriteByteInternalEx(void); diff --git a/src/micetools/lib/am/amDongle.c b/src/micetools/lib/am/amDongle.c new file mode 100644 index 0000000..505052e --- /dev/null +++ b/src/micetools/lib/am/amDongle.c @@ -0,0 +1,1127 @@ +#include "amDongle.h" + +#include "../libpcp/pcpa.h" +#include "../util/hex.h" + +AM_LIB_C_HEADER(amDongle, AM_DONGLE) + +AM_DONGLE_STATUS amDongleInit(void) { + if (amDongle.m_init) return AM_DONGLE_STATUS_ERR_ALREADY_INIT; + + memset(&amDongle, 0, sizeof amDongle); + amDongle.version = 0; + amDongle.seq = -1; + amDongle.field19_0x40 = -1; + amDongle.done_init = 0; + amDongle.available = 0; + // amDongle.field14_0x2c = 5; + amDongle.develop = 0; + amDongle.authCondition = 1; + amDongle.auth_ready = 0; + // amDongle.field6_0x18 = 0; + // amDongle.field7_0x1c = 0; + // amDongle.field8_0x20 = 0; + // amDongle.field13_0x28 = 1; + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_START; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_NONE; + amDongle.setupRetries = 0; + amDongle.requestCode = 0; + amDongle.result = 0; + // amDongle.field21_0x48 = 1; + // amDongle.field22_0x4c = 0; + amDongle.challengeNum = 0; + amDongle.ctrl_port = 40106; + amDongle.data_port = 40107; + amDongle.valueBuffer = NULL; + amDongle.dataBuffer = NULL; + // amDongle.field51_0x3440 = 0; + // amDongle.field53_0x3448 = 0; + + e_pcpa_t pcpa_err = pcpaInitStream(&amDongle.pcpa); + if (pcpa_err == e_pcpa_wsa_noinit) { + if (amDongleDebugLevel > 0) amiDebugLog("Error: Winsocket2 Library is not ready."); + return AM_DONGLE_STATUS_ERR_PRECONDITION; + } + if (pcpa_err != e_pcpa_ok) { + if (amDongleDebugLevel > 0) { + amiDebugLog("Error: System error happened in pcp stream. ErrorCode = %d.", + pcpa_err); + } + return AM_DONGLE_STATUS_ERR_SYS; + } + amDongle.m_init = 1; + return AM_DONGLE_STATUS_OK; +} + +AM_DONGLE_STATUS amDongleOpen(void) { + if (!amDongle.m_init) { + return AM_DONGLE_STATUS_ERR_NO_INIT; + } + if (!amDongle.done_init || !amDongle.available) { + return AM_DONGLE_STATUS_NG; + } + + e_pcpa_t pcpa_err = pcpaOpenClient(&amDongle.pcpa, "127.0.0.1", amDongle.ctrl_port, 90000, 0); + if (pcpa_err == e_pcpa_ok) { + amDongle.seq = AM_DONGLE_SEQ_OPEN; + amDongle.result = 1; + return AM_DONGLE_STATUS_OK; + } + if (pcpa_err == e_pcpa_to) { + amDongle.seq = AM_DONGLE_SEQ_WAIT_OPEN; + amDongle.field19_0x40 = 2; + amDongle.result = 1; + return AM_DONGLE_STATUS_OK; + } + if (amDongleDebugLevel > 0) { + amiDebugLog("Error : pcpaOpenClient(%d)", pcpa_err); + } + amDongle.seq = AM_DONGLE_SEQ_DONE; + return AM_DONGLE_STATUS_ERR_PCP; +} + +AM_DONGLE_STATUS amDongleOpenEx(void) { + if (amDongle.m_init == 0) return AM_DONGLE_STATUS_ERR_NO_INIT; + + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + + e_pcpa_t pcpa_err; + while (true) { + pcpa_err = + pcpaOpenClient(&amDongle.pcpa, "127.0.0.1", amDongle.ctrl_port, 90000, TIMEOUT_NONE); + if (pcpa_err == e_pcpa_ok) return AM_DONGLE_STATUS_OK; + if (pcpa_err != e_pcpa_timeout_open) break; + pcpaClose(&amDongle.pcpa); + } + if (amDongleDebugLevel > 0) amiDebugLog("Error : pcpaOpenClient(%d)", pcpa_err); + amDongle.seq = AM_DONGLE_SEQ_DONE; + amDongle.field19_0x40 = -1; + return AM_DONGLE_STATUS_ERR_NO_SERVER; +} + +BOOL amDongleIsDevelop(void) { + if (amDongle.done_init && amDongle.develop) { + return TRUE; + } + return FALSE; +} + +BOOL amDongleIsAvailable(void) { + if (amDongle.done_init && amDongle.available) { + return TRUE; + } + return FALSE; +} + +AM_DONGLE_STATUS amDongleCodeToStatus(void) { + char *codeStr = pcpaGetCommand(&amDongle.pcpa, "code"); + if (codeStr == NULL) return AM_DONGLE_STATUS_OK; + + int code = atoi(codeStr); + if (true) { + switch (code) { + case 0: + return AM_DONGLE_STATUS_OK; + case 1: + case 2: + return AM_DONGLE_STATUS_ERR_KEYCHIP; + case 50: + return AM_DONGLE_STATUS_ERR_VERIFY; + case 51: + return AM_DONGLE_STATUS_ERR_LOG_FULL; + case 52: + return AM_DONGLE_STATUS_ERR_NO_LOG; + case 53: + return AM_DONGLE_STATUS_ERR_ONE_WRITE; + case 54: + return AM_DONGLE_STATUS_ERR_COMMAND; + case 55: + return AM_DONGLE_STATUS_ERR_KEYCHIP_DATA; + } + } + return AM_DONGLE_STATUS_ERR_PCP; +} + +AM_DONGLE_STATUS amDongleSetupKeychip(void) { + if (amDongle.m_init == 0) return AM_DONGLE_STATUS_ERR_NO_INIT; + + e_pcpa_t pcpa_err; + pcp_send_data_t *send_data; + switch (amDongle.setupSeq) { + case AM_DONGLE_SETUP_SEQ_START: + send_data = pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.systemflag", "?"); + if (send_data == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + + send_data = pcpaAddSendPacket(&amDongle.pcpa, "cache", "0"); + if (send_data == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + pcpa_err = pcpaOpenClient(&amDongle.pcpa, "127.0.0.1", amDongle.ctrl_port, 90000, 0); + if (pcpa_err != e_pcpa_ok) { + if (pcpa_err != e_pcpa_to) { + if (amDongleDebugLevel > 0) + amiDebugLog("Error : pcpaOpenClient(%d)", pcpa_err); + + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_ERR; + return AM_DONGLE_STATUS_PENDING; + } + + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_WAIT; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_SEND; + return AM_DONGLE_STATUS_PENDING; + } + + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_SEND; + return AM_DONGLE_STATUS_PENDING; + + case AM_DONGLE_SETUP_SEQ_WAIT: + pcpa_err = pcpaIsBusy(&amDongle.pcpa, 0); + if (pcpa_err == e_pcpa_ok) { + AM_DONGLE_SETUP_SEQ next = amDongle.setupSeqNext; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_NONE; + amDongle.setupSeq = next; + return AM_DONGLE_STATUS_PENDING; + } + + if (pcpa_err == e_pcpa_timeout_open) { + if (amDongleDebugLevel > 0) { + amiDebugLog("Error : PCPA_RESULT_PROMPT_TIME_OUT_ERROR", 0xfffffff2); + } + pcpaClose(&amDongle.pcpa); + amDongle.setupSeq = 1; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_NONE; + return AM_DONGLE_STATUS_PENDING; + } + + if (pcpa_err == e_pcpa_to) return AM_DONGLE_STATUS_PENDING; + + if (amDongleDebugLevel > 0) amiDebugLog("Error : pcpaIsBusy(%d)", pcpa_err); + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_RETRY; + return AM_DONGLE_STATUS_PENDING; + + case AM_DONGLE_SETUP_SEQ_SEND: + pcpa_err = pcpaSendRequest(&amDongle.pcpa, 0); + if (pcpa_err == e_pcpa_ok) { + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_RECV; + return AM_DONGLE_STATUS_PENDING; + } + if (pcpa_err == e_pcpa_to) { + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_WAIT; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_RECV; + return AM_DONGLE_STATUS_PENDING; + } + + if (amDongleDebugLevel > 0) amiDebugLog("Error : pcpaSendRequest(%d)", pcpa_err); + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_RETRY; + return AM_DONGLE_STATUS_PENDING; + + case AM_DONGLE_SETUP_SEQ_RECV: + pcpa_err = pcpaRecvResponse(&amDongle.pcpa, 0); + if (pcpa_err == e_pcpa_ok) { + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_READ_RESPONSE; + return AM_DONGLE_STATUS_PENDING; + } + if (pcpa_err != e_pcpa_to) { + if (amDongleDebugLevel > 0) { + amiDebugLog("Error : pcpaRecvResponse(%d)", pcpa_err); + } + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_RETRY; + return AM_DONGLE_STATUS_PENDING; + } + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_WAIT; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_READ_RESPONSE; + return AM_DONGLE_STATUS_PENDING; + + case AM_DONGLE_SETUP_SEQ_READ_RESPONSE: + AM_DONGLE_STATUS code = amDongleCodeToStatus(); + if (code == AM_DONGLE_STATUS_OK) { + char *keyword = pcpaGetKeyword(&amDongle.pcpa, 0); + if (keyword == NULL) { + if (amDongleDebugLevel > 0) { + amiDebugLog("Error No Response!!"); + } + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_RETRY; + return AM_DONGLE_STATUS_PENDING; + } + + if (strcmp(keyword, "keychip.appboot.systemflag") == 0) { + unsigned char systemflag; + hex_to_byte(pcpaGetCommand(&amDongle.pcpa, keyword), &systemflag); + if (systemflag & 1) amDongle.develop = 1; + + send_data = pcpaSetSendPacket(&amDongle.pcpa, "keychip.version", "?"); + if (send_data == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + + send_data = pcpaAddSendPacket(&amDongle.pcpa, "cache", "0"); + if (send_data == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_SEND; + return AM_DONGLE_STATUS_PENDING; + } else if (strcmp(keyword, "keychip.version") == 0) { + ushort version; + hex_to_bin(pcpaGetCommand(&amDongle.pcpa, keyword), (unsigned char *)&version, + 4); + amDongle.version = ((version << 8) & 0xffff) | (version >> 8); + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_CLOSE; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_DONE; + return AM_DONGLE_STATUS_PENDING; + } else if (amDongleDebugLevel > 0) + amiDebugLog("Error Response!!"); + } else if (code == AM_DONGLE_STATUS_ERR_KEYCHIP) { + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_CLOSE; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_ERR; + return AM_DONGLE_STATUS_PENDING; + } + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_START; + return AM_DONGLE_STATUS_PENDING; + + case AM_DONGLE_SETUP_SEQ_CLOSE: + pcpaClose(&amDongle.pcpa); + AM_DONGLE_SETUP_SEQ next = amDongle.setupSeqNext; + amDongle.setupSeq = next; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_NONE; + if (next != AM_DONGLE_SETUP_SEQ_DONE) return AM_DONGLE_STATUS_PENDING; + + amDongle.available = 1; + amDongle.done_init = 1; + amDongle.seq = AM_DONGLE_SEQ_NONE; + amDongle.result = 0; + return AM_DONGLE_STATUS_PENDING; + + case AM_DONGLE_SETUP_SEQ_RETRY: + pcpaClose(&amDongle.pcpa); + amDongle.setupRetries++; + amDongle.setupSeqNext = AM_DONGLE_SETUP_SEQ_NONE; + if (amDongle.setupRetries > 2) { + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_ERR; + return AM_DONGLE_STATUS_PENDING; + } + + amDongle.setupSeq = AM_DONGLE_SETUP_SEQ_START; + return AM_DONGLE_STATUS_PENDING; + + case AM_DONGLE_SETUP_SEQ_DONE: + return AM_DONGLE_STATUS_OK; + + default: + return AM_DONGLE_STATUS_NG; + } +} + +// TODO: FUN_009f6940 !!! +AM_DONGLE_STATUS amDongleResponseCheck(void) { + char cVar1; + byte bVar2; + int *piVar4; + AM_DONGLE_STATUS AVar7; + int iVar9; + uint *puVar11; + uint local_8; + + char *keyword = pcpaGetKeyword(&amDongle.pcpa, 0); + char *command = pcpaGetCommand(&amDongle.pcpa, keyword); + char *sSize = pcpaGetCommand(&amDongle.pcpa, "size"); + char *sAddress = pcpaGetCommand(&amDongle.pcpa, "address"); + + amDongle.seq = AM_DONGLE_SEQ_DONE; + + if (keyword == NULL) { + if (amDongleDebugLevel > 0) amiDebugLog("Response Error!!! No Keyword."); + return AM_DONGLE_STATUS_ERR_PCP; + } + if (keyword[0] == '?') return AM_DONGLE_STATUS_ERR_NO_COMMAND; + + AVar7 = amDongleCodeToStatus(); + if (AVar7 != AM_DONGLE_STATUS_OK) { + if (AVar7 == AM_DONGLE_STATUS_ERR_KEYCHIP) { + if (amDongleDebugLevel > 0) amiDebugLog("Error Response KeychipError !!!"); + amDongle.available = 0; + amDongle.develop = 0; + } + return AVar7; + } + + if ((amDongle.requestCode & 0x80) != 0) { + char *sPort = pcpaGetCommand(&amDongle.pcpa, "port"); + if (sPort == NULL) + amDongle.data_port = 40107; + else + amDongle.data_port = atoi(sPort) & 0xffff; + amDongle.seq = 5; + } + + local_8 = 0; + + // TODO: ?? + if (false) { + return AM_DONGLE_STATUS_OK; + } + + switch (amDongle.requestCode) { + case AM_DONGLE_REQUEST_DECRYPT: + if (strcmp(keyword, "keychip.decrypt")) break; + hex_to_bin(command, amDongle.valueBuffer, 32); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_ENCRYPT: + if (strcmp(keyword, "keychip.encrypt") || command == NULL) break; + hex_to_bin(command, amDongle.valueBuffer, 32); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_GET_GAME_ID: + if (strcmp(keyword, "keychip.appboot.gameid") || command == NULL) break; + strcpy_s((char *)amDongle.valueBuffer, 5, (char *)command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_GET_SYSTEMFLAG: + if (strcmp(keyword, "keychip.appboot.systemflag") || command == NULL) break; + hex_to_bin(command, amDongle.valueBuffer, 2); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_GET_MODEL_TYPE: + if (strcmp(keyword, "keychip.appboot.modeltype") || command == NULL) break; + hex_to_bin(command, amDongle.valueBuffer, 2); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_GET_REGION: + if (strcmp(keyword, "keychip.appboot.region") || command == NULL) break; + hex_to_bin(command, amDongle.valueBuffer, 2); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_GET_PLATFORM_ID: + if (strcmp(keyword, "keychip.appboot.platformid") || command == NULL) break; + strcpy_s(amDongle.valueBuffer, 4, command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_GET_NETWORK_ADDRESS: + if (strcmp(keyword, "keychip.appboot.networkaddr") || command == NULL) break; + if (amDongle.valueBuffer != NULL) *(uint *)amDongle.valueBuffer = inet_addr(command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_GET_VERSION: + if (strcmp(keyword, "keychip.version") || command == NULL) break; + ushort version; + hex_to_bin(command, (unsigned char *)&version, 4); + *(ushort *)amDongle.valueBuffer = ((version << 8) & 0xffff) | version >> 8; + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_GET_KEYCHIP_ID: + if (strcmp(keyword, "keychip.billing.keyid") || command == NULL) break; + strcpy_s(amDongle.valueBuffer, 0x11, command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_GET_MAIN_ID: + if (strcmp(keyword, "keychip.billing.mainid") || command == NULL) break; + strcpy_s(amDongle.valueBuffer, 0xc, command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_GET_PLAYCOUNT: + if (strcmp(keyword, "keychip.billing.playcount") || command == NULL) break; + hex_to_int(amDongle.valueBuffer, command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_ADD_PLAYCOUNT: + if (strcmp(keyword, "keychip.billing.playcount") || command == NULL) break; + hex_to_int(amDongle.valueBuffer, command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_GET_PLAYLIMIT: + if (strcmp(keyword, "keychip.billing.playlimit") || command == NULL) break; + hex_to_int(amDongle.valueBuffer, command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_GET_NEARFULL: + if (strcmp(keyword, "keychip.billing.nearfull") || command == NULL) break; + hex_to_int(amDongle.valueBuffer, command); + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_TD_RESTORE: + if (strcmp(keyword, "keychip.tracedata.restore") || command == NULL) break; + if (strcmp(command, "1") == 0) { + pcp_send_data_t *packet = + pcpaSetSendPacket(&amDongle.pcpa, "keychip.tracedata.restore", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "0"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "update", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "restart", "0"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.seq = AM_DONGLE_SETUP_SEQ_WAIT; + return AM_DONGLE_STATUS_OK; + } + if (amDongle.valueBuffer != NULL) *(int *)amDongle.valueBuffer = command[0] - '0'; + return AM_DONGLE_STATUS_OK; + case AM_DONGLE_REQUEST_BILLING_TD_GET_LOG_NUM: + iVar9 = strcmp(keyword, "keychip.tracedata.get"); + if (((iVar9 == 0) && (command != NULL)) && (keyword = command, sAddress != NULL)) { + do { + bVar2 = *keyword; + keyword = keyword + 1; + } while (bVar2 != 0); + // FUN_009f6940(); + sSize = sAddress; + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + // FUN_009f6940(); + return AM_DONGLE_STATUS_OK; + } + break; + case AM_DONGLE_REQUEST_BILLING_TD_GET_FREE_LOG_NUM: + iVar9 = strcmp(keyword, "keychip.tracedata.put"); + if ((iVar9 == 0) && (keyword = command, command != NULL)) { + do { + bVar2 = *keyword; + keyword = keyword + 1; + } while (bVar2 != 0); + // FUN_009f6940(); + return AM_DONGLE_STATUS_OK; + } + break; + case AM_DONGLE_REQUEST_BILLING_TD_ERASE_USED_SECTOR: + iVar9 = strcmp(keyword, "keychip.tracedata.sectorerase"); + // goto LAB_009f7ff7; + case AM_DONGLE_REQUEST_BILLING_TD_ERASE_ALL: + iVar9 = strcmp(keyword, "keychip.tracedata.sectorerase"); + if ((iVar9 == 0) && (command != NULL)) { + piVar4 = (int *)amDongle.valueBuffer; + if (piVar4 == NULL) { + return AM_DONGLE_STATUS_OK; + } + *piVar4 = 0; + *piVar4 = 0; + *piVar4 = (char)*command + -0x30; + return AM_DONGLE_STATUS_OK; + } + break; + case AM_DONGLE_REQUEST_BILLING_TD_RESERVE_ERASABLE_SECTOR: + iVar9 = strcmp(keyword, "keychip.tracedata.sectorerase"); + if (iVar9 != 0) { + return AM_DONGLE_STATUS_ERR_PCP; + } + if (command != NULL) { + piVar4 = (int *)amDongle.valueBuffer; + if (piVar4 == NULL) { + return AM_DONGLE_STATUS_OK; + } + *piVar4 = 0; + *piVar4 = 0; + *piVar4 = (char)*command + -0x30; + return AM_DONGLE_STATUS_OK; + } + return AM_DONGLE_STATUS_ERR_PCP; + case AM_DONGLE_REQUEST_GET_DVDFLAG: + iVar9 = strcmp(keyword, "keychip.appboot.dvdflag"); + // goto LAB_009f7a26; + case AM_DONGLE_REQUEST_GET_DS_COMPUTE: + iVar9 = strcmp(keyword, "keychip.ds.compute"); + if ((iVar9 == 0) && (command != NULL)) { + keyword = command; + do { + bVar2 = *keyword; + keyword = keyword + 1; + } while (bVar2 != 0); + local_8 = (int)keyword - (int)(command + 1); + // FUN_009f6b40(command, amDongle.valueBuffer); + return AM_DONGLE_STATUS_OK; + } + break; + case AM_DONGLE_REQUEST_GET_SSD_PROOF: + iVar9 = strcmp(keyword, "keychip.ssd.proof"); + if ((iVar9 == 0) && (command != NULL)) { + keyword = command; + do { + bVar2 = *keyword; + keyword = keyword + 1; + } while (bVar2 != 0); + local_8 = (int)keyword - (int)(command + 1); + // FUN_009f6b40(command, amDongle.valueBuffer); + return AM_DONGLE_STATUS_OK; + } + break; + case AM_DONGLE_REQUEST_GET_FORMAT_TYPE: + iVar9 = strcmp(keyword, "keychip.appboot.formattype"); + if ((iVar9 == 0) && (command != NULL)) { + local_8 = 2; + // FUN_009f6b40(command, amDongle.valueBuffer); + return AM_DONGLE_STATUS_OK; + } + break; + case AM_DONGLE_WTF_81: + if (sSize == NULL) { + LAB_009f82b7: + amDongle.seq = 8; + return AM_DONGLE_STATUS_ERR_PCP; + } + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + goto LAB_009f82d7; + case AM_DONGLE_REQUEST_BILLING_GET_TRACEDATA: + if ((command == NULL) || (sSize == NULL)) goto LAB_009f82b7; + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + // FUN_009f6940(); + puVar11 = amDongle.field_0x3444; + goto LAB_009f82f2; + case AM_DONGLE_REQUEST_BILLING_GET_SIGNATURE_PK: + if (sSize == NULL) goto LAB_009f82b7; + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + goto LAB_009f82d7; + case AM_DONGLE_REQUEST_BILLING_GET_CA_CERT: + if (sSize == NULL) goto LAB_009f82b7; + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + // FUN_009f6940(); + puVar11 = (uint *)amDongle.dataBuffer; + goto LAB_009f82f2; + case AM_DONGLE_WTF_85: + if (sSize == NULL) goto LAB_009f82b7; + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + // FUN_009f6940(); + puVar11 = (uint *)amDongle.dataBuffer; + goto LAB_009f82f2; + case AM_DONGLE_WTF_C0: + if (sSize == NULL) goto LAB_009f82b7; + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + // FUN_009f6940(); + puVar11 = (uint *)amDongle.dataBuffer; + goto LAB_009f82f2; + case AM_DONGLE_WTF_C3: + if (sSize == NULL) goto LAB_009f82b7; + do { + cVar1 = *sSize; + sSize = sSize + 1; + } while (cVar1 != '\0'); + LAB_009f82d7: + // FUN_009f6940(); + puVar11 = (uint *)amDongle.dataBuffer; + LAB_009f82f2: + if (local_8 < *puVar11) { + *puVar11 = local_8; + } + return AM_DONGLE_STATUS_OK; + default: + return AM_DONGLE_STATUS_OK; + } + return AM_DONGLE_STATUS_ERR_PCP; + // LAB_009f7ff2: + // iVar9 = (1 - (uint)bVar13) - (uint)(bVar13 != 0); + // goto LAB_009f7ff7; + // LAB_009f7ce1: + // iVar9 = (1 - (uint)bVar13) - (uint)(bVar13 != 0); + // goto LAB_009f7ce6; + // LAB_009f7c82: + // iVar9 = (1 - (uint)bVar13) - (uint)(bVar13 != 0); + // goto LAB_009f7c87; + // LAB_009f7a21: + // iVar9 = (1 - (uint)bVar13) - (uint)(bVar13 != 0); + // goto LAB_009f7a26; +} + +AM_DONGLE_STATUS amDongleSendBinary(void) { + void *buffer; + uint bufferLength; + + switch (amDongle.requestCode) { + case AM_DONGLE_WTF_C0: + bufferLength = *(uint *)amDongle.dataBuffer; + buffer = amDongle.valueBuffer; + break; + case AM_DONGLE_REQUEST_BILLING_UPDATE_PLAYLIMIT: + buffer = amDongle.dataBuffer; + bufferLength = 128; + break; + case AM_DONGLE_REQUEST_BILLING_UPDATE_NEARFULL: + buffer = amDongle.dataBuffer; + bufferLength = 128; + break; + case AM_DONGLE_WTF_C3: + bufferLength = *(uint *)amDongle.dataBuffer; + buffer = amDongle.valueBuffer; + break; + default: + amDongle.seq = AM_DONGLE_SEQ_DONE; + amDongle.field19_0x40 = -1; + return AM_DONGLE_STATUS_ERR_PCP; + } + + pcpaSetSendBinaryBuffer(&amDongle.pcpa, buffer, bufferLength); + if (pcpaSendBinary(&amDongle.pcpa, TIMEOUT_NONE) != e_pcpa_ok) { + amDongle.seq = AM_DONGLE_SEQ_DONE; + return AM_DONGLE_STATUS_ERR_PCP; + } + + amDongle.seq = AM_DONGLE_SEQ_DONE; + return AM_DONGLE_STATUS_OK; +} + +AM_DONGLE_STATUS amDongleRecvBinary(void) { + void *buffer; + uint bufferLength; + + switch (amDongle.requestCode) { + case AM_DONGLE_WTF_80: + buffer = amDongle.valueBuffer; + bufferLength = 0x10; + break; + case AM_DONGLE_WTF_81: + case AM_DONGLE_REQUEST_BILLING_GET_CA_CERT: + bufferLength = *(uint *)amDongle.dataBuffer; + buffer = amDongle.valueBuffer; + break; + case AM_DONGLE_REQUEST_BILLING_GET_TRACEDATA: + bufferLength = *amDongle.field_0x3444; + buffer = amDongle.dataBuffer; + break; + case AM_DONGLE_REQUEST_BILLING_GET_SIGNATURE_PK: + case AM_DONGLE_WTF_85: + bufferLength = *(uint *)amDongle.dataBuffer; + buffer = amDongle.valueBuffer; + break; + default: + amDongle.seq = AM_DONGLE_SEQ_DONE; + amDongle.field19_0x40 = -1; + return AM_DONGLE_STATUS_ERR_PCP; + } + pcpaSetRecvBinaryBuffer(&amDongle.pcpa, buffer, bufferLength); + if (pcpaRecvBinary(&amDongle.pcpa, TIMEOUT_NONE) != e_pcpa_ok) { + amDongle.seq = AM_DONGLE_SEQ_DONE; + return AM_DONGLE_STATUS_ERR_PCP; + } + amDongle.seq = AM_DONGLE_SEQ_DONE; + return AM_DONGLE_STATUS_OK; +} + +AM_DONGLE_STATUS amDongleSendAndReceiveEx(void) { + AM_DONGLE_STATUS AVar1; + + amDongle.result = 0; + AVar1 = amDongleOpenEx(); + if (AVar1 != AM_DONGLE_STATUS_OK) amDongle.seq = AM_DONGLE_SEQ_DONE; + + while (amDongle.seq != AM_DONGLE_SEQ_DONE) { + e_pcpa_t err = pcpaSendRequest(&amDongle.pcpa, TIMEOUT_NONE); + if (err != e_pcpa_ok) { + if (amDongleDebugLevel > 0) amiDebugLog("Error : pcpaSendRequest(%d)", err); + + amDongle.field19_0x40 = -1; + AVar1 = AM_DONGLE_STATUS_ERR_PCP; + amDongle.seq = AM_DONGLE_SEQ_DONE; + break; + } + err = pcpaRecvResponse(&amDongle.pcpa, TIMEOUT_NONE); + if (err != e_pcpa_ok) { + amDongle.field19_0x40 = -1; + AVar1 = AM_DONGLE_STATUS_ERR_PCP; + amDongle.seq = AM_DONGLE_SEQ_DONE; + break; + } + + AVar1 = amDongleResponseCheck(); + if (amDongle.result != AM_DONGLE_STATUS_OK) AVar1 = amDongle.result; + + if (amDongle.seq == AM_DONGLE_SEQ_BINARY) { + err = pcpaOpenBinaryClient(&amDongle.pcpa, amDongle.data_port, TIMEOUT_NONE); + if (err == e_pcpa_ok) { + if ((amDongle.requestCode & 0x40) == 0) + amDongle.seq = AM_DONGLE_SEQ_RECV_BINARY; + else + amDongle.seq = AM_DONGLE_SEQ_SEND_BINARY; + + AVar1 = AM_DONGLE_STATUS_OK; + } else { + amDongle.seq = AM_DONGLE_SEQ_DONE; + AVar1 = AM_DONGLE_STATUS_ERR_PCP; + } + } + + if (amDongle.seq == AM_DONGLE_SEQ_SEND_BINARY) AVar1 = amDongleSendBinary(); + if (amDongle.seq == AM_DONGLE_SEQ_RECV_BINARY) AVar1 = amDongleRecvBinary(); + } + + pcpaCloseBinary(&amDongle.pcpa); + pcpaClose(&amDongle.pcpa); + amDongle.seq = AM_DONGLE_SEQ_NONE; + amDongle.result = 0; + return AVar1; +} + +AM_DONGLE_STATUS amDongleExit(void) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + + pcpaClose(&amDongle.pcpa); + memset(&amDongle, 0, sizeof amDongle); + amDongle.m_init = FALSE; + return AM_DONGLE_STATUS_OK; +} + +// TODO: These two functions for loading tables +int amDongleLoadDsTable(FILE *fp) { return 0; } +int amDongleLoadSsdTable(FILE *fp) { return 0; } + +AM_DONGLE_STATUS amDongleSetAuthConfig(char *authConfig) { + if (amDongle.m_init == 0) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (authConfig == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + if (strcmp(authConfig, "toolmode") != 0) { + HANDLE hFile = CreateFileA(authConfig, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + CloseHandle(hFile); + + FILE *fp; + fopen_s(&fp, authConfig, "rb"); + if (fp == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + if (!amDongleLoadDsTable(fp) || !amDongleLoadSsdTable(fp)) { + fclose(fp); + return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + } + fclose(fp); + } + + amDongle.auth_ready = 1; + amDongle.result = 0; + return AM_DONGLE_STATUS_OK; +} + +// PCP wrappers +AM_DONGLE_STATUS amDongleBillingGetKeychipId(char *keychipId, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (keychipId == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.billing.keyid", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = keychipId; + amDongle.requestCode = AM_DONGLE_REQUEST_BILLING_GET_KEYCHIP_ID; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetGameId(char *gameId, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (gameId == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.gameid", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = gameId; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_GAME_ID; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetPlatformId(char *platformId, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (platformId == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.platformid", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = platformId; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_PLATFORM_ID; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetSystemFlag(unsigned char *systemFlag, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (systemFlag == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.systemflag", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = systemFlag; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_SYSTEMFLAG; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetModelType(unsigned char *modelType, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (modelType == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.modeltype", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = modelType; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_MODEL_TYPE; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetRegion(unsigned char *region, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (region == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.region", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = region; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_REGION; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetNetworkAddress(unsigned int *networkAddress, + AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (networkAddress == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.networkaddr", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = networkAddress; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_NETWORK_ADDRESS; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetVersion(unsigned short *version, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (version == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.version", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "device", "n2"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = version; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_VERSION; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleGetPicVersion(unsigned short *picVersion, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (picVersion == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.version", "?"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + packet = pcpaAddSendPacket(&amDongle.pcpa, "cache", "0"); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + + amDongle.valueBuffer = picVersion; + amDongle.requestCode = AM_DONGLE_REQUEST_GET_VERSION; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} + +AM_DONGLE_STATUS amDongleEncrypt(unsigned char *pt, unsigned char *ct, + AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (pt == NULL || ct == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + char ptHex[32]; + bin_to_hex(ptHex, pt, 16); + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.encrypt", ptHex); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + + amDongle.valueBuffer = ct; + amDongle.requestCode = AM_DONGLE_REQUEST_ENCRYPT; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleDecrypt(unsigned char *ct, unsigned char *pt, + AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + + if (ct == NULL || pt == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + char ctHex[32]; + bin_to_hex(ctHex, ct, 16); + pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.decrypt", ctHex); + if (packet == NULL && amDongleDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + + amDongle.valueBuffer = pt; + amDongle.requestCode = AM_DONGLE_REQUEST_DECRYPT; + + if (blocking == AM_DONGLE_BLOCK) return amDongleSendAndReceiveEx(); + return amDongleOpen(); +} + +AM_DONGLE_STATUS amDongleBillingGetPlayCount(unsigned int *playCount, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + if (playCount == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *send_data = + pcpaSetSendPacket(&amDongle.pcpa, "keychip.billing.playcount", "?"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + } + send_data = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + } + amDongle.valueBuffer = playCount; + amDongle.requestCode = AM_DONGLE_REQUEST_BILLING_GET_PLAYCOUNT; + if (blocking == AM_DONGLE_BLOCK) { + return amDongleSendAndReceiveEx(); + } + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleBillingGetPlayLimit(unsigned int *playLimit, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + if (playLimit == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *send_data = + pcpaSetSendPacket(&amDongle.pcpa, "keychip.billing.playlimit", "?"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + } + send_data = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + } + amDongle.valueBuffer = playLimit; + amDongle.requestCode = AM_DONGLE_REQUEST_BILLING_GET_PLAYLIMIT; + if (blocking == AM_DONGLE_BLOCK) { + return amDongleSendAndReceiveEx(); + } + return amDongleOpen(); +} +AM_DONGLE_STATUS amDongleBillingGetNearfull(unsigned int *nearfull, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + if (nearfull == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *send_data = pcpaSetSendPacket(&amDongle.pcpa, "keychip.billing.nearfull", "?"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + } + send_data = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + } + amDongle.valueBuffer = nearfull; + amDongle.requestCode = AM_DONGLE_REQUEST_BILLING_GET_NEARFULL; + if (blocking == AM_DONGLE_BLOCK) { + return amDongleSendAndReceiveEx(); + } + return amDongleOpen(); +} + +AM_DONGLE_STATUS amDongleBillingAddPlayCount(void *playCount, AM_DONGLE_BLOCKING blocking) { + if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT; + if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY; + if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG; + if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY; + if (playCount == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *send_data = + pcpaSetSendPacket(&amDongle.pcpa, "keychip.billing.playcount", "1"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + } + send_data = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1"); + if (send_data == NULL && amDongleDebugLevel > 0) { + amiDebugLog("Error: pcpaAddSendPacket return NULL"); + } + amDongle.valueBuffer = playCount; + amDongle.requestCode = 0xf; + if (blocking == AM_DONGLE_BLOCK) { + return amDongleSendAndReceiveEx(); + } + return amDongleOpen(); +} diff --git a/src/micetools/lib/am/amDongle.h b/src/micetools/lib/am/amDongle.h new file mode 100644 index 0000000..674516a --- /dev/null +++ b/src/micetools/lib/am/amDongle.h @@ -0,0 +1,211 @@ +#pragma once + +#include + +#include "../_am.h" +#include "../libpcp/pcpa.h" + +typedef struct _AM_DONGLE_DS_CHALLENGE { + byte challenge[7]; + byte pages[4][20]; +} AM_DONGLE_DS_CHALLENGE; + +typedef struct _AM_DONGLE_SSD_CHALLENGE { + byte challenge[16]; + byte response[16]; +} AM_DONGLE_SSD_CHALLENGE; + +typedef enum { + AM_DONGLE_SEQ_NONE = 0, + AM_DONGLE_SEQ_WAIT_OPEN = 1, + AM_DONGLE_SEQ_OPEN = 2, + AM_DONGLE_SEQ_BINARY = 5, + AM_DONGLE_SEQ_SEND_BINARY = 6, + AM_DONGLE_SEQ_RECV_BINARY = 7, + AM_DONGLE_SEQ_DONE = 8, +} AM_DONGLE_SEQ; + +typedef struct _AM_DONGLE { + BOOL m_init; + BOOL done_init; + BOOL available; + BOOL develop; + BOOL auth_ready; + int authCondition; + // + int setupSeq; + int setupSeqNext; + int setupRetries; + AM_DONGLE_SEQ seq; + int field19_0x40; + int result; + // + int challengeNum; + ushort version; + ushort ctrl_port; + ushort data_port; + byte requestCode; + // + pcpa_t pcpa; + // + byte ssdChallenge[16]; + byte ssdResponse[16]; + byte ssdExpResponse[16]; + byte dsChallenge[16]; + byte dsResponse[16]; + byte dsExpResponse[16]; + byte challengePage; + AM_DONGLE_DS_CHALLENGE dsTable[100]; + AM_DONGLE_SSD_CHALLENGE ssdTable[100]; + void *valueBuffer; + void *dataBuffer; + uint *field_0x3444; +} AM_DONGLE; + +typedef enum { + AM_DONGLE_STATUS_OK = 0, + AM_DONGLE_STATUS_BUSY = 1, + AM_DONGLE_STATUS_PENDING = 2, + AM_DONGLE_STATUS_NG = -1, + AM_DONGLE_STATUS_ERR_INVALID_PARAM = -2, + AM_DONGLE_STATUS_ERR_NO_INIT = -3, + AM_DONGLE_STATUS_ERR_ALREADY_INIT = -4, + AM_DONGLE_STATUS_ERR_PCP = -5, + AM_DONGLE_STATUS_ERR_COMMAND = -6, + AM_DONGLE_STATUS_ERR_VERIFY = -7, + AM_DONGLE_STATUS_ERR_LOG_FULL = -8, + AM_DONGLE_STATUS_ERR_NO_LOG = -9, + AM_DONGLE_STATUS_ERR_ONE_WRITE = -10, + AM_DONGLE_STATUS_ERR_KEYCHIP_DATA = -11, + AM_DONGLE_STATUS_ERR_KEYCHIP = -12, + AM_DONGLE_STATUS_ERR_NO_SERVER = -13, + AM_DONGLE_STATUS_ERR_AUTH_READY = -14, + AM_DONGLE_STATUS_ERR_NO_COMMAND = -15, + AM_DONGLE_STATUS_ERR_SYS = -16, + AM_DONGLE_STATUS_ERR_PRECONDITION = -17, +} AM_DONGLE_STATUS; + +typedef enum { + AM_DONGLE_BLOCK = 0, + AM_DONGLE_NOBLOCK = 1, +} AM_DONGLE_BLOCKING; + +typedef enum { + AM_DONGLE_REQUEST_SET_IV = 1, + AM_DONGLE_REQUEST_DECRYPT = 2, + AM_DONGLE_REQUEST_ENCRYPT = 3, + AM_DONGLE_REQUEST_GET_GAME_ID = 4, + AM_DONGLE_REQUEST_GET_SYSTEMFLAG = 5, + AM_DONGLE_REQUEST_GET_MODEL_TYPE = 6, + AM_DONGLE_REQUEST_GET_REGION = 7, + AM_DONGLE_REQUEST_GET_PLATFORM_ID = 8, + AM_DONGLE_REQUEST_GET_NETWORK_ADDRESS = 9, + AM_DONGLE_REQUEST_GET_VERSION = 10, + AM_DONGLE_REQUEST_BILLING_GET_KEYCHIP_ID = 11, + AM_DONGLE_REQUEST_BILLING_GET_MAIN_ID = 12, + AM_DONGLE_REQUEST_BILLING_SET_MAIN_ID = 13, + AM_DONGLE_REQUEST_BILLING_GET_PLAYCOUNT = 14, + AM_DONGLE_REQUEST_BILLING_ADD_PLAYCOUNT = 15, + AM_DONGLE_REQUEST_BILLING_GET_PLAYLIMIT = 16, + AM_DONGLE_REQUEST_BILLING_GET_NEARFULL = 17, + AM_DONGLE_REQUEST_BILLING_TD_RESTORE = 18, + AM_DONGLE_REQUEST_BILLING_PUT_TRACEDATA = 19, + AM_DONGLE_REQUEST_BILLING_TD_GET_LOG_NUM = 20, + AM_DONGLE_REQUEST_BILLING_TD_GET_FREE_LOG_NUM = 21, + AM_DONGLE_REQUEST_BILLING_TD_LOGICAL_ERASE = 22, + AM_DONGLE_REQUEST_BILLING_TD_ERASE_USED_SECTOR = 23, + AM_DONGLE_REQUEST_BILLING_TD_ERASE_ALL = 24, + AM_DONGLE_REQUEST_BILLING_TD_RESERVE_ERASABLE_SECTOR = 25, + AM_DONGLE_REQUEST_GET_DVDFLAG = 26, + AM_DONGLE_REQUEST_GET_DS_COMPUTE = 27, + AM_DONGLE_REQUEST_GET_SSD_PROOF = 28, + // 29 + AM_DONGLE_REQUEST_GET_FORMAT_TYPE = 30, + + AM_DONGLE_WTF_80 = 0x80 | 0, + AM_DONGLE_WTF_81 = 0x80 | 1, + AM_DONGLE_REQUEST_BILLING_GET_TRACEDATA = 0x80 | 2, + AM_DONGLE_REQUEST_BILLING_GET_SIGNATURE_PK = 0x80 | 3, + AM_DONGLE_REQUEST_BILLING_GET_CA_CERT = 0x80 | 4, + AM_DONGLE_WTF_85 = 0x80 | 5, + + AM_DONGLE_WTF_C0 = 0xc0 | 0, + AM_DONGLE_REQUEST_BILLING_UPDATE_PLAYLIMIT = 0xc0 | 1, + AM_DONGLE_REQUEST_BILLING_UPDATE_NEARFULL = 0xc0 | 2, + AM_DONGLE_WTF_C3 = 0xc0 | 3, +} AM_DONGLE_REQUEST; + +typedef enum _AM_DONGLE_SETUP_SEQ { + AM_DONGLE_SETUP_SEQ_NONE = 0, + AM_DONGLE_SETUP_SEQ_START = 1, + AM_DONGLE_SETUP_SEQ_WAIT = 2, + AM_DONGLE_SETUP_SEQ_SEND = 3, + AM_DONGLE_SETUP_SEQ_RECV = 4, + AM_DONGLE_SETUP_SEQ_READ_RESPONSE = 5, + AM_DONGLE_SETUP_SEQ_CLOSE = 6, + AM_DONGLE_SETUP_SEQ_RETRY = 7, + AM_DONGLE_SETUP_SEQ_DONE = 8, + AM_DONGLE_SETUP_SEQ_ERR = 9, +} AM_DONGLE_SETUP_SEQ; + +AM_LIB_H_HEADER(amDongle, AM_DONGLE) + +AM_DONGLE_STATUS amDongleInit(void); +AM_DONGLE_STATUS amDongleOpen(void); +AM_DONGLE_STATUS amDongleOpenEx(void); +BOOL amDongleIsDevelop(void); +BOOL amDongleIsAvailable(void); +AM_DONGLE_STATUS amDongleCodeToStatus(void); +AM_DONGLE_STATUS amDongleSetupKeychip(void); +AM_DONGLE_STATUS amDongleSendAndReceiveEx(void); +AM_DONGLE_STATUS amDongleResponseCheck(void); +AM_DONGLE_STATUS amDongleExit(void); +AM_DONGLE_STATUS amDongleSetAuthConfig(char *authConfig); + +AM_DONGLE_STATUS amDongleGetGameId(char *gameId, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleGetPlatformId(char *platformId, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleGetSystemFlag(unsigned char *systemFlag, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleGetModelType(unsigned char *modelType, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleGetRegion(unsigned char *region, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleGetNetworkAddress(unsigned int *networkAddress, + AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleGetVersion(unsigned short *version, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleGetPicVersion(unsigned short *picVersion, AM_DONGLE_BLOCKING blocking); + +AM_DONGLE_STATUS amDongleBillingGetKeychipId(void *keychipId, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleBillingGetPlayCount(unsigned int *playCount, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleBillingGetPlayLimit(unsigned int *playLimit, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleBillingAddPlayCount(void *playCount, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleBillingGetNearfull(unsigned int *nearfull, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleEncrypt(unsigned char *pt, unsigned char *ct, AM_DONGLE_BLOCKING blocking); +AM_DONGLE_STATUS amDongleDecrypt(unsigned char *ct, unsigned char *pt, AM_DONGLE_BLOCKING blocking); + +void amDongleBillingGetCaCertification(void); +void amDongleBillingGetMainId(void); +void amDongleBillingGetPlaylimit(void); +void amDongleBillingGetSignaturePubKey(void); +void amDongleBillingGetTraceData(void); +void amDongleBillingPutTraceData(void); +void amDongleBillingSetMainId(void); +void amDongleBillingTdEraseAll(void); +void amDongleBillingTdEraseUsedSector(void); +void amDongleBillingTdGetFreeLogNum(void); +void amDongleBillingTdGetLogNum(void); +void amDongleBillingTdLogicalErase(void); +void amDongleBillingTdReserveErasableSector(void); +void amDongleBillingTdRestore(void); +void amDongleBillingUpdateNearfull(void); +void amDongleBillingUpdatePlaylimit(void); + +void amDongleBusy(void); +void amDongleGetAuthCondition(void); +void amDongleGetDsMac(void); +void amDongleGetDvdFlag(void); +void amDongleGetFormatType(void); +void amDongleGetResult(void); +void amDongleGetSeed(void); +void amDongleGetSsdResponse(void); +void amDongleRequestSsdHostProof(void); +void amDongleSetAuthCondition(void); +void amDongleSetIv(void); +void amDongleUpdate(void); diff --git a/src/micetools/lib/am/amEeprom.c b/src/micetools/lib/am/amEeprom.c index 2ff85f8..d18cdec 100644 --- a/src/micetools/lib/am/amEeprom.c +++ b/src/micetools/lib/am/amEeprom.c @@ -1,86 +1,397 @@ #include "amEeprom.h" -#include "../mice/crc.h" +#pragma comment(lib, "Setupapi.lib") + +#include "../../dll/smbus.h" +#include "../ami/ami.h" + +AM_LIB_C_HEADER(amEeprom, AM_EEPROM) HANDLE amEepromCreateDeviceFile(const GUID *guid, LPCSTR resource, DWORD member_index) { - SP_DEVICE_INTERFACE_DATA interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_A interface_detail[204]; + SP_DEVICE_INTERFACE_DATA interfaceData; + SP_DEVICE_INTERFACE_DETAIL_DATA_A interfaceDetail[204]; - if (!guid) return INVALID_HANDLE_VALUE; + if (!guid) { + if (amEepromDebugLevel > 0) amiDebugLog("PARAM Error."); + return INVALID_HANDLE_VALUE; + } HDEVINFO DeviceInfoSet = SetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); - if (DeviceInfoSet == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; - - interface_data.cbSize = 0x1c; - BOOL s; - s = SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, guid, member_index, &interface_data); - if (!s) goto fail; - - interface_detail[0].cbSize = 5; - s = SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet, &interface_data, interface_detail, - sizeof interface_detail, NULL, NULL); - if (!s) goto fail; - - char device_path[260]; - strcpy_s(device_path, sizeof device_path, interface_detail[0].DevicePath); - - if (resource != NULL) { - strcat_s(device_path, 4, "\\"); - strcat_s(device_path, 4, resource); + if (DeviceInfoSet == INVALID_HANDLE_VALUE) { + if (amEepromDebugLevel > 0) + amiDebugLog("SetupDiGetClassDevs Error(%ld).", GetLastError()); + return INVALID_HANDLE_VALUE; + } + + interfaceData.cbSize = 28; + BOOL s; + s = SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, guid, member_index, &interfaceData); + if (!s) { + if (amEepromDebugLevel > 0) + amiDebugLog("SetupDiEnumDeviceInterfaces Error(%ld).", GetLastError()); + SetupDiDestroyDeviceInfoList(DeviceInfoSet); + return INVALID_HANDLE_VALUE; + } + + interfaceDetail[0].cbSize = 5; + s = SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet, &interfaceData, interfaceDetail, + sizeof interfaceDetail, NULL, NULL); + if (!s) { + if (amEepromDebugLevel > 0) + amiDebugLog("SetupDiGetDeviceInterfaceDetailA Error(%ld).", GetLastError()); + SetupDiDestroyDeviceInfoList(DeviceInfoSet); + return INVALID_HANDLE_VALUE; + } + + char fileName[260]; + strcpy_s(fileName, sizeof fileName, interfaceDetail[0].DevicePath); + + if (resource != NULL) { + strcat_s(fileName, 4, "\\"); + strcat_s(fileName, 4, resource); } - printf("Using device located at %s\n", device_path); HANDLE device = - CreateFileA(device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, NULL); SetupDiDestroyDeviceInfoList(DeviceInfoSet); return device; - -fail: - SetupDiDestroyDeviceInfoList(DeviceInfoSet); - return INVALID_HANDLE_VALUE; } -BOOL amEepromReadBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data) { - mxsmbus_i2c_packet smbus_req = { - .status = 0, - .prt = 0x09, - .addr = SMBUS_EEPROM, - .reg = reg << 5, - .dlen = len, - .data = { 0 }, - }; +AM_EEPROM_STATUS amEepromGetDriverVersion(AM_EEPROM *device, LPDWORD version) { + if (device == NULL || version == NULL) { + if (amEepromDebugLevel > 0) amiDebugLog("PARAM Error."); + return AM_EEPROM_STATUS_ERR_INVALID_PARAM; + } + if (device->m_superio == INVALID_HANDLE_VALUE) { + if (amEepromDebugLevel > 0) amiDebugLog("Device not opened."); + return AM_EEPROM_STATUS_ERR_SYS; + } - DWORD _dummy; - BOOL s = DeviceIoControl(mxsmbus, IOCTL_MXSMBUS_I2C, &smbus_req, sizeof smbus_req, - &smbus_req, sizeof smbus_req, &_dummy, NULL); - if (!s) return FALSE; - if (smbus_req.status) return FALSE; - memcpy(data, smbus_req.data, len); - return TRUE; + DWORD bytesReturned; + DWORD buffer; + BOOL s = DeviceIoControl(device->m_superio, IOCTL_MXSMBUS_GET_VERSION, NULL, 0, &buffer, 4, + &bytesReturned, NULL); + + if (s && bytesReturned == sizeof buffer) { + *version = buffer; + return AM_EEPROM_STATUS_OK; + } + + if (amEepromDebugLevel > 0) amiDebugLog("DeviceIoControl error(%ld).", GetLastError()); + return AM_EEPROM_STATUS_ERR_SYS; } -BOOL amEepromWriteBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data) { - mxsmbus_i2c_packet smbus_req = { - .status = 0, - .prt = 0x08, - .addr = SMBUS_EEPROM, - .reg = reg << 5, - .dlen = len, - .data = { 0 }, - }; - memcpy(smbus_req.data, data, sizeof smbus_req.data); +AM_EEPROM_STATUS amEepromCreateMutex(AM_EEPROM *device) { + SECURITY_ATTRIBUTES muxAttrs; + SECURITY_DESCRIPTOR securityDescriptor; + SID_IDENTIFIER_AUTHORITY idAuth; - DWORD _dummy; - BOOL s = DeviceIoControl(mxsmbus, IOCTL_MXSMBUS_I2C, &smbus_req, sizeof smbus_req, - &smbus_req, sizeof smbus_req, &_dummy, NULL); - if (!s) return FALSE; - if (smbus_req.status) return FALSE; - memcpy(data, smbus_req.data, len); - return TRUE; + PSID *pSid = &device->m_sid; + idAuth.Value[0] = 0; + idAuth.Value[1] = 0; + idAuth.Value[2] = 0; + idAuth.Value[3] = 0; + idAuth.Value[4] = 0; + idAuth.Value[5] = 1; + + if (!AllocateAndInitializeSid(&idAuth, 1, 0, 0, 0, 0, 0, 0, 0, 0, pSid)) { + if (amEepromDebugLevel > 0) + amiDebugLog("AllocateAndInitializeSid Error in amEepromInit."); + *pSid = NULL; + goto amEepromCreateMutexError; + } + + if (!InitializeSecurityDescriptor(&securityDescriptor, 1)) { + if (amEepromDebugLevel > 0) + amiDebugLog("InitializeSecurityDescriptor Error in amEepromInit."); + goto amEepromCreateMutexError; + } + + if (!SetSecurityDescriptorDacl(&securityDescriptor, TRUE, NULL, FALSE)) { + if (amEepromDebugLevel > 0) + amiDebugLog("SetSecurityDescriptorDacl Error in amEepromInit."); + goto amEepromCreateMutexError; + } + + muxAttrs.lpSecurityDescriptor = &securityDescriptor; + muxAttrs.nLength = 12; + muxAttrs.bInheritHandle = FALSE; + if ((device->m_mutex = CreateMutexA(&muxAttrs, FALSE, "Global\\AM_EEPROM_MUTEX")) != NULL) { + return AM_EEPROM_STATUS_OK; + } + + if (amEepromDebugLevel > 0) amiDebugLog("CreateMutexA Error(%ld).", GetLastError()); + +amEepromCreateMutexError: + if (device->m_mutex != NULL) { + CloseHandle(device->m_mutex); + device->m_mutex = NULL; + } + if (*pSid != NULL) { + FreeSid(*pSid); + *pSid = NULL; + } + return AM_EEPROM_STATUS_ERR_SYS; } -void amEepromRepairChecksum(BYTE *data) { - DWORD check = crc32(28, data + 4, 0); - ((DWORD*)data)[0] = check; +AM_EEPROM_STATUS amEepromInit(AM_EEPROM_TIMEOUT *timeout) { + if (amEeprom.m_init) return AM_EEPROM_STATUS_ERR_ALREADY_INIT; + + amEeprom.m_prt = AM_EEPROM_ADDR; + amEeprom.m_timeout.ReadTimeout = AM_EEPROM_DEFAULT_TIMEOUT; + amEeprom.m_timeout.WriteTimeout = AM_EEPROM_DEFAULT_TIMEOUT; + + int ret = amEepromCreateMutex(&amEeprom); + if (ret != 0) { + if (amEepromDebugLevel > 0) + amiDebugLog("amEepromCreateMutex Error!! Error Code is %ld!!", ret); + ret = AM_EEPROM_STATUS_ERR_SYS; + goto amEepromInitError; + } + + if (ret != 0) { + if (amEepromDebugLevel > 0) + amiDebugLog("amEepromCreateMutex Error!! Error Code is %ld!!", ret); + ret = AM_EEPROM_STATUS_ERR_SYS; + goto amEepromInitError; + } + + amEeprom.m_superio = amEepromCreateDeviceFile(&MXSMBUS_GUID, 0, 0); + if (amEeprom.m_superio == INVALID_HANDLE_VALUE) { + if (amEepromDebugLevel > 0) + amiDebugLog("amEepromCreateDeviceFile Error in amEepromInit."); + ret = AM_EEPROM_STATUS_ERR_SYS; + goto amEepromInitError; + } + + DWORD driverVersion; + ret = amEepromGetDriverVersion(&amEeprom, &driverVersion); + if (ret != 0) { + amiDebugLog("amEepromGetDriverVerision Error."); + goto amEepromInitError; + } + + if ((driverVersion & 0xffff) != 1) { + if (amEepromDebugLevel > 0) + amiDebugLog( + "Unknown SMBUS Driver Protocol(0x%08x). Please update SMBUS driver or user " + "program.\n", + driverVersion); + + ret = AM_EEPROM_STATUS_ERR_PROTOCOL_VER; + goto amEepromInitError; + } + + if (timeout != NULL) { + amEeprom.m_timeout.ReadTimeout = timeout->ReadTimeout; + amEeprom.m_timeout.WriteTimeout = timeout->WriteTimeout; + } + amEeprom.m_init = TRUE; + return AM_EEPROM_STATUS_OK; + +amEepromInitError: + amEeprom.m_init = TRUE; + amEepromExit(); + return ret; +} + +AM_EEPROM_STATUS amEepromExit() { + if (!amEeprom.m_init) { + if (amEepromDebugLevel > 0) amiDebugLog("No Init Error!!"); + return AM_EEPROM_STATUS_ERR_NO_INIT; + } + if (amEeprom.m_superio != INVALID_HANDLE_VALUE) { + CloseHandle(amEeprom.m_superio); + amEeprom.m_superio = INVALID_HANDLE_VALUE; + } + if (amEeprom.m_mutex != NULL) { + CloseHandle(amEeprom.m_mutex); + amEeprom.m_mutex = NULL; + } + if (amEeprom.m_sid != NULL) { + FreeSid(amEeprom.m_sid); + amEeprom.m_sid = NULL; + } + amEeprom.m_init = FALSE; + return AM_EEPROM_STATUS_OK; +} + +BOOL amEepromI2CReadBlock(AM_EEPROM *device, WORD reg, BYTE nBytes, LPBYTE buffer) { + if (device == NULL || buffer == NULL || nBytes == 0 || nBytes >= 0x21) { + return false; + } + + MXSMBUS_I2C_PACKET packet; + packet.v_addr = device->m_prt; + packet.command_code = reg; + packet.status = 0; + packet.command = MXSMBUS_CMD_READ_BLOCK; + packet.nbytes = nBytes; + + DWORD bytesReturned; + BOOL s = DeviceIoControl(device->m_superio, IOCTL_MXSMBUS_I2C, &packet, sizeof packet, &packet, + sizeof packet, &bytesReturned, NULL); + if (!s || bytesReturned != sizeof packet) { + return false; + } + + if (packet.status != 0) { + if (amEepromDebugLevel > 0) + amiDebugLog(" .. SMBus read error. prt=0x%02x addr=0x%02x reg=0x%04x", + packet.command, packet.v_addr, packet.command_code); + return false; + } + + memcpy(buffer, packet.data, nBytes); + return true; +} + +BOOL amEepromI2CWriteBlock(AM_EEPROM *device, WORD reg, BYTE nBytes, LPBYTE buffer) { + if (device == NULL || buffer == NULL || nBytes == 0 || nBytes >= 0x21) { + return false; + } + + MXSMBUS_I2C_PACKET packet; + packet.v_addr = device->m_prt; + packet.command_code = reg; + packet.status = 0; + packet.command = MXSMBUS_CMD_WRITE_BLOCK; + packet.nbytes = nBytes; + memcpy(packet.data, buffer, nBytes); + + DWORD bytesReturned; + BOOL s = DeviceIoControl(device->m_superio, IOCTL_MXSMBUS_I2C, &packet, sizeof packet, &packet, + sizeof packet, &bytesReturned, NULL); + if (!s || bytesReturned != sizeof packet) { + return false; + } + + if (packet.status != 0) { + if (amEepromDebugLevel > 0) + amiDebugLog( + " .. SMBus write error. status=0x%02x, prt=0x%02x addr=0x%02x reg=0x%04x\n", + packet.status, packet.command, packet.v_addr, packet.command_code); + return false; + } + + return true; +} + +BOOL amiEepromWait(AM_EEPROM *device, int timeout) { + amtime_t startTime; + amtime_t nowTime; + + if (device == NULL) return FALSE; + + MXSMBUS_REQUEST_PACKET packet; + packet.status = 24; + packet.command = MXSMBUS_CMD_READ_BYTE; + packet.v_addr = device->m_prt; + packet.command_code = 0; + packet.nbytes = 0; + packet.data[0] = 0; + packet.data[1] = 0; + + amiTimerGet(&startTime); + while (1) { + amiTimerGet(&nowTime); + DWORD bytesReturned; + DeviceIoControl(device->m_superio, IOCTL_MXSMBUS_REQUEST, &packet, sizeof packet, &packet, + sizeof packet, &bytesReturned, NULL); + if (packet.status == 0) return TRUE; + + if (amiTimerDiffUsec(&startTime, &nowTime) > timeout * 1000) return FALSE; + } +} + +AM_EEPROM_STATUS amEepromRead(WORD reg, LPBYTE buf, DWORD length) { + if (amEeprom.m_init == 0) { + if (amEepromDebugLevel > 0) amiDebugLog("No Init Error."); + return AM_EEPROM_STATUS_ERR_NO_INIT; + } + if (buf == NULL || length == 0) return AM_EEPROM_STATUS_ERR_INVALID_PARAM; + + DWORD err = WaitForSingleObject(amEeprom.m_mutex, 256); + if (err == WAIT_FAILED) { + if (amEepromDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld).", GetLastError()); + return AM_EEPROM_STATUS_ERR_SYS; + } + if (err == WAIT_TIMEOUT) return AM_EEPROM_STATUS_ERR_GET_MUTEX; + + if (!(err == WAIT_OBJECT_0 || err == WAIT_ABANDONED)) { + if (amEepromDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld). Return Value is %d.", GetLastError(), + err); + return AM_EEPROM_STATUS_ERR_SYS; + } + + while (length != 0) { + BYTE readSize = 0x20; + if ((reg & 0x1f) != 0) readSize = 0x20 - (reg & 0x1f); + if (length <= readSize) readSize = length & 0xff; + + if (!amiEepromWait(&amEeprom, amEeprom.m_timeout.ReadTimeout)) + return AM_EEPROM_STATUS_ERR_TIMEOUT; + + if (!amEepromI2CReadBlock(&amEeprom, reg, readSize, buf)) return AM_EEPROM_STATUS_ERR_READ; + + buf += readSize; + reg += readSize; + length -= readSize; + } + + if (!ReleaseMutex(amEeprom.m_mutex)) { + if (amEepromDebugLevel > 0) amiDebugLog("ReleaseMutex Error(%ld).", GetLastError()); + return AM_EEPROM_STATUS_ERR_SYS; + } + + return AM_EEPROM_STATUS_OK; +} + +AM_EEPROM_STATUS amEepromWrite(WORD reg, LPBYTE buf, DWORD length) { + if (amEeprom.m_init == 0) { + if (amEepromDebugLevel > 0) amiDebugLog("No Init Error."); + return AM_EEPROM_STATUS_ERR_NO_INIT; + } + if (buf == NULL || length == 0) return AM_EEPROM_STATUS_ERR_INVALID_PARAM; + + DWORD err = WaitForSingleObject(amEeprom.m_mutex, 256); + if (err == WAIT_FAILED) { + if (amEepromDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld).", GetLastError()); + return AM_EEPROM_STATUS_ERR_SYS; + } + if (err == WAIT_TIMEOUT) return AM_EEPROM_STATUS_ERR_GET_MUTEX; + + if (!(err == WAIT_OBJECT_0 || err == WAIT_ABANDONED)) { + if (amEepromDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld). Return Value is %d.", GetLastError(), + err); + return AM_EEPROM_STATUS_ERR_SYS; + } + + while (length != 0) { + BYTE writeSize = 0x20; + if ((reg & 0x1f) != 0) writeSize = 0x20 - (reg & 0x1f); + if (length <= writeSize) writeSize = length & 0xff; + + if (!amiEepromWait(&amEeprom, amEeprom.m_timeout.WriteTimeout)) + return AM_EEPROM_STATUS_ERR_TIMEOUT; + + if (!amEepromI2CWriteBlock(&amEeprom, reg, writeSize, buf)) + return AM_EEPROM_STATUS_ERR_WRITE; + + buf += writeSize; + reg += writeSize; + length -= writeSize; + } + + if (!ReleaseMutex(amEeprom.m_mutex)) { + if (amEepromDebugLevel > 0) amiDebugLog("ReleaseMutex Error(%ld).", GetLastError()); + return AM_EEPROM_STATUS_ERR_SYS; + } + + return AM_EEPROM_STATUS_OK; } diff --git a/src/micetools/lib/am/amEeprom.h b/src/micetools/lib/am/amEeprom.h index 0a8b7dc..84e2d3f 100644 --- a/src/micetools/lib/am/amEeprom.h +++ b/src/micetools/lib/am/amEeprom.h @@ -1,13 +1,59 @@ +#pragma once + #include #include "../../dll/smbus.h" +#include "../_am.h" -DEFINE_GUID(MXSMBUS_GUID, 0x5C49E1FE, 0x3FEC, 0x4B8D, 0xA4, 0xB5, 0x76, 0xBE, 0x70, 0x25, 0xD8, 0x42); -DEFINE_GUID(PLATFORM_GUID, 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3e, 0x30, 0x1F, 0x73); +AM_LIB_H_HEADER(amEeprom, AM_EEPROM) + +typedef enum { + AM_EEPROM_STATUS_OK = 0, + AM_EEPROM_STATUS_NG = -1, + AM_EEPROM_STATUS_ERR_INVALID_PARAM = -2, + AM_EEPROM_STATUS_ERR_NO_INIT = -3, + AM_EEPROM_STATUS_ERR_ALREADY_INIT = -4, + AM_EEPROM_STATUS_ERR_SYS = -5, + AM_EEPROM_STATUS_ERR_READ = -6, + AM_EEPROM_STATUS_ERR_WRITE = -7, + AM_EEPROM_STATUS_ERR_TIMEOUT = -8, + AM_EEPROM_STATUS_ERR_GET_MUTEX = -9, + AM_EEPROM_STATUS_ERR_PROTOCOL_VER = -10, +} AM_EEPROM_STATUS; + +typedef struct { + int ReadTimeout; + int WriteTimeout; +} AM_EEPROM_TIMEOUT; + +typedef struct _AM_EEPROM { + BOOL m_init; + AM_EEPROM_TIMEOUT m_timeout; + HANDLE m_mutex; + HANDLE m_superio; + BYTE m_prt; + PSID m_sid; +} AM_EEPROM; +#define AM_EEPROM_DEFAULT_TIMEOUT 6 + +#define AM_EEPROM_ADDR 0x57 + +DEFINE_GUID(MXSMBUS_GUID, 0x5C49E1FE, 0x3FEC, 0x4B8D, 0xA4, 0xB5, 0x76, 0xBE, 0x70, 0x25, 0xD8, + 0x42); +DEFINE_GUID(PLATFORM_GUID, 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3e, 0x30, 0x1F, + 0x73); HANDLE amEepromCreateDeviceFile(const GUID *guid, LPCSTR resource, DWORD member_index); +AM_EEPROM_STATUS amEepromGetDriverVersion(AM_EEPROM *device, LPDWORD version); +AM_EEPROM_STATUS amEepromCreateMutex(AM_EEPROM *device); -BOOL amEepromReadBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data); -BOOL amEepromWriteBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data); +BOOL amEepromI2CReadBlock(AM_EEPROM *device, WORD reg, BYTE nBytes, LPBYTE buffer); +BOOL amEepromI2CWriteBlock(AM_EEPROM *device, WORD reg, BYTE nBytes, LPBYTE buffer); -void amEepromRepairChecksum(BYTE* data); +AM_EEPROM_STATUS amEepromInit(AM_EEPROM_TIMEOUT *timeout); +AM_EEPROM_STATUS amEepromExit(void); +AM_EEPROM_STATUS amEepromRead(WORD reg, LPBYTE buf, DWORD length); +AM_EEPROM_STATUS amEepromWrite(WORD reg, LPBYTE buf, DWORD length); + +// TODO: +void amEepromSetTimeout(void); diff --git a/src/micetools/lib/am/amGcatcher.h b/src/micetools/lib/am/amGcatcher.h new file mode 100644 index 0000000..8f1f42f --- /dev/null +++ b/src/micetools/lib/am/amGcatcher.h @@ -0,0 +1,4 @@ +void amGcatcherInit(void); +void amGcatcherIsUpdate(void); +void amGcatcherReloadInfo(void); +void amGcatcherStartCatcher(void); diff --git a/src/micetools/lib/am/amGdeliver.h b/src/micetools/lib/am/amGdeliver.h new file mode 100644 index 0000000..acc23d5 --- /dev/null +++ b/src/micetools/lib/am/amGdeliver.h @@ -0,0 +1,3 @@ +void amGdeliverInit(void); +void amGdeliverReadSegment(void); +void amGdeliverResSetThread(void); diff --git a/src/micetools/lib/am/amGfetcher.h b/src/micetools/lib/am/amGfetcher.h new file mode 100644 index 0000000..64c2249 --- /dev/null +++ b/src/micetools/lib/am/amGfetcher.h @@ -0,0 +1,3 @@ +void amGfetcherInit(void); +void amGfetcherReqIsReleaseEx(void); +void amGfetcherReqRestart(void); diff --git a/src/micetools/lib/am/amHardware.h b/src/micetools/lib/am/amHardware.h new file mode 100644 index 0000000..2fe9739 --- /dev/null +++ b/src/micetools/lib/am/amHardware.h @@ -0,0 +1 @@ +void amHardwareReset(void); diff --git a/src/micetools/lib/am/amHm.h b/src/micetools/lib/am/amHm.h new file mode 100644 index 0000000..f5daa6c --- /dev/null +++ b/src/micetools/lib/am/amHm.h @@ -0,0 +1,23 @@ +void amHmChangeBank(void); +void amHmExit(void); +void amHmGetCautionFlag(void); +void amHmGetLPCChipId(void); +void amHmI2CReadByte(void); +void amHmI2CWriteByte(void); +void amHmInit(void); +void amHmLpcReadByte(void); +void amHmLpcWriteByte(void); +void amHmModifyByteWithBankNum(void); +void amHmProbeSuperIoDevice(void); +void amHmReadByteWithBankNum(void); +void amHmReadFanInternal(void); +void amHmReadTemperatureInternal(void); +void amHmReadVoltageInternal(void); +void amHmResetCautionFlag(void); +void amHmSetEnable(void); +void amHmSetFanconMode(void); +void amHmSetFanControlInternal(void); +void amHmSetThermoCruise(void); +void amHmUpdate(void); +void amHmWriteByte(void); +void amHmWriteByteWithBankNum(void); diff --git a/src/micetools/lib/am/amInstall.c b/src/micetools/lib/am/amInstall.c new file mode 100644 index 0000000..860ed76 --- /dev/null +++ b/src/micetools/lib/am/amInstall.c @@ -0,0 +1,580 @@ +#include "amInstall.h" + +#include "../util/hex.h" + +AM_LIB_C_HEADER(amInstall, AM_INSTALL) + +/*********************************************************/ +AM_INSTALL_STATUS amInstallResponseCheckQuerySlotStatus(AM_INSTALL_SLOT_STATUS *slotStatus) { + return AM_INSTALL_STATUS_OK; +} +int amInstallResponseCheckQuerySemStatus(void) { return -1; } +int amInstallResponseCheckQueryAppStatus(void) { return -1; } +AM_INSTALL_STATUS amInstallResponseCheckQuerySpd(void *param_1) { return AM_INSTALL_STATUS_OK; } +AM_INSTALL_STATUS amInstallResponseCheckQueryAppdataStatus(int *param_1) { + return AM_INSTALL_STATUS_OK; +} +AM_INSTALL_STATUS amInstallSuicideSub(char *keyword) { return AM_INSTALL_STATUS_OK; } +/*********************************************************/ + +bool amInstallPcpaGetUlonglong(unsigned long long *dest, char *keyword) { + if (keyword == NULL || dest == NULL) return false; + char *command = pcpaGetCommand(&amInstall.m_pcp, keyword); + if (command == NULL) return false; + + errno = 0; + char *end = NULL; + unsigned long long value = strtoull(command, &end, 0); + if (errno == ERANGE || end == NULL || end[0] != '\0') return false; + *dest = value; + return true; +} + +AM_INSTALL_STATUS amInstallResponseCheckQueryBr(AM_INSTALL_BOOT_RECORD *bootRecord) { + if (bootRecord == NULL) return AM_INSTALL_STATUS_ERR_INVALID_PARAM; + + ZeroMemory(bootRecord, sizeof bootRecord); + + amInstallPcpaGetUlonglong(&bootRecord->epbr, "epbr"); + amInstallPcpaGetUlonglong(&bootRecord->original0, "original0"); + amInstallPcpaGetUlonglong(&bootRecord->original1, "original1"); + amInstallPcpaGetUlonglong(&bootRecord->patch0, "patch0"); + amInstallPcpaGetUlonglong(&bootRecord->patch1, "patch1"); + amInstallPcpaGetUlonglong(&bootRecord->os, "os"); + + return AM_INSTALL_STATUS_OK; +} + +/*********************************************************/ + +AM_INSTALL_STATUS amInstallInit(void) { + if (amInstall.m_init) return AM_INSTALL_STATUS_ERR_ALREADY_INIT; + + amInstall.m_seq = AM_INSTALL_SEQ_NONE; + amInstall.m_nextSeq = AM_INSTALL_SEQ_INVALID; + amInstall.m_requestCode = 0; + amInstall.m_result = AM_INSTALL_STATUS_OK; + amInstall.m_sendBufferLen = 0; + amInstall.m_semid = 0; + amInstall.m_cmdPort = 40102; + amInstall.m_dataPort = 40103; + + e_pcpa_t err = pcpaInitStream(&amInstall.m_pcp); + if (err == e_pcpa_wsa_noinit) { + if (amInstallDebugLevel > 0) amiDebugLog("Error: Winsocket2 Library is not ready."); + return AM_INSTALL_STATUS_ERR_PRECONDITION; + } + if (err != e_pcpa_ok) { + if (amInstallDebugLevel > 0) + amiDebugLog("Error: System error happened in pcp stream. ErrorCode = %d.", err); + return AM_INSTALL_STATUS_ERR_SYS; + } + + amInstall.m_init = true; + return AM_INSTALL_STATUS_OK; +} + +AM_INSTALL_STATUS amInstallUpdate(void) { + AM_INSTALL_STATUS status; + + if (!amInstall.m_init) return AM_INSTALL_STATUS_ERR_NO_INIT; + + switch (amInstall.m_seq) { + case AM_INSTALL_SEQ_BUSY: + status = amInstallBusy(); + break; + case AM_INSTALL_SEQ_SEND_REQUEST: + status = amInstallSendRequest(); + if (status != AM_INSTALL_STATUS_OK) { + amInstall.m_result = status; + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_SEQ_RECV_RESPONSE: + status = amInstallRecvResponse(); + break; + case AM_INSTALL_SEQ_CHECK_RESPONSE: + status = amInstallResponseCheck(); + if (status != AM_INSTALL_STATUS_OK) { + amInstall.m_result = status; + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_SEQ_OPEN_BINARY: + status = amInstallOpenBinary(); + break; + case AM_INSTALL_SEQ_SEND_BINARY: + status = amInstallSendBinaryBuffer(1); + if (status != AM_INSTALL_STATUS_OK) { + amInstall.m_result = status; + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_SEQ_EXIT: + amInstallExit(); + amInstall.m_result = AM_INSTALL_STATUS_OK; + return AM_INSTALL_STATUS_OK; + default: + return AM_INSTALL_STATUS_OK; + } + + if (status != AM_INSTALL_STATUS_OK) { + amInstall.m_result = status; + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_OK; +} + +AM_INSTALL_STATUS amInstallBusy(void) { + e_pcpa_t err = pcpaIsBusy(&amInstall.m_pcp, 0); + if (err == e_pcpa_ok) { + amInstall.m_seq = amInstall.m_nextSeq; + amInstall.m_nextSeq = AM_INSTALL_SEQ_INVALID; + } else if (err != e_pcpa_to) { + if (amInstallDebugLevel > 0) + amiDebugLog("pcpaIsBusy() Error(%d), NextStatus = %d", err, amInstall.m_nextSeq); + amInstall.m_nextSeq = AM_INSTALL_SEQ_INVALID; + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + + if (err == e_pcpa_no_server) return AM_INSTALL_STATUS_ERR_NO_SERVER; + return AM_INSTALL_STATUS_ERR_PCP; + } + return AM_INSTALL_STATUS_OK; +} + +AM_INSTALL_STATUS amInstallSendRequest(void) { + e_pcpa_t err = pcpaSendRequest(&amInstall.m_pcp, 0); + if (err == e_pcpa_ok) { + amInstall.m_seq = AM_INSTALL_SEQ_RECV_RESPONSE; + return AM_INSTALL_STATUS_OK; + } + if (err == e_pcpa_to) { + amInstall.m_seq = AM_INSTALL_SEQ_BUSY; + amInstall.m_nextSeq = AM_INSTALL_SEQ_RECV_RESPONSE; + return AM_INSTALL_STATUS_OK; + } + + if (amInstallDebugLevel > 0) amiDebugLog("pcpaSendRequest() Error!!"); + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + return AM_INSTALL_STATUS_ERR_PCP; +} + +AM_INSTALL_STATUS amInstallRecvResponse(void) { + e_pcpa_t err = pcpaRecvResponse(&amInstall.m_pcp, 0); + if (err == e_pcpa_ok) { + amInstall.m_seq = AM_INSTALL_SEQ_CHECK_RESPONSE; + return AM_INSTALL_STATUS_OK; + } + if (err == e_pcpa_to) { + amInstall.m_seq = AM_INSTALL_SEQ_BUSY; + amInstall.m_nextSeq = AM_INSTALL_SEQ_CHECK_RESPONSE; + return AM_INSTALL_STATUS_OK; + } + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + return AM_INSTALL_STATUS_ERR_PCP; +} + +AM_INSTALL_STATUS amInstallCodeToStatus(void) { + char *sResult = pcpaGetCommand(&amInstall.m_pcp, "result"); + char *sCode = pcpaGetCommand(&amInstall.m_pcp, "code"); + if (sResult == NULL) { + return AM_INSTALL_STATUS_ERR_PCP; + } + if (sCode != NULL) { + switch (atoi(sCode)) { + case 0: + return AM_INSTALL_STATUS_OK; + case 1: + return AM_INSTALL_STATUS_ERR_NO_STORAGE; + case 2: + return AM_INSTALL_STATUS_ERR_FORMAT; + case 4: + return AM_INSTALL_STATUS_ERR_EX_PARTITION; + case 5: + return AM_INSTALL_STATUS_ERR_READ_STORAGE; + case 6: + return AM_INSTALL_STATUS_ERR_WRITE_STORAGE; + case 7: + return AM_INSTALL_STATUS_ERR_SPD_CRC; + case 8: + return AM_INSTALL_STATUS_ERR_SPD_VERSION; + case 20: + return AM_INSTALL_STATUS_ERR_SEMAPHORE_ID; + case 21: + return AM_INSTALL_STATUS_ERR_GET_SEMAPHORE; + case 22: + return AM_INSTALL_STATUS_ERR_INVALID_LOCK_ID; + case 40: + return AM_INSTALL_STATUS_ERR_NO_SLOT; + case 41: + return AM_INSTALL_STATUS_ERR_READ_SLOT; + case 42: + return AM_INSTALL_STATUS_ERR_WRITE_SLOT; + case 60: + return AM_INSTALL_STATUS_ERR_DIFF_APPLICATION; + case 61: + return AM_INSTALL_STATUS_ERR_APPLICATION_SIZE; + case 62: + return AM_INSTALL_STATUS_ERR_SEGMENT_OFFSET; + case 63: + return AM_INSTALL_STATUS_ERR_UPDATE_STATUS; + case 64: + return AM_INSTALL_STATUS_ERR_REQUEST; + } + } + if (strcmp(sResult, "success") == 0) return AM_INSTALL_STATUS_OK; + + if (strcmp(sResult, "invalid_parameter") != 0) { + if (strcmp(sResult, "invalid_request") != 0) { + return AM_INSTALL_STATUS_ERR_PCP; + } + } + return AM_INSTALL_STATUS_ERR_INVALID_COMMAND; +} + +bool amInstallPcpaGetInt(char *keyword, unsigned int *dest) { + if (keyword == NULL || dest == NULL) return false; + char *command = pcpaGetCommand(&amInstall.m_pcp, keyword); + if (command == NULL) return false; + + errno = 0; + char *end = NULL; + unsigned int value = strtoul(command, &end, 0); + if (errno == ERANGE || end == NULL || end[0] != '\0') return false; + *dest = value; + return true; +} + +AM_INSTALL_STATUS amInstallTaskRequest(char *keyword) { + pcp_send_data_t *sendData; + + if (strcmp(keyword, "query_appdata_status") == 0) { + int status; + if (amInstallResponseCheckQueryAppdataStatus(&status) != AM_INSTALL_STATUS_OK) + return AM_INSTALL_STATUS_ERR_PCP; + + bool failed = ((status == 1) || (status == 2)); + if (status == 0) { + sendData = pcpaSetSendPacket(&amInstall.m_pcp, "request", "check_appdata"); + if (sendData == NULL && amInstallDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL\n"); + sendData = pcpaAddSendPacket(&amInstall.m_pcp, "execute", "1"); + if (sendData == NULL && amInstallDebugLevel > 0) + amiDebugLog("Error: pcpaAddSendPacket return NULL\n"); + + amInstall.m_seq = AM_INSTALL_SEQ_SEND_REQUEST; + } + if (!failed) { + return AM_INSTALL_STATUS_OK; + } + } else { + if (strcmp(keyword, "check_appdata") != 0 && strcmp(keyword, "format_appdata") != 0) + return AM_INSTALL_STATUS_ERR_PCP; + } + + sendData = pcpaSetSendPacket(&amInstall.m_pcp, "request", "query_appdata_status"); + if (sendData == 0 && amInstallDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL\n"); + + amInstall.m_seq = AM_INSTALL_SEQ_SEND_REQUEST; + return AM_INSTALL_STATUS_OK; +} + +AM_INSTALL_STATUS amInstallResponseCheck(void) { + char *realKeyword = pcpaGetKeyword(&amInstall.m_pcp, 0); + char *keyword = pcpaGetCommand(&amInstall.m_pcp, "response"); + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + if (realKeyword == NULL) { + if (amInstallDebugLevel > 0) amiDebugLog("Response Error!!! No Keyword."); + return AM_INSTALL_STATUS_ERR_PCP; + } + + if (realKeyword[0] == '?') return AM_INSTALL_STATUS_ERR_NO_COMMAND; + if (keyword == NULL) { + if (amInstallDebugLevel > 0) amiDebugLog("Error : No Response"); + return AM_INSTALL_STATUS_ERR_PCP; + } + + AM_INSTALL_STATUS response_error = amInstallCodeToStatus(); + if (response_error != AM_INSTALL_STATUS_OK) return response_error; + + switch (amInstall.m_requestCode) { + case AM_INSTALL_REQUEST_QUERY_SLOT_STATUS: + if (strcmp(keyword, "query_slot_status") != 0) { + amInstall.m_result = AM_INSTALL_STATUS_ERR_PCP; + return AM_INSTALL_STATUS_OK; + } + amInstallResponseCheckQuerySlotStatus((AM_INSTALL_SLOT_STATUS *)amInstall.m_value); + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_INSTALL: + if (strcmp(keyword, "install") != 0) return AM_INSTALL_STATUS_ERR_PCP; + unsigned int port = 40103; + amInstallPcpaGetInt("port", &port); + amInstall = amInstall; + amInstall.m_dataPort = port & 0xffff; + amInstall.m_seq = AM_INSTALL_SEQ_OPEN_BINARY; + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_UNINSTALL: + if (strcmp(keyword, "uninstall") != 0) return AM_INSTALL_STATUS_ERR_PCP; + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_CHECK: + if (strcmp(keyword, "check") != 0) return AM_INSTALL_STATUS_ERR_PCP; + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_QUERY_APPLICATION_STATUS: + if (strcmp(keyword, "query_application_status") != 0) return AM_INSTALL_STATUS_ERR_PCP; + + *(unsigned int *)amInstall.m_value = amInstallResponseCheckQueryAppStatus(); + amInstallPcpaGetInt("busyslot", (unsigned int *)amInstall.Unk51c); + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_SET_APPLICATION_STATUS: + if (strcmp(keyword, "set_application_status") != 0) return AM_INSTALL_STATUS_ERR_PCP; + + if (pcpaGetCommand(&amInstall.m_pcp, "lockid") == NULL) return AM_INSTALL_STATUS_OK; + amInstallPcpaGetInt("lockid", (unsigned int *)amInstall.m_value); + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_QUERY_SBR_BOOTSLOT: + if (strcmp(keyword, "query_sbr_bootslot") != 0) return AM_INSTALL_STATUS_ERR_PCP; + unsigned int bootslot = 0; + amInstallPcpaGetInt("bootslot", &bootslot); + *(unsigned int *)amInstall.m_value = bootslot; + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_SET_SBR_BOOTSLOT: + if (strcmp(keyword, "set_sbr_bootslot") != 0) return AM_INSTALL_STATUS_ERR_PCP; + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_QUERY_SEMAPHORE_STATUS: + if (strcmp(keyword, "query_semaphore_status") != 0) return AM_INSTALL_STATUS_ERR_PCP; + *(unsigned int *)amInstall.m_value = amInstallResponseCheckQuerySemStatus(); + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_GET_SEMAPHORE: + if (strcmp(keyword, "get_semaphore") == 0) { + unsigned int semid = 0; + amInstallPcpaGetInt("semid", &semid); + *(unsigned int *)amInstall.m_value = semid; + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_ERR_PCP; + case AM_INSTALL_REQUEST_RELEASE_SEMAPHORE: + if (strcmp(keyword, "release_semaphore") == 0) return AM_INSTALL_STATUS_OK; + return AM_INSTALL_STATUS_ERR_PCP; + case AM_INSTALL_REQUEST_QUERY_SPD: + if (strcmp(keyword, "query_spd") == 0) { + amInstallResponseCheckQuerySpd(amInstall.m_value); + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_ERR_PCP; + case AM_INSTALL_REQUEST_QUERY_BR: + if (strcmp(keyword, "query_br") == 0) { + amInstallResponseCheckQueryBr(amInstall.m_value); + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_ERR_PCP; + case AM_INSTALL_REQUEST_QUERY_APPDATA_STATUS: + if (strcmp(keyword, "query_appdata_status") != 0) return AM_INSTALL_STATUS_ERR_PCP; + if (amInstallResponseCheckQueryAppdataStatus(amInstall.m_value) != AM_INSTALL_STATUS_OK) + return AM_INSTALL_STATUS_ERR_PCP; + + if ((*(int *)amInstall.m_value != 4) && (*(int *)amInstall.m_value != 5)) + return AM_INSTALL_STATUS_OK; + + char *sId = pcpaGetCommand(&amInstall.m_pcp, "id"); + if (sId == NULL) return AM_INSTALL_STATUS_ERR_PCP; + strcpy_s(amInstall.Unk51c, 4, sId); + return AM_INSTALL_STATUS_OK; + case AM_INSTALL_REQUEST_15: + case AM_INSTALL_REQUEST_16: + return amInstallTaskRequest(keyword); + case AM_INSTALL_REQUEST_QUERY_VOLUME_NAME: + if (strcmp(keyword, "query_volume_name") == 0) { + char *sName = pcpaGetCommand(&amInstall.m_pcp, "name"); + if (sName == NULL) return AM_INSTALL_STATUS_OK; + + size_t hexLen = strlen(sName); + if (hexLen > 512) hexLen = 512; + hex_to_bin(sName, amInstall.m_value, hexLen); + return AM_INSTALL_STATUS_OK; + } + return AM_INSTALL_STATUS_ERR_PCP; + case AM_INSTALL_REQUEST_18: + return amInstallSuicideSub(keyword); + default: + return AM_INSTALL_STATUS_OK; + } +} + +AM_INSTALL_STATUS amInstallOpenBinary(void) { + e_pcpa_t err = pcpaOpenBinaryClient(&amInstall.m_pcp, amInstall.m_dataPort, 0); + if (err == e_pcpa_ok) { + amInstall.m_seq = AM_INSTALL_SEQ_SEND_BINARY; + return AM_INSTALL_STATUS_OK; + } + if (err == e_pcpa_to) { + amInstall.m_seq = AM_INSTALL_SEQ_BUSY; + amInstall.m_nextSeq = AM_INSTALL_SEQ_SEND_BINARY; + return AM_INSTALL_STATUS_OK; + } + + if (amInstallDebugLevel > 0) amiDebugLog("pcpaOpenBinaryClient() Error!!"); + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + return AM_INSTALL_STATUS_ERR_PCP; +} + +AM_INSTALL_STATUS amInstallSendBinaryBuffer(AM_INSTALL_BLOCKING blocking) { + timeout_t timeout = blocking == AM_INSTALL_BLOCK ? TIMEOUT_NONE : 0; + if (amInstall.m_requestCode != 2) { + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + amInstall.m_nextSeq = AM_INSTALL_SEQ_INVALID; + return AM_INSTALL_STATUS_ERR_PCP; + } + + pcpaSetSendBinaryBuffer(&amInstall.m_pcp, amInstall.m_value, amInstall.m_sendBufferLen); + e_pcpa_t err = pcpaSendBinary(&amInstall.m_pcp, timeout); + if (err == 0) { + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + return AM_INSTALL_STATUS_OK; + } + if (err == 1) { + amInstall.m_seq = AM_INSTALL_SEQ_BUSY; + amInstall.m_nextSeq = AM_INSTALL_SEQ_EXIT; + return AM_INSTALL_STATUS_OK; + } + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + return AM_INSTALL_STATUS_ERR_PCP; +} +AM_INSTALL_STATUS amInstallExit(void) { + pcpaCloseBinary(&amInstall.m_pcp); + pcpaClose(&amInstall.m_pcp); + amInstall.m_seq = AM_INSTALL_SEQ_NONE; + amInstall.m_result = AM_INSTALL_STATUS_OK; + return AM_INSTALL_STATUS_OK; +} + +AM_INSTALL_STATUS amInstallOpenBinaryEx(void) { + e_pcpa_t err = pcpaOpenBinaryClient(&amInstall.m_pcp, amInstall.m_dataPort, TIMEOUT_NONE); + if (err != e_pcpa_ok) { + pcpaCloseBinary(&amInstall.m_pcp); + pcpaClose(&amInstall.m_pcp); + amInstall.m_seq = AM_INSTALL_SEQ_NONE; + amInstall.m_result = AM_INSTALL_STATUS_OK; + amInstall.m_nextSeq = AM_INSTALL_SEQ_INVALID; + return AM_INSTALL_STATUS_ERR_PCP; + } + amInstall.m_seq = AM_INSTALL_SEQ_SEND_BINARY; + return AM_INSTALL_STATUS_OK; +} + +AM_INSTALL_STATUS amInstallSendAndReceiveEx(void) { + AM_INSTALL_STATUS err; + + amInstall.m_result = AM_INSTALL_STATUS_OK; + err = amInstallOpenEx(); + if (err == AM_INSTALL_STATUS_OK) { + do { + err = amInstallSendAndRecvEx(); + if (err != AM_INSTALL_STATUS_OK) return err; + + err = amInstallResponseCheck(); + if (amInstall.m_result != AM_INSTALL_STATUS_OK) err = amInstall.m_result; + + if (amInstall.m_seq == AM_INSTALL_SEQ_OPEN_BINARY) { + err = amInstallOpenBinaryEx(); + if (err != AM_INSTALL_STATUS_OK) return err; + + err = amInstallSendBinaryBuffer(AM_INSTALL_BLOCK); + if (err != AM_INSTALL_STATUS_OK) break; + } + } while (amInstall.m_seq != AM_INSTALL_SEQ_EXIT); + + pcpaCloseBinary(&amInstall.m_pcp); + pcpaClose(&amInstall.m_pcp); + amInstall.m_seq = AM_INSTALL_SEQ_NONE; + amInstall.m_result = AM_INSTALL_STATUS_OK; + } + return err; +} + +AM_INSTALL_STATUS amInstallSendAndRecvEx(void) { + e_pcpa_t err = pcpaSendRequest(&amInstall.m_pcp, TIMEOUT_NONE); + if (err != e_pcpa_ok) { + if (amInstallDebugLevel > 0) amiDebugLog("pcpaSendRequest Error!!"); + + pcpaCloseBinary(&amInstall.m_pcp); + pcpaClose(&amInstall.m_pcp); + amInstall = amInstall; + amInstall.m_seq = AM_INSTALL_SEQ_NONE; + amInstall.m_result = AM_INSTALL_STATUS_OK; + amInstall.m_nextSeq = AM_INSTALL_SEQ_INVALID; + return AM_INSTALL_STATUS_ERR_PCP; + } + err = pcpaRecvResponse(&amInstall.m_pcp, TIMEOUT_NONE); + if (err != e_pcpa_ok) { + pcpaCloseBinary(&amInstall.m_pcp); + pcpaClose(&amInstall.m_pcp); + amInstall = amInstall; + amInstall.m_seq = AM_INSTALL_SEQ_NONE; + amInstall.m_result = AM_INSTALL_STATUS_OK; + if (amInstallDebugLevel > 0) amiDebugLog("pcpaRecvResponse Error!!"); + + return AM_INSTALL_STATUS_ERR_PCP; + } + return AM_INSTALL_STATUS_OK; +} + +AM_INSTALL_STATUS amInstallOpenEx(void) { + e_pcpa_t err = + pcpaOpenClient(&amInstall.m_pcp, "127.0.0.1", amInstall.m_cmdPort, 60000, TIMEOUT_NONE); + if (err == e_pcpa_ok) { + return AM_INSTALL_STATUS_OK; + } + if (err == e_pcpa_timeout_open) { + pcpaClose(&amInstall.m_pcp); + return amInstallOpenEx(); + } + if (amInstallDebugLevel > 0) amiDebugLog("pcpaOpenClient() Error(%d)", err); + pcpaCloseBinary(&amInstall.m_pcp); + pcpaClose(&amInstall.m_pcp); + amInstall = amInstall; + amInstall.m_seq = AM_INSTALL_SEQ_NONE; + amInstall.m_result = AM_INSTALL_STATUS_OK; + return AM_INSTALL_STATUS_ERR_NO_SERVER; +} + +AM_INSTALL_STATUS amInstallOpen(void) { + e_pcpa_t err = pcpaOpenClient(&amInstall.m_pcp, "127.0.0.1", amInstall.m_cmdPort, 60000, 0); + amInstall = amInstall; + if (err == e_pcpa_ok) { + amInstall.m_seq = AM_INSTALL_SEQ_SEND_REQUEST; + amInstall.m_result = AM_INSTALL_STATUS_BUSY; + return AM_INSTALL_STATUS_OK; + } + if (err == e_pcpa_to) { + amInstall.m_seq = AM_INSTALL_SEQ_BUSY; + amInstall.m_nextSeq = AM_INSTALL_SEQ_SEND_REQUEST; + amInstall.m_result = AM_INSTALL_STATUS_BUSY; + return AM_INSTALL_STATUS_OK; + } + amInstall.m_seq = AM_INSTALL_SEQ_EXIT; + return AM_INSTALL_STATUS_ERR_PCP; +} + +AM_INSTALL_STATUS amInstallGetResult(void) { + if (amInstall.m_init == 0) { + amInstall.m_result = AM_INSTALL_STATUS_OK; + return AM_INSTALL_STATUS_ERR_NO_INIT; + } + return amInstall.m_result; +} + +AM_INSTALL_STATUS amInstallGetBr(AM_INSTALL_BOOT_RECORD *bootRecord, AM_INSTALL_BLOCKING blocking) { + if (!amInstall.m_init) return AM_INSTALL_STATUS_ERR_NO_INIT; + if (amInstall.m_seq != AM_INSTALL_SEQ_NONE) return AM_INSTALL_STATUS_BUSY; + if (bootRecord == NULL) return AM_INSTALL_STATUS_ERR_INVALID_PARAM; + + pcp_send_data_t *send_data = pcpaSetSendPacket(&amInstall.m_pcp, "request", "query_br"); + if (send_data == NULL && amInstallDebugLevel > 0) + amiDebugLog("Error: pcpaSetSendPacket return NULL"); + + amInstall.m_value = bootRecord; + amInstall.m_requestCode = AM_INSTALL_REQUEST_QUERY_BR; + if (blocking == AM_INSTALL_BLOCK) return amInstallSendAndReceiveEx(); + return amInstallOpen(); +} diff --git a/src/micetools/lib/am/amInstall.h b/src/micetools/lib/am/amInstall.h new file mode 100644 index 0000000..559fd48 --- /dev/null +++ b/src/micetools/lib/am/amInstall.h @@ -0,0 +1,211 @@ +#pragma once + +#include + +#include "../_am.h" +#include "../libpcp/pcpa.h" +#include "amSysData.h" + +AM_LIB_H_HEADER(amInstall, AM_INSTALL) + +typedef enum { + AM_INSTALL_APPLICATION_STATUS_INVALID = -1, + AM_INSTALL_APPLICATION_STATUS_INACTIVE = 0, + AM_INSTALL_APPLICATION_STATUS_ACTIVE = 1, +} AM_INSTALL_APPLICATION_STATUS; + +typedef enum { + AM_INSTALL_BLOCK = 0, + AM_INSTALL_NOBLOCK = 1, +} AM_INSTALL_BLOCKING; + +typedef enum { + AM_INSTALL_FORMAT_STATUS_ERROR = -1, + AM_INSTALL_FORMAT_STATUS_UNKNOWN = 0, + AM_INSTALL_FORMAT_STATUS_CHECKING = 1, + AM_INSTALL_FORMAT_STATUS_FORMATTING = 2, + AM_INSTALL_FORMAT_STATUS_NEEDED = 3, + AM_INSTALL_FORMAT_STATUS_AVAILABLE = 4, + AM_INSTALL_FORMAT_STATUS_RESTORED = 5, +} AM_INSTALL_FORMAT_STATUS; + +typedef enum { + AM_INSTALL_INSTALL_STATUS_INVALID = -1, + AM_INSTALL_INSTALL_STATUS_EMPTY = 0, + AM_INSTALL_INSTALL_STATUS_INSTALL = 1, + AM_INSTALL_INSTALL_STATUS_CHECK = 2, + AM_INSTALL_INSTALL_STATUS_COMPLETE = 3, +} AM_INSTALL_INSTALL_STATUS; + +typedef enum { + AM_INSTALL_SLOT_INVALID = -1, + AM_INSTALL_SLOT_ORIGINAL_0 = 0, + AM_INSTALL_SLOT_ORIGINAL_1 = 1, + AM_INSTALL_SLOT_ORIGINAL_F = 2, + AM_INSTALL_SLOT_ORIGINAL_B = 3, + AM_INSTALL_SLOT_PATCH_0 = 4, + AM_INSTALL_SLOT_PATCH_1 = 5, + AM_INSTALL_SLOT_PATCH_F = 6, + AM_INSTALL_SLOT_PATCH_B = 7, + AM_INSTALL_SLOT_OS = 8, + AM_INSTALL_SLOT_APPLICATION = 9, +} AM_INSTALL_SLOT; + +typedef enum { + AM_INSTALL_STATUS_OK = 0, + AM_INSTALL_STATUS_BUSY = 1, + + AM_INSTALL_STATUS_NG = -1, + AM_INSTALL_STATUS_ERR_INVALID_PARAM = -2, + AM_INSTALL_STATUS_ERR_NO_INIT = -3, + AM_INSTALL_STATUS_ERR_ALREADY_INIT = -4, + AM_INSTALL_STATUS_ERR_INVALID_COMMAND = -5, + AM_INSTALL_STATUS_ERR_PCP = -6, + AM_INSTALL_STATUS_ERR_NO_SERVER = -7, + AM_INSTALL_STATUS_ERR_NO_STORAGE = -8, + AM_INSTALL_STATUS_ERR_FORMAT = -9, + AM_INSTALL_STATUS_ERR_EX_PARTITION = -10, + AM_INSTALL_STATUS_ERR_READ_STORAGE = -11, + AM_INSTALL_STATUS_ERR_WRITE_STORAGE = -12, + AM_INSTALL_STATUS_ERR_SPD_CRC = -13, + AM_INSTALL_STATUS_ERR_SPD_VERSION = -14, + AM_INSTALL_STATUS_ERR_SEMAPHORE_ID = -15, + AM_INSTALL_STATUS_ERR_GET_SEMAPHORE = -16, + AM_INSTALL_STATUS_ERR_NO_SLOT = -17, + AM_INSTALL_STATUS_ERR_READ_SLOT = -18, + AM_INSTALL_STATUS_ERR_WRITE_SLOT = -19, + AM_INSTALL_STATUS_ERR_DIFF_APPLICATION = -20, + AM_INSTALL_STATUS_ERR_APPLICATION_SIZE = -21, + AM_INSTALL_STATUS_ERR_SEGMENT_OFFSET = -22, + AM_INSTALL_STATUS_ERR_UPDATE_STATUS = -23, + AM_INSTALL_STATUS_ERR_REQUEST = -24, + AM_INSTALL_STATUS_ERR_INVALID_LOCK_ID = -25, + AM_INSTALL_STATUS_ERR_NO_COMMAND = -26, + AM_INSTALL_STATUS_ERR_SYS = -27, + AM_INSTALL_STATUS_ERR_PRECONDITION = -28, +} AM_INSTALL_STATUS; + +typedef struct { + AM_INSTALL_INSTALL_STATUS m_Status; + char m_GameId[8]; + unsigned int m_PackageVersion; + AM_SYSDATA_TIMESTAMP m_TimeStamp; + unsigned int m_NumSegs; + unsigned int m_SegSize; + char m_PlatformId[4]; + unsigned int m_Flag; + unsigned int m_OsVersion; + unsigned int m_OsSegCount; + AM_SYSDATA_TIMESTAMP m_OrgTimeStamp; + unsigned int m_OrgPackageVersion; + unsigned int m_InstalledSegs; +} AM_INSTALL_SLOT_STATUS; + +typedef struct { + unsigned long long epbr; + unsigned long long original0; + unsigned long long original1; + unsigned long long patch0; + unsigned long long patch1; + unsigned long long os; +} AM_INSTALL_BOOT_RECORD; + +typedef enum { + AM_INSTALL_SEQ_INVALID = -1, + + AM_INSTALL_SEQ_NONE = 0, + AM_INSTALL_SEQ_BUSY = 1, + AM_INSTALL_SEQ_SEND_REQUEST = 2, + AM_INSTALL_SEQ_RECV_RESPONSE = 3, + AM_INSTALL_SEQ_CHECK_RESPONSE = 4, + AM_INSTALL_SEQ_OPEN_BINARY = 5, + AM_INSTALL_SEQ_SEND_BINARY = 6, + AM_INSTALL_SEQ_EXIT = 7, +} AM_INSTALL_SEQ; + +typedef enum { + AM_INSTALL_REQUEST_QUERY_SLOT_STATUS = 1, + AM_INSTALL_REQUEST_INSTALL = 2, + AM_INSTALL_REQUEST_UNINSTALL = 3, + AM_INSTALL_REQUEST_CHECK = 4, + AM_INSTALL_REQUEST_QUERY_APPLICATION_STATUS = 5, + AM_INSTALL_REQUEST_SET_APPLICATION_STATUS = 6, + AM_INSTALL_REQUEST_QUERY_SBR_BOOTSLOT = 7, + AM_INSTALL_REQUEST_SET_SBR_BOOTSLOT = 8, + AM_INSTALL_REQUEST_QUERY_SEMAPHORE_STATUS = 9, + AM_INSTALL_REQUEST_GET_SEMAPHORE = 10, + AM_INSTALL_REQUEST_RELEASE_SEMAPHORE = 11, + AM_INSTALL_REQUEST_QUERY_SPD = 12, + AM_INSTALL_REQUEST_QUERY_BR = 13, + AM_INSTALL_REQUEST_QUERY_APPDATA_STATUS = 14, + AM_INSTALL_REQUEST_15 = 15, + AM_INSTALL_REQUEST_16 = 16, + AM_INSTALL_REQUEST_QUERY_VOLUME_NAME = 17, + AM_INSTALL_REQUEST_18 = 18, +} AM_INSTALL_REQUEST; + +typedef struct _AM_INSTALL { + BOOL m_init; + AM_INSTALL_SEQ m_nextSeq; + AM_INSTALL_REQUEST m_requestCode; + AM_INSTALL_STATUS m_result; + unsigned int m_sendBufferLen; + unsigned int m_semid; + AM_INSTALL_SEQ m_seq; + pcpa_t m_pcp; + unsigned int Unk510; + unsigned short m_cmdPort; + unsigned short m_dataPort; + void* m_value; + void* Unk51c; +} AM_INSTALL; + +bool amInstallPcpaGetUlonglong(unsigned long long *dest, char *keyword); +bool amInstallPcpaGetInt(char *keyword, unsigned int *dest); + +AM_INSTALL_STATUS amInstallResponseCheckQueryBr(AM_INSTALL_BOOT_RECORD *bootRecord); + +AM_INSTALL_STATUS amInstallInit(void); +AM_INSTALL_STATUS amInstallUpdate(void); +AM_INSTALL_STATUS amInstallBusy(void); +AM_INSTALL_STATUS amInstallSendRequest(void); +AM_INSTALL_STATUS amInstallRecvResponse(void); +AM_INSTALL_STATUS amInstallCodeToStatus(void); +AM_INSTALL_STATUS amInstallResponseCheck(void); +AM_INSTALL_STATUS amInstallOpenBinary(void); +AM_INSTALL_STATUS amInstallOpenBinaryEx(void); +AM_INSTALL_STATUS amInstallSendBinaryBuffer(AM_INSTALL_BLOCKING blocking); +AM_INSTALL_STATUS amInstallExit(void); + +AM_INSTALL_STATUS amInstallSendAndReceiveEx(void); +AM_INSTALL_STATUS amInstallSendAndRecvEx(void); +AM_INSTALL_STATUS amInstallOpenEx(void); +AM_INSTALL_STATUS amInstallOpen(void); + +AM_INSTALL_STATUS amInstallGetBr(void *bootRecord, AM_INSTALL_BLOCKING blocking); +AM_INSTALL_STATUS amInstallGetResult(void); + +void amInstallGetAppdataStatus(void); +void amInstallGetApplicationStatus(void); +void amInstallGetSbrBootslot(void); +void amInstallGetSemaphore(void); +void amInstallGetSemaphoreStatus(void); +void amInstallGetSlotStatus(void); +void amInstallGetSpd(void); +void amInstallGetVolumeName(void); +void amInstallPcpAddCommandApplicationStatus(void); +void amInstallPcpAddCommandBootSlot(void); +void amInstallPcpAddCommandForce(void); +void amInstallPcpAddCommandInteger(void); +void amInstallPcpAddCommandSlot(void); +void amInstallPcpAddCommandSlotStatus(void); +void amInstallReleaseSemaphore(void); +void amInstallRequestCheck(void); +void amInstallRequestCheckAppdataInternal(void); +void amInstallRequestFormatAppdata(void); +void amInstallRequestInstall(void); +void amInstallRequestUninstall(void); +void amInstallSetApplicationStatusEx(void); +void amInstallSetSbrBootslot(void); +AM_INSTALL_STATUS amInstallTaskRequest(char*); +AM_INSTALL_STATUS amInstallSuicideSub(char*); diff --git a/src/micetools/lib/am/amJvs.h b/src/micetools/lib/am/amJvs.h new file mode 100644 index 0000000..517568d --- /dev/null +++ b/src/micetools/lib/am/amJvs.h @@ -0,0 +1,2 @@ +void amJvsInit(void); +void amJvsInitEx(void); diff --git a/src/micetools/lib/am/amJvsUpdate.h b/src/micetools/lib/am/amJvsUpdate.h new file mode 100644 index 0000000..1bb4153 --- /dev/null +++ b/src/micetools/lib/am/amJvsUpdate.h @@ -0,0 +1 @@ +void amJvsUpdate(void); diff --git a/src/micetools/lib/am/amJvsp.h b/src/micetools/lib/am/amJvsp.h new file mode 100644 index 0000000..fdbce1d --- /dev/null +++ b/src/micetools/lib/am/amJvsp.h @@ -0,0 +1,3 @@ +void amJvspAckSwInput(void); +void amJvspGetReport(void); +void amJvspMakeReportIndex(void); diff --git a/src/micetools/lib/am/amJvst.h b/src/micetools/lib/am/amJvst.h new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/lib/am/amJvstDriver.h b/src/micetools/lib/am/amJvstDriver.h new file mode 100644 index 0000000..0ef0db2 --- /dev/null +++ b/src/micetools/lib/am/amJvstDriver.h @@ -0,0 +1,3 @@ +void amJvstDriverExit(void); +void amJvstDriverSetup(void); +void amJvstDriverSetupComm(void); diff --git a/src/micetools/lib/am/amJvstThread.h b/src/micetools/lib/am/amJvstThread.h new file mode 100644 index 0000000..2b13c79 --- /dev/null +++ b/src/micetools/lib/am/amJvstThread.h @@ -0,0 +1 @@ +void amJvstThreadInit(void); diff --git a/src/micetools/lib/am/amLib.h b/src/micetools/lib/am/amLib.h new file mode 100644 index 0000000..39ef023 --- /dev/null +++ b/src/micetools/lib/am/amLib.h @@ -0,0 +1,2 @@ +void amLibSetErrorLog(void); +void amLibSetupErrorLogInfo(void); diff --git a/src/micetools/lib/am/amLog.h b/src/micetools/lib/am/amLog.h new file mode 100644 index 0000000..39b8fcf --- /dev/null +++ b/src/micetools/lib/am/amLog.h @@ -0,0 +1,2 @@ +void amLogInit(void); +void amLogSetEventOption(void); diff --git a/src/micetools/lib/am/amMacAddress.h b/src/micetools/lib/am/amMacAddress.h new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/lib/am/amMaster.h b/src/micetools/lib/am/amMaster.h new file mode 100644 index 0000000..65e3a7e --- /dev/null +++ b/src/micetools/lib/am/amMaster.h @@ -0,0 +1,27 @@ +void amMasterBusy(void); +void amMasterCheckResponse(void); +void amMasterEraseLog(void); +void amMasterExitA(void); +void amMasterExitW(void); +void amMasterGetBackupEventLogParam(void); +void amMasterGetCurrentProcess(void); +void amMasterGetFirstApplicationStart(void); +void amMasterGetNextProcessA(void); +void amMasterGetNextProcessW(void); +void amMasterGetProcessActivation(void); +void amMasterGetProcessCount(void); +void amMasterGetProcessFault(void); +void amMasterGetResult(void); +void amMasterInit(void); +void amMasterIsDevelop(void); +void amMasterOpen(void); +void amMasterOpenEx(void); +void amMasterOutputLog(void); +void amMasterReconnectUsbDevice(void); +void amMasterRecvResponse(void); +void amMasterSendAndRecvEx(void); +void amMasterSendRequest(void); +void amMasterSetBackupEventLogParam(void); +void amMasterSetNextProcessA(void); +void amMasterSetProcessActivation(void); +void amMasterUpdate(void); diff --git a/src/micetools/lib/am/amNetwork.h b/src/micetools/lib/am/amNetwork.h new file mode 100644 index 0000000..87b7f7a --- /dev/null +++ b/src/micetools/lib/am/amNetwork.h @@ -0,0 +1,15 @@ +void amNetworkBusy(void); +void amNetworkInit(void); +void amNetworkModifyPropertySub(void); +void amNetworkOpen(void); +void amNetworkOpenEx(void); +void amNetworkRecvResponse(void); +void amNetworkRequestDhcpStatusEth(void); +void amNetworkRequestMacAddressEth(void); +void amNetworkRequestModifyPropertyEth(void); +void amNetworkRequestPropertyEth(void); +void amNetworkRequestPropertySub(void); +void amNetworkResponseCheck(void); +void amNetworkSendAndRecvEx(void); +void amNetworkSendRequest(void); +void amNetworkSetCommandModifyProperty(void); diff --git a/src/micetools/lib/am/amOemstring.c b/src/micetools/lib/am/amOemstring.c new file mode 100644 index 0000000..ffee241 --- /dev/null +++ b/src/micetools/lib/am/amOemstring.c @@ -0,0 +1,190 @@ +#include "amOemstring.h" + +#include + +#include "../dmi/dmi.h" +#include "../mice/mice.h" + +AM_LIB_C_HEADER(amOemstring, AM_OEMSTRING) + +#define amOemstringScanStart 0xf0000 +#define amOemstringScanStep 0x7ff0 +#define amOemstringScanEnd 0xfffdf +void amiOemstringLocateDMITable(HANDLE hColumba, LPDWORD lpDmiBase, LPWORD lpDmiLength) { + AM_COLUMBA_REQUEST request; + char buffer[amOemstringScanStep + 24]; + + int scanAddr = amOemstringScanStart; + do { + request.m_physAddr.LowPart = scanAddr & 0xffffffff; + request.m_physAddr.HighPart = scanAddr >> 31; + request.m_elementSize = 1; + request.m_elementCount = sizeof buffer; + + DWORD bytesOut = 0; + BOOL ret = DeviceIoControl(hColumba, IOCTL_COLUMBA_READ, &request, sizeof request, buffer, + sizeof buffer, &bytesOut, NULL); + if (ret && bytesOut == sizeof buffer) { + LPBYTE pBuffer = (LPBYTE)&buffer; + for (int i = 0; i < (sizeof buffer) - 8; i++) { + if (memcmp(pBuffer, "_DMI_", 5) == 0) { + *lpDmiLength = *((LPWORD)(pBuffer + 6)); + *lpDmiBase = *((LPDWORD)(pBuffer + 8)); + return; + } + pBuffer++; + } + } + + scanAddr += amOemstringScanStep; + } while (scanAddr <= amOemstringScanEnd); +} + +void amiOemstringStoreString(BYTE type, int stringno, LPSTR string) { + if (type == DmiTypeBios) { + if (stringno == 1) + strncpy_s(amOemstring.m_biosVersion, sizeof amOemstring.m_biosVersion, string, 0xff); + if (stringno == 2) + strncpy_s(amOemstring.m_biosDate, sizeof amOemstring.m_biosDate, string, 0xff); + } else if (type == DmiTypeSystem) { + if (stringno == 0) + strncpy_s(amOemstring.m_systemManufacturer, sizeof amOemstring.m_systemManufacturer, + string, 0xff); + + } else if (type == DmiTypeString) { + if (stringno < 5) + strncpy_s(amOemstring.m_strings[stringno], sizeof amOemstring.m_strings[stringno], + string, 0xff); + } +} + +BOOL amiOemstringLoadStrings(void) { + if (amOemstring.m_loaded) return TRUE; + ZeroMemory(&amOemstring, sizeof amOemstring); + + BYTE buffer[0x10000]; + + HANDLE hColumba = CreateFileW(L"\\\\.\\columba", GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + if (hColumba == INVALID_HANDLE_VALUE) return FALSE; + + DWORD me = 0; + + DWORD dmiBase = 0; + WORD dmiLength = 0; + + amiOemstringLocateDMITable(hColumba, &dmiBase, &dmiLength); + if (dmiBase == 0) return FALSE; + + AM_COLUMBA_REQUEST request; + request.m_physAddr.QuadPart = dmiBase; + request.m_elementSize = 1; + + if (dmiBase + 0x10000 < 0x100001) { + request.m_elementCount = 0x10000; + } else { + request.m_elementCount = 0x100000 - dmiBase; + } + + DWORD nBytesReturned; + if (!DeviceIoControl(hColumba, IOCTL_COLUMBA_READ, &request, sizeof request, buffer, + sizeof buffer, &nBytesReturned, NULL)) { + return FALSE; + } + + if (nBytesReturned != 0x10000) return FALSE; + + BYTE type_seen[128] = { 0 }; + + LPBYTE pBuffer = (LPBYTE)&buffer; + while (1) { + DMI_SECTION_HEADER* header = (DMI_SECTION_HEADER*)pBuffer; + if (header->Length == 0) break; + // Avoid reading outside the DMI tables + if ((pBuffer - (LPBYTE)&buffer) + header->Length >= dmiLength) break; + // Avoid reading outside the buffer! + if ((pBuffer - (LPBYTE)&buffer) + header->Length >= sizeof buffer) break; + + BYTE type = header->Type; + pBuffer += header->Length; + + int stringno = 0; + do { + if (!type_seen[type]) amiOemstringStoreString(type, stringno, (LPSTR)pBuffer); + stringno++; + + while (pBuffer[0] != '\0') pBuffer++; + pBuffer++; + } while (pBuffer[0] != '\0'); + pBuffer++; + + if (type < sizeof type_seen) type_seen[type] = 1; + } + + amOemstring.m_loaded = TRUE; + CloseHandle(hColumba); + return TRUE; +} + +AM_OEMSTRING_STATUS amOemstringGetManufacturer(LPSTR manufacturer) { + if (manufacturer == NULL) return AM_OEMSTRING_STATUS_ERR_INVALID_PARAM; + if (amiOemstringLoadStrings() == 0) { + manufacturer[0] = '\0'; + return AM_OEMSTRING_STATUS_ERR_SYS; + } + strncpy_s(manufacturer, sizeof amOemstring.m_systemManufacturer, + amOemstring.m_systemManufacturer, 0xffffffff); + return AM_OEMSTRING_STATUS_OK; +} + +AM_OEMSTRING_STATUS amOemstringGetSBiosVer(LPSTR biosVersion) { + if (biosVersion == NULL) return AM_OEMSTRING_STATUS_ERR_INVALID_PARAM; + if (amiOemstringLoadStrings() == 0) { + biosVersion[0] = '\0'; + return AM_OEMSTRING_STATUS_ERR_SYS; + } + strncpy_s(biosVersion, sizeof amOemstring.m_biosVersion, amOemstring.m_biosVersion, 0xffffffff); + return AM_OEMSTRING_STATUS_OK; +} + +AM_OEMSTRING_STATUS amOemstringGetSBiosReleaseDate(LPSTR biosDate) { + if (biosDate == NULL) return AM_OEMSTRING_STATUS_ERR_INVALID_PARAM; + if (amiOemstringLoadStrings() == 0) { + biosDate[0] = '\0'; + return AM_OEMSTRING_STATUS_ERR_SYS; + } + strncpy_s(biosDate, sizeof amOemstring.m_biosDate, amOemstring.m_biosDate, 0xffffffff); + return AM_OEMSTRING_STATUS_OK; +} + +AM_OEMSTRING_STATUS amOemstringGetOemstring(LPSTR oemstring, int which) { + LPSTR sVal; + + if (oemstring == NULL) return AM_OEMSTRING_STATUS_ERR_INVALID_PARAM; + + switch (which) { + case 0: + sVal = amOemstring.m_strings[0]; + break; + case 1: + sVal = amOemstring.m_strings[1]; + break; + case 2: + sVal = amOemstring.m_strings[2]; + break; + case 3: + sVal = amOemstring.m_strings[3]; + break; + case 4: + sVal = amOemstring.m_strings[4]; + break; + default: + sVal = NULL; + } + + oemstring[0] = '\0'; + if (sVal == NULL) return AM_OEMSTRING_STATUS_ERR_INVALID_PARAM; + if (amiOemstringLoadStrings() == 0) return AM_OEMSTRING_STATUS_ERR_SYS; + strncpy_s(oemstring, sizeof amOemstring.m_strings[0], sVal, 0xffffffff); + return AM_OEMSTRING_STATUS_OK; +} diff --git a/src/micetools/lib/am/amOemstring.h b/src/micetools/lib/am/amOemstring.h new file mode 100644 index 0000000..0a04288 --- /dev/null +++ b/src/micetools/lib/am/amOemstring.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "../_am.h" + +AM_LIB_H_HEADER(amOemstring, AM_OEMSTRING) + +// Much easier than pulling in winddk.h +typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; +typedef struct { + PHYSICAL_ADDRESS m_physAddr; + DWORD m_elementSize; + DWORD m_elementCount; +} AM_COLUMBA_REQUEST; + +typedef struct _AM_OEMSTRING { + BOOL m_loaded; + CHAR m_biosVersion[32]; + CHAR m_biosDate[11]; + CHAR m_systemManufacturer[32]; + CHAR m_strings[5][32]; +} AM_OEMSTRING; + + +typedef enum { + AM_OEMSTRING_STATUS_OK = 0, + AM_OEMSTRING_STATUS_NG = -1, + AM_OEMSTRING_STATUS_ERR_INVALID_PARAM = -2, + AM_OEMSTRING_STATUS_ERR_SYS = -3, +} AM_OEMSTRING_STATUS; + + +void amiOemstringLocateDMITable(HANDLE hColumba, LPDWORD lpDmiBase, LPWORD lpDmiLength); +void amiOemstringStoreString(BYTE type, int stringno, LPSTR string); +BOOL amiOemstringLoadStrings(void); + +AM_OEMSTRING_STATUS amOemstringGetManufacturer(LPSTR manufacturer); +AM_OEMSTRING_STATUS amOemstringGetOemstring(LPSTR oemstring, int which); +AM_OEMSTRING_STATUS amOemstringGetSBiosVer(LPSTR biosVersion); +AM_OEMSTRING_STATUS amOemstringGetSBiosReleaseDate(LPSTR biosDate); diff --git a/src/micetools/lib/am/amPlatform.c b/src/micetools/lib/am/amPlatform.c new file mode 100644 index 0000000..41320d6 --- /dev/null +++ b/src/micetools/lib/am/amPlatform.c @@ -0,0 +1,239 @@ +#include "amPlatform.h" + +#include "../ami/amiDebug.h" +#include "amEeprom.h" +#include "amOemstring.h" +#include "amSram.h" + +AM_LIB_C_HEADER(amPlatform, AM_PLATFORM) + +#define _amEepromRead (amPlatformRead_t *)&amEepromRead +#define _amEepromWrite (amPlatformWrite_t *)&amEepromWrite +#define _amSramRead (amPlatformRead_t *)&amSramRead +#define _amSramWrite (amPlatformWrite_t *)&amSramWrite + +AM_PLATFORM_NV_DEVICE_CONFIG amPlatformNvDevices[3][4] = { + // RingEdge 1 + { + { + .m_base = 0x0, + .m_size = 0x1000, + .m_blockSize = 1, + .m_read = _amEepromRead, + .m_write = _amEepromWrite, + }, + { + .m_base = 0x1000, + .m_size = 0x1000, + .m_blockSize = 1, + .m_read = _amEepromRead, + .m_write = _amEepromWrite, + }, + { + .m_base = 0, + .m_size = 0x4000, + .m_blockSize = 512, + .m_read = _amSramRead, + .m_write = _amSramWrite, + }, + { + .m_base = 0x4000, + .m_size = 0x1FC000, + .m_blockSize = 512, + .m_read = _amSramRead, + .m_write = _amSramWrite, + }, + }, + // RingEdge 2 + { + { + .m_base = 0x0, + .m_size = 0x1000, + .m_blockSize = 1, + .m_read = _amEepromRead, + .m_write = _amEepromWrite, + }, + { + .m_base = 0x1000, + .m_size = 0x1000, + .m_blockSize = 1, + .m_read = _amEepromRead, + .m_write = _amEepromWrite, + }, + { + .m_base = 0, + .m_size = 0x4000, + .m_blockSize = 4, + .m_read = _amSramRead, + .m_write = _amSramWrite, + }, + { + .m_base = 0x4000, + .m_size = 0x1FC000, + .m_blockSize = 4, + .m_read = _amSramRead, + .m_write = _amSramWrite, + }, + }, + // RingWide + { + { + .m_base = 0x0, + .m_size = 0x1000, + .m_blockSize = 1, + .m_read = _amEepromRead, + .m_write = _amEepromWrite, + }, + { + .m_base = 0x1000, + .m_size = 0x1000, + .m_blockSize = 1, + .m_read = _amEepromRead, + .m_write = _amEepromWrite, + }, + { + .m_base = 0, + .m_size = 0x4000, + .m_blockSize = 512, + .m_read = _amSramRead, + .m_write = _amSramWrite, + }, + { + .m_base = 0x4000, + .m_size = 0x3C000, + .m_blockSize = 512, + .m_read = _amSramRead, + .m_write = _amSramWrite, + }, + }, +}; + +AM_PLATFORM_NV_DEVICE_CONFIG *amPlatformGetNvDevice(AM_PLATFORM_NV_DEVICE device) { + if (device > 0 && device < _NUM_AM_PLATFORM_NV_DEVICE) { + AM_PLATFORM_BOARD_TYPE boardType; + amPlatformGetBoardType(&boardType); + switch (boardType) { + case AM_PLATFORM_BOARD_TYPE_RINGEDGE: + return &(amPlatformNvDevices[0][device]); + case AM_PLATFORM_BOARD_TYPE_RW_SPEC_1: + case AM_PLATFORM_BOARD_TYPE_RW_SPEC_2: + return &(amPlatformNvDevices[2][device]); + case AM_PLATFORM_BOARD_TYPE_RINGEDGE2: + return &(amPlatformNvDevices[1][device]); + } + } + return NULL; +} + +AM_PLATFORM_STATUS amPlatformGetPlatformId(AM_PLATFORM_PLATFORM_ID *platformId) { + if (platformId == NULL) { + if (amPlatformDebugLevel > 0) amiDebugLog("PARAM Error!!"); + return AM_PLATFORM_STATUS_ERR_INVALID_PARAM; + } + + char oemstringPlatform[32]; + char oemstringManufacturer[32]; + + /** + * If platform starts with "AAM" (RW) or "AAL" (RE): + * copy it into m_platformId verbatim + * Otherwise + * fetch the manufacturer name + * If manufacturer is "NEC" + * m_platformId = "AAL" (RE) + * If manufacturer if "Supermicro" or "Advantech" + * m_platformId = "AAM" (RW) + */ + + if (!amPlatform.m_platformIdCached) { + if (amOemstringGetOemstring(oemstringPlatform, 2) != AM_OEMSTRING_STATUS_OK) { + if (amPlatformDebugLevel > 0) + amiDebugLog("amOemstringGetOemstring Error!! (%d)", + AM_PLATFORM_STATUS_ERR_SYS); + return AM_PLATFORM_STATUS_ERR_SYS; + } + + if (strcmp(oemstringPlatform, PLATFORM_RINGEDGE) == 0 || + strcmp(oemstringPlatform, PLATFORM_RINGWIDE) == 0) { + strncpy_s(amPlatform.m_platformId.strPlatformId, + sizeof amPlatform.m_platformId.strPlatformId, oemstringPlatform, 0xffffffff); + } else if (amOemstringGetManufacturer(oemstringManufacturer) == AM_OEMSTRING_STATUS_OK) { + if (strcmp(oemstringManufacturer, "NEC") == 0) { + strncpy_s(amPlatform.m_platformId.strPlatformId, + sizeof amPlatform.m_platformId.strPlatformId, PLATFORM_RINGEDGE, + 0xffffffff); + } else if (strcmp(oemstringManufacturer, "Supermicro") == 0 || + strcmp(oemstringManufacturer, "Advantech") == 0) { + strncpy_s(amPlatform.m_platformId.strPlatformId, + sizeof amPlatform.m_platformId.strPlatformId, PLATFORM_RINGWIDE, + 0xffffffff); + } + } + amPlatform.m_platformIdCached = TRUE; + } + + memcpy(platformId->strPlatformId, amPlatform.m_platformId.strPlatformId, + sizeof amPlatform.m_platformId.strPlatformId); + return amPlatform.m_platformIdCached ? AM_PLATFORM_STATUS_OK : AM_PLATFORM_STATUS_ERR_SYS; +} + +AM_PLATFORM_STATUS amPlatformGetBoardType(AM_PLATFORM_BOARD_TYPE *boardType) { + AM_PLATFORM_PLATFORM_ID platformId; + char oemstring4[32]; + char oemstringManufacturer[32]; + + if (boardType == NULL) { + if (amPlatformDebugLevel > 0) amiDebugLog("PARAM Error!!"); + return AM_PLATFORM_STATUS_ERR_INVALID_PARAM; + } + + if (amPlatform.m_boardTypeCached) { + *boardType = amPlatform.m_boardType; + return AM_PLATFORM_STATUS_OK; + } + if (amPlatformGetPlatformId(&platformId) != AM_PLATFORM_STATUS_OK || + amOemstringGetManufacturer(oemstringManufacturer) != AM_OEMSTRING_STATUS_OK) { + *boardType = amPlatform.m_boardType; + return AM_PLATFORM_STATUS_ERR_SYS; + } + + if (strcmp(platformId.strPlatformId, PLATFORM_RINGWIDE) == 0) { + if (strcmp(oemstringManufacturer, "Supermicro") == 0) { + *boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_RW_SPEC_1; + } else if (strcmp(oemstringManufacturer, "Advantech") == 0) { + *boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_RW_SPEC_2; + } else { + *boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_UNKNOWN; + } + + amPlatform.m_boardTypeCached = TRUE; + return AM_PLATFORM_STATUS_OK; + } + + if (strcmp(platformId.strPlatformId, PLATFORM_RINGEDGE) == 0) { + if (strcmp(oemstringManufacturer, "NEC") == 0) { + ZeroMemory(oemstring4, sizeof oemstring4); + + if (amOemstringGetOemstring(oemstring4, 4) != AM_OEMSTRING_STATUS_OK) { + *boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_UNKNOWN; + return AM_PLATFORM_STATUS_ERR_SYS; + } + + if (strcmp(oemstring4, PLATFORM_RINGEDGE2) == 0) { + *boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_RINGEDGE2; + amPlatform.m_boardTypeCached = TRUE; + return AM_PLATFORM_STATUS_OK; + } + + if (strcmp(oemstring4, "") == 0 || strcmp(oemstring4, " ") == 0) { + *boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_RINGEDGE; + amPlatform.m_boardTypeCached = TRUE; + return AM_PLATFORM_STATUS_OK; + } + } + } + + *boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_UNKNOWN; + amPlatform.m_boardTypeCached = TRUE; + return AM_PLATFORM_STATUS_OK; +} diff --git a/src/micetools/lib/am/amPlatform.h b/src/micetools/lib/am/amPlatform.h new file mode 100644 index 0000000..e30d74a --- /dev/null +++ b/src/micetools/lib/am/amPlatform.h @@ -0,0 +1,112 @@ +#pragma once + +#include + +#include "../_am.h" + +AM_LIB_H_HEADER(amPlatform, AM_PLATFORM) + +#define PLATFORM_RINGWIDE "AAM" +#define PLATFORM_RINGEDGE "AAL" +#define PLATFORM_RINGEDGE2 "AAL2" // Also AAS in places + +typedef struct { + char strPlatformId[4]; +} AM_PLATFORM_PLATFORM_ID; + +typedef enum { + AM_PLATFORM_BOARD_TYPE_RINGEDGE = 0, + AM_PLATFORM_BOARD_TYPE_RW_SPEC_1 = 1, // Supermicro + AM_PLATFORM_BOARD_TYPE_RW_SPEC_2 = 2, // Advantech + AM_PLATFORM_BOARD_TYPE_RINGEDGE2 = 3, + AM_PLATFORM_BOARD_TYPE_UNKNOWN = 4, +} AM_PLATFORM_BOARD_TYPE; + +typedef struct _AM_PLATFORM { + BOOL m_boardTypeCached; + AM_PLATFORM_BOARD_TYPE m_boardType; + BOOL m_platformIdCached; + AM_PLATFORM_PLATFORM_ID m_platformId; +} AM_PLATFORM; + +typedef struct { + char strVendorId[5]; + char strDeviceId[5]; + char strSubId[9]; +} AM_PLATFORM_ID_GROUP; + +typedef enum { + AM_PLATFORM_STATUS_OK = 0, + AM_PLATFORM_STATUS_NO_INFO = 1, + AM_PLATFORM_STATUS_BUSY = 2, + AM_PLATFORM_STATUS_NG = -1, + AM_PLATFORM_STATUS_ERR_INVALID_PARAM = -2, + AM_PLATFORM_STATUS_ERR_SYS = -3, + AM_PLATFORM_STATUS_ERR_NO_OPEN = -4, + AM_PLATFORM_STATUS_ERR_ALREADY_OPEN = -5, + AM_PLATFORM_STATUS_ERR_NO_REQUEST = -6, + AM_PLATFORM_STATUS_ERR_ALREADY_REQUEST = -7, + AM_PLATFORM_STATUS_ERR_BUFF_SIZE = -8, + AM_PLATFORM_STATUS_ERR_NO_INIT = -9, + AM_PLATFORM_STATUS_ERR_ALREADY_INIT = -10, + AM_PLATFORM_STATUS_NOT_SUPPORT = -11, +} AM_PLATFORM_STATUS; + +typedef enum { + AM_PLATFORM_NV_DEVICE_EEPROM = 0, + AM_PLATFORM_NV_DEVICE_EEPROM_DUP = 1, + AM_PLATFORM_NV_DEVICE_SRAM = 2, + AM_PLATFORM_NV_DEVICE_SRAM_DUP = 3, + _NUM_AM_PLATFORM_NV_DEVICE, +} AM_PLATFORM_NV_DEVICE; + +typedef int(amPlatformRead_t)(WORD addr, LPBYTE buf, DWORD length); +typedef int(amPlatformWrite_t)(WORD addr, LPBYTE buf, DWORD length); + +typedef struct { + DWORD m_base; + DWORD m_size; + DWORD m_blockSize; + amPlatformRead_t* m_read; + amPlatformWrite_t* m_write; +} AM_PLATFORM_NV_DEVICE_CONFIG; + +AM_PLATFORM_NV_DEVICE_CONFIG* amPlatformGetNvDevice(AM_PLATFORM_NV_DEVICE device); + +AM_PLATFORM_STATUS amPlatformGetBoardType(AM_PLATFORM_BOARD_TYPE* boardType); +AM_PLATFORM_STATUS amPlatformGetPlatformId(AM_PLATFORM_PLATFORM_ID* platformId); + +// TODO: + +void amPlatformAsyncClose(void); +void amPlatformAsyncReqUsbDeviceCount(void); +void amPlatformAsyncResUsbDeviceCount(void); +void amPlatformChangeDisplayModeAmd(void); +void amPlatformChangeDisplayModeNvidia(void); +void amPlatformChangeDisplayModeNvidiaEx(void); +void amPlatformChangeDisplayResolutionAmd(void); +void amPlatformChangeDisplayResolutionNvidia(void); +void amPlatformChangeDisplayResolutionNvidiaEx(void); +void amPlatformChangeDisplayResolutionWinAPI(void); +void amPlatformDestroyCheckInterfaceHandle(void); +void amPlatformGetAvailableAmdDriver(void); +void amPlatformGetAvailableNvidiaDriver(void); +void amPlatformGetBiosInfo(void); +void amPlatformGetCheckInterfaceHandle(void); +void amPlatformGetComInfo(void); +void amPlatformGetDevInfo(void); +void amPlatformGetGpuPstate(void); +void amPlatformGetGraphicInfo(void); +void amPlatformGetMemorySize(void); +void amPlatformGetOsVersion(void); +void amPlatformGetOsVersion(void); +void amPlatformGetPartitionInfo(void); +void amPlatformGetPlatformIdEx(void); +void amPlatformGetPortName(void); +void amPlatformGetSearchDevInfo(void); +void amPlatformGetSoundInfo(void); +void amPlatformGetStorageInfo(void); +void amPlatformNvapiInit(void); +void amPlatformSetDisplayMode(void); +void amPlatformSetDisplayResolution(void); +void amPlatformSetDisplayResolutionAndMode(void); \ No newline at end of file diff --git a/src/micetools/lib/am/amRtc.h b/src/micetools/lib/am/amRtc.h new file mode 100644 index 0000000..927de45 --- /dev/null +++ b/src/micetools/lib/am/amRtc.h @@ -0,0 +1,10 @@ +void amRtcConvertStructToTimet(void); +void amRtcConvertSystemToTimet(void); +void amRtcConvertTimetToStruct(void); +void amRtcConvertTimetToSystem(void); +void amRtcFinalize(void); +void amRtcGetServerTime(void); +void amRtcInit(void); +void amRtcSetClockAndTimeZone(void); +void amRtcSetSysClockSetting(void); +void amRtcStartupTimeZone(void); diff --git a/src/micetools/lib/am/amSerialId.c b/src/micetools/lib/am/amSerialId.c new file mode 100644 index 0000000..5c86a1c --- /dev/null +++ b/src/micetools/lib/am/amSerialId.c @@ -0,0 +1,37 @@ +#include "amSerialId.h" + +AM_LIB_C_HEADER(amSerialId, AM_SERIAL_ID) + +BOOL amSerialIdIsValid(char *id_string) { + if (id_string == NULL) return FALSE; + + for (int i = 0; i < 15; i++) { + char chr = id_string[i]; + + if (chr == '\0') return FALSE; + if (chr > 0x7f) return FALSE; + + if (i == 4) { + if (chr != '-') return FALSE; + } else if (i < 8 || i > 15) { + if (!isdigit(chr) && !isupper(chr)) return FALSE; + + if (chr == 'I') return FALSE; + + if (chr == 'O') return FALSE; + } else { + if (!isdigit(chr)) return FALSE; + } + } + return id_string[16] == '\0'; +} + +BOOL amSerialIdConvert(char *id_string, char *serial_id) { + if (id_string == NULL || serial_id == NULL) return FALSE; + if (!amSerialIdIsValid(id_string)) return FALSE; + + ZeroMemory(serial_id, 12); + memcpy_s(serial_id, 17, id_string, 4); + memcpy_s(serial_id + 4, 13, id_string + 5, 7); + return TRUE; +} \ No newline at end of file diff --git a/src/micetools/lib/am/amSerialId.h b/src/micetools/lib/am/amSerialId.h new file mode 100644 index 0000000..bcb243e --- /dev/null +++ b/src/micetools/lib/am/amSerialId.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include "../_am.h" + +AM_LIB_H_HEADER(amSerialId, AM_SERIAL_ID) + +typedef struct _AM_SERIAL_ID { + unsigned char Rsv00; +} AM_SERIAL_ID; + +BOOL amSerialIdIsValid(char *id_string); +BOOL amSerialIdConvert(char *id_string, char *serial_id); diff --git a/src/micetools/lib/am/amSram.c b/src/micetools/lib/am/amSram.c new file mode 100644 index 0000000..97d3913 --- /dev/null +++ b/src/micetools/lib/am/amSram.c @@ -0,0 +1,298 @@ +#include "amSram.h" + +#include "../ami/ami.h" +#include "../mice/ioctl.h" + +AM_LIB_C_HEADER(amSram, AM_SRAM) + +AM_SRAM_STATUS amSramCreateMutex(AM_SRAM *device) { + SECURITY_ATTRIBUTES muxAttrs; + SECURITY_DESCRIPTOR securityDescriptor; + SID_IDENTIFIER_AUTHORITY idAuth; + + PSID *pSid = &device->m_sid; + idAuth.Value[0] = 0; + idAuth.Value[1] = 0; + idAuth.Value[2] = 0; + idAuth.Value[3] = 0; + idAuth.Value[4] = 0; + idAuth.Value[5] = 1; + + if (!AllocateAndInitializeSid(&idAuth, '\x01', 0, 0, 0, 0, 0, 0, 0, 0, pSid)) { + if (amSramDebugLevel > 0) + amiDebugLog("AllocateAndInitializeSid Error in amSramInit."); + *pSid = NULL; + goto amSramCreateMutexError; + } + + if (!InitializeSecurityDescriptor(&securityDescriptor, 1)) { + if (amSramDebugLevel > 0) + amiDebugLog("InitializeSecurityDescriptor Error in amSramInit."); + goto amSramCreateMutexError; + } + + if (!SetSecurityDescriptorDacl(&securityDescriptor, TRUE, NULL, FALSE)) { + if (amSramDebugLevel > 0) { + amiDebugLog("amSramCreateMutex", 0x43a, + "SetSecurityDescriptorDacl Error in amSramInit.\n"); + } + goto amSramCreateMutexError; + } + + muxAttrs.lpSecurityDescriptor = &securityDescriptor; + muxAttrs.nLength = 12; + muxAttrs.bInheritHandle = FALSE; + if ((device->m_mutex = CreateMutexA(&muxAttrs, FALSE, "Global\\AM_SRAM_MUTEX")) != NULL) { + return AM_SRAM_STATUS_OK; + } + + if (amSramDebugLevel > 0) amiDebugLog("CreateMutexA Error(%ld).", GetLastError()); + +amSramCreateMutexError: + if (device->m_mutex != NULL) { + CloseHandle(device->m_mutex); + device->m_mutex = NULL; + } + if (*pSid != NULL) { + FreeSid(*pSid); + *pSid = NULL; + } + return AM_SRAM_STATUS_ERR_SYS; +} + +AM_SRAM_STATUS amSramInit(void) { + if (amSram.m_init) return AM_SRAM_STATUS_ERR_ALREADY_INIT; + + amSram.m_readTimeout = -1; + amSram.m_writeTimeout = -1; + amSram.Unk20 = -1; + + AM_SRAM_STATUS status = amSramCreateMutex(&amSram); + if (status != AM_SRAM_STATUS_OK) { + if (amSramDebugLevel > 0) + amiDebugLog("amSramCreateMutex Error!! Error Code is %ld!!", status); + goto amSramInitErrorSys; + } + + amSram.m_handle = CreateFileW(L"\\\\.\\mxsram", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_SUPPORTS_REPARSE_POINTS, NULL); + if (amSram.m_handle == INVALID_HANDLE_VALUE) { + if (amSramDebugLevel > 0) + amiDebugLog("CreateFileW Error!! Error Code is %ld!!", GetLastError()); + goto amSramInitErrorSys; + } + + DWORD bytesReturned; + DWORD version; + BOOL s = DeviceIoControl(amSram.m_handle, IOCTL_MXSRAM_PING, NULL, 0, &version, sizeof version, + &bytesReturned, NULL); + if (!s || bytesReturned != sizeof version) { + if (amSramDebugLevel > 0) + amiDebugLog("DeviceIoControl Error!! Error Code is %ld!!", GetLastError()); + goto amSramInitErrorSys; + } + + if ((version & 0xffff) != 1) { + if (amSramDebugLevel > 0) { + amiDebugLog( + "Sram Driver Protocol Mismatched. Detected Driver Version " + ": 0x%08lx. Pl ease Update Sram Driver or User Program.\n", + version); + } + goto amSramInitErrorSys; + } + + DISK_GEOMETRY driveGeometry; + s = DeviceIoControl(amSram.m_handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveGeometry, + sizeof driveGeometry, &bytesReturned, NULL); + if (!s || bytesReturned != sizeof driveGeometry) { + if (amSramDebugLevel > 0) + amiDebugLog("DeviceIoControl Error!! Error Code is %ld!!", GetLastError()); + goto amSramInitErrorSys; + } + + amSram.m_sectorSize = driveGeometry.BytesPerSector; + amSram.m_size.QuadPart = driveGeometry.Cylinders.QuadPart * driveGeometry.TracksPerCylinder * + driveGeometry.SectorsPerTrack * driveGeometry.BytesPerSector; + if (amSram.m_size.QuadPart == 0) { + if (amSramDebugLevel > 0) amiDebugLog("Get Sram Size Error!!"); + goto amSramInitErrorSys; + } + + DWORD sectorSize; + s = DeviceIoControl(amSram.m_handle, IOCTL_MXSRAM_GET_SECTOR_SIZE, NULL, 0, §orSize, + sizeof sectorSize, &bytesReturned, NULL); + if (s) { + if (bytesReturned != sizeof sectorSize) { + if (amSramDebugLevel > 0) + amiDebugLog("DeviceIoControl Error!! Error Code is %ld!!", GetLastError()); + goto amSramInitErrorSys; + } + amSram.m_sectorSize = sectorSize; + } + + if (amSram.m_sectorSize <= AM_SRAM_MAX_SECTOR_SIZE) { + amSram.m_init = TRUE; + return AM_SRAM_STATUS_OK; + } + + if (amSramDebugLevel) + amiDebugLog("Internal Error. sector size(%d)is too large.", amSram.m_sectorSize); + goto amSramInitErrorSys; + +amSramInitErrorSys: + amSram.m_init = TRUE; + amSramExit(); + return AM_SRAM_STATUS_ERR_SYS; +} + +AM_SRAM_STATUS amSramExit(void) { + if (!amSram.m_init) { + if (amSramDebugLevel > 0) amiDebugLog("No Init Error!!"); + return AM_SRAM_STATUS_ERR_NO_INIT; + } + + if (amSram.m_handle != INVALID_HANDLE_VALUE) { + CloseHandle(amSram.m_handle); + amSram.m_handle = INVALID_HANDLE_VALUE; + } + if (amSram.m_mutex != NULL) { + CloseHandle(amSram.m_mutex); + amSram.m_mutex = NULL; + } + if (amSram.m_sid != NULL) { + FreeSid(amSram.m_sid); + amSram.m_sid = NULL; + } + amSram.m_init = FALSE; + return AM_SRAM_STATUS_OK; +} + +AM_SRAM_STATUS amSramReadInternal(AM_SRAM *device, LONG addressLow, LONG addressHigh, LPVOID buffer, + DWORD nBytes) { + if (SetFilePointer(device->m_handle, addressLow, &addressHigh, 0) == INVALID_SET_FILE_POINTER) { + DWORD lastErr = GetLastError(); + if (lastErr != 0) { + if (amSramDebugLevel > 0) amiDebugLog("SetFilePointer Error(%d).", lastErr); + + return AM_SRAM_STATUS_ERR_SYS; + } + } + + DWORD bytesRead; + BOOL s = ReadFile(device->m_handle, buffer, nBytes, &bytesRead, NULL); + if (!s || nBytes != bytesRead) { + if (amSramDebugLevel > 0) amiDebugLog("ReadFile Error(%d).", GetLastError()); + return AM_SRAM_STATUS_ERR_READ; + } + + return AM_SRAM_STATUS_OK; +} + +AM_SRAM_STATUS amSramWriteInternal(AM_SRAM *device, LONG addressLow, LONG addressHigh, + LPCVOID buffer, DWORD nBytes) { + if (SetFilePointer(device->m_handle, addressLow, &addressHigh, 0) == INVALID_SET_FILE_POINTER) { + DWORD lastErr = GetLastError(); + if (lastErr != 0) { + if (amSramDebugLevel > 0) amiDebugLog("SetFilePointer Error(%d).", lastErr); + + return AM_SRAM_STATUS_ERR_SYS; + } + } + + DWORD bytesRead; + BOOL s = WriteFile(device->m_handle, buffer, nBytes, &bytesRead, NULL); + if (!s || nBytes != bytesRead) { + if (amSramDebugLevel > 0) amiDebugLog("WriteFile Error(%d).", GetLastError()); + return AM_SRAM_STATUS_ERR_WRITE; + } + + return AM_SRAM_STATUS_OK; +} + +AM_SRAM_STATUS amSramRead(DWORD src, LPVOID pDst, DWORD size) { + if (!amSram.m_init) { + if (amSramDebugLevel > 0) amiDebugLog("Not initialized."); + return AM_SRAM_STATUS_ERR_NO_INIT; + } + + if (pDst == NULL || !size || size % amSram.m_sectorSize || src % amSram.m_sectorSize) { + if (amSramDebugLevel > 0) + amiDebugLog("Illegal parameter(s). Src=0x%08x pDst=0x%p Size=0x%08x", src, pDst, + size); + return AM_SRAM_STATUS_ERR_INVALID_PARAM; + } + + if (src > amSram.m_size.QuadPart - amSram.m_sectorSize || src + size > amSram.m_size.QuadPart) { + if (amSramDebugLevel > 0) + amiDebugLog("Address range is invalid. Src=0x%08x Size=0x%08x", src, size); + + return AM_SRAM_STATUS_ERR_DOMAIN; + } + + DWORD err = WaitForSingleObject(amSram.m_mutex, amSram.m_readTimeout); + if (err == WAIT_FAILED) { + if (amSramDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld).", GetLastError()); + return AM_SRAM_STATUS_ERR_SYS; + } + if (err == WAIT_TIMEOUT) return AM_SRAM_STATUS_ERR_GET_MUTEX; + + if (!(err == WAIT_OBJECT_0 || err == WAIT_ABANDONED)) { + if (amSramDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld). Return Value is %d.", GetLastError(), + err); + return AM_SRAM_STATUS_ERR_SYS; + } + + AM_SRAM_STATUS status = amSramReadInternal(&amSram, src, 0, pDst, size); + if (!ReleaseMutex(amSram.m_mutex)) { + if (amSramDebugLevel > 0) amiDebugLog("ReleaseMutex Error(%ld).", GetLastError()); + return AM_SRAM_STATUS_ERR_SYS; + } + return status; +} + +AM_SRAM_STATUS amSramWrite(LPCVOID pSrc, DWORD dst, DWORD size) { + if (!amSram.m_init) { + if (amSramDebugLevel > 0) amiDebugLog("Not initialized."); + return AM_SRAM_STATUS_ERR_NO_INIT; + } + + if (pSrc == NULL || !size || size % amSram.m_sectorSize || dst % amSram.m_sectorSize) { + if (amSramDebugLevel > 0) + amiDebugLog("Illegal parameter(s). pSrc=0x%p Dst=0x%08x Size=0x%08x", pSrc, dst, + size); + return AM_SRAM_STATUS_ERR_INVALID_PARAM; + } + + if (dst > amSram.m_size.QuadPart - amSram.m_sectorSize || dst + size > amSram.m_size.QuadPart) { + if (amSramDebugLevel > 0) + amiDebugLog("Address range is invalid. Dst=0x%08x Size=0x%08x", dst, size); + + return AM_SRAM_STATUS_ERR_DOMAIN; + } + + DWORD err = WaitForSingleObject(amSram.m_mutex, amSram.m_readTimeout); + if (err == WAIT_FAILED) { + if (amSramDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld).", GetLastError()); + return AM_SRAM_STATUS_ERR_SYS; + } + if (err == WAIT_TIMEOUT) return AM_SRAM_STATUS_ERR_GET_MUTEX; + + if (!(err == WAIT_OBJECT_0 || err == WAIT_ABANDONED)) { + if (amSramDebugLevel > 0) + amiDebugLog("WaitForSingleObject Error(%ld). Return Value is %d.", GetLastError(), + err); + return AM_SRAM_STATUS_ERR_SYS; + } + + AM_SRAM_STATUS status = amSramWriteInternal(&amSram, dst, 0, pSrc, size); + if (!ReleaseMutex(amSram.m_mutex)) { + if (amSramDebugLevel > 0) amiDebugLog("ReleaseMutex Error(%ld).", GetLastError()); + return AM_SRAM_STATUS_ERR_SYS; + } + return status; +} diff --git a/src/micetools/lib/am/amSram.h b/src/micetools/lib/am/amSram.h new file mode 100644 index 0000000..7b6e6a3 --- /dev/null +++ b/src/micetools/lib/am/amSram.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include "../_am.h" + +AM_LIB_H_HEADER(amSram, AM_SRAM) + +typedef struct _AM_SRAM { + DWORD m_init; + HANDLE m_handle; + LARGE_INTEGER m_size; + DWORD m_sectorSize; + HANDLE m_mutex; + int m_readTimeout; + int m_writeTimeout; + int Unk20; + PSID m_sid; +} AM_SRAM; + +typedef enum { + AM_SRAM_STATUS_OK = 0, + AM_SRAM_STATUS_NG = -1, + AM_SRAM_STATUS_ERR_INVALID_PARAM = -2, + AM_SRAM_STATUS_ERR_NO_INIT = -3, + AM_SRAM_STATUS_ERR_ALREADY_INIT = -4, + AM_SRAM_STATUS_ERR_PROTOCOL_VER = -5, + AM_SRAM_STATUS_ERR_SYS = -6, + AM_SRAM_STATUS_ERR_READ = -7, + AM_SRAM_STATUS_ERR_WRITE = -8, + AM_SRAM_STATUS_ERR_COPY = -9, + AM_SRAM_STATUS_ERR_DOMAIN = -10, + AM_SRAM_STATUS_ERR_GET_MUTEX = -11, + AM_SRAM_STATUS_ERR_NOT_SUPPORT = -12, +} AM_SRAM_STATUS; + +#define AM_SRAM_MAX_SECTOR_SIZE 0x800 + +AM_SRAM_STATUS amSramCreateMutex(AM_SRAM *device); +AM_SRAM_STATUS amSramInit(void); +AM_SRAM_STATUS amSramExit(void); + +AM_SRAM_STATUS amSramReadInternal(AM_SRAM *device, LONG addressLow, LONG addressHigh, LPVOID buffer, + DWORD nBytes); +AM_SRAM_STATUS amSramWriteInternal(AM_SRAM *device, LONG addressLow, LONG addressHigh, + LPCVOID buffer, DWORD nBytes); + +AM_SRAM_STATUS amSramRead(DWORD src, LPVOID pDst, DWORD size); +AM_SRAM_STATUS amSramWrite(LPCVOID pSrc, DWORD dst, DWORD size); + +// TODO: + +void amSramCopy(void); +void amSramGetSectorSize(void); +void amSramGetSize(void); +void amSramSetTimeout(void); diff --git a/src/micetools/lib/am/amStorage.h b/src/micetools/lib/am/amStorage.h new file mode 100644 index 0000000..b8bcafc --- /dev/null +++ b/src/micetools/lib/am/amStorage.h @@ -0,0 +1,25 @@ +void amStorageBsGetCount(void); +void amStorageBsGetIdentify(void); +void amStorageBsGetSmartData(void); +void amStorageBsIsBuStarage(void); +void amStorageBsRequestHwReset(void); +void amStorageBsRequestUnlock(void); +void amStorageBusy(void); +void amStorageGetDriveLetter(void); +void amStorageGetStorageCount(void); +void amStorageGetStorageInfo(void); +void amStorageGetVolume(void); +void amStorageInit(void); +void amStorageOpenBinary(void); +void amStorageOpenEx(void); +void amStorageRequestCheck(void); +void amStorageRequestFormat(void); +void amStorageRequestMount(void); +void amStorageRequestUnmountByDriveLetter(void); +void amStorageRequestUnmountByStorageId(void); +void amStorageResponseCheck(void); +void amStorageSendAndRecvEx(void); +void amStorageSendRequest(void); +void amStorageSetVolume(void); +void amStorageTaskRequest(void); +void amStorageWaitReady(void); diff --git a/src/micetools/lib/am/amSysData.h b/src/micetools/lib/am/amSysData.h new file mode 100644 index 0000000..3d59260 --- /dev/null +++ b/src/micetools/lib/am/amSysData.h @@ -0,0 +1,12 @@ +typedef struct { + unsigned short m_Year; + unsigned char m_Month; + unsigned char m_Day; + unsigned char m_Hour; + unsigned char m_Minute; + unsigned char m_Second; + unsigned char Rsv07[1]; +} AM_SYSDATA_TIMESTAMP; + +void amSysDataGetDotClockTiming(void); +void amSysDataGetOsVersionString(void); diff --git a/src/micetools/lib/am/amtimer.c b/src/micetools/lib/am/amtimer.c deleted file mode 100644 index fee995f..0000000 --- a/src/micetools/lib/am/amtimer.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -int frequency_loaded = 0; -LARGE_INTEGER frequency; - -amtime_t* amiTimerGet(amtime_t* time) { - LARGE_INTEGER counter; - - if (time == NULL) return NULL; - - if (frequency_loaded == 0) { - QueryPerformanceFrequency(&frequency); - frequency_loaded = 1; - } - QueryPerformanceCounter(&counter); - time->microseconds = (unsigned int)((counter.QuadPart * 1000000) / frequency.QuadPart); - time->seconds = (unsigned int)(counter.QuadPart / frequency.QuadPart); - return time; -} diff --git a/src/micetools/lib/am/meson.build b/src/micetools/lib/am/meson.build index d51cb35..99c1b68 100644 --- a/src/micetools/lib/am/meson.build +++ b/src/micetools/lib/am/meson.build @@ -1,10 +1,70 @@ -amlib = static_library( - 'am', +amOemstring = static_library( + 'amOemstring', + sources: [ + 'amOemstring.c', + ], +) + +amEeprom = static_library( + 'amEeprom', sources: [ - 'amTimer.c', 'amEeprom.c', ], link_with: [ - mice_lib + amiDebug, + amiCrc, + ], +) + +amSram = static_library( + 'amSram', + sources: [ + 'amSram.c', + ], + link_with: [ + amiDebug, + ], +) + +amPlatform = static_library( + 'amPlatform', + sources: [ + 'amPlatform.c', + ], + link_with: [ + amiDebug, + amSram, + amEeprom, + ], +) + +amDongle = static_library( + 'amDongle', + sources: [ + 'amDongle.c', + ], + link_with: [ + amiDebug, + util_lib, + libpcp, + ], +) + +amSerialId = static_library( + 'amSerialId', + sources: [ + 'amSerialId.c', + ], +) + +amInstall = static_library( + 'amInstall', + sources: [ + 'amInstall.c', + ], + link_with: [ + amiDebug, + util_lib, + libpcp, ], ) diff --git a/src/micetools/lib/ami/ami.h b/src/micetools/lib/ami/ami.h new file mode 100644 index 0000000..9c1613a --- /dev/null +++ b/src/micetools/lib/ami/ami.h @@ -0,0 +1,5 @@ +#pragma once + +#include "amiCrc.h" +#include "amiDebug.h" +#include "amiTimer.h" diff --git a/src/micetools/lib/ami/amiCrc.c b/src/micetools/lib/ami/amiCrc.c new file mode 100644 index 0000000..bdc2516 --- /dev/null +++ b/src/micetools/lib/ami/amiCrc.c @@ -0,0 +1,30 @@ +#include "amiCrc.h" + +#define CRC32_POLYNOMIAL 0xedb88320 + +AM_LIB_C_HEADER(amiCrc, AMI_CRC) + +void amiCrc32RCreateTable(unsigned int *table) { + for (int i = 0; i < 256; i++) { + unsigned int value = (~i & 1) - 1 & CRC32_POLYNOMIAL; + value = ((i >> 1 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = ((i >> 2 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = ((i >> 3 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = ((i >> 4 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = ((i >> 5 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = ((i >> 6 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + table[0] = ((i >> 7 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + table++; + } +} + +unsigned int amiCrc32RGet(unsigned int *table, int length, unsigned char *data, + unsigned int initial) { + unsigned int value = ~initial; + while (length > 0) { + value = value >> 8 ^ table[(data[0] ^ value) & 0xff]; + length += -1; + data++; + } + return ~value; +} diff --git a/src/micetools/lib/ami/amiCrc.h b/src/micetools/lib/ami/amiCrc.h new file mode 100644 index 0000000..754b5f1 --- /dev/null +++ b/src/micetools/lib/ami/amiCrc.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../_am.h" + +AM_LIB_H_HEADER(amiCrc, AMI_CRC) + +typedef struct _AMI_CRC { + unsigned int m_init; + unsigned int m_table[256]; +} AMI_CRC; + +void amiCrc32RCreateTable(unsigned int *table); +unsigned int amiCrc32RGet(unsigned int *table, int length, unsigned char *data, + unsigned int initial); + +#define amCrc32RCreateTable() \ + do { \ + if (!amiCrc.m_init) { \ + amiCrc32RCreateTable(amiCrc.m_table); \ + amiCrc.m_init = 1; \ + } \ + } while (0) +#define amCrc32RGet(length, data, initial) \ + amiCrc32RGet(amiCrc.m_table, (length), (data), (initial)) diff --git a/src/micetools/lib/ami/amiCri.h b/src/micetools/lib/ami/amiCri.h new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/lib/ami/amiDebug.c b/src/micetools/lib/ami/amiDebug.c new file mode 100644 index 0000000..71fca30 --- /dev/null +++ b/src/micetools/lib/ami/amiDebug.c @@ -0,0 +1,54 @@ +#include "amiDebug.h" + +#include "../mice/mice.h" + +AM_LIB_C_HEADER(amiDebug, AM_DEBUG) + +FILE* amiDebugFile; +amiDebugCallback_t* amiDebugCallback; + +int amiDebugVprintf(LPCSTR format, va_list args) { + if (amiDebugCallback == NULL) { + return vfprintf_s(amiDebugFile ? amiDebugFile : stderr, format, args); + } + + char buffer[1024]; + vsnprintf_s(buffer, sizeof buffer, sizeof buffer - 1, format, args); + return (*amiDebugCallback)(buffer); +} + +int amiDebugPrintf(LPCSTR format, ...) { + va_list args; + va_start(args, format); + int ret = amiDebugVprintf(format, args); + va_end(args); + return ret; +} + +int amiDebugVprintfEx(LPCSTR caller, DWORD line, LPCSTR format, va_list args) { + char buf[1024]; + + int prefixLength = _snprintf_s(buf, sizeof buf, sizeof buf - 1, "%s: Line%d ", caller, line); + if (amiDebugCallback == NULL) { + FILE* file = amiDebugFile ? amiDebugFile : stderr; + if (-1 < fprintf_s(file, "%s", buf)) { + return vfprintf_s(file, format, args); + } + return 0; + } + + vsnprintf_s(buf + prefixLength, sizeof buf - prefixLength, (sizeof buf - 1) - prefixLength, + format, args); + return (*amiDebugCallback)(buf); +} + +int amiDebugPrintfEx(LPCSTR caller, DWORD line, LPCSTR format, ...) { + va_list args; + va_start(args, format); + int ret = amiDebugVprintfEx(caller, line, format, args); + va_end(args); + return ret; +} + +void amiDebugSetFile(FILE* file) { amiDebugFile = file; } +void amiDebugSetCallback(amiDebugCallback_t* callback) { amiDebugCallback = callback; } diff --git a/src/micetools/lib/ami/amiDebug.h b/src/micetools/lib/ami/amiDebug.h new file mode 100644 index 0000000..c76bc6c --- /dev/null +++ b/src/micetools/lib/ami/amiDebug.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include "../_am.h" + +typedef struct _AM_DEBUG { + unsigned char Rsv00; +} AM_DEBUG; +AM_LIB_H_HEADER(amiDebug, AM_DEBUG) + +typedef int(amiDebugCallback_t)(LPCSTR data); + +extern amiDebugCallback_t* amiDebugCallback; +extern FILE* amiDebugFile; + +int amiDebugVprintf(LPCSTR format, va_list args); +int amiDebugPrintf(LPCSTR format, ...); +#define amiDebugPrintf(fmt, ...) amiDebugPrintf(fmt, __VA_ARGS__) + +int amiDebugVprintfEx(LPCSTR caller, DWORD line, LPCSTR format, va_list args); +int amiDebugPrintfEx(LPCSTR caller, DWORD line, LPCSTR format, ...); +#define amiDebugLog(fmt, ...) amiDebugPrintfEx(__func__, __LINE__, fmt##"\n", __VA_ARGS__) + +void amiDebugSetFile(FILE* file); +void amiDebugSetCallback(amiDebugCallback_t* callback); diff --git a/src/micetools/lib/ami/amiLog.h b/src/micetools/lib/ami/amiLog.h new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/lib/ami/amiMd5.h b/src/micetools/lib/ami/amiMd5.h new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/lib/ami/amiTimer.c b/src/micetools/lib/ami/amiTimer.c new file mode 100644 index 0000000..11e4015 --- /dev/null +++ b/src/micetools/lib/ami/amiTimer.c @@ -0,0 +1,40 @@ +#include "amiTimer.h" + +int frequency_loaded = 0; +LARGE_INTEGER frequency; + +AM_LIB_C_HEADER(amiTimer, AMI_TIMER) + +amtime_t* amiTimerGet(amtime_t* time) { + LARGE_INTEGER counter; + + if (time == NULL) return NULL; + + if (frequency_loaded == 0) { + QueryPerformanceFrequency(&frequency); + frequency_loaded = 1; + } + QueryPerformanceCounter(&counter); + time->microseconds = (unsigned int)((counter.QuadPart * 1000000) / frequency.QuadPart); + time->seconds = (unsigned int)(counter.QuadPart / frequency.QuadPart); + return time; +} + +int amiTimerDiffSec(amtime_t* start, amtime_t* now) { + if (start == NULL || now == NULL) return -1; + + return (now->seconds - (now->microseconds < start->microseconds)) - start->seconds; +} + +int amiTimerDiffMsec(amtime_t* start, amtime_t* now) { + if (start == NULL || now == NULL) return -1; + + return (now->microseconds - start->microseconds) / 1000 + + (now->seconds - start->seconds) * 1000; +} + +int amiTimerDiffUsec(amtime_t* start, amtime_t* now) { + if (start == NULL || now == NULL) return -1; + + return ((now->seconds - start->seconds) * 1000000 - start->microseconds) + now->microseconds; +} diff --git a/src/micetools/lib/am/amtimer.h b/src/micetools/lib/ami/amiTimer.h similarity index 50% rename from src/micetools/lib/am/amtimer.h rename to src/micetools/lib/ami/amiTimer.h index 8ffd5ee..0478e60 100644 --- a/src/micetools/lib/am/amtimer.h +++ b/src/micetools/lib/ami/amiTimer.h @@ -2,9 +2,17 @@ #include +#include "../_am.h" + +AM_LIB_H_HEADER(amiTimer, AMI_TIMER) + +typedef struct _AMI_TIMER { + unsigned char Rsv00; +} AMI_TIMER; + typedef struct amtime { - unsigned int seconds; - unsigned int microseconds; + int seconds; + int microseconds; } amtime_t; amtime_t* amiTimerGet(amtime_t* time); @@ -13,5 +21,6 @@ amtime_t* amiTimerGet(amtime_t* time); #define _amTimeDelta(now, start) \ (((now).microseconds - (start).microseconds) / 1000 + ((now).seconds - (start).seconds) * 1000) -#define _amTimeDeltaMircos(now, start) \ - ((((now).seconds - (start).seconds) * 1000000 - (start).microseconds) + (now).microseconds) +int amiTimerDiffSec(amtime_t* start, amtime_t* now); +int amiTimerDiffMsec(amtime_t* start, amtime_t* now); +int amiTimerDiffUsec(amtime_t* start, amtime_t* now); diff --git a/src/micetools/lib/ami/meson.build b/src/micetools/lib/ami/meson.build new file mode 100644 index 0000000..175e7c7 --- /dev/null +++ b/src/micetools/lib/ami/meson.build @@ -0,0 +1,20 @@ +amiCrc = static_library( + 'amiCrc', + sources: [ + 'amiCrc.c', + ], +) + +amiTimer = static_library( + 'amiTimer', + sources: [ + 'amiTimer.c', + ], +) + +amiDebug = static_library( + 'amiDebug', + sources: [ + 'amiDebug.c', + ], +) diff --git a/src/micetools/lib/ams/amsHttp.h b/src/micetools/lib/ams/amsHttp.h new file mode 100644 index 0000000..20f9b59 --- /dev/null +++ b/src/micetools/lib/ams/amsHttp.h @@ -0,0 +1,11 @@ +void amsHttpByWinHttpDownload(void); +void amsHttpByWinHttpGetResponseCode(void); +void amsHttpByWinHttpGetResponseData(void); +void amsHttpByWinHttpGetResponseSize(void); +void amsHttpByWinHttpInit(void); +void amsHttpByWinHttpParseUrl(void); +void amsHttpByWinHttpSetUserAgent(void); +void amsHttpContextCheckPreCondition(void); +void amsHttpContextSetup(void); +void amsHttpDownload(void); +void amsHttpShareDataSetup(void); diff --git a/src/micetools/lib/dmi/dmi.c b/src/micetools/lib/dmi/dmi.c index fd0c83b..59d204f 100644 --- a/src/micetools/lib/dmi/dmi.c +++ b/src/micetools/lib/dmi/dmi.c @@ -7,7 +7,7 @@ WORD dmi_size = 0; WORD _dmi_max = 0; DMI_BIOS deafult_dmi_bios = { - .Head.Type = 0x00, + .Head.Type = DmiTypeBios, .Head.Length = 0x12, .Head.Handle = 0x0000, .Vendor = 0x01, // "American Megatrends Inc." @@ -23,7 +23,7 @@ DMI_BIOS deafult_dmi_bios = { }; DMI_SYSTEM default_dmi_system = { - .Head.Type = 0x01, + .Head.Type = DmiTypeSystem, .Head.Length = 0x08, .Head.Handle = 0x0001, .Manufacturer = 0x01, // "NEC" @@ -33,7 +33,7 @@ DMI_SYSTEM default_dmi_system = { }; DMI_STRING deafult_dmi_string = { - .Head.Type = 0x0b, + .Head.Type = DmiTypeString, .Head.Length = 0x05, .Head.Handle = 0x0002, .NoStrings = 0x00, @@ -115,4 +115,4 @@ BYTE dmi_calc_checksum(const char* buf, int len) { int a; for (a = 0; a < len; a++) sum += buf[a]; return (BYTE)(sum == 0); -} \ No newline at end of file +} diff --git a/src/micetools/lib/dmi/dmi.h b/src/micetools/lib/dmi/dmi.h index 3f0cda0..08e06da 100644 --- a/src/micetools/lib/dmi/dmi.h +++ b/src/micetools/lib/dmi/dmi.h @@ -4,16 +4,20 @@ extern LPBYTE dmi_table; extern WORD dmi_size; -// #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop)) +enum DmiType { + DmiTypeBios = 0, + DmiTypeSystem = 1, + DmiTypeString = 11, +}; +typedef BYTE DmiType_t; -#pragma pack(1) +#pragma pack(push, 1) typedef struct { - BYTE Type; + DmiType_t Type; BYTE Length; WORD Handle; } DMI_SECTION_HEADER; -#pragma pack(1) typedef struct { CHAR Signature[5]; BYTE Checksum; @@ -24,7 +28,6 @@ typedef struct { BYTE Reserved; } DMI_HEADER; -#pragma pack(1) typedef struct { DMI_SECTION_HEADER Head; BYTE Vendor; @@ -39,7 +42,6 @@ typedef struct { BYTE ECVerMinor; } DMI_BIOS; -#pragma pack(1) typedef struct { DMI_SECTION_HEADER Head; BYTE Manufacturer; @@ -48,11 +50,11 @@ typedef struct { BYTE Serial; } DMI_SYSTEM; -#pragma pack(1) typedef struct { DMI_SECTION_HEADER Head; BYTE NoStrings; } DMI_STRING; +#pragma pack(pop) static void dmi_init(void); static void dmi_append(void* data, WORD size); diff --git a/src/micetools/lib/json/LICESNSE b/src/micetools/lib/json/LICESNSE deleted file mode 100644 index d6d6972..0000000 --- a/src/micetools/lib/json/LICESNSE +++ /dev/null @@ -1,25 +0,0 @@ - - Copyright (C) 2012-2021 the json-parser authors All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. \ No newline at end of file diff --git a/src/micetools/lib/json/README.txt b/src/micetools/lib/json/README.txt deleted file mode 100644 index 20cf08d..0000000 --- a/src/micetools/lib/json/README.txt +++ /dev/null @@ -1 +0,0 @@ -https://github.com/json-parser/json-parser diff --git a/src/micetools/lib/json/json.c b/src/micetools/lib/json/json.c deleted file mode 100644 index 70834bc..0000000 --- a/src/micetools/lib/json/json.c +++ /dev/null @@ -1,818 +0,0 @@ -/* vim: set et ts=3 sw=3 sts=3 ft=c: - * - * Copyright (C) 2012-2021 the json-parser authors All rights reserved. - * https://github.com/json-parser/json-parser - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "json.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "../util/hex.h" - -#define JSON_INT_MAX 9223372036854775807LL - -typedef unsigned int json_uchar; - -const struct _json_value json_value_none = { 0 }; - -static int would_overflow(json_int_t value, json_char b) { return ((JSON_INT_MAX - (b - '0')) / 10) < value; } - -typedef struct { - size_t used_memory; - - json_settings settings; - int first_pass; - - const json_char *ptr; - unsigned int cur_line, cur_col; -} json_state; - -static void *default_alloc(size_t size, int zero) { return zero ? calloc(1, size) : malloc(size); } - -static void *json_alloc(json_state *state, size_t size, int zero) { - if ((ULONG_MAX - 8 - state->used_memory) < size) return 0; - - if (state->settings.max_memory && (state->used_memory += size) > state->settings.max_memory) { - return 0; - } - - return default_alloc(size, zero); -} - -static int new_value(json_state *state, json_value **top, json_value **root, json_value **alloc, json_type type) { - json_value *value; - size_t values_size; - - if (!state->first_pass) { - value = *top = *alloc; - *alloc = (*alloc)->_reserved.next_alloc; - - if (!*root) *root = value; - - switch (value->type) { - case json_array: - if (value->u.array.length == 0) break; - if (!(value->u.array.values = - (json_value **)json_alloc(state, value->u.array.length * sizeof(json_value *), 0))) { - return 0; - } - value->u.array.length = 0; - break; - case json_object: - if (value->u.object.length == 0) break; - - values_size = sizeof(*value->u.object.values) * value->u.object.length; - - if (!(value->u.object.values = (json_object_entry *)json_alloc( - state, values_size + ((uintptr_t)value->u.object.values), 0))) { - return 0; - } - value->_reserved.object_mem = (void *)(((char *)value->u.object.values) + values_size); - value->u.object.length = 0; - break; - case json_string: - if (!(value->u.string.ptr = - (json_char *)json_alloc(state, (value->u.string.length + 1) * sizeof(json_char), 0))) { - return 0; - } - value->u.string.length = 0; - break; - default: - break; - }; - - return 1; - } - - if (!(value = (json_value *)json_alloc(state, sizeof(json_value) + state->settings.value_extra, 1))) { - return 0; - } - - if (!*root) *root = value; - - value->type = type; - value->parent = *top; - -#ifdef JSON_TRACK_SOURCE - value->line = state->cur_line; - value->col = state->cur_col; -#endif - - if (*alloc) (*alloc)->_reserved.next_alloc = value; - - *alloc = *top = value; - - return 1; -} - -#define whitespace \ - case '\n': \ - ++state.cur_line; \ - state.cur_col = 0; /* FALLTHRU */ \ - case ' ': /* FALLTHRU */ \ - case '\t': /* FALLTHRU */ \ - case '\r' - -#define string_add(b) \ - do { \ - if (!state.first_pass) string[string_length] = b; \ - ++string_length; \ - } while (0); - -#define line_and_col state.cur_line, state.cur_col - -static const long flag_next = 1 << 0, flag_reproc = 1 << 1, flag_need_comma = 1 << 2, flag_seek_value = 1 << 3, - flag_escaped = 1 << 4, flag_string = 1 << 5, flag_need_colon = 1 << 6, flag_done = 1 << 7, - flag_num_negative = 1 << 8, flag_num_zero = 1 << 9, flag_num_e = 1 << 10, - flag_num_e_got_sign = 1 << 11, flag_num_e_negative = 1 << 12, flag_line_comment = 1 << 13, - flag_block_comment = 1 << 14, flag_num_got_decimal = 1 << 15; - -json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t length, char *error_buf) { - char error[json_error_max]; - const json_char *end; - json_value *top, *root, *alloc = 0; - json_state state = {0}; - long flags = 0; - int num_digits = 0; - double num_e = 0, num_fraction = 0; - - /* Skip UTF-8 BOM - */ - if (length >= 3 && ((unsigned char)json[0]) == 0xEF && ((unsigned char)json[1]) == 0xBB && - ((unsigned char)json[2]) == 0xBF) { - json += 3; - length -= 3; - } - - error[0] = '\0'; - end = (json + length); - - memcpy(&state.settings, settings, sizeof(json_settings)); - - for (state.first_pass = 1; state.first_pass >= 0; --state.first_pass) { - json_uchar uchar; - unsigned char uc_b1, uc_b2, uc_b3, uc_b4; - json_char *string = 0; - unsigned int string_length = 0; - - top = root = 0; - flags = flag_seek_value; - - state.cur_line = 1; - - for (state.ptr = json;; ++state.ptr) { - json_char b = (state.ptr == end ? 0 : *state.ptr); - - if (flags & flag_string) { - if (!b) { - snprintf(error, json_error_max, "%u:%u: Unexpected EOF in string", line_and_col); - goto e_failed; - } - - if (string_length > UINT_MAX - 8) goto e_overflow; - - if (flags & flag_escaped) { - flags &= ~flag_escaped; - - switch (b) { - case 'b': - string_add('\b'); - break; - case 'f': - string_add('\f'); - break; - case 'n': - string_add('\n'); - break; - case 'r': - string_add('\r'); - break; - case 't': - string_add('\t'); - break; - case 'u': - - if (end - state.ptr <= 4 || (uc_b1 = hex_value(*++state.ptr)) == 0xFF || - (uc_b2 = hex_value(*++state.ptr)) == 0xFF || - (uc_b3 = hex_value(*++state.ptr)) == 0xFF || - (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { - snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, b); - goto e_failed; - } - - uc_b1 = (uc_b1 << 4) | uc_b2; - uc_b2 = (uc_b3 << 4) | uc_b4; - uchar = (uc_b1 << 8) | uc_b2; - - if ((uchar & 0xF800) == 0xD800) { - json_uchar uchar2; - - if (end - state.ptr <= 6 || (*++state.ptr) != '\\' || (*++state.ptr) != 'u' || - (uc_b1 = hex_value(*++state.ptr)) == 0xFF || - (uc_b2 = hex_value(*++state.ptr)) == 0xFF || - (uc_b3 = hex_value(*++state.ptr)) == 0xFF || - (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { - snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, - b); - goto e_failed; - } - - uc_b1 = (uc_b1 << 4) | uc_b2; - uc_b2 = (uc_b3 << 4) | uc_b4; - uchar2 = (uc_b1 << 8) | uc_b2; - - uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); - } - - if (sizeof(json_char) >= sizeof(json_uchar) || (uchar <= 0x7F)) { - string_add((json_char)uchar); - break; - } - - if (uchar <= 0x7FF) { - if (state.first_pass) - string_length += 2; - else { - string[string_length++] = (char)(0xC0 | (uchar >> 6)); - string[string_length++] = (char)(0x80 | (uchar & 0x3F)); - } - - break; - } - - if (uchar <= 0xFFFF) { - if (state.first_pass) - string_length += 3; - else { - string[string_length++] = 0xE0 | (char)((uchar >> 12)); - string[string_length++] = 0x80 | (char)(((uchar >> 6) & 0x3F)); - string[string_length++] = 0x80 | (char)((uchar & 0x3F)); - } - - break; - } - - if (state.first_pass) - string_length += 4; - else { - string[string_length++] = 0xF0 | (char)((uchar >> 18)); - string[string_length++] = 0x80 | (char)(((uchar >> 12) & 0x3F)); - string[string_length++] = 0x80 | (char)(((uchar >> 6) & 0x3F)); - string[string_length++] = 0x80 | (char)((uchar & 0x3F)); - } - - break; - - default: - string_add(b); - }; - - continue; - } - - if (b == '\\') { - flags |= flag_escaped; - continue; - } - - if (b == '"') { - if (!state.first_pass) string[string_length] = 0; - - flags &= ~flag_string; - string = 0; - - switch (top->type) { - case json_string: - top->u.string.length = string_length; - flags |= flag_next; - - break; - - case json_object: - if (state.first_pass) { - json_char **chars = (json_char **)&top->u.object.values; - chars[0] += string_length + 1; - } else { - top->u.object.values[top->u.object.length].name = - (json_char *)top->_reserved.object_mem; - - top->u.object.values[top->u.object.length].name_length = string_length; - - (*(json_char **)&top->_reserved.object_mem) += string_length + 1; - } - - flags |= flag_seek_value | flag_need_colon; - continue; - - default: - break; - }; - } else { - string_add(b); - continue; - } - } - - if (state.settings.settings & json_enable_comments) { - if (flags & (flag_line_comment | flag_block_comment)) { - if (flags & flag_line_comment) { - if (b == '\r' || b == '\n' || !b) { - flags &= ~flag_line_comment; - --state.ptr; /* so null can be reproc'd */ - } - - continue; - } - - if (flags & flag_block_comment) { - if (!b) { - snprintf(error, json_error_max, "%u:%u: Unexpected EOF in block comment", line_and_col); - goto e_failed; - } - - if (b == '*' && state.ptr < (end - 1) && state.ptr[1] == '/') { - flags &= ~flag_block_comment; - ++state.ptr; /* skip closing sequence */ - } - - continue; - } - } else if (b == '/') { - if (!(flags & (flag_seek_value | flag_done)) && top->type != json_object) { - snprintf(error, json_error_max, "%u:%u: Comment not allowed here", line_and_col); - goto e_failed; - } - - if (++state.ptr == end) { - snprintf(error, json_error_max, "%u:%u: EOF unexpected", line_and_col); - goto e_failed; - } - - switch (b = *state.ptr) { - case '/': - flags |= flag_line_comment; - continue; - - case '*': - flags |= flag_block_comment; - continue; - - default: - snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in comment opening sequence", - line_and_col, b); - goto e_failed; - }; - } - } - - if (flags & flag_done) { - if (!b) break; - - switch (b) { - whitespace: - continue; - - default: - snprintf(error, json_error_max, "%u:%u: Trailing garbage: `%c`", line_and_col, b); - goto e_failed; - }; - } - - if (flags & flag_seek_value) { - switch (b) { - whitespace: - continue; - - case ']': - if (top && top->type == json_array) - flags = (flags & ~(flag_need_comma | flag_seek_value)) | flag_next; - else { - snprintf(error, json_error_max, "%u:%u: Unexpected `]`", line_and_col); - goto e_failed; - } - - break; - - default: - if (flags & flag_need_comma) { - if (b == ',') { - flags &= ~flag_need_comma; - continue; - } else { - snprintf(error, json_error_max, "%u:%u: Expected `,` before `%c`", line_and_col, b); - - goto e_failed; - } - } - - if (flags & flag_need_colon) { - if (b == ':') { - flags &= ~flag_need_colon; - continue; - } else { - snprintf(error, json_error_max, "%u:%u: Expected `:` before `%c`", line_and_col, b); - - goto e_failed; - } - } - - flags &= ~flag_seek_value; - - switch (b) { - case '{': - if (!new_value(&state, &top, &root, &alloc, json_object)) goto e_alloc_failure; - - continue; - - case '[': - if (!new_value(&state, &top, &root, &alloc, json_array)) goto e_alloc_failure; - - flags |= flag_seek_value; - continue; - - case '"': - if (!new_value(&state, &top, &root, &alloc, json_string)) goto e_alloc_failure; - - flags |= flag_string; - - string = top->u.string.ptr; - string_length = 0; - - continue; - - case 't': - if ((end - state.ptr) <= 3 || *(++state.ptr) != 'r' || *(++state.ptr) != 'u' || - *(++state.ptr) != 'e') { - goto e_unknown_value; - } - - if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; - - top->u.boolean = 1; - - flags |= flag_next; - break; - - case 'f': - if ((end - state.ptr) <= 4 || *(++state.ptr) != 'a' || *(++state.ptr) != 'l' || - *(++state.ptr) != 's' || *(++state.ptr) != 'e') { - goto e_unknown_value; - } - - if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; - - flags |= flag_next; - break; - - case 'n': - if ((end - state.ptr) <= 3 || *(++state.ptr) != 'u' || *(++state.ptr) != 'l' || - *(++state.ptr) != 'l') { - goto e_unknown_value; - } - - if (!new_value(&state, &top, &root, &alloc, json_null)) goto e_alloc_failure; - - flags |= flag_next; - break; - default: - if (isdigit((unsigned char)b) || b == '-') { - if (!new_value(&state, &top, &root, &alloc, json_integer)) goto e_alloc_failure; - - if (!state.first_pass) { - while (isdigit((unsigned char)b) || b == '+' || b == '-' || b == 'e' || - b == 'E' || b == '.') { - if ((++state.ptr) == end) { - b = 0; - break; - } - - b = *state.ptr; - } - - flags |= flag_next | flag_reproc; - break; - } - - flags &= ~(flag_num_negative | flag_num_e | flag_num_e_got_sign | - flag_num_e_negative | flag_num_zero); - - num_digits = 0; - num_fraction = 0; - num_e = 0; - - if (b != '-') { - flags |= flag_reproc; - break; - } - - flags |= flag_num_negative; - continue; - } else { - snprintf(error, json_error_max, "%u:%u: Unexpected `%c` when seeking value", - line_and_col, b); - goto e_failed; - } - }; - }; - } else { - switch (top->type) { - case json_object: - switch (b) { - whitespace: - continue; - case '"': - if (flags & flag_need_comma) { - snprintf(error, json_error_max, "%u:%u: Expected `,` before `\"`", line_and_col); - goto e_failed; - } - - flags |= flag_string; - - string = (json_char *)top->_reserved.object_mem; - string_length = 0; - - break; - - case '}': - flags = (flags & ~flag_need_comma) | flag_next; - break; - - case ',': - if (flags & flag_need_comma) { - flags &= ~flag_need_comma; - break; - } /* FALLTHRU */ - - default: - snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in object", line_and_col, b); - goto e_failed; - }; - break; - - case json_integer: - case json_double: - if (isdigit((unsigned char)b)) { - ++num_digits; - - if (top->type == json_integer || flags & flag_num_e) { - if (!(flags & flag_num_e)) { - if (flags & flag_num_zero) { - snprintf(error, json_error_max, "%u:%u: Unexpected `0` before `%c`", - line_and_col, b); - goto e_failed; - } - - if (num_digits == 1 && b == '0') flags |= flag_num_zero; - } else { - flags |= flag_num_e_got_sign; - num_e = (num_e * 10) + (b - '0'); - continue; - } - - if (would_overflow(top->u.integer, b)) { - json_int_t integer = top->u.integer; - --num_digits; - --state.ptr; - top->type = json_double; - top->u.dbl = (double)integer; - continue; - } - - top->u.integer = (top->u.integer * 10) + (b - '0'); - continue; - } - - if (flags & flag_num_got_decimal) - num_fraction = (num_fraction * 10) + (b - '0'); - else - top->u.dbl = (top->u.dbl * 10) + (b - '0'); - - continue; - } - - if (b == '+' || b == '-') { - if ((flags & flag_num_e) && !(flags & flag_num_e_got_sign)) { - flags |= flag_num_e_got_sign; - - if (b == '-') flags |= flag_num_e_negative; - - continue; - } - } else if (b == '.' && top->type == json_integer) { - json_int_t integer = top->u.integer; - - if (!num_digits) { - snprintf(error, json_error_max, "%u:%u: Expected digit before `.`", line_and_col); - goto e_failed; - } - - top->type = json_double; - top->u.dbl = (double)integer; - - flags |= flag_num_got_decimal; - num_digits = 0; - continue; - } - - if (!(flags & flag_num_e)) { - if (top->type == json_double) { - if (!num_digits) { - snprintf(error, json_error_max, "%u:%u: Expected digit after `.`", line_and_col); - goto e_failed; - } - - top->u.dbl += num_fraction / pow(10.0, num_digits); - } - - if (b == 'e' || b == 'E') { - flags |= flag_num_e; - - if (top->type == json_integer) { - json_int_t integer = top->u.integer; - top->type = json_double; - top->u.dbl = (double)integer; - } - - num_digits = 0; - flags &= ~flag_num_zero; - - continue; - } - } else { - if (!num_digits) { - snprintf(error, json_error_max, "%u:%u: Expected digit after `e`", line_and_col); - goto e_failed; - } - - top->u.dbl *= pow(10.0, (flags & flag_num_e_negative ? -num_e : num_e)); - } - - if (flags & flag_num_negative) { - if (top->type == json_integer) - top->u.integer = -top->u.integer; - else - top->u.dbl = -top->u.dbl; - } - - flags |= flag_next | flag_reproc; - break; - - default: - break; - }; - } - - if (flags & flag_reproc) { - flags &= ~flag_reproc; - --state.ptr; - } - - if (flags & flag_next) { - flags = (flags & ~flag_next) | flag_need_comma; - - if (!top->parent) { - /* root value done */ - - flags |= flag_done; - continue; - } - - if (top->parent->type == json_array) flags |= flag_seek_value; - - if (!state.first_pass) { - json_value *parent = top->parent; - - switch (parent->type) { - case json_object: - parent->u.object.values[parent->u.object.length].value = top; - break; - case json_array: - parent->u.array.values[parent->u.array.length] = top; - break; - default: - break; - }; - } - - if ((++top->parent->u.array.length) > UINT_MAX - 8) goto e_overflow; - top = top->parent; - continue; - } - } - - alloc = root; - } - - return root; - -e_unknown_value: - snprintf(error, json_error_max, "%u:%u: Unknown value", line_and_col); - goto e_failed; - -e_alloc_failure: - snprintf(error, json_error_max, "Memory allocation failure"); - goto e_failed; - -e_overflow: - snprintf(error, json_error_max, "%u:%u: Too long (caught overflow)", line_and_col); - goto e_failed; - -e_failed: - if (error_buf) { - if (*error) - memcpy(error_buf, error, json_error_max); - else - snprintf(error_buf, json_error_max, "Unknown error"); - } - - if (state.first_pass) alloc = root; - - while (alloc) { - top = alloc->_reserved.next_alloc; - free(alloc); - alloc = top; - } - - if (!state.first_pass) json_value_free(root); - - return 0; -} - -json_value *json_parse(const json_char *json, size_t length) { - json_settings settings = {0}; - return json_parse_ex(&settings, json, length, 0); -} - -void json_value_free(json_value *value) { - json_value *cur_value; - - if (!value) return; - - value->parent = 0; - - while (value) { - switch (value->type) { - case json_array: - - if (!value->u.array.length) { - free(value->u.array.values); - break; - } - - value = value->u.array.values[--value->u.array.length]; - continue; - - case json_object: - - if (!value->u.object.length) { - free(value->u.object.values); - break; - } - - value = value->u.object.values[--value->u.object.length].value; - continue; - - case json_string: - - free(value->u.string.ptr); - break; - - default: - break; - }; - - cur_value = value; - value = value->parent; - free(cur_value); - } -} diff --git a/src/micetools/lib/json/json.h b/src/micetools/lib/json/json.h deleted file mode 100644 index 269c091..0000000 --- a/src/micetools/lib/json/json.h +++ /dev/null @@ -1,114 +0,0 @@ -/* vim: set et ts=3 sw=3 sts=3 ft=c: - * - * Copyright (C) 2012-2021 the json-parser authors All rights reserved. - * https://github.com/json-parser/json-parser - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _JSON_H -#define _JSON_H - -#ifndef json_char -#define json_char char -#endif - -#ifndef json_int_t -#define json_int_t __int64 -#endif - -#include - -typedef struct { - unsigned long max_memory; /* should be size_t, but would modify the API */ - int settings; - size_t value_extra; /* how much extra space to allocate for values? */ -} json_settings; - -#define json_enable_comments 0x01 - -typedef enum { - json_none, - json_object, - json_array, - json_integer, - json_double, - json_string, - json_boolean, - json_null -} json_type; - -extern const struct _json_value json_value_none; - -typedef struct _json_object_entry { - json_char *name; - unsigned int name_length; - struct _json_value *value; -} json_object_entry; - -typedef struct _json_value { - struct _json_value *parent; - - json_type type; - - union { - int boolean; - json_int_t integer; - double dbl; - - struct { - unsigned int length; - json_char *ptr; /* null terminated */ - } string; - - struct { - unsigned int length; - json_object_entry *values; - } object; - - struct { - unsigned int length; - struct _json_value **values; - } array; - } u; - - union { - struct _json_value *next_alloc; - void *object_mem; - } _reserved; - -#ifdef JSON_TRACK_SOURCE - unsigned int line, col; -#endif - -} json_value; - -json_value *json_parse(const json_char *json, size_t length); - -#define json_error_max 128 -json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t length, char *error); - -void json_value_free(json_value *); - -#endif \ No newline at end of file diff --git a/src/micetools/lib/json/meson.build b/src/micetools/lib/json/meson.build deleted file mode 100644 index 511c164..0000000 --- a/src/micetools/lib/json/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -json_lib = static_library( - 'micejson', - sources: [ - 'json.c', - ], - link_with: [util_lib] -) diff --git a/src/micetools/lib/libpcp/meson.build b/src/micetools/lib/libpcp/meson.build index 5cd61d7..ea7401a 100644 --- a/src/micetools/lib/libpcp/meson.build +++ b/src/micetools/lib/libpcp/meson.build @@ -18,6 +18,6 @@ libpcp = static_library( ws2, ], link_with: [ - amlib, + amiTimer, ], ) diff --git a/src/micetools/lib/libpcp/pcp.h b/src/micetools/lib/libpcp/pcp.h index 427af75..da3a1a0 100644 --- a/src/micetools/lib/libpcp/pcp.h +++ b/src/micetools/lib/libpcp/pcp.h @@ -10,12 +10,12 @@ #include #include -#include "../am/amtimer.h" +#include "../ami/ami.h" #define PCP_CHAR_PROMPT '>' #define PCP_CHAR_BINACK '$' #define PCP_CHAR_HASH '#' -#define PCP_CHAR_UNKNOWN '?' +#define PCP_CHAR_QMARK '?' #define PCP_CHAR_SEP '&' #define PCP_CHAR_EQU '=' #define PCP_CHAR_CR '\r' @@ -50,7 +50,7 @@ typedef struct pcp_send_data { // Errors #define OPEN_MODE_GLOBAL 0 -#define OPEN_MODE_1 1 +#define OPEN_MODE_LOCAL 1 // #define OPEN_MODE_2 2 typedef enum binary_mode { diff --git a/src/micetools/lib/libpcp/pcpa.c b/src/micetools/lib/libpcp/pcpa.c index 083f59a..6198c89 100644 --- a/src/micetools/lib/libpcp/pcpa.c +++ b/src/micetools/lib/libpcp/pcpa.c @@ -20,8 +20,8 @@ e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err) { return (e_pcpa_t)-15; case e_pcpp_timeout_open: return e_pcpa_timeout_open; - case -11: - return (e_pcpa_t)-13; + case e_pcpp_no_server: + return e_pcpa_no_server; case e_pcpp_recv_unset: return e_pcpa_cb_table_full; case -9: @@ -64,7 +64,7 @@ void pcpaClose(pcpa_t *stream) { } pcppClose(&stream->pcpp); stream->err = e_pcpa_unknown; - stream->state = 0; + stream->state = pcpa_state_none; stream->callback_table = NULL; stream->callback_max = 0; stream->callback_count = 0; @@ -97,7 +97,7 @@ e_pcpa_t pcpaInitStream(pcpa_t *stream) { } stream->err = e_pcpa_unknown; - stream->state = 0; + stream->state = pcpa_state_none; stream->callback_table = NULL; stream->callback_max = 0; stream->callback_count = 0; @@ -115,6 +115,26 @@ e_pcpa_t pcpaInitStream(pcpa_t *stream) { return e_pcpa_ok; } +e_pcpa_t pcpaOpenClient(pcpa_t *stream, char *ipAddr, ushort port, uint param_4, + timeout_t timeout) { + if (stream == NULL) { + PCP_LOG("error PCPA stream isn\'t set\n"); + return e_pcpa_stream_unset; + } + if (ipAddr == 0) { + PCP_LOG("error PCPA IpAddr isn\'t set\n"); + return e_pcpa_param_invalid; + } + + stream->state = pcpa_state_wait_prompt; + e_pcpa_t err = + _pcpaGetErrorFromPcpp(pcppOpenClient(&stream->pcpp, ipAddr, port, param_4, timeout)); + stream->err = err; + if (err != e_pcpa_to) stream->state = pcpa_state_none; + + return err; +} + e_pcpa_t pcpaOpenServerWithBinary(pcpa_t *stream, int open_mode, u_short port, u_short binary_port, undefined4 param_5) { e_pcpa_t err; @@ -154,7 +174,7 @@ e_pcpa_t pcpaOpenServerWithBinary(pcpa_t *stream, int open_mode, u_short port, u return stream->err = e_pcpa_generic; } - stream->state = 0; + stream->state = pcpa_state_none; return e_pcpa_ok; } @@ -186,7 +206,8 @@ e_pcpa_t pcpaSetCallbackFunc(pcpa_t *stream, char *keyword, pcpa_callback *callb if (stream->callback_count >= stream->callback_max) return e_pcpa_cb_table_full; - sprintf_s(stream->callback_table[stream->callback_count].keyword, PCP_KEYWORD_MAX, "%s", keyword); + sprintf_s(stream->callback_table[stream->callback_count].keyword, PCP_KEYWORD_MAX, "%s", + keyword); stream->callback_table[stream->callback_count].callback = callback; stream->callback_table[stream->callback_count].data = data; stream->callback_count++; @@ -194,7 +215,8 @@ e_pcpa_t pcpaSetCallbackFunc(pcpa_t *stream, char *keyword, pcpa_callback *callb return stream->err = e_pcpa_ok; } -e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t *stream, pcpa_cb_table_t *callback_table, uint callbacks_max) { +e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t *stream, pcpa_cb_table_t *callback_table, + uint callbacks_max) { if (stream == NULL) { PCP_LOG("error PCPA stream isn\'t set\n"); return e_pcpa_stream_unset; @@ -251,7 +273,7 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { do { ms = 0; switch (stream->state) { - case 0: + case pcpa_state_none: amiTimerGet(&time); ms = _amTimeDelta(time, time_start); if (timeout_ms != -1) { @@ -263,7 +285,7 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { local_14 = timeout; } } - stream->state = 3; + stream->state = pcpa_state_wait_request; iVar5 = pcppRecvRequest(&stream->pcpp, &stream->recv_data, timeout); eVar4 = _errP2A(iVar5); stream->err = eVar4; @@ -277,15 +299,15 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { goto joined_r0x00454a58; } } else { - stream->state = 0; + stream->state = pcpa_state_none; } } break; default: stream->err = e_pcpa_unknown; goto LAB_00454d84; - case 3: - case 4: + case pcpa_state_wait_request: + case pcpa_state_send_response: case 9: amiTimerGet(&time); ms = _amTimeDelta(time, time_start); @@ -303,13 +325,13 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { stream->err = eVar4; timeout = local_14; if (eVar4 != e_pcpa_to) { - if (stream->state == 4) { + if (stream->state == pcpa_state_send_response) { memset(&stream->send_data, 0, PCP_BUF_MAX); (stream->send_data).length = 0; } if (stream->err == e_pcpa_ok) { if (stream->binary_mode == binary_mode_none) { - stream->state = (stream->state != 3) - 1 & 10; + stream->state = (stream->state != pcpa_state_wait_request) - 1 & 10; amiTimerGet(&time); if (timeout_ms != -1) { ms = _amTimeDelta(time, time_start); @@ -321,10 +343,11 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { } } else { pcpaCloseBinary(stream); - stream->state = 0; + stream->state = pcpa_state_none; stream->binary_mode = binary_mode_none; if (stream->binary_mode_after_cb != NULL) { - (*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data); + (*stream->binary_mode_after_cb)(stream, + stream->binary_mode_after_data); stream->binary_mode_after_cb = NULL; } amiTimerGet(&time); @@ -337,16 +360,17 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { if ((stream->state == 9) && (stream->binary_mode != binary_mode_none)) { pcpaCloseBinary(stream); if (stream->binary_mode_after_cb != NULL) { - (*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data); + (*stream->binary_mode_after_cb)(stream, + stream->binary_mode_after_data); stream->binary_mode_after_cb = NULL; } stream->binary_mode = binary_mode_none; } - stream->state = 0; + stream->state = pcpa_state_none; } } break; - case 7: + case pcpa_state_send_request_binary: callback = stream->binary_mode_before_cb; (stream->pcpp).last_active = _amTimeMs(time_start); if (callback != NULL) { @@ -367,7 +391,7 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { eVar4 = pcpaSendBinary(stream, timeout); stream->err = eVar4; if (eVar4 == e_pcpa_to) { - stream->state = 9; + stream->state = pcpa_state_wait_binary; } else { pcpaCloseBinary(stream); if (stream->binary_mode_after_cb != NULL) { @@ -375,7 +399,7 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { stream->binary_mode_after_cb = NULL; } stream->binary_mode = binary_mode_none; - stream->state = 0; + stream->state = pcpa_state_none; if (stream->err == e_pcpa_ok) { LAB_00454a1a: amiTimerGet(&time); @@ -388,7 +412,7 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { } } break; - case 8: + case pcpa_state_wait_response_binary: callback = stream->binary_mode_before_cb; (stream->pcpp).last_active = _amTimeMs(time_start); if (callback != NULL) { @@ -409,7 +433,7 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { eVar4 = pcpaRecvBinary(stream, timeout); stream->err = eVar4; if (eVar4 == e_pcpa_to) { - stream->state = 9; + stream->state = pcpa_state_wait_binary; } else { pcpaCloseBinary(stream); if (stream->binary_mode_after_cb != NULL) { @@ -417,7 +441,7 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { stream->binary_mode_after_cb = NULL; } stream->binary_mode = binary_mode_none; - stream->state = 0; + stream->state = pcpa_state_none; if (stream->err == e_pcpa_ok) goto LAB_00454a1a; PCP_LOG("error pcpaRecvBinary\n"); } @@ -456,7 +480,8 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { iVar3 = 0; LAB_004547cd: if (iVar3 == 0) { - (stream->callback_table[ms].callback)(stream, stream->callback_table[ms].data); + (stream->callback_table[ms].callback)(stream, + stream->callback_table[ms].data); goto LAB_004547f1; } ms = ms + 1; @@ -478,11 +503,11 @@ e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) { eVar4 = _errP2A(iVar5); stream->err = eVar4; if (eVar4 == e_pcpa_to) { - stream->state = 4; + stream->state = pcpa_state_send_response; } else { memset(&stream->send_data, 0, PCP_BUF_MAX); (stream->send_data).length = 0; - stream->state = 0; + stream->state = pcpa_state_none; } if (stream->binary_mode != binary_mode_none) { stream->state = (stream->binary_mode == binary_mode_send) ? 7 : 8; @@ -511,10 +536,11 @@ e_pcpa_t pcpaRecvBinary(pcpa_t *stream, uint something) { return stream->err = e_pcpa_cb_table_full; } - stream->state = 8; + stream->state = pcpa_state_wait_response_binary; e_pcpa_t err; - stream->err = err = _errP2A(pcppRecvBinary(&stream->pcpp, stream->recv_buffer, stream->recv_buffer_len, something)); - if (err != e_pcpa_to) stream->state = 0; + stream->err = err = _errP2A( + pcppRecvBinary(&stream->pcpp, stream->recv_buffer, stream->recv_buffer_len, something)); + if (err != e_pcpa_to) stream->state = pcpa_state_none; return err; } @@ -532,15 +558,16 @@ e_pcpa_t pcpaSendBinary(pcpa_t *stream, uint param_2) { return stream->err; } - stream->state = 7; + stream->state = pcpa_state_send_request_binary; e_pcpa_t err; - stream->err = err = _errP2A(pcppSendBinary(&stream->pcpp, stream->send_buffer, stream->send_buffer_len, param_2)); - if (err != e_pcpa_to) stream->state = 0; + stream->err = err = _errP2A( + pcppSendBinary(&stream->pcpp, stream->send_buffer, stream->send_buffer_len, param_2)); + if (err != e_pcpa_to) stream->state = pcpa_state_none; return err; } -e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t *stream, byte *send_buffer, size_t len) { +e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t *stream, unsigned char *send_buffer, size_t len) { if (stream == NULL) { PCP_LOG("error PCPA stream isn\'t set\n"); return e_pcpa_stream_unset; @@ -598,7 +625,7 @@ e_pcpa_t pcpaSetBinaryMode(pcpa_t *stream, binary_mode_t binary_mode) { return e_pcpa_ok; } -e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t *stream, byte *recv_buffer, size_t len) { +e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t *stream, unsigned char *recv_buffer, size_t len) { if (stream == NULL) { PCP_LOG("error PCPA stream isn\'t set\n"); return e_pcpa_stream_unset; @@ -628,3 +655,162 @@ char *pcpaGetKeyword(pcpa_t *stream, uint keyword_num) { } return pcppGetKeyword(&stream->recv_data, keyword_num); } + +e_pcpa_t pcpaIsBusy(pcpa_t *pcpa, timeout_t timeout) { + amtime_t now; + amtime_t start; + + if (pcpa == NULL) { + PCP_LOG("error PCPA stream isn\'t set\n"); + return e_pcpa_stream_unset; + } + + amiTimerGet(&start); + e_pcpa_t err = _pcpaGetErrorFromPcpp(pcppIsBusy(&pcpa->pcpp, timeout)); + pcpa->err = err; + if (err == e_pcpa_to) return e_pcpa_to; + + if (pcpa->state == pcpa_state_send_request) + memset(pcpa->send_data.data, 0, sizeof pcpa->send_data.data); + if (pcpa->err != e_pcpa_to) pcpa->state = pcpa_state_none; + + if (pcpa->state == 11) { + pcpa->state = 12; + if (timeout != TIMEOUT_NONE) { + amiTimerGet(&now); + uint dt = _amTimeDelta(now, start); + if (dt < timeout) { + timeout -= dt; + } else { + timeout = 0; + } + } + err = _pcpaGetErrorFromPcpp(pcppRecvResponse(&pcpa->pcpp, &pcpa->recv_data, timeout)); + pcpa->err = err; + if (err != e_pcpa_to) pcpa->state = pcpa_state_none; + } else if (pcpa->state == 13) { + pcpa->state = 14; + if (timeout != TIMEOUT_NONE) { + amiTimerGet(&now); + uint dt = _amTimeDelta(now, start); + if (dt < timeout) { + timeout -= dt; + } else { + timeout = 0; + } + } + + e_pcpp_t pcpp_err; + if (pcpa->binary_mode == binary_mode_send) { + pcpp_err = + pcppSendBinary(&pcpa->pcpp, pcpa->send_buffer, pcpa->send_buffer_len, timeout); + } else { + pcpp_err = + pcppRecvBinary(&pcpa->pcpp, pcpa->recv_buffer, pcpa->recv_buffer_len, timeout); + } + err = _pcpaGetErrorFromPcpp(pcpp_err); + pcpa->err = err; + if (err != e_pcpa_to) { + pcppCloseBinary(&pcpa->pcpp); + return pcpa->err; + } + } else if (pcpa->state == 14 && pcpa->err != e_pcpa_to) { + pcppCloseBinary(&pcpa->pcpp); + return pcpa->err; + } + return pcpa->err; +} + +e_pcpa_t pcpaSendRequest(pcpa_t *stream, timeout_t timeout) { + if (stream == NULL) { + PCP_LOG("error PCPA stream isn\'t set\n"); + return e_pcpa_stream_unset; + } + + stream->state = pcpa_state_send_request; + e_pcpa_t err = + _pcpaGetErrorFromPcpp(pcppSendRequestTable(&stream->pcpp, &stream->send_data, timeout)); + stream->err = err; + if (err != e_pcpa_to) { + if (err != e_pcpa_ok) PCP_LOG("Error : pcppSendRequestTable(%d)\n", err); + memset(&stream->send_data, 0, sizeof stream->send_data); + stream->state = pcpa_state_none; + } + return stream->err; +} + +e_pcpa_t pcpaRecvResponse(pcpa_t *stream, timeout_t timeout) { + if (stream == NULL) { + PCP_LOG("error PCPA stream isn\'t set\n"); + return e_pcpa_stream_unset; + } + + stream->state = pcpa_state_wait_response; + e_pcpa_t err = + _pcpaGetErrorFromPcpp(pcppRecvResponse(&stream->pcpp, &stream->recv_data, timeout)); + stream->err = err; + if (err != e_pcpa_to) { + if (err != e_pcpa_ok) PCP_LOG("Error : pcppRecvResponse(%d)\n", err); + stream->state = pcpa_state_none; + } + return err; +} + +e_pcpa_t pcpaOpenBinaryClient(pcpa_t *stream, ushort port, timeout_t timeout) { + if (stream == NULL) { + PCP_LOG("error PCPA stream isn\'t set\n"); + return e_pcpa_stream_unset; + } + + SOCKADDR_IN *addr = (SOCKADDR_IN *)pcppGetSockAddr(&stream->pcpp, false); + stream->state = pcpa_state_open_binary; + char *ipAddr = inet_ntoa(addr->sin_addr); + + e_pcpa_t pcpa_err = + _pcpaGetErrorFromPcpp(pcppOpenBinaryClient(&stream->pcpp, ipAddr, port, timeout)); + stream->err = pcpa_err; + if (pcpa_err == e_pcpa_to) { + stream->state = pcpa_state_none; + } + return pcpa_err; +} + +e_pcpa_t pcpaAccessClient(pcpa_t *stream, timeout_t timeout) { + if (stream == NULL) { + PCP_LOG("error PCPA stream isn\'t set\n"); + return e_pcpa_stream_unset; + } + + amtime_t start, now; + e_pcpp_t pcpa_err; + + amiTimerGet(&start); + stream->state = pcpa_state_send_request_table; + + pcpa_err = + _pcpaGetErrorFromPcpp(pcppSendRequestTable(&stream->pcpp, &stream->send_data, timeout)); + stream->err = pcpa_err; + if (pcpa_err != e_pcpa_to) stream->state = pcpa_state_none; + + if (pcpa_err != e_pcpa_ok) return pcpa_err; + + if (pcpa_err == 0) { + stream->state = pcpa_state_12; + + if (timeout != TIMEOUT_NONE) { + amiTimerGet(&now); + uint delta = amiTimerDiffMsec(&start, &now); + if (delta < timeout) { + timeout -= delta; + } else { + timeout = 0; + } + } + + pcpa_err = + _pcpaGetErrorFromPcpp(pcppRecvResponse(&stream->pcpp, &stream->recv_data, timeout)); + stream->err = pcpa_err; + if (pcpa_err != e_pcpa_to) stream->state = pcpa_state_none; + } + return pcpa_err; +} diff --git a/src/micetools/lib/libpcp/pcpa.h b/src/micetools/lib/libpcp/pcpa.h index 0f93891..cdec847 100644 --- a/src/micetools/lib/libpcp/pcpa.h +++ b/src/micetools/lib/libpcp/pcpa.h @@ -1,3 +1,5 @@ +#pragma once + #include "pcpp.h" typedef enum e_pcpa { @@ -13,6 +15,7 @@ typedef enum e_pcpa { e_pcpa_cb_table_full = -9, e_pcpa_stream_unset = -10, e_pcpa_cb_table_unset = -11, + e_pcpa_no_server = -13, e_pcpa_timeout_open = -14, e_pcpa_inval_addr = -17, e_pcpa_already_open = -18, @@ -20,6 +23,22 @@ typedef enum e_pcpa { e_pcpa_unknown = -21, } e_pcpa_t; +typedef enum { + pcpa_state_none = 0, + pcpa_state_wait_prompt = 1, + pcpa_state_send_request = 2, + pcpa_state_wait_request = 3, + pcpa_state_send_response = 4, + pcpa_state_wait_response = 5, + pcpa_state_open_binary = 6, + pcpa_state_send_request_binary = 7, + pcpa_state_wait_response_binary = 8, + pcpa_state_wait_binary = 9, + + pcpa_state_send_request_table = 11, + pcpa_state_12 = 12, +} pcpa_state_t; + e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err); #define _errP2A(err) _pcpaGetErrorFromPcpp(err) @@ -60,6 +79,7 @@ void pcpaClose(pcpa_t* stream); void pcpaCloseBinary(pcpa_t* stream); char* pcpaGetKeyword(pcpa_t* stream, uint keyword_num); e_pcpa_t pcpaInitStream(pcpa_t* stream); +e_pcpa_t pcpaOpenClient(pcpa_t* stream, char* ipAddr, ushort port, uint param_4, timeout_t timeout); e_pcpa_t pcpaOpenServerWithBinary(pcpa_t* stream, int open_mode, ushort port, ushort binary_port, undefined4 param_5); e_pcpa_t pcpaRecvBinary(pcpa_t* stream, undefined4 something); e_pcpa_t pcpaSendBinary(pcpa_t* stream, undefined4 something); @@ -69,8 +89,14 @@ e_pcpa_t pcpaSetBeforeBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* call e_pcpa_t pcpaSetBinaryMode(pcpa_t* stream, binary_mode_t binary_mode); e_pcpa_t pcpaSetCallbackFunc(pcpa_t* stream, char* keyword, pcpa_callback* callback, void* data); e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t* stream, pcpa_cb_table_t* callback_table, uint callbacks_max); -e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t* stream, byte* recv_buffer, size_t len); -e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t* stream, byte* send_buffer, size_t len); +e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t* stream, unsigned char* recv_buffer, size_t len); +e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t* stream, unsigned char* send_buffer, size_t len); pcp_send_data_t* pcpaSetSendPacket(pcpa_t* stream, char* keyword, char* value); pcp_send_data_t *pcpaAddSendPacket(pcpa_t *stream, char *keyword, char *value); char* pcpaGetCommand(pcpa_t* pcpa, char* command); +e_pcpa_t pcpaIsBusy(pcpa_t *pcpa, timeout_t timeout); +e_pcpa_t pcpaSendRequest(pcpa_t *stream, timeout_t timeout); +e_pcpa_t pcpaRecvResponse(pcpa_t *stream, timeout_t timeout); +e_pcpa_t pcpaOpenBinaryClient(pcpa_t *stream, ushort port, timeout_t timeout); + +e_pcpa_t pcpaAccessClient(pcpa_t* stream, timeout_t timeout); diff --git a/src/micetools/lib/libpcp/pcpp.c b/src/micetools/lib/libpcp/pcpp.c index 4ee7b3e..9ed4846 100644 --- a/src/micetools/lib/libpcp/pcpp.c +++ b/src/micetools/lib/libpcp/pcpp.c @@ -2,16 +2,17 @@ int FUN_00459d00(amtime_t* t1, amtime_t* t2) { if (t1 == NULL || t2 == NULL) return -1; - return ((t2->seconds - t1->seconds) * 1000000 - t1->microseconds) + t2->microseconds; // Swapped + return ((t2->seconds - t1->seconds) * 1000000 - t1->microseconds) + + t2->microseconds; // Swapped } // TODO: Invert these conditions to be clearer -int pcpp_isValidChar(char chr) { - if (!isalnum(chr) && chr != '.' && chr != '_' && chr != '-' && chr != ':' && chr != '@' && chr != '%' && - chr != '/' && chr != '\\' && chr != '#' && chr != '{' && chr != '}') { - return 0; +int pcppIsValidDataChar(char chr) { + if (isalnum(chr) || chr == '.' || chr == '_' || chr == '-' || chr == ':' || chr == '@' || + chr == '%' || chr == '/' || chr == '\\' || chr == '#' || chr == '{' || chr == '}') { + return 1; } - return 1; + return 0; } e_pcpp_t _pcppGetErrorFromPcpt(int err) { @@ -62,13 +63,13 @@ bool pcppCheckPrompt(pcpp_t* stream) { bool found = false; for (uint cursor = 0; cursor < max; cursor++) { - unsigned char* pos = stream->read_bytes_buf + cursor; + char* pos = stream->read_bytes_buf + cursor; if (stream->read_bytes_buf[cursor] == '>') { if (cursor < stream->read_bytes_num) { do { *pos = pos[1]; pos++; - } while (pos + (-204 - (int)stream) < (unsigned char*)stream->read_bytes_num); + } while (pos + (-204 - (int)stream) < (char*)stream->read_bytes_num); } stream->read_bytes_num--; @@ -80,18 +81,18 @@ bool pcppCheckPrompt(pcpp_t* stream) { return found; } -e_pcpp_t pcppCheckRecvMsg(unsigned char* recv_data, size_t buf_len, int param_3) { +e_pcpp_t pcppCheckRecvMsg(char* recv_data, size_t buf_len, int param_3) { bool bVar1 = true; - int local_8 = 0; if (recv_data == NULL) { PCP_LOG("pointer error\n"); return e_pcpp_param_invalid; } + int check_offset = 0; while (1) { - local_8 = buf_len - local_8; - uint recv_err = pcppRecvCheck(recv_data, &local_8); + check_offset = buf_len - check_offset; + uint recv_err = pcppRecvCheck(recv_data, &check_offset); if (recv_err == 1) return e_pcpp_param_invalid; if (recv_err == 8) { @@ -101,8 +102,8 @@ e_pcpp_t pcppCheckRecvMsg(unsigned char* recv_data, size_t buf_len, int param_3) if (recv_err == 7 && !bVar1) return e_pcpp_param_invalid; } - recv_data += local_8; - local_8++; + recv_data += check_offset; + check_offset++; bVar1 = false; if (recv_err == 0 || recv_err == 6 || recv_err == 7 || recv_err == 8) { @@ -111,59 +112,59 @@ e_pcpp_t pcppCheckRecvMsg(unsigned char* recv_data, size_t buf_len, int param_3) } } -uint pcppCheckStr(unsigned char* recv_data, uint* found_at, int* find_failed) { +pcpp_char_type_t pcppCheckStr(char* recv_data, uint* found_at, int* is_qmark) { bool end = false; - bool bVar2 = false; + bool saw_data = false; uint idx = 0; - if (recv_data == NULL || find_failed == NULL || found_at == NULL) { + if (recv_data == NULL || is_qmark == NULL || found_at == NULL) { PCP_LOG("pointer error\n"); - return 0; + return pcpp_char_error; } - *find_failed = 0; - if (*found_at == 0) return 0; + *is_qmark = 0; + if (*found_at == 0) { + PCP_LOG("stream exhausted\n"); + return pcpp_char_error; + } do { char chr = recv_data[idx]; if (PCP_WHITESPACE(chr)) { - if (bVar2) end = true; - } else { - if (!pcpp_isValidChar(chr)) { - if (recv_data[idx] != PCP_CHAR_UNKNOWN) { - *found_at = idx + 1; - switch (recv_data[idx]) { - case PCP_CHAR_SEP: - return 5; - case PCP_CHAR_CR: - if (recv_data[idx + 1] != '\n') return 3; - *found_at = idx + 2; - return 4; - case PCP_CHAR_LF: - return 2; - case PCP_CHAR_EQU: - return 1; - default: - return 0; - } - } - if (bVar2 || end) { - *found_at = idx + 1; - return 0; - } + if (saw_data) end = true; + } else if (pcppIsValidDataChar(chr)) { + if (end || *is_qmark != 0) { + *found_at = idx + 1; + return pcpp_char_error; + } + saw_data = true; + } else if (chr == PCP_CHAR_QMARK) { + if (saw_data || end) { + *found_at = idx + 1; + return pcpp_char_error; + } - *find_failed = 1; - } else { - if (end || *find_failed != 0) { - *found_at = idx + 1; - return 0; - } - bVar2 = true; + *is_qmark = 1; + } else { + *found_at = idx + 1; + switch (chr) { + case PCP_CHAR_SEP: + return pcpp_char_sep; + case PCP_CHAR_CR: + if (recv_data[idx + 1] != '\n') return pcpp_char_crlf; + *found_at = idx + 2; + return pcpp_char_cr; + case PCP_CHAR_LF: + return pcpp_char_lf; + case PCP_CHAR_EQU: + return pcpp_char_equ; + default: + return pcpp_char_error; } } idx++; - if (*found_at <= idx) return 0; + if (*found_at <= idx) return pcpp_char_error; } while (true); } @@ -178,14 +179,13 @@ void pcppClose(pcpp_t* stream) { stream->field_0xb8 = 0; stream->last_active = 0; - stream->state = 0; + stream->state = pcpp_state_none; stream->err = e_pcpp_unknown; stream->recv_data_buffer = NULL; memset(stream->read_bytes_buf, 0, sizeof stream->read_bytes_buf); stream->read_bytes_size = sizeof stream->read_bytes_buf; stream->read_bytes_num = 0; stream->resp_buffer = NULL; - stream->resp_buffer_len = 0; ZERO(stream->send_buf); stream->send_buf_len = PCP_SEND_BUF_MAX; stream->field_0x1e8 = 0; @@ -210,15 +210,15 @@ void pcppCloseBinary(pcpp_t* stream) { stream->read_bytes_num = 0; memset(stream->read_bytes_buf, 0, sizeof stream->read_bytes_buf); stream->resp_buffer = NULL; - stream->resp_buffer_len = 0; amtime_t time; amiTimerGet(&time); stream->last_active = _amTimeMs(time); - stream->state = 0; + stream->state = pcpp_state_none; } -e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t timeout, pcpp_t* stream, int param_4, uint* blocking_time) { +e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t timeout, pcpp_t* stream, int param_4, + uint* blocking_time) { byte bVar1; uint uVar2; uint uVar3; @@ -230,7 +230,8 @@ e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t timeout, pcpp_t* stream, in } amiTimerGet(&local_8); - uVar2 = (local_8.seconds * 1000 - stream->last_active) + local_8.microseconds / 1000; // swapped + uVar2 = + (local_8.seconds * 1000 - stream->last_active) + local_8.microseconds / 1000; // swapped if (param_1 <= uVar2) { *blocking_time = 0; return 1; @@ -318,7 +319,7 @@ e_pcpp_t pcppInitStream(pcpp_t* stream) { stream->field_0xb8 = 0; stream->last_active = 0; - stream->state = 0; + stream->state = pcpp_state_none; stream->err = e_pcpp_unknown; stream->recv_data_buffer = NULL; ZERO(stream->read_bytes_buf); @@ -326,7 +327,6 @@ e_pcpp_t pcppInitStream(pcpp_t* stream) { stream->read_bytes_size = sizeof stream->read_bytes_buf; stream->read_bytes_num = 0; stream->resp_buffer = NULL; - stream->resp_buffer_len = 0; ZERO(stream->send_buf); stream->field_0x1e8 = 0; stream->send_binary_buf = NULL; @@ -345,6 +345,71 @@ e_pcpp_t pcppInitStream(pcpp_t* stream) { return e_pcpp_ok; } +e_pcpp_t pcppOpenClient(pcpp_t* stream, char* ipAddr, ushort port, uint param_4, + timeout_t timeout) { + e_pcpp_t iVar1; + uint uVar3; + amtime_t start; + amtime_t now; + + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (ipAddr == NULL) { + PCP_LOG("error IpAddr isn\'t set\n"); + return e_pcpp_param_invalid; + } + + stream->state = pcpp_state_open; + stream->field_0xb8 = param_4; + stream->open = 0; + amiTimerGet(&start); + iVar1 = start.microseconds / 1000 + start.seconds * 1000; + stream->last_active = iVar1; + e_pcpp_t err = pcppGetBlockingTime(stream->field_0x210, timeout, stream, iVar1, &timeout); + e_pcpp_t err2 = _pcppGetErrorFromPcpt(pcptOpenClient(&stream->sock, ipAddr, port, timeout)); + stream->err = err2; + if (err2 == e_pcpp_to) { + if (err == e_pcpp_ok) { + return e_pcpp_to; + } + stream->err = e_pcpp_no_server; + PCP_LOG("error Time out error\n"); + } + if (stream->err == 0) { + amiTimerGet(&now); + stream->last_active = now.microseconds / 1000 + now.seconds * 1000; + if (timeout != TIMEOUT_NONE) { + uVar3 = (now.microseconds - start.microseconds) / 1000 + + (now.seconds - start.seconds) * 1000; + if (uVar3 < timeout) { + timeout -= uVar3; + } else { + timeout = 0; + } + } + stream->open = 1; + stream->state = pcpp_state_wait_prompt; + err = pcppRecvPrompt(stream, stream->field_0xb8, timeout); + stream->err = err; + if ((err == e_pcpp_to) || (stream->state = pcpp_state_none, err == e_pcpp_ok)) + goto LAB_00a16a90; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + err = stream->err; + PCP_LOG("error pcppRecvPrompt error = %d\n", err); + } else { + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + stream->state = pcpp_state_none; + err = stream->err; + PCP_LOG("error pcptOpenClient error = %d\n", err); + } +LAB_00a16a90: + return stream->err; +} + e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port) { if (stream == NULL) { PCP_LOG("error PCPP stream isn\'t set\n"); @@ -354,10 +419,10 @@ e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port) { amtime_t time; amiTimerGet(&time); stream->last_active = _amTimeMs(time); - stream->state = 0; + stream->state = pcpp_state_none; if (open_mode != 0 && open_mode != 1) { PCP_LOG("error Open Mode isn\'t set\n"); - stream->state = 0; + stream->state = pcpp_state_none; return stream->err = e_pcpp_param_invalid; } @@ -373,6 +438,44 @@ e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port) { return e_pcpp_ok; } +e_pcpp_t pcppOpenBinaryClient(pcpp_t* stream, char* ipAddr, ushort port, timeout_t timeout) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (ipAddr == NULL) { + PCP_LOG("error IpAddr isn\'t set\n"); + return e_pcpp_param_invalid; + } + stream->state = pcpp_state_open_binary; + + amtime_t time; + amiTimerGet(&time); + stream->last_active = _amTimeMs(time); + + bool bVar1 = false; + if (timeout == TIMEOUT_NONE || + (stream->field_0x210 <= timeout && timeout != stream->field_0x210)) { + bVar1 = true; + } + + e_pcpp_t pcpp_err = + _pcppGetErrorFromPcpt(pcptOpenClient(&stream->data_sock, ipAddr, port, timeout)); + stream->err = pcpp_err; + if (pcpp_err == e_pcpp_to && bVar1) { + stream->err = e_pcpp_no_server; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + + if (stream->err != e_pcpp_to) stream->state = pcpp_state_none; + if (stream->err == e_pcpp_ok) { + amiTimerGet(&time); + stream->last_active = _amTimeMs(time); + } + return stream->err; +} + e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, u_short port, undefined4 param_4) { if (stream == NULL) { PCP_LOG("error PCPP stream isn\'t set\n"); @@ -383,7 +486,7 @@ e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, u_short port, undefined4 PCP_LOG("error Open Mode isn\'t set\n"); stream->err = e_pcpp_param_invalid; - stream->state = 0; + stream->state = pcpp_state_none; return e_pcpp_param_invalid; } @@ -428,43 +531,59 @@ pcp_send_data_t* pcppSetSendPacket(pcp_send_data_t* send_data, char* keyword, ch return NULL; } -uint pcppRecvCheck(unsigned char* buf, int* found_at) { - uint uVar1; - uint uVar3; - int find_failed; - uint found_at_; - int local_4; - - uVar3 = 0; - find_failed = 0; - if (buf == NULL || found_at == NULL) { +uint pcppRecvCheck(char* buf, int* offset) { + if (buf == NULL || offset == NULL) { PCP_LOG("pointer error\n"); return 1; } - local_4 = *found_at; - *found_at = 0; - for (int uVar2 = 0; uVar2 < 2; uVar2++) { - found_at_ = local_4 - uVar3; - uVar1 = pcppCheckStr(&buf[uVar3], &found_at_, &find_failed); - *found_at = *found_at + found_at_; + uint total_length = *offset; + *offset = 0; - switch (uVar1) { - case 0: + uint local_offset = 0; + + /** + * The following are the patterns this function validates against: + * + * * ? [equ ] -> 1 NG eg ?= + * * . [sep ] -> 3 -> eg keychip.version& + * * ? [sep ] -> 5 -> eq ?& + * * . [crlf] -> 6 OK eg keychip.version\r\n + * * ? [crlf] -> 8 OK eg ?\r\n + * * . [equ ] -> continue \/ eg keychip.version= + * + * * . [equ ] . [crlf] -> 0 OK eg keychip.version=1\r\n + * * . [equ ] * [equ ] -> 1 NG eg keychip.version=1= + * * . [equ ] . [sep ] -> 2 -> eg keychip.version=1& + * * . [equ ] ? [sep ] -> 4 -> eg keychip.version=?& + * * . [equ ] ? [crlf] -> 7 OK eg keychip.version=?\r\n + */ + + for (int is_value = 0; is_value < 2; is_value++) { + uint nbytes = total_length - local_offset; + int is_qmark = 0; + pcpp_char_type_t char_type = pcppCheckStr(&buf[local_offset], &nbytes, &is_qmark); + *offset += nbytes; + + switch (char_type) { + case pcpp_char_error: return 1; - case 1: - if (uVar2) return 1; - uVar3 = found_at_; - if (find_failed) return 1; + + case pcpp_char_equ: + if (is_value) return 1; + local_offset = nbytes; + if (is_qmark) return 1; break; - case 2: - case 3: - case 4: - if (uVar2) return find_failed ? 7 : 0; - return find_failed ? 8 : 6; - case 5: - if (uVar2) return find_failed ? 4 : 2; - return find_failed ? 5 : 3; + + case pcpp_char_lf: + case pcpp_char_crlf: + case pcpp_char_cr: + if (is_value) return is_qmark ? 7 : 0; + return is_qmark ? 8 : 6; + + case pcpp_char_sep: + if (is_value) return is_qmark ? 4 : 2; + return is_qmark ? 5 : 3; } } return 1; @@ -483,7 +602,8 @@ e_pcpp_t pcppSendResponseTable(pcpp_t* stream, pcp_send_data_t* data, timeout_t return pcppSendResponse(stream, data, data->length + 2, timeout_ms); } -e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, timeout_t timeout_ms) +e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, + timeout_t timeout_ms) { e_pcpp_t err; @@ -499,27 +619,29 @@ e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t b } if (buf_len > PCP_BUF_MAX - 1) { + PCP_LOG("error Response buffer over\n"); return stream->err = e_pcpp_param_invalid; } amiTimerGet(&time); - stream->err = err = pcppCheckRecvMsg(resp_buffer->data, buf_len, 0); + stream->err = err = pcppCheckRecvMsg((char*)resp_buffer->data, buf_len, 0); if (err != e_pcpp_ok) { - stream->state = 0; + stream->state = pcpp_state_none; pcppResetRead(stream); PCP_LOG("error Send message format error\n"); + printf("'%s'\n", resp_buffer->data); return stream->err; } + resp_buffer->length = buf_len; stream->resp_buffer = resp_buffer; - stream->resp_buffer_len = buf_len; - stream->state = 6; - err = pcpp_something(&time, timeout_ms, stream, &stream->sock, resp_buffer->data, &stream->resp_buffer_len, - stream->field_0x204, stream->field_0x210, -6); + stream->state = pcpp_state_send_response; + err = pcpp_something(&time, timeout_ms, stream, &stream->sock, resp_buffer->data, + &resp_buffer->length, stream->field_0x204, stream->field_0x210, -6); stream->err = err; if (err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; if (err != e_pcpp_ok) { pcptCloseDataSock(&stream->sock); pcppResetRead(stream); @@ -535,7 +657,6 @@ void pcppResetRead(pcpp_t* stream) { stream->read_bytes_num = 0; ZERO_BUF(stream->read_bytes_buf); stream->resp_buffer = NULL; - stream->resp_buffer_len = 0; } e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t timeout) { @@ -562,17 +683,17 @@ e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t } stream->recv_data_buffer = recv_data; amiTimerGet(&start); - stream->state = 2; + stream->state = pcpp_state_send_prompt; err = pcppSendPrompt(stream, uVar1, timeout_ms); stream->err = err; if (err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (err == e_pcpp_ok) { stream->open = 0; amiTimerGet(&now); stream->last_active = _amTimeMs(now); - stream->state = 5; + stream->state = pcpp_state_recv_request; if (timeout_ms != TIMEOUT_NONE) { uint elapsed = _amTimeDelta(now, start); if (elapsed < timeout_ms) { @@ -591,7 +712,7 @@ e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t return e_pcpp_to; } } else { - stream->state = 0; + stream->state = pcpp_state_none; if (err == e_pcpp_ok) { amiTimerGet(&now2); stream->last_active = _amTimeMs(now2); @@ -602,8 +723,8 @@ e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t return err; } -e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3) { - unsigned char* recv_data; +e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 timeout) { + char* recv_data; if (stream == NULL) { PCP_LOG("error PCPP stream isn\'t set\n"); @@ -612,7 +733,7 @@ e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3) stream->field_0x214 = 0; - e_pcpp_t err = pcppRecvAllMsg(param_3, stream, bReRecv); + e_pcpp_t err = pcppRecvAllMsg(stream, timeout, bReRecv); if (err != e_pcpp_ok) return err; recv_data = stream->read_bytes_buf; @@ -624,7 +745,8 @@ e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3) uint local_4 = 0; pcppChangeRequest(stream, &local_4); - if (local_4 < stream->read_bytes_num) memcpy(recv_data + local_4, recv_data, stream->read_bytes_num); + if (local_4 < stream->read_bytes_num) + memcpy(recv_data + local_4, recv_data, stream->read_bytes_num); stream->read_bytes_num -= local_4; stream->read_bytes_size += local_4; @@ -656,7 +778,8 @@ LAB_00456133: *send_len = 1; if ((stream->sock).open == PCPT_LISTENING) stream->open = 1; - e_pcpp_t err = _errT2P(pcptSend(&stream->sock, stream->send_buf, send_len, stream->field_0x204, timeout_ms)); + e_pcpp_t err = _errT2P(pcptSend(&stream->sock, (unsigned char*)stream->send_buf, send_len, + stream->field_0x204, timeout_ms)); if (has_timeout && err == e_pcpp_to) { err = stream->open ? -12 : -6; @@ -669,7 +792,7 @@ LAB_00456133: return err; } -e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv) { +e_pcpp_t pcppRecvAllMsg(pcpp_t* stream, uint param_1, bool* bReRecv) { uint* recv_buf_len; int iVar1; e_pcpt_t err; @@ -704,19 +827,18 @@ e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv) { iVar1 = pcppGetBlockingTime(uVar3, param_1, stream, _amTimeMs(local_10), &local_14); recv_buf_len = &stream->read_bytes_size; *recv_buf_len = PCP_BUF_MAX - stream->read_bytes_num; - err = pcptRecv(&stream->sock, (stream->read_bytes_buf + stream->read_bytes_num), recv_buf_len, local_14); - eVar2 = _errT2P(err); + eVar2 = _errT2P(pcptRecv(&stream->sock, + (unsigned char*)(stream->read_bytes_buf + stream->read_bytes_num), + recv_buf_len, local_14)); if (eVar2 == e_pcpp_to) { - if (iVar1 == 0) { - return e_pcpp_to; - } + if (iVar1 == 0) return e_pcpp_to; + eVar2 = e_pcpp_timeout_closed - (uint)(stream->field_0x214 != 0); pcptCloseDataSock(&stream->sock); *recv_buf_len = PCP_BUF_MAX; stream->read_bytes_num = 0; ZERO_BUF(stream->read_bytes_buf); stream->resp_buffer = NULL; - stream->resp_buffer_len = 0; } if (eVar2 != e_pcpp_ok) { return eVar2; @@ -741,9 +863,6 @@ e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv) { } pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, uint* lenout) { - byte bVar5 = 0; - byte bVar6 = 0; - if (stream == NULL || lenout == NULL) { PCP_LOG("pointer error\n"); return NULL; @@ -772,13 +891,13 @@ pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, uint* lenout) { } bool comment = false; - + byte string_idx = 0; size_t i; for (i = 0; i < stream->read_bytes_num; i++) { char chr = stream->read_bytes_buf[i]; if (chr == PCP_CHAR_CR || chr == PCP_CHAR_LF) { - stream->recv_data_buffer->strings[++bVar6] = PCP_CHAR_EOF; + stream->recv_data_buffer->strings[string_idx] = PCP_CHAR_EOF; if (i + 1 < stream->read_bytes_num && stream->read_bytes_buf[i] == PCP_CHAR_CR && stream->read_bytes_buf[i + 1] == PCP_CHAR_LF) i++; @@ -793,36 +912,35 @@ pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, uint* lenout) { } switch (chr) { - case PCP_CHAR_UNKNOWN: - stream->recv_data_buffer->strings[bVar6++] = PCP_CHAR_UNKNOWN; + case PCP_CHAR_QMARK: + stream->recv_data_buffer->strings[string_idx++] = PCP_CHAR_QMARK; break; case PCP_CHAR_SEP: if (stream->recv_data_buffer->cmd_count > PCP_CMDS_MAX) { PCP_LOG("Buffer size error\n"); return NULL; } - stream->recv_data_buffer->strings[++bVar6] = PCP_CHAR_EOF; - stream->recv_data_buffer->keywords[stream->recv_data_buffer->cmd_count] = bVar6++; + stream->recv_data_buffer->strings[string_idx] = PCP_CHAR_EOF; + stream->recv_data_buffer->keywords[stream->recv_data_buffer->cmd_count] = + ++string_idx; stream->recv_data_buffer->cmd_count++; - bVar5 = bVar6; break; case PCP_CHAR_EQU: if (stream->recv_data_buffer->cmd_count > PCP_CMDS_MAX) { PCP_LOG("Buffer size error\n"); return NULL; } - stream->recv_data_buffer->strings[++bVar6] = PCP_CHAR_EOF; - stream->recv_data_buffer->keywords[stream->recv_data_buffer->cmd_count + PCP_CMDS_MAX - 1] = bVar6++; - bVar5 = bVar6; + stream->recv_data_buffer->strings[string_idx] = PCP_CHAR_EOF; + stream->recv_data_buffer + ->keywords[stream->recv_data_buffer->cmd_count + PCP_CMDS_MAX - 1] = + ++string_idx; break; case PCP_CHAR_HASH: comment = true; break; default: - bVar6 = bVar5; - if (pcpp_isValidChar(chr)) { - stream->recv_data_buffer->strings[bVar5++] = stream->read_bytes_buf[i]; - } + if (pcppIsValidDataChar(chr)) + stream->recv_data_buffer->strings[string_idx++] = stream->read_bytes_buf[i]; } } *lenout = i + 1; @@ -851,7 +969,9 @@ int pcppRecvPrompt(pcpp_t* stream, undefined4 param_2, int param_3) { iVar1 = pcppGetBlockingTime(param_2, param_3, stream, _amTimeMs(start), &local_c); recv_buf_len = &stream->read_bytes_size; - err = _errT2P(pcptRecv(&stream->sock, stream->read_bytes_buf + stream->read_bytes_num, recv_buf_len, local_c)); + err = _errT2P(pcptRecv(&stream->sock, + (unsigned char*)(stream->read_bytes_buf + stream->read_bytes_num), + recv_buf_len, local_c)); if (err == e_pcpp_to) break; if (err != e_pcpp_ok) { return err; @@ -888,8 +1008,10 @@ e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, timeout_t timeo amiTimerGet(&now); e_pcpp_t eVar1 = - pcpp_something(&now, timeout_ms, stream, (pcpt_t*)stream, stream->resp_buffer->data, &stream->resp_buffer_len, - stream->field_0x204, param_2, stream->open ? e_pcpp_timeout_open : e_pcpp_timeout_closed); + pcpp_something(&now, timeout_ms, stream, &stream->sock, stream->resp_buffer->data, + &stream->resp_buffer->length, stream->field_0x204, param_2, + stream->open ? e_pcpp_timeout_open : e_pcpp_timeout_closed); + if (eVar1 != e_pcpp_to && eVar1 != e_pcpp_ok) { pcptCloseDataSock(&stream->sock); pcppResetRead(stream); @@ -903,7 +1025,7 @@ e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, timeout_t timeo e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, uint param_4) { size_t* psVar1; - unsigned char** send_buf; + char** send_buf; int iVar2; e_pcpt_t eVar3; e_pcpp_t eVar4; @@ -930,7 +1052,7 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, *psVar1 = buf_len; stream->recv_binary_buf_len = buf_len; stream->field_0x1fc = 0; - stream->state = 11; + stream->state = pcpp_state_recv_binary; memset(recv_buf, 0, buf_len); do { bVar6 = (stream->data_sock).open != PCPT_LISTENING; @@ -944,17 +1066,17 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, } iVar2 = pcppGetBlockingTime(uVar5, param_4, stream, _amTimeMs(now), &recvb_local); stream->field_0x214 = 1; - eVar3 = pcptRecv(&stream->data_sock, stream->recv_binary_buf + stream->field_0x1fc, psVar1, recvb_local); + eVar3 = pcptRecv(&stream->data_sock, stream->recv_binary_buf + stream->field_0x1fc, psVar1, + recvb_local); eVar4 = _errT2P(eVar3); stream->err = eVar4; if ((eVar4 == e_pcpp_to) && (iVar2 != 0)) { - stream->err = bVar6 ? -13 : -11; + stream->err = bVar6 ? -13 : e_pcpp_no_server; pcptCloseDataSock(&stream->sock); stream->read_bytes_size = PCP_BUF_MAX; stream->read_bytes_num = 0; memset(stream->read_bytes_buf, 0, PCP_BUF_MAX); stream->resp_buffer = NULL; - stream->resp_buffer_len = 0; } eVar4 = stream->err; if (eVar4 == e_pcpp_to) { @@ -964,7 +1086,7 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, } } else { if (eVar4 != e_pcpp_ok) { - stream->state = 0; + stream->state = pcpp_state_none; goto LAB_00455e91; } } @@ -973,14 +1095,17 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, stream->field_0x214 = 0; amiTimerGet(&local_10); stream->last_active = _amTimeMs(local_10); - if (stream->recv_binary_buf_len < stream->field_0x1fc || stream->recv_binary_buf_len == stream->field_0x1fc) { - send_buf = (unsigned char**)&stream->send_buf; + if (stream->recv_binary_buf_len < stream->field_0x1fc || + stream->recv_binary_buf_len == stream->field_0x1fc) { + send_buf = (char**)&stream->send_buf; psVar1 = &stream->send_buf_len; - stream->state = 12; + stream->state = pcpp_state_send_binary_ack; *send_buf[0] = PCP_CHAR_BINACK; *psVar1 = 1; - iVar2 = pcppGetBlockingTime(stream->field_0x20c, param_4, stream, _amTimeMs(now), &recvb_local); - eVar3 = pcptSend(&stream->sock, *send_buf, psVar1, stream->field_0x208, recvb_local); + iVar2 = pcppGetBlockingTime(stream->field_0x20c, param_4, stream, _amTimeMs(now), + &recvb_local); + eVar3 = pcptSend(&stream->sock, (unsigned char*)*send_buf, psVar1, stream->field_0x208, + recvb_local); eVar4 = _errT2P(eVar3); stream->err = eVar4; if ((eVar4 == e_pcpp_to) && (iVar2 != 0)) { @@ -990,23 +1115,25 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, } eVar4 = stream->err; if (eVar4 != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (eVar4 == e_pcpp_ok) { amiTimerGet(&local_10); stream->last_active = _amTimeMs(local_10); - stream->state = 13; - iVar2 = pcppGetBlockingTime(stream->field_0x208, param_4, stream, _amTimeMs(now), &recvb_local); + stream->state = pcpp_state_send_binary_ack_wait; + iVar2 = pcppGetBlockingTime(stream->field_0x208, param_4, stream, _amTimeMs(now), + &recvb_local); *psVar1 = PCP_SEND_BUF_MAX; ZERO(stream->send_buf); - eVar3 = pcptRecv(&stream->data_sock, *send_buf, psVar1, recvb_local); + eVar3 = + pcptRecv(&stream->data_sock, (unsigned char*)*send_buf, psVar1, recvb_local); eVar4 = _errT2P(eVar3); stream->err = eVar4; if ((iVar2 != 0) && (eVar4 == e_pcpp_to)) { stream->err = -13; } if (stream->err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err == e_pcpp_closed) { stream->err = e_pcpp_ok; @@ -1018,7 +1145,8 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, } while (true); } -e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_t param_3, uint param_4) +e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_t param_3, + uint param_4) { size_t* psVar1; @@ -1043,17 +1171,19 @@ e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_ amiTimerGet(&local_8); pVar2 = (stream->data_sock).open; psVar1 = &stream->field_0x1f0; - stream->state = 9; + stream->state = pcpp_state_send_binary; *psVar1 = param_3; stream->send_binary_buf = send_binary_buffer; if (pVar2 == PCPT_LISTENING) { amiTimerGet(&local_10); stream->last_active = _amTimeMs(local_10); - eVar3 = pcpp_something(&local_8, param_4, stream, &stream->data_sock, stream->send_binary_buf, psVar1, - stream->field_0x208, stream->field_0x210, -11); + eVar3 = + pcpp_something(&local_8, param_4, stream, &stream->data_sock, stream->send_binary_buf, + psVar1, stream->field_0x208, stream->field_0x210, -11); stream->err = eVar3; } else { - eVar5 = pcptSend(&stream->data_sock, send_binary_buffer, psVar1, stream->field_0x208, param_4); + eVar5 = + pcptSend(&stream->data_sock, send_binary_buffer, psVar1, stream->field_0x208, param_4); eVar3 = _errT2P(eVar5); iVar4 = (stream->data_sock).field_0x54; stream->err = eVar3; @@ -1064,18 +1194,19 @@ e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_ } eVar3 = stream->err; if (eVar3 != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (eVar3 == e_pcpp_ok) { amiTimerGet(&local_10); stream->last_active = _amTimeMs(local_10); - stream->state = 10; + stream->state = pcpp_state_send_binary_wait; psVar1 = &stream->send_buf_len; *psVar1 = 8; ZERO(stream->send_buf); stream->field_0x1e8 = 0; - iVar4 = pcppGetBlockingTime(stream->field_0x20c, param_4, stream, _amTimeMs(local_8), &local_14); - eVar5 = pcptRecv(&stream->sock, stream->send_buf, psVar1, local_14); + iVar4 = pcppGetBlockingTime(stream->field_0x20c, param_4, stream, _amTimeMs(local_8), + &local_14); + eVar5 = pcptRecv(&stream->sock, (unsigned char*)stream->send_buf, psVar1, local_14); eVar3 = _errT2P(eVar5); stream->err = eVar3; if ((iVar4 != 0) && (eVar3 == e_pcpp_to)) { @@ -1085,13 +1216,13 @@ e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_ } eVar3 = stream->err; if (eVar3 != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (eVar3 == e_pcpp_ok) { stream->field_0x1e8 = stream->field_0x1e8 + *psVar1; uVar6 = 0; *psVar1 = 8 - stream->field_0x1e8; - stream->state = 0; + stream->state = pcpp_state_none; stream->err = -9; if (stream->field_0x1e8 != 0) { while (*(char*)((int)&stream->send_buf + uVar6) != PCP_CHAR_BINACK) { @@ -1110,15 +1241,15 @@ e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { size_t* psVar1; - unsigned char** send_buf; + char** send_buf; undefined4 uVar2; int iVar3; e_pcpt_t eVar4; int iVar5; uint uVar6; e_pcpp_t eVar7; - unsigned char* pcVar8; - unsigned char* pcVar9; + char* pcVar8; + char* pcVar9; uint uVar10; uint uVar11; bool bVar12; @@ -1140,12 +1271,13 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { return e_pcpp_param_invalid; } amiTimerGet(&local_18); + switch (stream->state) { - case 0: + case pcpp_state_none: stream->err = e_pcpp_no_client; break; - case 1: - case 8: + case pcpp_state_open: + case pcpp_state_open_binary: if (stream->state == 1) { if (stream->open == 0) { uVar2 = stream->field_0x210; @@ -1171,14 +1303,15 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { stream->last_active = _amTimeMs(local_10); if (stream->state != 8) { if (stream->open != 0) { - stream->read_bytes_num = stream->read_bytes_num + stream->read_bytes_size; + stream->read_bytes_num = + stream->read_bytes_num + stream->read_bytes_size; stream->read_bytes_size = PCP_BUF_MAX - stream->read_bytes_num; iVar3 = pcppCheckPrompt(stream); if (iVar3 != 0) goto LAB_00457676; stream->err = ~e_pcpp_no_client; goto LAB_00457660; } - stream->state = 3; + stream->state = pcpp_state_wait_prompt; if (uVar11 != TIMEOUT_NONE) { amiTimerGet(&local_8); uVar6 = (local_8.microseconds - local_18.microseconds) / 1000 + @@ -1194,7 +1327,7 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { stream->err = eVar7; if (eVar7 != e_pcpp_to) { amiTimerGet(&local_10); - stream->state = 0; + stream->state = pcpp_state_none; stream->last_active = _amTimeMs(local_10); return stream->err; } @@ -1207,12 +1340,12 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { if (stream->state == 1) { stream->err = 0xfffffff5 - (uint)(stream->open != 0); } else { - stream->err = -11; + stream->err = e_pcpp_no_server; } goto LAB_00457392; - case 2: - case 4: - case 6: + case pcpp_state_send_prompt: + case pcpp_state_send_request: + case pcpp_state_send_response: uVar6 = uVar11; if ((stream->sock).field_0x54 != 0) { bVar12 = (stream->sock).open != PCPT_LISTENING; @@ -1222,7 +1355,8 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { uVar2 = stream->field_0x210; } bVar12 = !bVar12; - local_20 = pcppGetBlockingTime(uVar2, uVar11, stream, _amTimeMs(local_18), &timeout); + local_20 = + pcppGetBlockingTime(uVar2, uVar11, stream, _amTimeMs(local_18), &timeout); uVar6 = timeout; } eVar4 = pcptIsBusy(&stream->sock, uVar6); @@ -1235,8 +1369,9 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { if (stream->state != 2) goto LAB_004577b4; stream->open = 0; amiTimerGet(&local_8); - stream->state = 5; - iVar3 = pcppGetBlockingTime(stream->field_0xb8, uVar11, stream, _amTimeMs(local_18), &timeout); + stream->state = pcpp_state_recv_request; + iVar3 = pcppGetBlockingTime(stream->field_0xb8, uVar11, stream, + _amTimeMs(local_18), &timeout); eVar7 = pcppRecvRequestMain(stream, &local_24, timeout); stream->err = eVar7; if ((eVar7 == e_pcpp_to) && (iVar3 != 0)) { @@ -1249,7 +1384,7 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { stream->state = 14; } } else { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err == e_pcpp_ok) goto LAB_004574b8; break; @@ -1257,11 +1392,11 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { goto LAB_004577af; } if (local_20 == 0) break; - stream->err = (-(uint)bVar12 & 0xfffffffb) - 6; + stream->err = bVar12 ? e_pcpp_no_server : e_pcpp_timeout_closed; goto LAB_00457392; - case 3: - case 5: - case 7: + case pcpp_state_wait_prompt: + case pcpp_state_recv_request: + case pcpp_state_recv_response: if (stream->field_0x214 == 0) { uVar2 = stream->field_0xb8; } else { @@ -1269,25 +1404,25 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } iVar3 = pcppGetBlockingTime(uVar2, uVar11, stream, _amTimeMs(local_18), &timeout); uVar6 = timeout; - eVar4 = pcptIsBusy(&stream->sock, timeout); - eVar7 = _errT2P(eVar4); + eVar7 = _errT2P(pcptIsBusy(&stream->sock, timeout)); stream->err = eVar7; if (eVar7 != e_pcpp_to) { if (eVar7 != e_pcpp_ok) { LAB_00457660: - stream->state = 0; + stream->state = pcpp_state_none; return stream->err; } stream->read_bytes_num = stream->read_bytes_num + stream->read_bytes_size; stream->field_0x214 = 0; stream->read_bytes_size = PCP_BUF_MAX - stream->read_bytes_num; - if (stream->state == 3) { + if (stream->state == pcpp_state_wait_prompt) { uVar6 = uVar11; if (uVar11 != TIMEOUT_NONE) { amiTimerGet(&local_8); - uVar6 = -(uint)((uint)((local_8.microseconds - local_18.microseconds) / 1000 + - (local_8.seconds - local_18.seconds) * 1000) < uVar11) & - uVar11; + uVar6 = + -(uint)((uint)((local_8.microseconds - local_18.microseconds) / 1000 + + (local_8.seconds - local_18.seconds) * 1000) < uVar11) & + uVar11; } eVar7 = pcppRecvPrompt(stream, stream->field_0xb8, uVar6); stream->err = eVar7; @@ -1296,15 +1431,18 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { if (stream->open == 0) { if (uVar11 != TIMEOUT_NONE) { amiTimerGet(&local_8); - uVar11 = -(uint)((uint)((local_8.microseconds - local_18.microseconds) / 1000 + - (local_8.seconds - local_18.seconds) * 1000) < uVar11) & - uVar11; + uVar11 = + -(uint)((uint)((local_8.microseconds - local_18.microseconds) / + 1000 + + (local_8.seconds - local_18.seconds) * 1000) < + uVar11) & + uVar11; } - stream->state = 4; + stream->state = pcpp_state_send_request; eVar7 = pcppSendRequestMain(stream, stream->field_0xb8, uVar11); stream->err = eVar7; if ((eVar7 != e_pcpp_to) && (eVar7 != e_pcpp_ok)) { - stream->state = 0; + stream->state = pcpp_state_none; return eVar7; } } @@ -1324,7 +1462,7 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } uVar6 = uVar11 - uVar10; } - eVar7 = pcppRecvAllMsg(uVar6, stream, &local_24); + eVar7 = pcppRecvAllMsg(stream, uVar6, &local_24); stream->err = eVar7; if (eVar7 != e_pcpp_ok) { if (eVar7 == e_pcpp_to) { @@ -1350,7 +1488,8 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { if (iVar3 == 0) goto LAB_0045848d; } pcVar8 = stream->read_bytes_buf; - eVar7 = pcppCheckRecvMsg(pcVar8, stream->read_bytes_num, (uint)(stream->state == 5)); + eVar7 = + pcppCheckRecvMsg(pcVar8, stream->read_bytes_num, (uint)(stream->state == 5)); stream->err = eVar7; if (eVar7 == e_pcpp_ok) { pcppChangeRequest(stream, &timeout); @@ -1366,19 +1505,19 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { LAB_00458226: stream->read_bytes_num = stream->read_bytes_num - timeout; stream->read_bytes_size = stream->read_bytes_size + timeout; - stream->state = 0; + stream->state = pcpp_state_none; amiTimerGet(&local_18); stream->last_active = _amTimeMs(local_18); return stream->err; } - stream->state = 0; + stream->state = pcpp_state_none; pcppResetRead(stream); PCP_LOG("error Response format error\n"); return stream->err; } if (iVar3 == 0) break; if (stream->field_0x214 == 0) { - stream->err = (-(uint)(stream->open != 0) & 0xfffffffa) - 6; + stream->err = (stream->open != 0) ? e_pcpp_timeout_open : e_pcpp_timeout_closed; } else { stream->err = -7; } @@ -1386,9 +1525,9 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { pcptCloseDataSock(&stream->sock); pcppResetRead(stream); LAB_0045739d: - stream->state = 0; + stream->state = pcpp_state_none; return stream->err; - case 9: + case pcpp_state_send_binary: bVar12 = (stream->data_sock).open != PCPT_LISTENING; if (bVar12) { uVar2 = stream->field_0x208; @@ -1411,18 +1550,19 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { stream->last_active = _amTimeMs(local_10); } if (stream->err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err == e_pcpp_ok) { amiTimerGet(&local_10); stream->last_active = _amTimeMs(local_10); - stream->state = 10; + stream->state = pcpp_state_send_binary_wait; psVar1 = &stream->send_buf_len; *psVar1 = PCP_SEND_BUF_MAX; ZERO(stream->send_buf); stream->field_0x1e8 = 0; - iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); - eVar4 = pcptRecv(&stream->sock, stream->send_buf, psVar1, timeout); + iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, + _amTimeMs(local_18), &timeout); + eVar4 = pcptRecv(&stream->sock, (unsigned char*)stream->send_buf, psVar1, timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { @@ -1431,13 +1571,13 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { pcppResetRead(stream); } if (stream->err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err == e_pcpp_ok) { stream->field_0x1e8 = stream->field_0x1e8 + *psVar1; uVar11 = 0; *psVar1 = PCP_SEND_BUF_MAX - stream->field_0x1e8; - stream->state = 0; + stream->state = pcpp_state_none; stream->err = -9; if (stream->field_0x1e8 != 0) { do { @@ -1454,8 +1594,9 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } } break; - case 10: - iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); + case pcpp_state_send_binary_wait: + iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), + &timeout); eVar4 = pcptIsBusy(&stream->sock, timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; @@ -1465,7 +1606,7 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { pcppResetRead(stream); } if (stream->err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err == e_pcpp_ok) { amiTimerGet(&local_10); @@ -1488,7 +1629,7 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } } break; - case 11: + case pcpp_state_recv_binary: if (stream->field_0x214 != 0) { bVar12 = (stream->data_sock).open != PCPT_LISTENING; if (bVar12) { @@ -1514,7 +1655,7 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } else { if (eVar7 != e_pcpp_ok) { stream->field_0x214 = 0; - stream->state = 0; + stream->state = pcpp_state_none; goto LAB_00457b2e; } } @@ -1528,10 +1669,12 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { stream->recv_binary_buf_len != stream->field_0x1fc) { psVar1 = &stream->field_0x1f8; do { - iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, + _amTimeMs(local_18), &timeout); stream->field_0x214 = 1; eVar4 = - pcptRecv(&stream->data_sock, stream->recv_binary_buf + stream->field_0x1fc, psVar1, timeout); + pcptRecv(&stream->data_sock, stream->recv_binary_buf + stream->field_0x1fc, + psVar1, timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; if ((eVar7 == e_pcpp_to) && (iVar3 != 0)) { @@ -1545,7 +1688,7 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { if (eVar7 != e_pcpp_ok) goto switchD_004572ff_caseD_10; } else { if (eVar7 != e_pcpp_ok) { - stream->state = 0; + stream->state = pcpp_state_none; goto LAB_00457c47; } } @@ -1557,13 +1700,15 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } while (stream->field_0x1fc <= stream->recv_binary_buf_len && stream->recv_binary_buf_len != stream->field_0x1fc); } - send_buf = (unsigned char**)&stream->send_buf; + send_buf = (char**)&stream->send_buf; psVar1 = &stream->send_buf_len; - stream->state = 12; + stream->state = pcpp_state_send_binary_ack; *send_buf[0] = PCP_CHAR_BINACK; *psVar1 = 1; - local_20 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); - eVar4 = pcptSend(&stream->sock, *send_buf, psVar1, stream->field_0x204, timeout); + local_20 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), + &timeout); + eVar4 = pcptSend(&stream->sock, (unsigned char*)*send_buf, psVar1, stream->field_0x204, + timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; if ((eVar7 == e_pcpp_to) && (local_20 != 0)) { @@ -1572,23 +1717,24 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { pcppResetRead(stream); } if (stream->err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err == e_pcpp_ok) { amiTimerGet(&local_10); stream->last_active = _amTimeMs(local_10); - stream->state = 13; - iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + stream->state = pcpp_state_send_binary_ack_wait; + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, + _amTimeMs(local_18), &timeout); *psVar1 = PCP_SEND_BUF_MAX; ZERO(stream->send_buf); - eVar4 = pcptRecv(&stream->data_sock, *send_buf, psVar1, timeout); + eVar4 = pcptRecv(&stream->data_sock, (unsigned char*)*send_buf, psVar1, timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { stream->err = -13; } if (stream->err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err == e_pcpp_closed) { stream->err = e_pcpp_ok; @@ -1599,8 +1745,9 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } } break; - case 12: - iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); + case pcpp_state_send_binary_ack: + iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), + &timeout); eVar4 = pcptIsBusy(&stream->sock, timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; @@ -1610,16 +1757,18 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { pcppResetRead(stream); } if (stream->err != e_pcpp_to) { - stream->state = 0; + stream->state = pcpp_state_none; } if (stream->err != e_pcpp_ok) break; - stream->state = 13; + stream->state = pcpp_state_send_binary_ack_wait; amiTimerGet(&local_10); stream->last_active = _amTimeMs(local_10); - iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), + &timeout); stream->send_buf_len = PCP_SEND_BUF_MAX; ZERO(stream->send_buf); - eVar4 = pcptRecv(&stream->data_sock, stream->send_buf, &stream->send_buf_len, timeout); + eVar4 = pcptRecv(&stream->data_sock, (unsigned char*)stream->send_buf, + &stream->send_buf_len, timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { @@ -1627,13 +1776,14 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { pcptCloseDataSock(&stream->sock); pcppResetRead(stream); } - if (stream->err != e_pcpp_to) stream->state = 0; + if (stream->err != e_pcpp_to) stream->state = pcpp_state_none; if (stream->err != e_pcpp_closed) break; stream->err = e_pcpp_ok; goto LAB_004574b8; - case 13: - iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + case pcpp_state_send_binary_ack_wait: + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), + &timeout); eVar4 = pcptIsBusy(&stream->data_sock, timeout); eVar7 = _errT2P(eVar4); stream->err = eVar7; @@ -1651,10 +1801,10 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { LAB_004577af: pcppResetRead(stream); LAB_004577b4: - stream->state = 0; + stream->state = pcpp_state_none; return stream->err; case 14: - case 15: + case pcpp_state_wait_response: amiTimerGet(&local_8); uVar6 = _amTimeDelta(local_8, local_18); stream->field_0x214 = 1; @@ -1665,14 +1815,15 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { uVar11 = 0; } } - eVar7 = pcppRecvAllMsg(uVar11, stream, &local_24); + eVar7 = pcppRecvAllMsg(stream, uVar11, &local_24); stream->err = eVar7; if (eVar7 == e_pcpp_ok) { pcVar8 = stream->read_bytes_buf; - eVar7 = pcppCheckRecvMsg(pcVar8, stream->read_bytes_num, (uint)(stream->state == 14)); + eVar7 = + pcppCheckRecvMsg(pcVar8, stream->read_bytes_num, (uint)(stream->state == 14)); stream->err = eVar7; if (eVar7 != e_pcpp_ok) { - stream->state = 0; + stream->state = pcpp_state_none; pcppResetRead(stream); PCP_LOG("error Response format error\n"); return stream->err; @@ -1698,12 +1849,14 @@ e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { } goto LAB_0045739d; } + switchD_004572ff_caseD_10: return stream->err; } -int pcpp_something(amtime_t* time, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, unsigned char* send_buf, - size_t* send_len, undefined4 param_7, undefined4 param_8, int fallback_err) { +int pcpp_something(amtime_t* time, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, + unsigned char* send_buf, size_t* send_len, undefined4 param_7, + undefined4 param_8, int fallback_err) { uint iVar1; uint blocking_time; amtime_t now; @@ -1742,17 +1895,165 @@ pcp_send_data_t* pcppAddSendPacket(pcp_send_data_t* send_data, char* keyword, ch size_t kwLen = strlen(keyword); if (value == NULL) { if (existing_length + kwLen + 3 < PCP_BUF_MAX) { - sprintf_s((char*)&send_data->data[existing_length], PCP_BUF_MAX - existing_length, "&%s\r\n", keyword); + sprintf_s((char*)&send_data->data[existing_length], PCP_BUF_MAX - existing_length, + "&%s\r\n", keyword); send_data->length += kwLen + 1; return send_data; } } else { size_t valLen = strlen(value); if (existing_length + kwLen + valLen + 4 < PCP_BUF_MAX) { - sprintf_s((char*)&send_data->data[existing_length], PCP_BUF_MAX - existing_length, "&%s=%s\r\n", keyword, value); + sprintf_s((char*)&send_data->data[existing_length], PCP_BUF_MAX - existing_length, + "&%s=%s\r\n", keyword, value); send_data->length += valLen + kwLen + 2; return send_data; } } return NULL; } + +e_pcpp_t pcppSendRequestTable(pcpp_t* stream, pcp_send_data_t* request_buffer, timeout_t timeout) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + + if (request_buffer == NULL) { + PCP_LOG("error Request buffer isn\'t set\n"); + return e_pcpp_param_invalid; + } + + return pcppSendRequest(stream, request_buffer, request_buffer->length + 2, timeout); +} + +e_pcpp_t pcppSendRequest(pcpp_t* stream, pcp_send_data_t* request_buffer, uint nbytes, + timeout_t timeout) { + amtime_t local_18; + amtime_t local_10; + amtime_t local_8; + + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (request_buffer == NULL) { + PCP_LOG("error Request buffer isn\'t set\n"); + return e_pcpp_param_invalid; + } + + if (0x100 < nbytes) { + PCP_LOG("error Request buffer over\n"); + return (stream->err = e_pcpp_param_invalid); + } + + amiTimerGet(&local_10); + e_pcpp_t pcpp_err = pcppCheckRecvMsg((char*)&request_buffer->data, nbytes, 1); + stream->err = pcpp_err; + if (pcpp_err != e_pcpp_ok) { + stream->state = pcpp_state_none; + pcppResetRead(stream); + PCP_LOG("error Message format error\n"); + return stream->err; + } + + request_buffer->length = nbytes; + stream->resp_buffer = request_buffer; + + *(uint*)stream->send_buf = nbytes; + if (stream->open == 0) { + stream->state = pcpp_state_wait_prompt; + pcpp_err = pcppRecvPrompt(stream, stream->field_0xb8, timeout); + stream->err = pcpp_err; + if (pcpp_err != e_pcpp_to) { + stream->state = pcpp_state_none; + } + if (pcpp_err != e_pcpp_ok) { + return pcpp_err; + } + } + + amiTimerGet(&local_18); + stream->state = pcpp_state_send_request; + + pcpp_err = pcppSendRequestMain(stream, stream->field_0xb8, timeout); + stream->err = pcpp_err; + if (pcpp_err != e_pcpp_to) { + stream->state = pcpp_state_none; + amiTimerGet(&local_8); + stream->last_active = local_8.microseconds / 1000 + local_8.seconds * 1000; + stream->open = 0; + } + return stream->err; +} + +e_pcpp_t pcppRecvResponse(pcpp_t* stream, pcp_parse_data_t* buffer, timeout_t timeout) { + int iVar1; + amtime_t local_8; + + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return -5; + } + + if (buffer == NULL) { + PCP_LOG("error Response buffer isn\'t set\n"); + return -5; + } + + stream->recv_data_buffer = buffer; + stream->state = pcpp_state_recv_response; + stream->field_0x214 = 0; + bool bReRecv; + iVar1 = pcppRecvAllMsg(stream, timeout, &bReRecv); + stream->err = iVar1; + if (iVar1 != e_pcpp_ok) { + if (iVar1 != e_pcpp_to) { + stream->state = pcpp_state_none; + return iVar1; + } + if (stream != NULL) stream->state = pcpp_state_wait_response; + return e_pcpp_to; + } + + char* pcVar5 = stream->read_bytes_buf; + iVar1 = pcppCheckRecvMsg(pcVar5, stream->read_bytes_num, 0); + stream->err = iVar1; + if (iVar1 == 0) { + uint lenout; + pcppChangeRequest(stream, &lenout); + uint ppVar2 = lenout; + char* pcVar3 = pcVar5; + if (lenout < stream->read_bytes_num) { + do { + *pcVar3 = pcVar5[ppVar2]; + ppVar2++; + pcVar3++; + } while (ppVar2 < stream->read_bytes_num); + } + stream->read_bytes_num = stream->read_bytes_num - (int)lenout; + stream->read_bytes_size = (stream->read_bytes_size - 0x46) + lenout; + stream->state = pcpp_state_none; + stream->err = 0; + amiTimerGet(&local_8); + stream->last_active = local_8.microseconds / 1000 + local_8.seconds * 1000; + } else { + stream->state = pcpp_state_none; + pcppResetRead(stream); + PCP_LOG("error Response format error\n"); + return stream->err; + } + + return stream->err; +} + +SOCKADDR* pcppGetSockAddr(pcpp_t* stream, bool is_data) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return NULL; + } + + if (is_data) { + return &(stream->data_sock).client_addr; + } + return &(stream->sock).client_addr; +} \ No newline at end of file diff --git a/src/micetools/lib/libpcp/pcpp.h b/src/micetools/lib/libpcp/pcpp.h index 95efb22..cd142e3 100644 --- a/src/micetools/lib/libpcp/pcpp.h +++ b/src/micetools/lib/libpcp/pcpp.h @@ -1,3 +1,5 @@ +#pragma once + #include "pcpt.h" #define PCPP_CLOSED 0 @@ -15,6 +17,7 @@ typedef enum e_pcpp { e_pcpp_param_invalid = -5, e_pcpp_timeout_closed = -6, e_pcpp_recv_unset = -10, + e_pcpp_no_server = -11, e_pcpp_timeout_open = -12, e_pcpp_inval_addr = -15, e_pcpp_wsa_noinit = -16, @@ -22,16 +25,42 @@ typedef enum e_pcpp { e_pcpp_uk1 = -14, e_pcpp_uk2 = -13, - e_pcpp_uk3 = -11, e_pcpp_uk4 = -9, e_pcpp_uk5 = -8, e_pcpp_uk6 = -7, e_pcpp_uk7 = -4, } e_pcpp_t; +typedef enum { + pcpp_char_sep = 5, + pcpp_char_cr = 4, + pcpp_char_crlf = 3, + pcpp_char_lf = 2, + pcpp_char_equ = 1, + pcpp_char_error = 0, +} pcpp_char_type_t; + e_pcpp_t _pcppGetErrorFromPcpt(e_pcpt_t err); #define _errT2P(err) _pcppGetErrorFromPcpt(err) +typedef enum { + pcpp_state_none = 0, + pcpp_state_open = 1, + pcpp_state_send_prompt = 2, + pcpp_state_wait_prompt = 3, + pcpp_state_send_request = 4, + pcpp_state_recv_request = 5, + pcpp_state_send_response = 6, + pcpp_state_recv_response = 7, + pcpp_state_open_binary = 8, + pcpp_state_send_binary = 9, + pcpp_state_send_binary_wait = 10, + pcpp_state_recv_binary = 11, + pcpp_state_send_binary_ack = 12, + pcpp_state_send_binary_ack_wait = 13, + pcpp_state_wait_response = 15, +} pcpp_state_t; + typedef struct pcpp { pcpt_t sock; pcpt_t data_sock; @@ -40,12 +69,11 @@ typedef struct pcpp { uint state; e_pcpp_t err; pcp_parse_data_t* recv_data_buffer; - unsigned char read_bytes_buf[PCP_BUF_MAX]; + char read_bytes_buf[PCP_BUF_MAX]; uint read_bytes_size; uint read_bytes_num; pcp_send_data_t* resp_buffer; - uint resp_buffer_len; - unsigned char send_buf[PCP_SEND_BUF_MAX]; + char send_buf[PCP_SEND_BUF_MAX]; size_t send_buf_len; uint field_0x1e8; unsigned char* send_binary_buf; @@ -66,30 +94,41 @@ typedef struct pcpp { pcp_send_data_t* pcppAddSendPacket(pcp_send_data_t* stream, char* key, char* value); pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, uint* lenout); bool pcppCheckPrompt(pcpp_t* stream); -e_pcpp_t pcppCheckRecvMsg(unsigned char* recv_data, size_t buf_len, int param_3); -uint pcppCheckStr(unsigned char* param_1, uint* pcp_len, int* pcp_overflow); +e_pcpp_t pcppCheckRecvMsg(char* recv_data, size_t buf_len, int param_3); +uint pcppCheckStr(char* param_1, uint* pcp_len, int* pcp_overflow); void pcppClose(pcpp_t* stream); void pcppCloseBinary(pcpp_t* stream); -e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t param_2, pcpp_t* stream, int param_4, uint* blocking_time); +e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t param_2, pcpp_t* stream, int param_4, + uint* blocking_time); char* pcppGetCommand(pcp_parse_data_t* pcpa, char* command); char* pcppGetKeyword(pcp_parse_data_t* recvData, uint keyword_num); SOCKET pcppGetServerSocket(pcpp_t* stream, int which); e_pcpp_t pcppInitStream(pcpp_t* stream); e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout); +e_pcpp_t pcppOpenClient(pcpp_t* stream, char* ipAddr, ushort port, uint param_4, timeout_t timeout); e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port); e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, ushort port, undefined4 param_4); -e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv); +e_pcpp_t pcppRecvAllMsg(pcpp_t* stream, uint param_1, bool* bReRecv); e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, uint param_4); -uint pcppRecvCheck(unsigned char* buf, int* found_at); +uint pcppRecvCheck(char* buf, int* found_at); e_pcpp_t pcppRecvPrompt(pcpp_t* stream, undefined4 param_2, int param_3); e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t timeout); e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3); -e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_t param_3, uint param_4); +e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_t param_3, + uint param_4); e_pcpp_t pcppSendPrompt(pcpp_t* stream, uint param_2, timeout_t timeout_ms); e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, timeout_t timeout_ms); -e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, timeout_t timeout_ms); +e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, + timeout_t timeout_ms); e_pcpp_t pcppSendResponseTable(pcpp_t* stream, pcp_send_data_t* data, timeout_t timeout_ms); pcp_send_data_t* pcppSetSendPacket(pcp_send_data_t* send_data, char* keyword, char* value); -e_pcpp_t pcpp_something(amtime_t* now, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, unsigned char* send_buf, - size_t* send_len, undefined4 param_7, undefined4 param_8, e_pcpp_t fallback_err); +e_pcpp_t pcpp_something(amtime_t* now, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, + unsigned char* send_buf, size_t* send_len, undefined4 param_7, + undefined4 param_8, e_pcpp_t fallback_err); void pcppResetRead(pcpp_t* param_1); +e_pcpp_t pcppSendRequestTable(pcpp_t* stream, pcp_send_data_t* request_buffer, timeout_t timeout); +e_pcpp_t pcppSendRequest(pcpp_t* stream, pcp_send_data_t* request_buffer, uint nbytes, + timeout_t timeout); +e_pcpp_t pcppRecvResponse(pcpp_t* stream, pcp_parse_data_t* buffer, timeout_t timeout); +e_pcpp_t pcppOpenBinaryClient(pcpp_t* stream, char* ipAddr, ushort port, timeout_t timeout); +SOCKADDR* pcppGetSockAddr(pcpp_t* stream, bool is_data); diff --git a/src/micetools/lib/libpcp/pcpt.c b/src/micetools/lib/libpcp/pcpt.c index 82c40b6..babf91a 100644 --- a/src/micetools/lib/libpcp/pcpt.c +++ b/src/micetools/lib/libpcp/pcpt.c @@ -304,9 +304,10 @@ e_pcpt_t pcptOpenServer(pcpt_t *stream, int open_mode, ushort port) { return stream->err = err; } - SOCKADDR_IN addr = { .sin_family = AF_INET, - .sin_port = ntohs(port), - .sin_addr.s_addr = ntohl(0) }; + SOCKADDR_IN addr; + addr.sin_family = AF_INET; + addr.sin_port = ntohs(port); + addr.sin_addr.s_addr = ntohl(0); if (open_mode != OPEN_MODE_GLOBAL) { INT len = sizeof &addr.sin_addr.s_addr; @@ -340,6 +341,129 @@ e_pcpt_t pcptOpenServer(pcpt_t *stream, int open_mode, ushort port) { return stream->err = e_pcpt_unknown; } +e_pcpt_t pcptOpenClient(pcpt_t *stream, char *ipAddr, ushort port, timeout_t timeout) { + pcpt_t *pcpt; + uint uVar6; + amtime_t start; + amtime_t now; + + pcpt = stream; + if ((stream == NULL) || (ipAddr == NULL)) { + PCP_LOG("error PCP stream isn\'t set\n"); + return e_pcpt_pointer_unset; + } + if (stream->client_sock != 0xffffffff) { + return stream->err = e_pcpt_already_open; + } + + stream->field_0x58 = 0; + stream->open = PCPT_CLOSED; + stream->client_open = 1; + + ZeroMemory(&stream->client_addr, sizeof stream->client_addr); + SOCKADDR_IN *pAddr = &stream->client_addr; + pAddr->sin_port = ntohs(port); + pAddr->sin_family = AF_INET; + pAddr->sin_addr.s_addr = inet_addr(ipAddr); + + SOCKET s = socket(AF_INET, SOCK_STREAM, 0); + pcpt->client_sock = s; + if (s == SOCKET_INVAL) { + return pcpt->err = _errW2T(GetLastError()); + } + + uint so_linger = (uint)(!!stream->so_linger); + setsockopt(stream->client_sock, SOL_SOCKET, SO_LINGER, (void *)&so_linger, sizeof so_linger); + + uint nodelay = (uint)(!stream->tcp_nodelay); + setsockopt(stream->client_sock, IPPROTO_TCP, TCP_NODELAY, (void *)&nodelay, sizeof nodelay); + + amiTimerGet(&start); + do { + port = 0; + HANDLE client_event = WSACreateEvent(); + pcpt->client_event = client_event; + if (client_event == 0) { + closesocket(pcpt->client_sock); + pcpt->err = -0x11; + pcpt->client_sock = 0xffffffff; + return pcpt->err; + } + WSAEventSelect(pcpt->client_sock, client_event, 0x30); + + if (connect(pcpt->client_sock, &stream->client_addr, 0x10) != -1) { + WSAEventSelect(pcpt->client_sock, 0, 0); + WSACloseEvent(pcpt->client_event); + pcpt->client_event = 0; + + u_long local_40 = 0; + ioctlsocket(pcpt->client_sock, FIONBIO, &local_40); + + client_event = WSACreateEvent(); + pcpt->client_event = client_event; + if (client_event == 0) { + closesocket(pcpt->client_sock); + pcpt->err = -0x11; + pcpt->client_sock = 0xffffffff; + return pcpt->err; + } + WSAEventSelect(pcpt->client_sock, client_event, 0x23); + pcpt->err = 0; + pcpt->client_open = 0; + pcpt->open = 2; + return 0; + } + if ((pcpt->err = _errW2T(GetLastError())) != e_pcpt_to) { + u_long local_40 = 0; + ioctlsocket(pcpt->client_sock, FIONBIO, &local_40); + return pcpt->err; + } + amiTimerGet(&now); + if (timeout == TIMEOUT_NONE) { + LAB_00a19435: + uVar6 = pcpt->config_0; + } else { + uVar6 = (now.microseconds - start.microseconds) / 1000 + + (now.seconds - start.seconds) * 1000; + if (uVar6 < timeout) { + uVar6 = timeout - uVar6; + } else { + port = 1; + uVar6 = 0; + } + if (pcpt->config_0 <= uVar6 && uVar6 != pcpt->config_0) goto LAB_00a19435; + } + if ((pcpt->err = pcptCheckConnectAble(pcpt, uVar6)) != e_pcpt_to) { + pcpt->client_open = 0; + if (pcpt->err == e_pcpt_ok) { + pcpt->open = 2; + return pcpt->err; + } + return pcpt->err; + } + if (port != 0) { + pcpt->err = 1; + amiTimerGet(&start); + pcpt->field_0x40 = start.microseconds / 1000 + start.seconds * 1000; + return pcpt->err; + } + WSAEventSelect(pcpt->client_sock, 0, 0); + WSACloseEvent(pcpt->client_event); + pcpt->client_event = 0; + closesocket(pcpt->client_sock); + + pcpt->client_sock = SOCKET_INVAL; + s = socket(AF_INET, SOCK_STREAM, 0); + pcpt->client_sock = s; + if (s == SOCKET_INVAL) { + return pcpt->err = _errW2T(GetLastError()); + } + if (pcpt->err != e_pcpt_to) { + return pcpt->err; + } + } while (true); +} + e_pcpt_t pcptRecv(pcpt_t *sock, unsigned char *recv_buf, size_t *recv_buf_len, timeout_t timeout_ms) { e_pcpt_t err; @@ -347,13 +471,19 @@ e_pcpt_t pcptRecv(pcpt_t *sock, unsigned char *recv_buf, size_t *recv_buf_len, amtime_t start; if (sock == NULL || recv_buf == NULL || recv_buf_len == NULL) { - printf("%p %p %p\n", sock, recv_buf, recv_buf_len); PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } - if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open; - if (sock->client_open != 0) return sock->err = e_pcpt_already_connected; + if (sock->open == PCPT_CLOSED) { + PCP_LOG("error PCP not open\n"); + return sock->err = e_pcpt_not_open; + } + // TODO: URGENT: Something in the FSM causes this condition to error out! + // if (sock->client_open != 0) { + // PCP_LOG("error PCP already connected\n"); + // return sock->err = e_pcpt_already_connected; + // } sock->recv_buf = recv_buf; sock->recv_buf_count = recv_buf_len; @@ -414,8 +544,14 @@ e_pcpt_t pcptSend(pcpt_t *sock, unsigned char *send_buf, size_t *send_len, uint return e_pcpt_pointer_unset; } - if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open; - if (sock->client_open != 0) return sock->err = e_pcpt_already_connected; + if (sock->open == PCPT_CLOSED) { + PCP_LOG("error PCP not open\n"); + return sock->err = e_pcpt_not_open; + } + if (sock->client_open != 0) { + PCP_LOG("error PCP already connected\n"); + return sock->err = e_pcpt_already_connected; + } sock->send_buf_count = send_len; sock->send_buf = send_buf; diff --git a/src/micetools/lib/libpcp/pcpt.h b/src/micetools/lib/libpcp/pcpt.h index 0a67d4d..8f80d94 100644 --- a/src/micetools/lib/libpcp/pcpt.h +++ b/src/micetools/lib/libpcp/pcpt.h @@ -1,3 +1,5 @@ +#pragma once + #include "pcp.h" typedef enum e_pcpt { @@ -59,6 +61,7 @@ e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint e_pcpt_t pcptIsBusy(pcpt_t* sock, timeout_t timeout_ms); e_pcpt_t pcptOpenDataSockServer(pcpt_t* sock, timeout_t timeout_ms); e_pcpt_t pcptOpenServer(pcpt_t* sock, int open_mode, ushort port); +e_pcpt_t pcptOpenClient(pcpt_t *stream, char *ipAddr, ushort port, timeout_t timeout); e_pcpt_t pcptRecv(pcpt_t* sock, unsigned char* recv_buf, size_t* recv_buf_len, timeout_t timeout_ms); e_pcpt_t pcptSend(pcpt_t* sock, unsigned char* send_buf, size_t* send_len, uint param_4, timeout_t timeout_ms); e_pcpt_t pcptSendAllMsg(pcpt_t* sock, timeout_t timeout_ms); diff --git a/src/micetools/lib/meson.build b/src/micetools/lib/meson.build index 00b2686..48847ce 100644 --- a/src/micetools/lib/meson.build +++ b/src/micetools/lib/meson.build @@ -1,9 +1,10 @@ subdir('util') # This is the only lib that should ever be link_with'd by another lib -subdir('json') subdir('dmi') -subdir('mice') -subdir('am') -subdir('mxk') -fs = import('fs') +subdir('ami') subdir('libpcp') +subdir('am') + +subdir('mice') + +subdir('mxk') diff --git a/src/micetools/lib/mice/config.c b/src/micetools/lib/mice/config.c index 8839355..2806a58 100644 --- a/src/micetools/lib/mice/config.c +++ b/src/micetools/lib/mice/config.c @@ -12,6 +12,7 @@ config_t MiceConfig = { #define CFG_bool(s, n, default, comment) .n = default, #define CFG_int(s, n, default, comment) .n = default, #define CFG_hex(s, n, precision, default, comment) .n = 0x##default, +#define CFG_ipv4(s, n, a, b, c, d, comment) .n = (a << 24) | (b << 16) | (c << 8) | d, #define ENDSECTION(s) \ } \ , @@ -20,11 +21,11 @@ config_t MiceConfig = { }; void fprintf_prefix(FILE *file, const char *prefix, const char *text) { - char* copy = (char*)malloc(strlen(text) + 1); + char *copy = (char *)malloc(strlen(text) + 1); memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); - char* next_token; - char* token = strtok_s(copy, "\n", &next_token); + char *next_token; + char *token = strtok_s(copy, "\n", &next_token); while (token != NULL) { fprintf(file, "%s%s\n", prefix, token); token = strtok_s(NULL, "\n", &next_token); @@ -42,35 +43,35 @@ void make_default_config() { }; int first_section = true; -#define CFG_str(s, n, default, comment) \ +#define CFG_str(s, n, default, comment) \ if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ - fprintf(config_file, "; (string) default = %s\n", default); \ - fprintf(config_file, "%s = %s\n", #n, default); + fprintf(config_file, "%s = %s ;(string)\n", #n, default); -#define CFG_bool(s, n, default, comment) \ - if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ - fprintf(config_file, "; (bool) default = %s\n", default ? "true" : "false"); \ - fprintf(config_file, "%s = %s\n", #n, default ? "true" : "false"); - -#define CFG_int(s, n, default, comment) \ +#define CFG_bool(s, n, default, comment) \ if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ - fprintf(config_file, "; (int) default = %d\n", default); \ - fprintf(config_file, "%s = %d\n", #n, default); + fprintf(config_file, "%s = %s ;(bool)\n", #n, default ? "true" : "false"); -#define CFG_hex(s, n, precision, default, comment) \ - if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ - fprintf(config_file, "; (hex) default = %.*X\n", precision, 0x##default); \ - fprintf(config_file, "%s = %.*X\n", #n, precision, 0x##default); +#define CFG_int(s, n, default, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %d ;(int)\n", #n, default); -#define SECTION(s, comment) \ - if (!first_section) fprintf(config_file, "\n"); \ - first_section = false; \ +#define CFG_hex(s, n, precision, default, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %.*X ;(hex, %d byte%s)\n", #n, precision, 0x##default, precision, \ + precision == 1 ? "" : "s"); + +#define CFG_ipv4(s, n, a, b, c, d, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu ;(ipv4)\n", #n, a, b, c, d); + +#define SECTION(s, comment) \ + if (!first_section) fprintf(config_file, "\n"); \ + first_section = false; \ if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ fprintf(config_file, "[%s]\n", #s); -#define HEADER(comment) \ - if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ - first_section = false; +#define COMMENT(comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); #include "config.def" @@ -99,6 +100,15 @@ int handler(void *user, const char *section, const char *name, const char *value cfg->s.n = strtol(value, &end, 16); \ if (end == value || *end != '\0' || errno == ERANGE) cfg->s.n = 0x##default; \ } +#define CFG_ipv4(s, n, a, b, c, d, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \ + cfg->s.n = strtol(value, &end, 16); \ + unsigned char ip_a, ip_b, ip_c, ip_d; \ + if (sscanf_s(value, "%hhu.%hhu.%hhu.%hhu", &ip_a, &ip_b, &ip_c, &ip_d) == 4) \ + cfg->s.n = (ip_a << 24) | (ip_b << 16) | (ip_c << 8) | ip_d; \ + else \ + cfg->s.n = (a << 24) | (b << 16) | (c << 8) | d; \ + } #include "config.def" diff --git a/src/micetools/lib/mice/config.def b/src/micetools/lib/mice/config.def index d6ddb52..becf652 100644 --- a/src/micetools/lib/mice/config.def +++ b/src/micetools/lib/mice/config.def @@ -1,21 +1,22 @@ #ifndef SECTION #define SECTION(s, comment) #endif -#ifndef HEADER -#define HEADER(comment) +#ifndef COMMENT +#define COMMENT(comment) #endif #ifndef ENDSECTION #define ENDSECTION(s) #endif -HEADER("The main config file for micetools") +COMMENT("The main config file for micetools") +COMMENT("") SECTION(mice, "General mice settings") CFG_int(mice, log_level, 4, "1 = Game\n2 = Error\n3 = Warning\n4 = Info\n5 = Misc\n6 = Trace") CFG_bool(mice, log_to_file, false, "Also log out to log_file") CFG_str(mice, log_file, "log.txt", "The file to log to if log_to_file is enabled") CFG_bool(mice, apply_patches, true, "Load and apply patches from patches_file at runtime") -CFG_str(mice, patches_file, "patches.json", "The file to read patches from") +CFG_str(mice, patches_file, "patches.index", "The file to read patches from") ENDSECTION(mice) SECTION(launcher, "These options are only used during initial bootstrapping") @@ -26,6 +27,41 @@ CFG_str(launcher, mice_dll, "mice86.dll", "The path to mice's DLL") CFG_str(launcher, inject, "", "Extra DLLs to inject during boot") ENDSECTION(launcher) +SECTION(sysconf, "System configuration settings") +CFG_int(sysconf, region, 1, "Board region. 1 = Jpn, 2 = USA, 4 = Exp, 8 = Chn") +CFG_bool(sysconf, rental, false, "") +CFG_str(sysconf, serial, "AASE-01A65646203", "") +ENDSECTION(sysconf) + +SECTION(window, "Game window positioning settings") +CFG_bool(window, windowed, false, "Force games into windowed mode") +CFG_bool(window, borderless, true, "Should windowed games run borderless") +CFG_int(window, adaptor, 0, "Display adaptor to use") +CFG_bool(window, centre, true, "Centre the window. X and Y are used otherwise") +CFG_int(window, x, 0, "Window position X") +CFG_int(window, y, 0, "Window position Y") +CFG_int(window, w, 0, "Window width (0 to unset)") +CFG_int(window, h, 0, "Window height (0 to unset)") +ENDSECTION(window) + +SECTION(network, "Network configuration settings") +CFG_ipv4(network, ip_address, 192, 168, 103, 101, "") +CFG_ipv4(network, subnet_mask, 255, 255, 255, 0, "") +CFG_ipv4(network, gateway, 192, 168, 103, 254, "") +CFG_ipv4(network, primary_dns, 192, 168, 103, 254, "") +CFG_ipv4(network, secondary_dns, 0, 0, 0, 0, "") +COMMENT("Emulated DNS records. Routers must be pingable!") +CFG_ipv4(network, naominet_jp, 10, 0, 0, 2, "") +CFG_ipv4(network, ib_naominet_jp, 10, 0, 0, 2, "") +CFG_ipv4(network, aime_naominet_jp, 10, 0, 0, 2, "") +CFG_ipv4(network, tenporouter_loc, 127, 0, 0, 1, "") +CFG_ipv4(network, bbrouter_loc, 127, 0, 0, 1, "") +CFG_ipv4(network, mobirouter_loc, 127, 0, 0, 1, "") +CFG_ipv4(network, dslrouter_loc, 127, 0, 0, 1, "") +COMMENT("Second half of system mac address. The vendor prefix D8:BB:C1: will be prepended") +CFG_hex(network, mac, 6, 0A2F1D, "") +ENDSECTION(network) + SECTION(devices, "Specify COM ports for devices to attach, comma seperated") CFG_str(devices, aime_bd, "2", "AIME reader board") CFG_str(devices, touch_bd, "3", "maimai touch screen") @@ -33,14 +69,14 @@ CFG_str(devices, led_bd, "5,6,7,8", "maimai led boards") ENDSECTION(devices) SECTION(drivers, "Enable or disable drivers. Disabling any is not recommended.") -CFG_bool(drivers, columba, true, "Columba memory driver") -CFG_bool(drivers, mxsram, true, "SRAM driver") -CFG_bool(drivers, mxsuperio, true, "SuperIO driver") -CFG_bool(drivers, mxjvs, true, "JVS driver") -CFG_bool(drivers, mxhwreset, true, "System reboot driver") -CFG_bool(drivers, mxsmbus, true, "SMBus driver") -CFG_bool(drivers, mxparallel, true, "Parallel port driver") -CFG_bool(drivers, platform, true, "amPlatform driver") +CFG_bool(drivers, columba, true, "") +CFG_bool(drivers, mxsram, true, "") +CFG_bool(drivers, mxsuperio, true, "") +CFG_bool(drivers, mxjvs, true, "") +CFG_bool(drivers, mxhwreset, true, "") +CFG_bool(drivers, mxsmbus, true, "") +CFG_bool(drivers, mxparallel, true, "") +CFG_bool(drivers, platform, true, "") ENDSECTION(drivers) SECTION(hooks, "Enable or disable hooks. Disabling any is not recommended.") @@ -60,6 +96,7 @@ ENDSECTION(hooks) #undef CFG_int #undef CFG_bool #undef CFG_hex +#undef CFG_ipv4 #undef SECTION +#undef COMMENT #undef ENDSECTION -#undef HEADER diff --git a/src/micetools/lib/mice/config.h b/src/micetools/lib/mice/config.h index 79e2217..6d58d7c 100644 --- a/src/micetools/lib/mice/config.h +++ b/src/micetools/lib/mice/config.h @@ -8,6 +8,7 @@ typedef struct config { #define CFG_bool(s, n, default, comment) bool n; #define CFG_int(s, n, default, comment) int n; #define CFG_hex(s, n, precision, default, comment) int n; +#define CFG_ipv4(s, n, a, b, c, d, comment) unsigned int n; #define ENDSECTION(s) } s; #include "config.def" bool _keep_linter_happy; diff --git a/src/micetools/lib/mice/crc.c b/src/micetools/lib/mice/crc.c deleted file mode 100644 index bdef3a6..0000000 --- a/src/micetools/lib/mice/crc.c +++ /dev/null @@ -1,31 +0,0 @@ -unsigned int CRC_TABLE[256]; -unsigned int CTC_TABLE_BUILT = 0; - -#define CRC32_POLYNOMIAL 0xedb88320 - -void crc32_build_table() { - if (CTC_TABLE_BUILT) return; - CTC_TABLE_BUILT = 1; - - for (int i = 0; i < 256; i++) { - unsigned int value = (~i & 1) - 1 & CRC32_POLYNOMIAL; - value = (((int)i >> 1 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; - value = (((int)i >> 2 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; - value = (((int)i >> 3 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; - value = (((int)i >> 4 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; - value = (((int)i >> 5 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; - value = (((int)i >> 6 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; - CRC_TABLE[i] = (((int)i >> 7 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; - } -} - -unsigned int crc32(int length, unsigned char *data, unsigned int initial) { - crc32_build_table(); - - unsigned int value = ~initial; - while (length--) { - value = value >> 8 ^ CRC_TABLE[(*data ^ value) & 0xff]; - data++; - } - return ~value; -} diff --git a/src/micetools/lib/mice/crc.h b/src/micetools/lib/mice/crc.h deleted file mode 100644 index 462771f..0000000 --- a/src/micetools/lib/mice/crc.h +++ /dev/null @@ -1,2 +0,0 @@ -void crc32_build_table(); -unsigned int crc32(int length, unsigned char *data, unsigned int initial); diff --git a/src/micetools/lib/mice/ioctl.h b/src/micetools/lib/mice/ioctl.h index 021c746..800a6de 100644 --- a/src/micetools/lib/mice/ioctl.h +++ b/src/micetools/lib/mice/ioctl.h @@ -1,3 +1,4 @@ +#include #include #define FILE_DEVICE_SEGA 0x9c40 @@ -23,7 +24,6 @@ // amDipswGetDriverVersion // /\ uses either SUPERIO or SMBUS. Which is unknown atm. Uses 0x802 -// Same as IOCTL_MXSRAM_PING // amHmProbeSuperIoDevice #define IOCTL_MXSUPERIO_PING \ (DWORD) CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS) diff --git a/src/micetools/lib/mice/meson.build b/src/micetools/lib/mice/meson.build index 89c556c..ea3be91 100644 --- a/src/micetools/lib/mice/meson.build +++ b/src/micetools/lib/mice/meson.build @@ -3,12 +3,12 @@ mice_lib = static_library( sources: [ 'exe.c', 'patch.c', - 'crc.c', 'ringbuf.c', 'config.c', ], link_with: [ inih.get_variable('lib_inih'), - json_lib, - ] + util_lib, + amiCrc, + ], ) diff --git a/src/micetools/lib/mice/mice.h b/src/micetools/lib/mice/mice.h index 87830ff..9af4bb0 100644 --- a/src/micetools/lib/mice/mice.h +++ b/src/micetools/lib/mice/mice.h @@ -1,9 +1,13 @@ +#pragma once + #include #include -#include "ioctl.h" -#include "exe.h" -#include "patch.h" -#include "crc.h" -#include "ringbuf.h" #include "config.h" +#include "../am/am.h" +#include "../ami/ami.h" +#include "exe.h" +#include "ioctl.h" +#include "patch.h" +#include "ringbuf.h" +#include "version_fallback.h" diff --git a/src/micetools/lib/mice/patch.c b/src/micetools/lib/mice/patch.c index 73982bd..abfe809 100644 --- a/src/micetools/lib/mice/patch.c +++ b/src/micetools/lib/mice/patch.c @@ -1,248 +1,235 @@ #include "patch.h" +#include #include #include -bool fetch(json_value* object, char* name, json_value** value) { - if (object->type != json_object) return false; - for (size_t j = 0; j < object->u.object.length; j++) { - json_object_entry* entry = &(object->u.object.values[j]); - if (strncmp(name, entry->name, entry->name_length) == 0) { - *value = entry->value; - return true; - } - } - return false; -} -bool fetch_string(json_value* object, char* name, char** value) { - json_value* fetched; - if (!fetch(object, name, &fetched)) return false; - if (fetched->type != json_string) return false; - *value = fetched->u.string.ptr; - return true; -} -bool fetch_int(json_value* object, char* name, size_t* value) { - json_value* fetched; - if (!fetch(object, name, &fetched)) return false; - if (fetched->type != json_integer) return false; - *value = (size_t)fetched->u.integer; - return true; -} -bool fetch_bool(json_value* object, char* name, bool* value) { - json_value* fetched; - if (!fetch(object, name, &fetched)) return false; - if (fetched->type != json_boolean) return false; - *value = fetched->u.boolean; - return true; -} -void free_patches(patches_t* patches) { - if (patches->nopatchsets == 0) return; - for (int i = patches->nopatchsets - 1; i >= 0; i--) { - if (patches->patchsets[i] != NULL) { - for (size_t j = 0; j < patches->patchsets[i]->nopatches; j++) { - if (patches->patchsets[i]->patches[j].from != NULL) - free(patches->patchsets[i]->patches[j].from); - if (patches->patchsets[i]->patches[j].to != NULL) - free(patches->patchsets[i]->patches[j].to); - } - free(patches->patchsets[i]); - } - } - patches->nopatchsets = 0; +bool is_hex_char(char chr) { + return ('0' <= chr && chr <= '9') || ('a' <= chr && chr <= 'f') || ('A' <= chr && chr <= 'F'); } -json_value* load_json_from_file(char* path, char* error) { +patch_t patch_sentinel = { .count = 0 }; +patch_t* patch_list = &patch_sentinel; + +void commit_patch(patch_t* patch) { + if (!patch->count) return; + + patch_t* head = patch_list; + while (head->next) head = head->next; + head->next = patch; + patch->next = NULL; +} + +bool skip_whitespace(FILE* fp, char* cChr) { + while (*cChr == ' ') + if (!fread(cChr, 1, 1, fp)) return false; + return true; +} + +bool load_patches_file(const char* filename) { FILE* fp; - fopen_s(&fp, path, "r"); - if (fp == NULL) { - if (error != NULL) snprintf(error, json_error_max, "Failed to open patch file"); - return NULL; + if (fopen_s(&fp, filename, "r")) { + printf("Failed to open %s\n", filename); + return false; } - fseek(fp, 0L, SEEK_END); - size_t sz = ftell(fp); - rewind(fp); + parse_patches_state state = parse_patches_state_start; + char readBuffer[256]; + size_t rbPtr = 0; - char* json_buf = (char*)malloc(sz); - if (json_buf == NULL) { - if (error != NULL) snprintf(error, json_error_max, "Failed to allocate file buffer"); - fclose(fp); - return NULL; + char cChr; + patch_t* patch = NULL; + bool sol = true; + while (1) { + if (!fread(&cChr, 1, 1, fp)) goto patch_parser_eof; + + switch (state) { + case parse_patches_state_start: + if (cChr != '*' || !sol) { + if (cChr == '\r' || cChr == '\n') + sol = true; + else + sol = false; + continue; + } + + patch = (patch_t*)malloc(sizeof *patch); + ZeroMemory(patch, sizeof *patch); + rbPtr = 0; + + if (!fread(&cChr, 1, 1, fp)) goto patch_parser_eof; + state = parse_patches_state_addr; + if (!skip_whitespace(fp, &cChr)) goto patch_parser_eof; + // Falls through + + case parse_patches_state_addr: + if (is_hex_char(cChr)) { + readBuffer[rbPtr++] = cChr; + break; + } + if (rbPtr != 8) { + printf("Invalid address length: %d\n", rbPtr); + return false; + } + hex_to_int(&(size_t)patch->address, readBuffer); + + state = parse_patches_state_colon; + rbPtr = 0; + if (!skip_whitespace(fp, &cChr)) goto patch_parser_eof; + // Falls through + + case parse_patches_state_colon: + if (cChr != ':') { + printf("Syntax Error: expected : saw %c\n", cChr); + return false; + } + if (!fread(&cChr, 1, 1, fp)) goto patch_parser_eof; + state = parse_patches_state_match; + if (!skip_whitespace(fp, &cChr)) goto patch_parser_eof; + // Falls through + + case parse_patches_state_match: + if (is_hex_char(cChr)) { + readBuffer[rbPtr++] = cChr; + break; + } + + if (rbPtr % 2 != 0) { + printf("Match length must be even: saw %d\n", rbPtr); + return false; + } + + if (rbPtr != 0) { + patch->match = (unsigned char*)malloc(rbPtr / 2); + hex_to_bin(readBuffer, patch->match, rbPtr); + } + patch->count = rbPtr / 2; + + state = parse_patches_state_gt; + rbPtr = 0; + if (!skip_whitespace(fp, &cChr)) goto patch_parser_eof; + // Falls through + + case parse_patches_state_gt: + if (cChr != '>') { + printf("Syntax Error: expected > saw %c\n", cChr); + return false; + } + if (!fread(&cChr, 1, 1, fp)) goto patch_parser_eof; + state = parse_patches_state_replace; + if (!skip_whitespace(fp, &cChr)) goto patch_parser_eof; + // Falls through + + case parse_patches_state_replace: + if (is_hex_char(cChr)) { + readBuffer[rbPtr++] = cChr; + break; + } + + if (patch->count == 0) { + if (rbPtr == 0) { + printf("Replace length must be non-zero\n"); + return false; + } + if (rbPtr % 2 != 0) { + printf("Replace length must be even: saw %d\n", rbPtr); + return false; + } + patch->count = rbPtr / 2; + + patch->replace = (unsigned char*)malloc(rbPtr / 2); + hex_to_bin(readBuffer, patch->replace, rbPtr); + } else { + if (rbPtr != patch->count * 2) { + printf("Replace length must match: %d != %d\n", rbPtr, patch->count * 2); + return false; + } + + patch->replace = (unsigned char*)malloc(patch->count); + hex_to_bin(readBuffer, patch->replace, rbPtr); + } + + state = parse_patches_state_pound; + rbPtr = 0; + if (!skip_whitespace(fp, &cChr)) goto patch_parser_eof; + // Falls through + + case parse_patches_state_pound: + if (cChr == '\r' || cChr == '\n') { + commit_patch(patch); + state = parse_patches_state_start; + break; + } + if (cChr != '#') { + printf("Syntax Error: expected # saw %c\n", cChr); + return false; + } + + if (!fread(&cChr, 1, 1, fp)) goto patch_parser_eof; + state = parse_patches_state_name; + rbPtr = 0; + if (!skip_whitespace(fp, &cChr)) goto patch_parser_eof; + // Falls through + + case parse_patches_state_name: + if (cChr == '\r' || cChr == '\n') { + patch->name = (char*)malloc(rbPtr + 1); + memcpy(patch->name, readBuffer, rbPtr); + patch->name[rbPtr] = '\0'; + + commit_patch(patch); + state = parse_patches_state_start; + break; + } + readBuffer[rbPtr++] = cChr; + break; + } } - if (!(sz = fread(json_buf, 1, sz, fp))) { - if (error != NULL) snprintf(error, json_error_max, "Failed to read file"); - fclose(fp); - return NULL; - }; + +patch_parser_eof: + if (patch) commit_patch(patch); fclose(fp); - - json_settings settings = { 0 }; - return json_parse_ex(&settings, json_buf, sz, error); -} - -bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error, - const char* test_binary_name) { - patches->nopatchsets = set_count; - patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*)); - for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL; - - error[0] = '\0'; - for (int i = 0; i < set_count; i++) { - patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t)); - patches->patchsets[i] = patchset; - patchset->name = NULL; - patchset->description = NULL; - patchset->binary_name = NULL; - patchset->apply = false; - patchset->nopatches = 0; - - char *name, *description, *binary_name; - if (!fetch_string(set_json[i], "name", &name)) { - snprintf(error, json_error_max, "'name' missing for patch %d", i); - goto failed; - } - if (!fetch_string(set_json[i], "description", &description)) { - snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name); - goto failed; - } - if (!fetch_string(set_json[i], "binary_name", &binary_name)) binary_name = NULL; - - bool apply; - if (!fetch_bool(set_json[i], "apply", &apply)) { - snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name); - goto failed; - } - - if (binary_name && test_binary_name) { - if (strcmp(binary_name, test_binary_name) != 0) { - patchset->name = name; - patchset->description = description; - patchset->binary_name = binary_name; - patchset->apply = apply; - patchset->nopatches = 0; - continue; - } - } - - json_value* set_patches; - if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) { - char* patches_file_path; - if (fetch_string(set_json[i], "patches_file", &patches_file_path)) { - char load_error[json_error_max]; - set_patches = load_json_from_file(patches_file_path, load_error); - if (set_patches == NULL) { - fprintf(stderr, "W: patcher: Failed to load '%s': %s\n", patches_file_path, - load_error); - continue; - } - if (set_patches->type != json_array) { - fprintf(stderr, "W: patcher: Failed to load '%s': not an array\n", - patches_file_path); - continue; - } - } else { - snprintf(error, json_error_max, - "Neither 'patches' nor 'patchs_file' in patch %d (%s)", i, name); - goto failed; - } - } - - int count = set_patches->u.array.length; - patchset = (patchset_t*)realloc(patchset, sizeof(patchset_t) + (sizeof(patch_t) * count)); - patches->patchsets[i] = patchset; - - patchset->name = name; - patchset->description = description; - patchset->binary_name = binary_name; - patchset->apply = apply; - patchset->nopatches = count; - memset(patchset->patches, 0, count * (sizeof(patch_t))); - - for (int j = 0; j < count; j++) { - json_value* this_patch = set_patches->u.array.values[j]; - size_t at; - char *from, *to; - if (!fetch_int(this_patch, "at", &at)) { - char* at_str; - if (!fetch_string(this_patch, "at", &at_str)) { - snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j); - goto failed; - } - - if (strlen(at_str) > 8) { - snprintf(error, json_error_max, "invalid 'at' value for patch %s[%d]", name, j); - goto failed; - } - hex_to_bin(at_str, (void*)&at, 8); - at = _byteswap_ulong(at); // Endianess! - } - if (!fetch_string(this_patch, "from", &from)) { - snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j); - goto failed; - } - if (!fetch_string(this_patch, "to", &to)) { - snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j); - goto failed; - } - - char* patch_name; - if (!fetch_string(this_patch, "name", &patch_name)) patch_name = NULL; - - patchset->patches[j].name = patch_name; - patchset->patches[j].offset = at; - size_t size = strlen(from); - if (size != strlen(to)) { - snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", - name, j); - goto failed; - } - if (size % 2 != 0) { - snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j); - goto failed; - } - unsigned char* bin_from = patchset->patches[j].from = (unsigned char*)malloc(size / 2); - unsigned char* bin_to = patchset->patches[j].to = (unsigned char*)malloc(size / 2); - if (!hex_to_bin(from, bin_from, size)) { - snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j); - goto failed; - }; - if (!hex_to_bin(to, bin_to, size)) { - snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j); - goto failed; - }; - - patchset->patches[j].count = size / 2; - } - } - return true; - -failed: - free_patches(patches); - return false; } -bool load_patches(patches_t* patches, char* path, char* error, const char* test_binary_name) { - patches->nopatchsets = 0; - - json_value* parsed = load_json_from_file(path, error); - if (parsed == NULL) return false; - - int loaded_patches = 0; - json_value** patches_json; - if (parsed->type == json_array) { - loaded_patches = parsed->u.array.length; - patches_json = parsed->u.array.values; - } else if (parsed->type == json_object) { - loaded_patches = 1; - patches_json = &parsed; - } else { - snprintf(error, json_error_max, "Patch file format error"); - json_value_free(parsed); +bool load_patches(char* indexPath, char* exeName) { + FILE* fp; + if (fopen_s(&fp, indexPath, "r")) { + printf("Failed to open %s\n", indexPath); return false; } - if (!parse_patches(patches, patches_json, loaded_patches, error, test_binary_name)) - return false; + char cChr; + char nameBuffer[256]; + char patchBuffer[256]; + size_t which = 0; + size_t nPtr = 0; + size_t pPtr = 0; + while (fread(&cChr, 1, 1, fp)) { + if (cChr == '\r' || cChr == '\n') { + if (nPtr && pPtr) { + nameBuffer[nPtr] = '\0'; + patchBuffer[pPtr] = '\0'; + if (strcmp(nameBuffer, exeName) == 0) { + printf("Loading: %s\n", patchBuffer); + if (!load_patches_file(patchBuffer)) return false; + } + } + nPtr = pPtr = which = 0; + continue; + } + + if (cChr == ' ') continue; + if (cChr == ':') { + which++; + continue; + } + if (which == 0) + nameBuffer[nPtr++] = cChr; + else if (which == 1) + patchBuffer[pPtr++] = cChr; + } + + fclose(fp); return true; } diff --git a/src/micetools/lib/mice/patch.h b/src/micetools/lib/mice/patch.h index 61b456f..49893a2 100644 --- a/src/micetools/lib/mice/patch.h +++ b/src/micetools/lib/mice/patch.h @@ -2,39 +2,30 @@ #include #include -#include "../json/json.h" #include "../util/hex.h" -typedef struct { - size_t offset; +bool load_patches_file(const char* filename); +bool load_patches(char* indexPath, char* exeName); + +typedef struct _patch { + void* address; size_t count; + unsigned char* match; + unsigned char* replace; char* name; - unsigned char* from; - unsigned char* to; + + struct _patch* next; } patch_t; -typedef struct { - char* name; - char* description; - char* binary_name; - bool apply; - size_t nopatches; - patch_t patches[]; -} patchset_t; +extern patch_t* patch_list; -typedef struct { - size_t nopatchsets; - patchset_t** patchsets; -} patches_t; - -// Internal JSON helpers -bool fetch(json_value* object, char* name, json_value** value); -bool fetch_string(json_value* object, char* name, char** value); -bool fetch_int(json_value* object, char* name, size_t* value); -bool fetch_bool(json_value* object, char* name, bool* value); -bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error, - const char* test_binary_name); - -// Main two exports -void free_patches(patches_t* patches); -bool load_patches(patches_t* patches, char* path, char* error, const char* test_binary_name); +typedef enum { + parse_patches_state_start = 0, + parse_patches_state_addr, + parse_patches_state_colon, + parse_patches_state_match, + parse_patches_state_gt, + parse_patches_state_replace, + parse_patches_state_pound, + parse_patches_state_name, +} parse_patches_state; diff --git a/src/micetools/lib/mice/version_fallback.h b/src/micetools/lib/mice/version_fallback.h new file mode 100644 index 0000000..b8fb70b --- /dev/null +++ b/src/micetools/lib/mice/version_fallback.h @@ -0,0 +1,3 @@ +#ifndef MICE_VERSION +#define MICE_VERSION "0.0-pre" +#endif diff --git a/src/micetools/lib/mxk/meson.build b/src/micetools/lib/mxk/meson.build index eacb031..d94fd63 100644 --- a/src/micetools/lib/mxk/meson.build +++ b/src/micetools/lib/mxk/meson.build @@ -9,5 +9,5 @@ mxklib = static_library( include_directories: [ openssl_inc, ], - dependencies: [openssl_lib] + dependencies: [openssl_lib], ) diff --git a/src/micetools/lib/mxk/mxk.c b/src/micetools/lib/mxk/mxk.c index 8816bea..9aabe5d 100644 --- a/src/micetools/lib/mxk/mxk.c +++ b/src/micetools/lib/mxk/mxk.c @@ -1,7 +1,5 @@ #include "mxk.h" -#include "../am/amTimer.h" - BOOL mxkExchengeAesKey(HANDLE mxparallel) { FILETIME filetime; amtime_t now; @@ -52,7 +50,7 @@ BOOL mxkVersion(HANDLE mxparallel, unsigned short* version) { *version = ((unsigned short*)packet)[0]; return TRUE; } -#include + BOOL mxkSetMainId(HANDLE mxparallel, const unsigned char* main_id) { unsigned char packet[16]; diff --git a/src/micetools/lib/mxk/mxk.h b/src/micetools/lib/mxk/mxk.h index 540b649..18c6227 100644 --- a/src/micetools/lib/mxk/mxk.h +++ b/src/micetools/lib/mxk/mxk.h @@ -1,6 +1,8 @@ #pragma once #include +#include "../ami/ami.h" + extern unsigned char KEY_R[16]; extern unsigned char KEY_S[16]; extern unsigned char BILLING_PRIVKEY[917]; @@ -39,7 +41,7 @@ enum { }; // Structs -#pragma pack(1) +#pragma pack(push, 1) typedef struct { DWORD crc; DWORD format; @@ -54,14 +56,18 @@ typedef struct { BYTE __[216]; BYTE seed[16]; } appboot_t; +#pragma pack(pop) // Crypt void mxkSetKeyS(unsigned char* key_s); void mxkSetKeyR(unsigned char* key_r); void mxkSwapKeys(); -void mxkCryptEncryptData(unsigned char* ct, unsigned char* pt); -void mxkCryptDecryptData(unsigned char* ct, unsigned char* pt); +void mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, unsigned char* pt, const unsigned char* ct, size_t nbytes); +void mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv, const unsigned char* ct, unsigned char* pt, size_t nbytes); + +void mxkCryptEncryptData(unsigned char* ct, const unsigned char* pt); +void mxkCryptDecryptData(const unsigned char* ct, unsigned char* pt); void mxkSign(void* buffer, size_t nbytes, unsigned char* signature); void mxkSignValue(unsigned int value, unsigned char* signature); @@ -75,7 +81,7 @@ static void mxkTransportCtrlPortInOrOut(HANDLE mxparallel, BYTE flag); BOOL mxkTransportSend(HANDLE mxparallel, unsigned char* data, DWORD nbytes); HRESULT mxkTransportRecv(HANDLE mxparallel, unsigned char* data, DWORD nbytes); -BOOL mxkSendPacket(HANDLE mxparallel, unsigned char* packet); +BOOL mxkSendPacket(HANDLE mxparallel, const unsigned char* packet); BOOL mxkRecvPacket(HANDLE mxparallel, unsigned char* packet); void mxkTransportInitPic(HANDLE mxparallel); @@ -95,8 +101,8 @@ void mxkPacketReqNvramRead(unsigned char* packet, unsigned short addr, unsigned // MXK BOOL mxkExchengeAesKey(HANDLE mxparallel); BOOL mxkVersion(HANDLE mxparallel, unsigned short* version); -BOOL mxkSetMainId(HANDLE mxparallel, unsigned char* main_id); -BOOL mxkGetMainId(HANDLE mxparallel, const unsigned char* main_id); +BOOL mxkSetMainId(HANDLE mxparallel, const unsigned char* main_id); +BOOL mxkGetMainId(HANDLE mxparallel, unsigned char* main_id); BOOL mxkGetKeyId(HANDLE mxparallel, unsigned char* main_id); BOOL mxkGetAppBootInfo(HANDLE mxparallel, appboot_t* appboot); BOOL mxkGetPlayCounter(HANDLE mxparallel, DWORD* play_counter); diff --git a/src/micetools/lib/mxk/mxkCrypt.c b/src/micetools/lib/mxk/mxkCrypt.c index 36eab8b..ba7b26f 100644 --- a/src/micetools/lib/mxk/mxkCrypt.c +++ b/src/micetools/lib/mxk/mxkCrypt.c @@ -105,7 +105,29 @@ void mxkSwapKeys() { memcpy(KEY_S, temp, 16); } -void mxkCryptEncryptData(unsigned char* ct, unsigned char* pt) { +void mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, unsigned char* ct, const unsigned char* pt, size_t nbytes) { + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); + + int outl; + EVP_EncryptUpdate(ctx, ct, &outl, pt, nbytes); + unsigned char dump[16]; + EVP_EncryptFinal_ex(ctx, dump, &outl); + EVP_CIPHER_CTX_free(ctx); +} + +void mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv, const unsigned char* ct, unsigned char* pt, size_t nbytes) { + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 0); + + int outl; + EVP_DecryptUpdate(ctx, pt, &outl, ct, nbytes); + unsigned char dump[16]; + EVP_EncryptFinal_ex(ctx, dump, &outl); + EVP_CIPHER_CTX_free(ctx); +} + +void mxkCryptEncryptData(unsigned char* ct, const unsigned char* pt) { EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); EVP_CipherInit_ex(ctx, EVP_aes_128_ecb(), NULL, KEY_S, NULL, 1); @@ -116,14 +138,14 @@ void mxkCryptEncryptData(unsigned char* ct, unsigned char* pt) { EVP_CIPHER_CTX_free(ctx); } -void mxkCryptDecryptData(unsigned char* ct, unsigned char* pt) { +void mxkCryptDecryptData(const unsigned char* ct, unsigned char* pt) { EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); EVP_CipherInit_ex(ctx, EVP_aes_128_ecb(), NULL, KEY_R, NULL, 0); int outl; EVP_DecryptUpdate(ctx, pt, &outl, ct, 16); unsigned char dump[16]; - EVP_DecryptFinal_ex(ctx, dump, &outl); + EVP_EncryptFinal_ex(ctx, dump, &outl); EVP_CIPHER_CTX_free(ctx); } @@ -142,12 +164,13 @@ void mxkSign(void* buffer, size_t nbytes, unsigned char* signature) { EVP_MD_CTX_destroy(ctx); } -#pragma pack(1) +#pragma pack(push, 1) typedef struct { unsigned int value; unsigned char key_low[4]; unsigned char key_high[7]; } sign_payload_t; +#pragma pack(pop) void mxkSignValue(unsigned int value, unsigned char* signature) { sign_payload_t hash_data; diff --git a/src/micetools/lib/mxk/mxkPacket.c b/src/micetools/lib/mxk/mxkPacket.c index 5028d84..b06d98e 100644 --- a/src/micetools/lib/mxk/mxkPacket.c +++ b/src/micetools/lib/mxk/mxkPacket.c @@ -1,4 +1,3 @@ -#include "../am/amTimer.h" #include "mxk.h" void inline _mxkPacketInjectJunk(unsigned char* packet, size_t i) { diff --git a/src/micetools/lib/mxk/mxkTransport.c b/src/micetools/lib/mxk/mxkTransport.c index bfcc684..6c488d0 100644 --- a/src/micetools/lib/mxk/mxkTransport.c +++ b/src/micetools/lib/mxk/mxkTransport.c @@ -1,4 +1,3 @@ -#include "../am/amTimer.h" #include "../mice/ioctl.h" #include "mxk.h" @@ -68,7 +67,7 @@ BOOL mxkTransportSend(HANDLE mxparallel, unsigned char *data, DWORD nbytes) { if (status == 0) break; amiTimerGet(&now); if (DO_SLEEP_0) Sleep(0); - } while (_amTimeDeltaMircos(now, start) < 1000000); + } while (amiTimerDiffUsec(&start, &now) < 1000000); if (status != 0) { puts("SEND busy error"); @@ -78,7 +77,7 @@ BOOL mxkTransportSend(HANDLE mxparallel, unsigned char *data, DWORD nbytes) { while (mxkTransportWaitStrobeRelease(mxparallel)) { amiTimerGet(&now); if (DO_SLEEP_0) Sleep(0); - if (_amTimeDeltaMircos(now, start) > 999999) { + if (amiTimerDiffUsec(&start, &now) > 999999) { puts("SEND busy error"); return FALSE; } @@ -92,7 +91,7 @@ BOOL mxkTransportSend(HANDLE mxparallel, unsigned char *data, DWORD nbytes) { while (mxkTransportWaitStrobeReady(mxparallel)) { amiTimerGet(&now); if (DO_SLEEP_0) Sleep(0); - if (_amTimeDeltaMircos(now, start) > 999999'000) { + if (amiTimerDiffUsec(&start, &now) > 999999'000) { puts("SEND end error"); return FALSE; } @@ -119,7 +118,7 @@ HRESULT mxkTransportRecv(HANDLE mxparallel, unsigned char *data, DWORD nbytes) { if (status != 0) break; amiTimerGet(&now); if (DO_SLEEP_0 != 0) Sleep(0); - } while (_amTimeDeltaMircos(now, start) < 1000000'000); + } while (amiTimerDiffUsec(&start, &now) < 1000000'000); if (status == 0) { puts("RECV busy error 1"); @@ -130,7 +129,7 @@ HRESULT mxkTransportRecv(HANDLE mxparallel, unsigned char *data, DWORD nbytes) { amiTimerGet(&now); if (DO_SLEEP_0 != 0) Sleep(0); - if (_amTimeDeltaMircos(now, start) > 999999'000) { + if (amiTimerDiffUsec(&start, &now) > 999999'000) { puts("RECV busy error 2"); return FALSE; } @@ -144,7 +143,7 @@ HRESULT mxkTransportRecv(HANDLE mxparallel, unsigned char *data, DWORD nbytes) { while (mxkTransportWaitStrobeRelease(mxparallel)) { amiTimerGet(&now); if (DO_SLEEP_0) Sleep(0); - if (_amTimeDeltaMircos(now, start) > 999999) { + if (amiTimerDiffUsec(&start, &now) > 999999) { puts("RECV end error"); return FALSE; } @@ -154,7 +153,7 @@ HRESULT mxkTransportRecv(HANDLE mxparallel, unsigned char *data, DWORD nbytes) { return TRUE; } -BOOL mxkSendPacket(HANDLE mxparallel, unsigned char *packet) { +BOOL mxkSendPacket(HANDLE mxparallel, const unsigned char *packet) { unsigned char encrypted[16]; ZeroMemory(encrypted, 16); mxkCryptEncryptData(encrypted, packet); diff --git a/src/micetools/lib/util/hex.c b/src/micetools/lib/util/hex.c index 2ae6b58..08ce644 100644 --- a/src/micetools/lib/util/hex.c +++ b/src/micetools/lib/util/hex.c @@ -1,4 +1,24 @@ #include +#include + +int hex_to_byte(char *hex, unsigned char *val) { + if (hex == NULL) return -1; + + char hex_low = hex[0]; + if ('@' < hex_low) hex_low += -7; + + char hex_high = hex[1]; + if (hex_high < 'A') { + *val = (hex_low << 4) | hex_high - '0'; + return 0; + } + if (hex_high < 'a') { + *val = (hex_low << 4) | hex_high - '7'; + return 0; + } + *val = (hex_low << 4) | hex_high - 'W'; + return 0; +} unsigned char hex_value(char c) { if (isdigit((unsigned char)c)) return c - '0'; @@ -57,3 +77,26 @@ int hex_to_bin(char *hex, unsigned char *bin, int hex_len) { } return 1; } +void bin_to_hex(char *hex, unsigned char *bin, int nbytes) { + int hex_len = nbytes * 2; + while (nbytes--) { + if (bin[0] & 0x0f > 0x09) + hex[--hex_len] = (bin[0] & 0x0f) + 'a'; + else + hex[--hex_len] = (bin[0] & 0x0f) + '0'; + + if (bin[0] & 0xf0 > 0x90) + hex[--hex_len] = ((bin[0] & 0xf0) >> 4) + 'a'; + else + hex[--hex_len] = ((bin[0] & 0xf0) >> 4) + '0'; + + bin++; + } +} + +int hex_to_int(unsigned int *value, char *hex) { + unsigned int temp; + if (!hex_to_bin(hex, &temp, 8)) return 0; + *value = _byteswap_ulong(temp); + return 1; +} diff --git a/src/micetools/lib/util/hex.h b/src/micetools/lib/util/hex.h index df20a2b..fdaabe5 100644 --- a/src/micetools/lib/util/hex.h +++ b/src/micetools/lib/util/hex.h @@ -1,2 +1,5 @@ +int hex_to_byte(char *hex, unsigned char *val); unsigned char hex_value(char c); int hex_to_bin(char *hex, unsigned char *bin, int hex_len); +int hex_to_int(unsigned int *value, char *hex); +void bin_to_hex(char *hex, unsigned char *bin, int nbytes); diff --git a/src/micetools/maiBackupStructs.h b/src/micetools/maiBackupStructs.h new file mode 100644 index 0000000..4fc5a17 --- /dev/null +++ b/src/micetools/maiBackupStructs.h @@ -0,0 +1,181 @@ +#include + +#pragma pack(push, 1) + +/** + * @brief A sigle byte of EEPROM storage, seemingly unused + * Base: 1000 + * Backup: 100D + */ +typedef struct { + uint32_t m_Crc; + uint32_t m_GameId; + uint32_t m_Length; // = 5 + uint8_t Unk04; +} MAI_EEPROM_REGION0; +#define MAI_EEPROM_REGION0_BASE 0x1000 +#define MAI_EEPROM_REGION0_DUP 0x100d + +/** + * Base: 4000 + * Backup: 4034 + * Cleared by BACKUP DATA CLEAR + */ +typedef struct { + uint32_t m_Crc; + uint32_t m_GameId; + uint32_t m_Length; // = 44 + uint32_t m_NumberOfGames; + uint32_t m_TotalTime; + uint32_t m_TotalPlayTime; + uint32_t Unk10[4]; + uint32_t m_LongestPlayTime; + uint32_t m_ShortestPlayTime; + uint32_t m_AveragePlayTime; +} MAI_SRAM_REGION0; +#define MAI_SRAM_REGION0_BASE 0x4000 +#define MAI_SRAM_REGION0_DUP 0x4034 + +/** + * Base: 4068 + * Backup: 4090 + * Cleared by BACKUP DATA CLEAR + */ +typedef struct { + uint32_t m_Crc; + uint32_t m_GameId; + uint32_t m_Version; // = 190 + uint8_t Rsv04[28]; +} MAI_SRAM_REGION1; +#define MAI_SRAM_REGION1_BASE 0x4068 +#define MAI_SRAM_REGION1_DUP 0x4090 + +typedef struct { + uint8_t m_Reported; // 0 = 済 (not yet), 1 = 未 (already) + uint8_t Rsv01[3]; + uint32_t m_Timestamp; // Unix timestamp + uint32_t m_BackupClearTimestamp; // YYMMDDhhmm when displayed as int + uint32_t m_NumberOfCoinsInserted; + uint32_t m_CreditByCoinInsertion; + uint32_t m_CreditByServiceButton; + uint32_t m_PowerOnTime; // Excluding test mode + uint32_t m_TotalPlays; + uint32_t m_NumberOf1PGames; + uint32_t m_NumberOfSyncGames; + uint32_t m_NumberOfVsGames; + uint32_t m_NumberOfTutorials; + uint32_t m_NumberOfUploads; + uint32_t m_NumberOfNewCardFree; + uint32_t m_ErrorCount[8]; + uint32_t m_TotalPlayTime; + uint32_t m_ShortestPlayTime; + uint32_t m_LongestPlayTime; + uint8_t Rsv64[32]; +} MAI_SRAM_Meter; +/** + * @brief Accounting information + * Base: 40b8 + * Backup: 44c0 + * Cleared by BACKUP DATA CLEAR + */ +typedef struct { + uint32_t m_Crc; + uint32_t m_GameId; + uint32_t m_Version; // = 190 + uint32_t m_CreditToStart; + uint32_t m_CreditToStart2P; + uint32_t m_NumberOf1PGames; + uint32_t m_NumberOfSyncGames; + uint32_t m_NumberOfVsGames; + uint32_t m_NumberOfTutorials; + uint32_t m_NumberOfUploads; + uint32_t m_NumberOfGuestPlays; + uint32_t m_NumberOfNewUsers; + uint32_t m_NumberOfNewCardFree; + uint32_t m_NumberOfNewCardPaid; + uint32_t m_NumberOfNewWithMultiplePeople; + uint16_t m_Year; + uint8_t m_Month; + uint8_t m_Day; + uint8_t m_Hour; + uint8_t m_Minute; + uint8_t m_Second; + uint8_t Rsv3B; + MAI_SRAM_Meter m_Meter[7]; + uint32_t m_NumberOfCoinsInserted; + uint32_t m_CreditByCoinInsertion; + uint32_t m_CreditByServiceButton; + uint32_t m_NumberOfGames; + uint32_t m_TotalTime; + uint8_t Rsv3EC[20]; +} MAI_SRAM_REGION2; +#define MAI_SRAM_REGION2_BASE 0x40b8 +#define MAI_SRAM_REGION2_DUP 0x44c0 + +/** + * @brief Game Assignments + * Base: 48c8 + * Backup: 4950 + * Not cleared by BACKUP DATA CLEAR + */ +typedef struct { + uint32_t m_Crc; + uint32_t m_GameId; + uint32_t m_Version; // = 190 + uint8_t m_NumberOfTracks1P; // 3 or 4 + uint8_t m_NumberOfTracksMulti; // 3 or 4 + uint8_t m_NumberOfTracksEvent; // 1, 2, 3, 4 + uint8_t m_EventMode; // 0, 1 = OFF, ON + uint8_t m_OnlineMode; // 0, 1 = OFF, ON + uint8_t m_TotalMachine; // 1, 2 + uint8_t m_LinkId; // 1, 2 + uint8_t m_AdvertiseSound; // 0, 1, 2, 3, 4 = 0%, 25%, 50%, 75%, 100% + uint8_t m_AdvertiseMode; // 0, 1 = RANKING, BASIC + uint8_t m_CameraPosition; // 0, 1, 2 = NO CAMERA, RIGHT, LEFT + uint8_t m_TouchSensorCalib1P[17]; // all bytes in range 0-99, inclusive + uint8_t m_TouchSensorCalbi2P[17]; // all bytes in range 0-99, inclusive + uint8_t m_DressCode; // 0, 1 = LOW, HIGH + uint8_t m_CloseScheduleType; // 0, 1 = DAY, WEEK + uint8_t m_CloseScheduleHour[8]; // all bytes in range 0-30, inclusive, 0 = ALLTIME, [0] = Day, [1-7] = Week + uint8_t m_CloseScheduleMinute[8]; // all bytes in range 0-59, inclusive, [0] = Day, [1-7] = Week + uint8_t Rsv42[62]; +} MAI_SRAM_REGION3; +#define MAI_SRAM_REGION3_BASE 0x48c8 +#define MAI_SRAM_REGION3_DUP 0x4950 + +/** + * Base: 49d8 + * Backup: 4a20 + * Cleared by BACKUP DATA CLEAR + */ +typedef struct { + uint32_t m_Crc; + uint32_t m_GameId; + uint32_t m_Version; // = 190 + uint32_t m_Timestamp; // What is this? Hay's is Sat May 28 2022 07:27:40 GMT+0000. Maybe "last backup clear time" + uint8_t Rsv08[56]; +} MAI_SRAM_REGION4; +#define MAI_SRAM_REGION4_BASE 0x49d8 +#define MAI_SRAM_REGION4_DUP 0x4a20 + +/** + * @brief Something to do with downloads. Not going to get very far here until I have those working! + * Base: 4a68 + * Backup: 4ad0 + * Not cleared by BACKUP DATA CLEAR + */ +typedef struct { + uint32_t m_Crc; + uint32_t m_GameId; + uint32_t m_Version; // = 190 + uint32_t m_ErrorCount[8]; + uint8_t Unk24; + char m_GameVersion[5]; + char Unk2A[32]; + uint16_t Unk4A; + uint8_t Rsv4C[20]; +} MAI_SRAM_REGION5; +#define MAI_SRAM_REGION5_BASE 0x4a68 +#define MAI_SRAM_REGION5_DUP 0x4ad0 + +#pragma pack(pop) diff --git a/src/micetools/meson.build b/src/micetools/meson.build index b5f680a..d4bf048 100644 --- a/src/micetools/meson.build +++ b/src/micetools/meson.build @@ -2,6 +2,7 @@ subdir('lib') subdir('micepatch') subdir('micekeychip') +subdir('micemaster') subdir('launcher') subdir('dll') subdir('miceboot') diff --git a/src/micetools/micekeychip/callbacks/appboot.c b/src/micetools/micekeychip/callbacks/appboot.c index 572b1e6..2d267a7 100644 --- a/src/micetools/micekeychip/callbacks/appboot.c +++ b/src/micetools/micekeychip/callbacks/appboot.c @@ -9,18 +9,18 @@ void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_SYSTEMFLAG, sf); } void mxkPcpAbModelType(pcpa_t* stream, void* data) { - char mt[16]; - snprintf(mt, 16, "%02X", Config.appboot_modeltype); + char mt[3]; + snprintf(mt, 3, "%02X", Config.appboot_modeltype); pcpaSetSendPacket(stream, AB_MODELTYPE, mt); } void mxkPcpAbFormatType(pcpa_t* stream, void* data) { - char ft[16]; - snprintf(ft, 16, "%02X", Config.appboot_formattype); + char ft[3]; + snprintf(ft, 3, "%02X", Config.appboot_formattype); pcpaSetSendPacket(stream, AB_FORMATTYPE, ft); } void mxkPcpAbRegion(pcpa_t* stream, void* data) { - char rg[16]; - snprintf(rg, 16, "%02X", Config.appboot_region); + char rg[3]; + snprintf(rg, 3, "%02X", Config.appboot_region); pcpaSetSendPacket(stream, AB_REGION, rg); } void mxkPcpAbPlatformId(pcpa_t* stream, void* data) { @@ -30,8 +30,8 @@ void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_NETWORKADDRESS, Config.appboot_network); } void mxkPcpAbDvd(pcpa_t* stream, void* data) { - char dvd[16]; - snprintf(dvd, 16, "%02X", Config.appboot_dvdflag); + char dvd[3]; + snprintf(dvd, 3, "%02X", Config.appboot_dvdflag); pcpaSetSendPacket(stream, AB_DVD, dvd); } diff --git a/src/micetools/micekeychip/callbacks/billing.c b/src/micetools/micekeychip/callbacks/billing.c index 3d8c849..4ba3d3a 100644 --- a/src/micetools/micekeychip/callbacks/billing.c +++ b/src/micetools/micekeychip/callbacks/billing.c @@ -25,7 +25,7 @@ void mxkPcpPbNearfull(pcpa_t* stream, void* data) { char nf[9]; snprintf(nf, sizeof nf, "%08X", Config.billing_nearfull); - pcpaSetSendPacket(stream, BIL_NEARFUL, nf); + pcpaSetSendPacket(stream, BIL_NEARFULL, nf); } #define PUBKEY_BUF_MAX 1024 diff --git a/src/micetools/micekeychip/callbacks/callbacks.h b/src/micetools/micekeychip/callbacks/callbacks.h index 601efeb..6bbf560 100644 --- a/src/micetools/micekeychip/callbacks/callbacks.h +++ b/src/micetools/micekeychip/callbacks/callbacks.h @@ -54,7 +54,7 @@ pcpa_callback mxkPcpAbSeed; #define BIL_MAINID BILLING##"mainid" #define BIL_PLAYCOUNT BILLING##"playcount" #define BIL_PLAYLIMIT BILLING##"playlimit" -#define BIL_NEARFUL BILLING##"nearful" +#define BIL_NEARFULL BILLING##"nearfull" #define BIL_SIGNATURE BILLING##"signaturepubkey" #define BIL_CACERT BILLING##"cacertification" pcpa_callback mxkPcpPbKeyId; diff --git a/src/micetools/micekeychip/mxk.c b/src/micetools/micekeychip/mxk.c index 75ca34f..461e0b1 100644 --- a/src/micetools/micekeychip/mxk.c +++ b/src/micetools/micekeychip/mxk.c @@ -7,13 +7,16 @@ pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40]; byte BINARY_DATA[4096]; size_t BINARY_DATA_LEN; -void mxkBinaryCallback(pcpa_t* stream, void* data) { pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); } +void mxkBinaryCallback(pcpa_t* stream, void* data) { + pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); +} int mxkInit() { // Enable colour HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwMode = 0; - if (GetConsoleMode(hConsole, &dwMode)) SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + if (GetConsoleMode(hConsole, &dwMode)) + SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); WSADATA wsaData; int err = WSAStartup(2, &wsaData); @@ -41,8 +44,9 @@ e_pcpa_t mxkPcpStreamInit() { return err; } - err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER, - (sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0])); + err = pcpaSetCallbackFuncBuffer( + &PCP, CALLBACK_FUNCTION_BUFFER, + (sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0])); if (err != e_pcpa_ok) { printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err); return err; @@ -73,7 +77,7 @@ e_pcpa_t mxkPcpStreamInit() { pcpaSetCallbackFunc(&PCP, BIL_MAINID, mxkPcpPbMainId, NULL); pcpaSetCallbackFunc(&PCP, BIL_PLAYCOUNT, mxkPcpPbPlayCount, NULL); pcpaSetCallbackFunc(&PCP, BIL_PLAYLIMIT, mxkPcpPbPlayLimit, NULL); - pcpaSetCallbackFunc(&PCP, BIL_NEARFUL, mxkPcpPbNearfull, NULL); + pcpaSetCallbackFunc(&PCP, BIL_NEARFULL, mxkPcpPbNearfull, NULL); pcpaSetCallbackFunc(&PCP, BIL_SIGNATURE, mxkPcpPbSignaturePubKey, NULL); pcpaSetCallbackFunc(&PCP, BIL_CACERT, mxkPcpPbCaCertification, NULL); // Tracedata @@ -105,9 +109,10 @@ e_pcpa_t mxkPcpStreamInit() { puts("PCP binary port invalid"); exit(-1); } - int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1; + int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_LOCAL; - err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 0xffff, binary_port & 0xffff, 300000); + err = + pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 0xffff, binary_port & 0xffff, 300000); if (err != e_pcpa_ok && err != e_pcpa_to) { printf("pcpaOpenServerWithBinary Error. Code %d\n", err); return e_pcpa_not_open; diff --git a/src/micetools/micemaster/appLauncher.c b/src/micetools/micemaster/appLauncher.c new file mode 100644 index 0000000..b898288 --- /dev/null +++ b/src/micetools/micemaster/appLauncher.c @@ -0,0 +1,243 @@ +#include "appLauncher.h" + +#include +#include +#include + +#include "config.h" + +void appLauncherDefaultRegSet() { + // TODO: This +} + +char GAME_EXTENSIONS[3][4] = { + { 'c', 'o', 'm', '\0' }, + { 'e', 'x', 'e', '\0' }, + { 'b', 'a', 't', '\0' }, +}; + +DWORD __stdcall appLauncherAppThread(appLauncherAppInfo_t *appInfo) { + if (appInfo == NULL || appInfo->m_appLauncher == NULL) { + amiDebugLog("param error %p %p", appInfo, appInfo->m_appLauncher); + return 0xffffffff; + } + + PROCESS_INFORMATION processInformation; + STARTUPINFOW startupInfoW; + STARTUPINFOA startupInfoA; + char commandLine[64]; + char findPath[64]; + WCHAR workingDirectory[128]; + WCHAR wCommandLine[130]; + + intptr_t hFile; + struct _finddata_t next_file; + + bool skipSpawn = false; + bool appUser = false; + + switch (appInfo->m_mode) { + case 1: + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot_r); + break; + case 3: + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot_tr); + break; + case 5: + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot_d); + break; + case 6: + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot); + break; + + case 2: + if (appInfo->m_path[0] != '\0') { + sprintf_s(commandLine, sizeof commandLine, "%s", appInfo->m_path); + hFile = _findfirst(commandLine, &next_file); + if (hFile == -1) { + amiDebugLog("Error : Process does not exist"); + skipSpawn = true; + } + break; + } + + sprintf_s(findPath, sizeof findPath, "%s%s.*", "x:\\", "game"); + hFile = _findfirst(findPath, &next_file); + if (hFile == -1) { + amiDebugLog("Error : Process does not exist"); + skipSpawn = true; + break; + } + + do { + for (int i = 0; i < 3; i++) { + sprintf_s(findPath, 0x40, "%s.%s", "game", GAME_EXTENSIONS[i]); + + if (strcmp(findPath, next_file.name) == 0) { + sprintf_s(commandLine, 0x40, "%s%s", "x:\\", findPath); + _findclose(hFile); + appUser = true; + goto game_found; + } + } + } while (_findnext(hFile, &next_file) == 0); + + amiDebugLog("Error : Process does not exist"); + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot_r); + + game_found: + break; + + case 4: + sprintf_s(findPath, 0x40, "%s%s.*", "x:\\", "gametest"); + hFile = _findfirst(findPath, &next_file); + if (hFile == -1) { + amiDebugLog("Error : Process does not exist"); + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot_r); + break; + } + + do { + for (int i = 0; i < 3; i++) { + sprintf_s(findPath, 0x40, "%s.%s", "gametest", GAME_EXTENSIONS[i]); + + if (strcmp(findPath, next_file.name) == 0) { + sprintf_s(commandLine, 0x40, "%s%s", "x:\\", findPath); + _findclose(hFile); + appUser = true; + goto gametest_found; + } + } + } while (_findnext(hFile, &next_file) == 0); + + amiDebugLog("Error : Process does not exist"); + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot_r); + _findclose(hFile); + appUser = true; + + gametest_found: + break; + + default: + amiDebugLog("Error : Error Process"); + sprintf_s(commandLine, sizeof commandLine, "%s%s", Config.dir.execute, + Config.binary.segaboot_r); + } + + ZeroMemory(&startupInfoA, sizeof startupInfoA); + startupInfoA.cb = sizeof startupInfoA; + startupInfoA.dwFlags = 1; + startupInfoA.wShowWindow = 1; + ZeroMemory(&startupInfoW, sizeof startupInfoW); + startupInfoW.cb = sizeof startupInfoW; + startupInfoW.dwFlags = 1; + startupInfoW.wShowWindow = 1; + + if (!skipSpawn) { + BOOL success; + if (appUser) { + DWORD dwCreationFlags = 0; + + if (strstr(commandLine, "bat") != NULL) { + dwCreationFlags = CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS; + startupInfoW.wShowWindow = 0; + } + + ZeroMemory(wCommandLine, sizeof wCommandLine); + ZeroMemory(workingDirectory, sizeof workingDirectory); + + MultiByteToWideChar(0, 0, commandLine, strlen(commandLine), wCommandLine, + sizeof wCommandLine / sizeof wCommandLine[0]); + MultiByteToWideChar(0, 0, Config.dir.game, 4, workingDirectory, + sizeof workingDirectory / sizeof workingDirectory[0]); + + wchar_t *username = appInfo->m_appLauncher->m_username; + wchar_t *password = appInfo->m_appLauncher->m_password; + + if (wcslen(username) == 0) + MultiByteToWideChar(0, 0, Config.env.username, strlen(Config.env.username), + username, sizeof username / sizeof username[0]); + if (wcslen(password) == 0) + MultiByteToWideChar(0, 0, Config.env.password, strlen(Config.env.password), + password, sizeof password / sizeof password[0]); + + amiDebugLog("Creating process: %ls", wCommandLine); + success = CreateProcessWithLogonW(username, NULL, password, 0, NULL, wCommandLine, + dwCreationFlags, NULL, workingDirectory, + &startupInfoW, &processInformation); + } else { + amiDebugLog("Creating process: %s", commandLine); + success = CreateProcessA(NULL, commandLine, NULL, NULL, FALSE, + CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, NULL, NULL, + &startupInfoA, &processInformation); + } + + if (!success) { + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + amiDebugLog("ERROR : Close Process %s", commandLine); + } else { + if (WaitForSingleObject(processInformation.hProcess, INFINITE) == WAIT_FAILED) { + amiDebugLog("WaitForSingleObject Error:%d", GetLastError()); + } + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + } + } + + pcpa_t *stream = &(appInfo->m_appLauncher->m_pcp); + e_pcpa_t err; + if ((err = pcpaInitStream(stream)) != e_pcpa_ok) { + amiDebugLog("Error pcpaInitStream. Code %d", err); + return 0xffffffff; + } + do { + err = pcpaOpenClient(stream, "127.0.0.1", 40100, 60000, TIMEOUT_NONE); + if (err != e_pcpa_ok) pcpaClose(stream); + } while (err != e_pcpa_ok); + + if (pcpaSetSendPacket(stream, "mxmaster.foreground.active", "0") == NULL) { + pcpaClose(stream); + amiDebugLog("Error pcpaSetSendPacket return NULL"); + return 0xffffffff; + } + + if ((err = pcpaAccessClient(stream, TIMEOUT_NONE)) != e_pcpa_ok) { + amiDebugLog("Error : Not Access Master Thread. Code %d", err); + pcpaClose(stream); + return 0xffffffff; + } + pcpaClose(stream); + return 0; +} + +int appLauncherCreateThread(appLauncherAppInfo_t *appInfo, appLauncher_t *appLauncher) { + if (appLauncher->m_createdThread != 0) { + amiDebugLog("Error : already created thread"); + return 3; + } + + unsigned int mode = appInfo->m_mode; + appLauncher->m_appInfo.m_mode = mode; + strcpy_s(appLauncher->m_appInfo.m_path, sizeof appLauncher->m_appInfo.m_path, appInfo->m_path); + + if (mode == 1 || mode == 3 || mode == 5 || mode == 6) appLauncherDefaultRegSet(); + + HANDLE hThread = CreateThread(NULL, 0, &appLauncherAppThread, &appLauncher->m_appInfo, 0, + &appLauncher->m_threadAddr); + + appLauncher->m_hThread = hThread; + if (hThread == 0) { + amiDebugLog("Error : create thread errror"); + return 2; + } + appLauncher->m_createdThread = 1; + return 0; +} \ No newline at end of file diff --git a/src/micetools/micemaster/appLauncher.h b/src/micetools/micemaster/appLauncher.h new file mode 100644 index 0000000..fbd3ce0 --- /dev/null +++ b/src/micetools/micemaster/appLauncher.h @@ -0,0 +1,23 @@ +#include +#include + +#include "lib/libpcp/libpcp.h" + +struct appLauncher_; +typedef struct { + struct appLauncher_* m_appLauncher; + unsigned int m_mode; + char m_path[64]; +} appLauncherAppInfo_t; + +typedef struct appLauncher_ { + pcpa_t m_pcp; + HANDLE m_hThread; + appLauncherAppInfo_t m_appInfo; + bool m_createdThread; + DWORD m_threadAddr; + wchar_t m_username[64]; + wchar_t m_password[64]; +} appLauncher_t; + +int appLauncherCreateThread(appLauncherAppInfo_t* appInfo, appLauncher_t* appLauncher); diff --git a/src/micetools/micemaster/callbacks/callbacks.h b/src/micetools/micemaster/callbacks/callbacks.h new file mode 100644 index 0000000..54ce916 --- /dev/null +++ b/src/micetools/micemaster/callbacks/callbacks.h @@ -0,0 +1,36 @@ +#include "../lib/libpcp/libpcp.h" + +pcpa_callback mxkBinaryCallback; +extern byte BINARY_DATA[4096]; +extern size_t BINARY_DATA_LEN; + +#define MXMASTER "mxmaster." +#define FOREGROUND MXMASTER##"foreground." + +// Misc +#define MXM_RECONNECT_USB MXMASTER##"reconnect.usb.device" +#define MXM_DEVELOP MXMASTER##"develop" +pcpa_callback mxmPcpReconnectUsbDevice; +pcpa_callback mxmPcpCheckDevelopMode; + +// Logs +#define MXM_LOG_AVAILALBE MXMASTER##"logging_available" +#define MXM_OUTPUT_LOG MXMASTER##"output_log" +#define MXM_ERASE_LOG MXMASTER##"erase_log" +pcpa_callback mxmPcpLogAvailable; +pcpa_callback mxmPcpOutputLog; +pcpa_callback mxmPcpEraseLog; + +// Foreground control +#define MXM_FG_CURRENT FOREGROUND##"current" +#define MXM_FG_NEXT FOREGROUND##"next" +#define MXM_FG_ACTIVE FOREGROUND##"active" +#define MXM_FG_FAULT FOREGROUND##"fault" +#define MXM_FG_GETCOUNT FOREGROUND##"getcount" +#define MXM_FG_SETCOUNT FOREGROUND##"setcount" +pcpa_callback mxmPcpCurrentFgprocess; +pcpa_callback mxmPcpNextFgprocess; +pcpa_callback mxmPcpActiveFgprocess; +pcpa_callback mxmPcpFaultFgprocess; +pcpa_callback mxmPcpGetStartCount; +pcpa_callback mxmPcpSetStartCount; diff --git a/src/micetools/micemaster/callbacks/foreground.c b/src/micetools/micemaster/callbacks/foreground.c new file mode 100644 index 0000000..fbbe63b --- /dev/null +++ b/src/micetools/micemaster/callbacks/foreground.c @@ -0,0 +1,306 @@ +#include + +#include "../mxm.h" + +void mxmPcpCurrentFgprocess(pcpa_t* stream, MX_MASTER* mxMaster) { + char current[8]; + sprintf_s(current, sizeof current, "%d", mxMaster->m_current); + pcpaSetSendPacket(stream, MXM_FG_CURRENT, current); + + char* command = pcpaGetCommand(stream, MXM_FG_CURRENT); + if (command == NULL || strcmp(command, "?") != 0) pcpaAddSendPacket(stream, "code", "1"); +} + +void mxmPcpNextFgprocess(pcpa_t* stream, MX_MASTER* mxMaster) { + char next[8]; + char workStr[256]; + + char* command = pcpaGetCommand(stream, pcpaGetKeyword(stream, 0)); + char* path = pcpaGetCommand(stream, "path"); + char* errormsg = pcpaGetCommand(stream, "errormsg"); + char* size = pcpaGetCommand(stream, "size"); + + if (command == NULL) { + amiDebugLog("Error pcpaGetCommand"); + pcpaSetSendPacket(stream, MXM_FG_NEXT, "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + char* endPtr; + long lCommand = strtol(command, &endPtr, 10); + if (endPtr == command) { + sprintf_s(next, sizeof next, "%d", mxMaster->m_next); + pcpaSetSendPacket(stream, MXM_FG_NEXT, next); + + if (strcmp(command, "?") != 0) { + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + if (mxMaster->m_message[0] != '\0') + pcpaAddSendPacket(stream, "errormsg", mxMaster->m_message); + if (size == NULL) return; + + unsigned long lSize = strtoul(size, &endPtr, 10); + if (endPtr == size) { + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + if (mxMaster->m_binaryMessageLen > lSize) { + pcpaAddSendPacket(stream, "code", "5"); + return; + } + if (mxMaster->m_binaryMessageLen == 0) return; + + _itoa_s(mxMaster->m_binaryMessageLen, workStr, sizeof workStr, 10); + pcpaAddSendPacket(stream, "size", workStr); + _itoa_s(mxMaster->m_dataPort, workStr, sizeof workStr, 10); + pcpaAddSendPacket(stream, "port", workStr); + + pcpaSetBeforeBinaryModeCallBackFunc(stream, &mxmBeforeBinaryCallback, mxMaster); + pcpaSetAfterBinaryModeCallBackFunc(stream, &mxmAfterBinaryCallback, mxMaster); + pcpaSetBinaryMode(stream, binary_mode_send); + return; + } + + if (lCommand >= 0 && lCommand <= 5) { + mxMaster->m_next = lCommand; + + if (lCommand == 2) { + if (path == NULL) + mxMaster->m_nextPath[0] = '\0'; + else { + struct _finddata_t next_file; + intptr_t hFile = _findfirst(path, &next_file); + if (hFile == -1) { + amiDebugLog("Error : Process does not exist: %s", path); + mxMaster->m_next = 0; + + pcpaSetSendPacket(stream, MXM_FG_NEXT, "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + sprintf_s(mxMaster->m_nextPath, sizeof mxMaster->m_nextPath, "%s", path); + } + } + + sprintf_s(next, sizeof next, "%d", mxMaster->m_next); + pcpaSetSendPacket(stream, MXM_FG_NEXT, next); + + if (lCommand != 1) return; + + if (errormsg != NULL) { + if (!mxMaster->m_develop) { + if (mxMaster->m_message[0] == '\0') { + sprintf_s(mxMaster->m_message, sizeof mxMaster->m_message, "%s", errormsg); + } else { + amiDebugLog("Error : There is Already System message"); + pcpaAddSendPacket(stream, "code", "4"); + } + } else { + if (mxMaster->m_message[0] != '\0') { + ZeroMemory(mxMaster->m_message, sizeof mxMaster->m_message); + // amiDebugReportEvent(&eventSource, "mxmaster : System message was + // overwritten"); + } + } + } + if (size == NULL) return; + + if (!mxMaster->m_develop) { + if (mxMaster->m_binaryMessageLen != 0) { + amiDebugLog("Error : There is Already System message binnary\n"); + pcpaAddSendPacket(stream, "code", "4"); + return; + } + } else if (mxMaster->m_binaryMessageLen != 0) { + mxMaster->m_binaryMessageLen = 0; + ZeroMemory(mxMaster->m_binaryMessage, sizeof mxMaster->m_binaryMessage); + // amiDebugReportEvent(&eventSource, "mxmaster : System message binary was + // overwritten"); + } + + long recvLength = strtoul(size, &endPtr, 10); + if (endPtr == size) { + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + if (recvLength > sizeof mxMaster->m_binaryMessage) { + pcpaAddSendPacket(stream, "code", "5"); + return; + } + + pcpaAddSendPacket(stream, "size", size); + pcpaAddSendPacket(stream, "port", "40101"); + pcpaSetRecvBinaryBuffer(stream, mxMaster->m_binaryMessage, recvLength); + mxMaster->m_binaryMessageLen = recvLength; + pcpaSetBinaryMode(stream, binary_mode_recv); + return; + } + + pcpaSetSendPacket(stream, MXM_FG_NEXT, "?"); + pcpaAddSendPacket(stream, "code", "1"); +} + +void mxmPcpActiveFgprocess(pcpa_t* stream, MX_MASTER* mxMaster) { + char* command = pcpaGetCommand(stream, MXM_FG_ACTIVE); + if (command == NULL) { + amiDebugLog("Error pcpaGetCommand"); + pcpaSetSendPacket(stream, MXM_FG_ACTIVE, "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + if (strcmp(command, "1") == 0) { + if (mxMaster->m_current != 0) { + amiDebugLog("Error : There is Already Active process"); + pcpaSetSendPacket(stream, MXM_FG_ACTIVE, "1"); + pcpaAddSendPacket(stream, "code", "2"); + return; + } + if (mxMaster->m_next != 0) { + pcpaSetSendPacket(stream, MXM_FG_ACTIVE, "1"); + mxMaster->m_current = mxMaster->m_next; + mxMaster->m_next = 0; + mxMaster->m_field5_0x14 = 1; + mxMaster->m_field4_0x10 = 1; + return; + } + + pcpaSetSendPacket(stream, MXM_FG_ACTIVE, "0"); + pcpaAddSendPacket(stream, "code", "3"); + return; + } else if (strcmp(command, "0") == 0) { + pcpaSetSendPacket(stream, MXM_FG_ACTIVE, "0"); + if (mxMaster->m_develop == 0) { + if (mxMaster->m_next != 0) { + mxMaster->m_current = mxMaster->m_next; + mxMaster->m_next = 0; + mxMaster->m_field4_0x10 = 1; + return; + } + + mxMaster->m_fault = 1; + mxMaster->m_current = 1; + mxMaster->m_field4_0x10 = 1; + return; + } + + mxMaster->m_next = 0; + mxMaster->m_current = 0; + mxMaster->m_field4_0x10 = 1; + return; + } else { + pcpaSetSendPacket(stream, MXM_FG_ACTIVE, mxMaster->m_current == 0 ? "0" : "1"); + if (strcmp(command, "?") != 0) pcpaAddSendPacket(stream, "code", "1"); + } +} + +void mxmPcpFaultFgprocess(pcpa_t* stream, MX_MASTER* mxMaster) { + pcpaSetSendPacket(stream, MXM_FG_FAULT, mxMaster->m_fault ? "1" : "0"); + + char* command = pcpaGetCommand(stream, MXM_FG_FAULT); + if (command == NULL) { + amiDebugLog("Error pcpaGetCommand"); + pcpaSetSendPacket(stream, MXM_FG_FAULT, "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + if (strcmp(command, "?") != 0) pcpaAddSendPacket(stream, "code", "1"); +} + +void mxmPcpGetStartCount(pcpa_t* stream, MX_MASTER* mxMaster) { + char* command = pcpaGetCommand(stream, MXM_FG_GETCOUNT); + if (command == NULL) { + amiDebugLog("Error pcpaGetCommand"); + pcpaSetSendPacket(stream, MXM_FG_GETCOUNT, "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + long lWhich = strtol(command, NULL, 10); + int count = 0; + bool valid = false; + switch (lWhich) { + case 1: + count = mxMaster->m_countSystemBoot; + valid = true; + break; + case 2: + count = mxMaster->m_countGameBoot; + valid = true; + break; + case 3: + count = mxMaster->m_countSystemTest; + valid = true; + break; + case 4: + count = mxMaster->m_countGameTest; + valid = true; + break; + default: + valid = false; + break; + } + + pcpaSetSendPacket(stream, MXM_FG_GETCOUNT, command); + char workBuf[256]; + if (valid) { + sprintf_s(workBuf, sizeof workBuf, "%d", count); + pcpaAddSendPacket(stream, "count", workBuf); + } else { + pcpaAddSendPacket(stream, "code", "1"); + } +} + +void mxmPcpSetStartCount(pcpa_t* stream, MX_MASTER* mxMaster) { + char* command = pcpaGetCommand(stream, MXM_FG_SETCOUNT); + char* sCount = pcpaGetCommand(stream, "count"); + if (command == NULL) { + amiDebugLog("Error pcpaGetCommand"); + pcpaSetSendPacket(stream, MXM_FG_SETCOUNT, "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + if (sCount == NULL) { + pcpaSetSendPacket(stream, MXM_FG_SETCOUNT, "?"); + pcpaAddSendPacket(stream, "count", "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + long lWhich = strtol(command, NULL, 10); + long lCount = strtol(sCount, NULL, 10); + + bool valid = false; + switch (lWhich) { + case 1: + mxMaster->m_countSystemBoot = lCount; + valid = true; + break; + case 2: + mxMaster->m_countGameBoot = lCount; + valid = true; + break; + case 3: + mxMaster->m_countSystemTest = lCount; + valid = true; + break; + case 4: + mxMaster->m_countGameTest = lCount; + valid = true; + break; + default: + valid = false; + break; + } + + pcpaSetSendPacket(stream, MXM_FG_SETCOUNT, command); + if (valid) + pcpaAddSendPacket(stream, "count", sCount); + else + pcpaAddSendPacket(stream, "code", "1"); +} diff --git a/src/micetools/micemaster/callbacks/logs.c b/src/micetools/micemaster/callbacks/logs.c new file mode 100644 index 0000000..e8e1801 --- /dev/null +++ b/src/micetools/micemaster/callbacks/logs.c @@ -0,0 +1,214 @@ +#include +#include + +#include "../../lib/am/amInstall.h" +#include "../mxm.h" +#include "mxmEventLog.h" + +bool mxmEventLogAccessGetMainStorageDeviceNum(int* devNum) { + if (devNum == NULL) { + amiDebugLog("Error : Invalid Argument"); + return false; + } + + char windir[256]; + if (!GetSystemWindowsDirectoryA(windir, sizeof windir)) { + amiDebugLog("Error : GetSystemWindowsDirectoryA error"); + *devNum = -1; + return false; + } + + char windirDos[256]; + sprintf_s(windirDos, sizeof windirDos, "\\\\.\\%c:", windir[0]); + HANDLE hDevice = + CreateFileA(windirDos, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL); + if (hDevice == INVALID_HANDLE_VALUE) { + amiDebugLog("Error : CreateFile error ErrorNum = %d", GetLastError()); + *devNum = -1; + return false; + } + + STORAGE_DEVICE_NUMBER ioctlBuf; + DWORD bytesReturned; + if (!DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &ioctlBuf, + sizeof ioctlBuf, &bytesReturned, NULL)) { + amiDebugLog("Error : DeviceIoControl error ErrorNum = %d", GetLastError()); + CloseHandle(hDevice); + *devNum = -1; + return false; + } + + CloseHandle(hDevice); + *devNum = ioctlBuf.DeviceNumber; + return true; +} + +#define LOG_OFFSET (2047 * 512) + +bool mxmEventLogAccessEraseEventLogData(int deviceNum, unsigned long long address) { + char drivePath[MAX_PATH]; + ZeroMemory(drivePath, sizeof drivePath); + sprintf_s(drivePath, sizeof drivePath, "\\\\.\\PhysicalDrive%d", deviceNum); + + HANDLE hFile = + CreateFileA(drivePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + amiDebugLog("Error : CreateFile error"); + return false; + } + + char logBuffer[512]; + ZeroMemory(logBuffer, sizeof logBuffer); + + LARGE_INTEGER writeAddress; + writeAddress.QuadPart = address + LOG_OFFSET; + if (!SetFilePointerEx(hFile, writeAddress, NULL, 0)) { + CloseHandle(hFile); + amiDebugLog("SetFilePointerEx error"); + return false; + } + + DWORD bytesWritten; + if (!WriteFile(hFile, logBuffer, sizeof logBuffer, &bytesWritten, NULL)) { + CloseHandle(hFile); + amiDebugLog("WriteFile error %d", GetLastError()); + return false; + } + if (bytesWritten != sizeof logBuffer) { + CloseHandle(hFile); + amiDebugLog("Wriete Size Error"); + return false; + } + CloseHandle(hFile); + return true; +} + +bool mxmEventLogAccessLoadEpbr(AM_INSTALL_BOOT_RECORD* bootRecord) { + amtime_t start, now; + + if (amInstallInit() != AM_INSTALL_STATUS_OK) { + amiDebugLog("Error : amInstallInit."); + return false; + } + amiTimerGet(&start); + while (1) { + AM_INSTALL_STATUS err = amInstallGetBr(bootRecord, 0); + if (!((err == AM_INSTALL_STATUS_ERR_REQUEST) || + (err == AM_INSTALL_STATUS_ERR_UPDATE_STATUS) || + (err == AM_INSTALL_STATUS_ERR_GET_SEMAPHORE) || + (err == AM_INSTALL_STATUS_ERR_FORMAT) || (err == AM_INSTALL_STATUS_OK) || + (err == AM_INSTALL_STATUS_BUSY))) { + amiDebugLog("Error : amInstallGetBr error."); + amInstallExit(); + return false; + } + + amiTimerGet(&now); + if (amiTimerDiffSec(&start, &now) > 30) { + amiDebugLog("Error : amInstallGetBr time out error."); + amInstallExit(); + return false; + } + + if (err == AM_INSTALL_STATUS_OK) { + if (amInstallExit() == AM_INSTALL_STATUS_OK) return true; + + amiDebugLog("Error : amInstallExit."); + return false; + } + } +} + +bool mxmEventLogEraseLog() { + AM_INSTALL_BOOT_RECORD br; + ZeroMemory(&br, sizeof br); + int devNum = 0; + if (!mxmEventLogAccessGetMainStorageDeviceNum(&devNum)) return false; + if (!mxmEventLogAccessLoadEpbr(&br)) return false; + if (!mxmEventLogAccessEraseEventLogData(devNum, br.os)) return false; + return true; +} + +void mxmPcpLogAvailable(pcpa_t* stream, MX_MASTER* mxMaster) { + pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, mxMaster->m_loggingAvailable ? "1" : "0"); + + char* command = pcpaGetCommand(stream, MXM_LOG_AVAILALBE); + if (command == NULL) { + amiDebugLog("Error : Command is not set up."); + pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, "?"); + return; + } + bool metadataChanged = false; + if (strcmp(command, "?") != 0) { + if (strcmp(command, "1") == 0) { + mxMaster->m_loggingAvailable = true; + mxmEventLogInit(); + } else if (strcmp(command, "0") == 0) { + mxMaster->m_loggingAvailable = false; + if (MxmEventLog.m_filenamesSet) { + MxmEventLog.m_filenamesSet = false; + MxmEventLog.m_logDriveFound = false; + } + } else { + pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, "?"); + pcpaAddSendPacket(stream, "code", "1"); + return; + } + + command = pcpaGetCommand(stream, "backup_count"); + if (command != NULL) { + mxMaster->m_backupCount = strtol(command, NULL, 10); + metadataChanged = true; + } + command = pcpaGetCommand(stream, "clear_count"); + if (command != NULL) { + mxMaster->m_clearCount = strtol(command, NULL, 10); + metadataChanged = true; + } + command = pcpaGetCommand(stream, "interval"); + if (command != NULL) { + mxMaster->m_interval = strtol(command, NULL, 10); + metadataChanged = true; + } + mxMaster->m_backupMetadataChanged = metadataChanged; + } + + char buffer[256]; + pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, mxMaster->m_loggingAvailable ? "1" : 0); + + _itoa_s(mxMaster->m_backupCount, buffer, sizeof buffer, 10); + pcpaAddSendPacket(stream, "backup_count", buffer); + _itoa_s(mxMaster->m_clearCount, buffer, sizeof buffer, 10); + pcpaAddSendPacket(stream, "clear_count", buffer); + _itoa_s(mxMaster->m_interval, buffer, sizeof buffer, 10); + pcpaAddSendPacket(stream, "interval", buffer); +} + +void mxmPcpOutputLog(pcpa_t* stream, MX_MASTER* mxMaster) { + // Only allowed: 0, 1, 2 + pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "0"); + pcpaAddSendPacket(stream, "path", ""); +} + +void mxmPcpEraseLog(pcpa_t* stream, MX_MASTER* mxMaster) { + char* command = pcpaGetCommand(stream, MXM_ERASE_LOG); + if (command == NULL) { + amiDebugLog("Error : Command error"); + pcpaSetSendPacket(stream, MXM_ERASE_LOG, "1"); + return; + } + + if (strcmp(command, "0") == 0) { + if (!mxmEventLogEraseLog()) { + amiDebugLog("Error : EraseLog error"); + pcpaSetSendPacket(stream, MXM_ERASE_LOG, "1"); + } else { + pcpaSetSendPacket(stream, MXM_ERASE_LOG, "0"); + } + } else { + amiDebugLog("Error : Command error"); + pcpaSetSendPacket(stream, MXM_ERASE_LOG, "1"); + } +} diff --git a/src/micetools/micemaster/callbacks/misc.c b/src/micetools/micemaster/callbacks/misc.c new file mode 100644 index 0000000..3a8f18b --- /dev/null +++ b/src/micetools/micemaster/callbacks/misc.c @@ -0,0 +1,14 @@ +#include "../mxm.h" + +void mxmPcpReconnectUsbDevice(pcpa_t* stream, MX_MASTER* mxMaster) { + // Only allowed: 0, 1, 2 + pcpaSetSendPacket(stream, MXM_RECONNECT_USB, "0"); +} + +void mxmPcpCheckDevelopMode(pcpa_t* stream, MX_MASTER* mxMaster) { + pcpaSetSendPacket(stream, MXM_DEVELOP, mxMaster->m_develop ? "1" : 0); + + char* command = pcpaGetCommand(stream, MXM_DEVELOP); + if (command == NULL || strcmp(command, "?") != 0) + pcpaAddSendPacket(stream, "code", "1"); +} diff --git a/src/micetools/micemaster/config.c b/src/micetools/micemaster/config.c new file mode 100644 index 0000000..ed54706 --- /dev/null +++ b/src/micetools/micemaster/config.c @@ -0,0 +1,123 @@ +#include "config.h" + +#include +#include +#include + +#include "../../../subprojects/inih_dep/ini.h" + +config_t Config = { +#define SECTION(s, comment) .s = { +#define CFG_str(s, n, default, comment) .n = default, +#define CFG_bool(s, n, default, comment) .n = default, +#define CFG_int(s, n, default, comment) .n = default, +#define CFG_hex(s, n, precision, default, comment) .n = 0x##default, +#define CFG_ipv4(s, n, a, b, c, d, comment) .n = (a << 24) | (b << 16) | (c << 8) | d, +#define ENDSECTION(s) \ + } \ + , +#include "config.def" + ._keep_linter_happy = true +}; + +void fprintf_prefix(FILE *file, const char *prefix, const char *text) { + char *copy = (char *)malloc(strlen(text) + 1); + memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1); + + char *next_token; + char *token = strtok_s(copy, "\n", &next_token); + while (token != NULL) { + fprintf(file, "%s%s\n", prefix, token); + token = strtok_s(NULL, "\n", &next_token); + } + + free(copy); +} + +void make_default_config() { + FILE *config_file; + fopen_s(&config_file, CONFIG_PATH, "w"); + if (config_file == NULL) { + puts("Failed to create config file!"); + return; + }; + int first_section = true; + +#define CFG_str(s, n, default, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %s\n", #n, default); + +#define CFG_bool(s, n, default, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %s\n", #n, default ? "true" : "false"); + +#define CFG_int(s, n, default, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %d\n", #n, default); + +#define CFG_hex(s, n, precision, default, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %.*X\n", #n, precision, 0x##default, precision, \ + precision == 1 ? "" : "s"); + +#define CFG_ipv4(s, n, a, b, c, d, comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "%s = %hhu.%hhu.%hhu.%hhu\n", #n, a, b, c, d); + +#define SECTION(s, comment) \ + if (!first_section) fprintf(config_file, "\n"); \ + first_section = false; \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); \ + fprintf(config_file, "[%s]\n", #s); + +#define COMMENT(comment) \ + if (strlen(comment) != 0) fprintf_prefix(config_file, "; ", comment); + +#include "config.def" + + fclose(config_file); +} + +int handler(void *user, const char *section, const char *name, const char *value) { + config_t *cfg = (config_t *)user; + + char *end; + + if (false) + ; +#define CFG_str(s, n, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) cfg->s.n = _strdup(value); +#define CFG_bool(s, n, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) cfg->s.n = \ + strcmp(value, "true") == 0; +#define CFG_int(s, n, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \ + cfg->s.n = strtol(value, &end, 10); \ + if (end == value || *end != '\0' || errno == ERANGE) cfg->s.n = default; \ + } +#define CFG_hex(s, n, precision, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \ + cfg->s.n = strtol(value, &end, 16); \ + if (end == value || *end != '\0' || errno == ERANGE) cfg->s.n = 0x##default; \ + } +#define CFG_ipv4(s, n, a, b, c, d, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \ + cfg->s.n = strtol(value, &end, 16); \ + unsigned char ip_a, ip_b, ip_c, ip_d; \ + if (sscanf_s(value, "%hhu.%hhu.%hhu.%hhu", &ip_a, &ip_b, &ip_c, &ip_d) == 4) \ + cfg->s.n = (ip_a << 24) | (ip_b << 16) | (ip_c << 8) | ip_d; \ + else \ + cfg->s.n = (a << 24) | (b << 16) | (c << 8) | d; \ + } + +#include "config.def" + + return 1; +} + +void load_micemaster_config() { + if (ini_parse(CONFIG_PATH, handler, &Config) < 0) { + make_default_config(); + printf("Can't load '%s', using defaults\n", CONFIG_PATH); + } +} diff --git a/src/micetools/micemaster/config.def b/src/micetools/micemaster/config.def new file mode 100644 index 0000000..e8eb6f6 --- /dev/null +++ b/src/micetools/micemaster/config.def @@ -0,0 +1,47 @@ +#ifndef SECTION +#define SECTION(s, comment) +#endif +#ifndef COMMENT +#define COMMENT(comment) +#endif +#ifndef ENDSECTION +#define ENDSECTION(s) +#endif + +SECTION(dir, "Base directories") +CFG_str(dir, execute, "c:\\System\\Execute\\", "The system bootstrap directory") +CFG_str(dir, system, "s:\\", "The system binary directory") +CFG_str(dir, game, "x:\\", "The game working directory") +ENDSECTION(dir) + +SECTION(binary, "Binary names (command line arguments can be included)") +COMMENT("The following values are relative to [dir.system]") +CFG_str(binary, mxkeychip, "mxkeychip.exe", "") +CFG_str(binary, mxnetwork, "mxnetwork.exe -p 40104", "") +CFG_str(binary, mxstorage, "mxstorage.exe", "") +CFG_str(binary, mxjvs, "mxjvs.exe", "") +CFG_str(binary, mxinstaller, "mxinstaller.exe -cmdport 40102 -binport 40103", "") +CFG_str(binary, mxgcatcher, "mxgcatcher.exe", "") +CFG_str(binary, mxgfetcher, "mxgfetcher.exe", "") +CFG_str(binary, mxgdeliver, "mxgdeliver.exe", "") +COMMENT("--------------------------------------------------") +COMMENT("The following values are relative to [dir.execute]") +CFG_str(binary, segaboot, "mxsegaboot.exe", "") +CFG_str(binary, segaboot_d, "mxsegaboot.exe -d", "") +CFG_str(binary, segaboot_r, "mxsegaboot.exe -r", "") +CFG_str(binary, segaboot_tr, "mxsegaboot.exe -t -r", "") +ENDSECTION(binary) + +SECTION(env, "Environment configuration") +CFG_str(env, username, "appuser", "") +CFG_str(env, password, "segahard", "") +ENDSECTION(env) + +#undef CFG_str +#undef CFG_int +#undef CFG_bool +#undef CFG_hex +#undef CFG_ipv4 +#undef SECTION +#undef COMMENT +#undef ENDSECTION diff --git a/src/micetools/micemaster/config.h b/src/micetools/micemaster/config.h new file mode 100644 index 0000000..4e76223 --- /dev/null +++ b/src/micetools/micemaster/config.h @@ -0,0 +1,18 @@ +#include + +#define CONFIG_PATH "micemaster.ini" + +typedef struct config { +#define SECTION(s, comment) struct { +#define CFG_str(s, n, default, comment) char* n; +#define CFG_bool(s, n, default, comment) bool n; +#define CFG_int(s, n, default, comment) int n; +#define CFG_hex(s, n, precision, default, comment) int n; +#define CFG_ipv4(s, n, a, b, c, d, comment) unsigned int n; +#define ENDSECTION(s) } s; +#include "config.def" + bool _keep_linter_happy; +} config_t; + +void load_micemaster_config(); +extern config_t Config; diff --git a/src/micetools/micemaster/main.c b/src/micetools/micemaster/main.c new file mode 100644 index 0000000..d5d35b2 --- /dev/null +++ b/src/micetools/micemaster/main.c @@ -0,0 +1,521 @@ +#include + +#include "../lib/am/amInstall.h" +#include "mxm.h" + +void mxMasterMakeCopy(char* filename) { + char dest[256]; + char src[256]; + + sprintf_s(src, sizeof src, "%s%s", Config.dir.system, filename); + sprintf_s(dest, sizeof dest, "%s%s", Config.dir.execute, filename); + + if (!PathFileExistsA(src)) { + amiDebugLog("Error copy %s not exist", src); + return; + } + if (!PathFileExistsA(dest)) CopyFileA(src, dest, 0); +} + +bool mxMasterInitPcp(MX_MASTER* mxMaster) { + if (mxMaster->m_pcpaHasInit) return true; + + e_pcpa_t err; + pcpa_t* stream = &mxMaster->m_pcp; + + if ((err = pcpaInitStream(stream)) != e_pcpa_ok) { + amiDebugLog("pcpaInitStream Error. Code:%d", err); + return false; + } + + err = pcpaSetCallbackFuncBuffer( + stream, mxMaster->m_pcpCallbacks, + (sizeof mxMaster->m_pcpCallbacks) / (sizeof mxMaster->m_pcpCallbacks[0])); + if (err != e_pcpa_ok) { + amiDebugLog("pcpaSetCallBackFuncBuffer Error. Code:%d", err); + return false; + } + + // Misc + pcpaSetCallbackFunc(stream, MXM_RECONNECT_USB, mxmPcpReconnectUsbDevice, mxMaster); + pcpaSetCallbackFunc(stream, MXM_DEVELOP, mxmPcpCheckDevelopMode, mxMaster); + // Logs + pcpaSetCallbackFunc(stream, MXM_LOG_AVAILALBE, mxmPcpLogAvailable, mxMaster); + pcpaSetCallbackFunc(stream, MXM_OUTPUT_LOG, mxmPcpOutputLog, mxMaster); + pcpaSetCallbackFunc(stream, MXM_ERASE_LOG, mxmPcpEraseLog, mxMaster); + // Foreground control + pcpaSetCallbackFunc(stream, MXM_FG_CURRENT, mxmPcpCurrentFgprocess, mxMaster); + pcpaSetCallbackFunc(stream, MXM_FG_NEXT, mxmPcpNextFgprocess, mxMaster); + pcpaSetCallbackFunc(stream, MXM_FG_ACTIVE, mxmPcpActiveFgprocess, mxMaster); + pcpaSetCallbackFunc(stream, MXM_FG_FAULT, mxmPcpFaultFgprocess, mxMaster); + pcpaSetCallbackFunc(stream, MXM_FG_GETCOUNT, mxmPcpGetStartCount, mxMaster); + pcpaSetCallbackFunc(stream, MXM_FG_SETCOUNT, mxmPcpSetStartCount, mxMaster); + + mxMaster->m_pcpaHasInit = true; + return true; +} + +bool mxMasterOpen(MX_MASTER* mxMaster) { + e_pcpa_t err = pcpaOpenServerWithBinary(&mxMaster->m_pcp, mxMaster->m_openMode, + mxMaster->m_controlPort, mxMaster->m_dataPort, 60000); + if (err != e_pcpa_ok && err != e_pcpa_to) { + amiDebugLog("pcpaOpenServerWithBinary Error. Code %d", err); + return false; + } + + amiDebugLog("Listening on %s:%d (:%d)", + mxMaster->m_openMode == OPEN_MODE_GLOBAL ? "0.0.0.0" : "127.0.0.1", + mxMaster->m_controlPort, mxMaster->m_dataPort); + return true; +} + +bool mxMasterInit(MX_MASTER* mxMaster) { + mxMaster->m_develop = 0; + mxMaster->m_fault = 0; + mxMaster->m_current = 0; + mxMaster->m_next = 0; + mxMaster->m_field5_0x14 = 0; + mxMaster->m_field4_0x10 = 0; + mxMaster->m_backupMetadataChanged = false; + mxMaster->m_loggingAvailable = false; + mxMaster->m_backupCount = 0; + mxMaster->m_clearCount = 0; + mxMaster->m_interval = 0; + mxMaster->m_countGameBoot = 0; + mxMaster->m_countSystemBoot = 0; + mxMaster->m_countGameTest = 0; + mxMaster->m_countSystemTest = 0; + mxMaster->m_binaryMessageLen = 0; + ZeroMemory(mxMaster->m_binaryMessage, sizeof mxMaster->m_binaryMessage); + + mxMasterMakeCopy("mxsegaboot.exe"); + mxMasterMakeCopy("mxauthdisc.exe"); + mxMasterMakeCopy("mxshellexecute.exe"); + mxMasterMakeCopy("ringmaster_pub.pem"); + mxMasterMakeCopy("develop_regset.txt"); + mxMasterMakeCopy("lockid.txt"); + mxMasterMakeCopy("d3dref9.dll"); + mxMasterMakeCopy("mxsegaboot_2052.dll"); + + return mxMasterInitPcp(mxMaster); +} + +bool mxMasterLoadKeychipInfo(MX_MASTER* mxMaster) { + AM_DONGLE_STATUS err; + + amiDebugLog("Waiting for dongle setup"); + if ((err = amDongleInit()) != AM_DONGLE_STATUS_OK) { + amiDebugLog("Error amDongleInit. Code %d", err); + return false; + } + if ((err = amDongleSetAuthConfig("toolmode")) != AM_DONGLE_STATUS_OK) { + amiDebugLog("Error amDongleSetAuthConfig. Code %d", err); + amDongleExit(); + return false; + } + + amtime_t start, now; + int tDelta; + amiTimerGet(&start); + do { + err = amDongleSetupKeychip(); + amiTimerGet(&now); + tDelta = amiTimerDiffSec(&start, &now); + } while (err == AM_DONGLE_STATUS_PENDING && tDelta < 60); + if (err == AM_DONGLE_STATUS_PENDING) { + amiDebugLog("Error amDongleSetupKeychip timeout"); + amDongleExit(); + return false; + } + if (err != AM_DONGLE_STATUS_OK) { + amiDebugLog("Error amDongleSetupKeychip. Code %d", err); + amDongleExit(); + return false; + } + + if (!amDongleIsAvailable()) { + amiDebugLog("Error amDongleIsAvailable"); + amDongleExit(); + return false; + } + + mxMaster->m_develop = amDongleIsDevelop(); + + amiTimerGet(&start); + do { + err = amDongleGetGameId(mxMaster->m_gameId, AM_DONGLE_BLOCK); + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP) return false; + if (err == AM_DONGLE_STATUS_NG) return false; + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP_DATA) return false; + if (err == AM_DONGLE_STATUS_ERR_INVALID_PARAM) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_INIT) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_SERVER) return false; + + amiTimerGet(&now); + tDelta = amiTimerDiffSec(&start, &now); + if (tDelta > 30) return false; + } while (err != AM_DONGLE_STATUS_OK); + + amiTimerGet(&start); + do { + err = amDongleGetPlatformId(mxMaster->m_platformId, AM_DONGLE_BLOCK); + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP) return false; + if (err == AM_DONGLE_STATUS_NG) return false; + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP_DATA) return false; + if (err == AM_DONGLE_STATUS_ERR_INVALID_PARAM) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_INIT) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_SERVER) return false; + + amiTimerGet(&now); + tDelta = amiTimerDiffSec(&start, &now); + if (tDelta > 30) return false; + } while (err != AM_DONGLE_STATUS_OK); + + amiTimerGet(&start); + do { + err = amDongleGetNetworkAddress((unsigned int*)&(mxMaster->m_networkAddr.S_un.S_addr), + AM_DONGLE_BLOCK); + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP) return false; + if (err == AM_DONGLE_STATUS_NG) return false; + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP_DATA) return false; + if (err == AM_DONGLE_STATUS_ERR_INVALID_PARAM) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_INIT) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_SERVER) return false; + + amiTimerGet(&now); + tDelta = amiTimerDiffSec(&start, &now); + if (tDelta > 30) return false; + } while (err != AM_DONGLE_STATUS_OK); + + amiTimerGet(&start); + do { + err = amDongleBillingGetKeychipId(mxMaster->m_keychipId, AM_DONGLE_BLOCK); + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP) return false; + if (err == AM_DONGLE_STATUS_NG) return false; + if (err == AM_DONGLE_STATUS_ERR_KEYCHIP_DATA) return false; + if (err == AM_DONGLE_STATUS_ERR_INVALID_PARAM) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_INIT) return false; + if (err == AM_DONGLE_STATUS_ERR_NO_SERVER) return false; + + amiTimerGet(&now); + tDelta = amiTimerDiffSec(&start, &now); + if (tDelta > 30) return false; + } while (err != AM_DONGLE_STATUS_OK); + + amDongleExit(); + return true; +} + +void mxMasterSysProcessesStart(MX_MASTER* mxMaster) { + char startup[4][128]; + + strcpy_s(startup[0], sizeof startup[0], Config.binary.mxkeychip); + strcpy_s(startup[1], sizeof startup[1], Config.binary.mxnetwork); + strcpy_s(startup[2], sizeof startup[2], Config.binary.mxstorage); + strcpy_s(startup[3], sizeof startup[3], Config.binary.mxjvs); + + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInformation; + DWORD dwCreationFlags; + BOOL ret; + + for (int i = 0; i < 4; i++) { + dwCreationFlags = CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS; + ZeroMemory(&startupInfo, sizeof startupInfo); + startupInfo.cb = sizeof startupInfo; + startupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.wShowWindow = 0; + + if (strstr(startup[i], "mxjvs.exe") != NULL) { + WIN32_FIND_DATAA findData; + + HANDLE hFindFile = FindFirstFileA(startup[i], &findData); + if (hFindFile == INVALID_HANDLE_VALUE) continue; + FindClose(hFindFile); + if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) continue; + dwCreationFlags = CREATE_NO_WINDOW | HIGH_PRIORITY_CLASS; + } + + ret = CreateProcessA(NULL, startup[i], NULL, NULL, 0, dwCreationFlags, NULL, NULL, + &startupInfo, &processInformation); + if (!ret) amiDebugLog("Close Process %s", startup[i]); + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + } + + Sleep(2000); + + if (mxMasterLoadKeychipInfo(mxMaster)) { + mxMaster->m_current = 1; + mxMaster->m_kcReady = 0; + } else { + mxMaster->m_kcReady = 1; + } + + char mxinstaller[128]; + sprintf_s(mxinstaller, sizeof mxinstaller, mxMaster->m_develop ? "%s -openmode any" : "%s", + Config.binary.mxinstaller); + + startupInfo.cb = sizeof startupInfo; + startupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.wShowWindow = 0; + ret = CreateProcessA(NULL, mxinstaller, NULL, NULL, 0, 0x8000020, NULL, NULL, &startupInfo, + &processInformation); + if (!ret) amiDebugLog("Close Process %s", mxinstaller); + + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + mxMaster->m_current = mxMaster->m_develop ? 5 : 1; +} + +void mxMasterFdcProcessesStart(MX_MASTER* mxMaster) { + char startup[3][128]; + + strcpy_s(startup[0], sizeof startup[0], Config.binary.mxgcatcher); + strcpy_s(startup[1], sizeof startup[1], Config.binary.mxgfetcher); + strcpy_s(startup[2], sizeof startup[2], Config.binary.mxgdeliver); + + if (mxMaster->m_kcReady != 0) { + char* format; + char* networkAddr = inet_ntoa(mxMaster->m_networkAddr); + + if (mxMaster->m_develop == 0) { + format = " %s %s %s %s"; + } else { + format = " -d %s %s %s %s"; + } + + char workBuf[128]; + sprintf_s(workBuf, sizeof workBuf, format, mxMaster->m_platformId, mxMaster->m_gameId, + networkAddr, mxMaster->m_keychipId); + + for (int i = 0; i < 3; i++) { + strcat_s(startup[i], sizeof startup[i], workBuf); + } + } + + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInformation; + DWORD dwCreationFlags; + BOOL ret; + + for (int i = 0; i < 3; i++) { + dwCreationFlags = CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS; + ZeroMemory(&startupInfo, sizeof startupInfo); + startupInfo.cb = sizeof startupInfo; + startupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.wShowWindow = 0; + + ret = CreateProcessA(NULL, startup[i], NULL, NULL, 0, dwCreationFlags, NULL, NULL, + &startupInfo, &processInformation); + if (!ret) amiDebugLog("Close Process %s", startup[i]); + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + } +} + +void mxMasterFirstFgProcessesStart(MX_MASTER* mxMaster) { + appLauncherAppInfo_t appInfo; + + appInfo.m_mode = mxMaster->m_current; + if (appInfo.m_mode == 1) { + appInfo.m_mode = 6; + } else if (appInfo.m_mode != 2 && appInfo.m_mode != 3 && appInfo.m_mode != 4 && + appInfo.m_mode != 5) { + amiDebugLog("Error : Not Process Mode"); + mxMaster->m_current = 1; + appInfo.m_mode = 6; + } + + switch (appInfo.m_mode) { + case 1: + case 5: + case 6: + mxMaster->m_countSystemBoot = mxMaster->m_countSystemBoot + 1; + break; + case 2: + mxMaster->m_countGameBoot = mxMaster->m_countGameBoot + 1; + break; + case 3: + mxMaster->m_countSystemTest = mxMaster->m_countSystemTest + 1; + break; + case 4: + mxMaster->m_countGameTest = mxMaster->m_countGameTest + 1; + break; + } + + appLauncherCreateThread(&appInfo, mxMaster->m_appLauncher); +} + +void mxMasterMainLoop(MX_MASTER* mxMaster) { + mxMaster->m_loggingAvailable = false; + mxMaster->m_backupMetadataChanged = false; + mxMaster->m_backupCount = 1; + mxMaster->m_clearCount = 100; + mxMaster->m_interval = 60; + // if (mxEventLog_0044e5d8.init == 0) { + // mxEventLog_0044e5d8.backup_count = 1; + // mxEventLog_0044e5d8.clear_count = 100; + // mxEventLog_0044e5d8.interval = 60; + // mxEventLog_0044e5d8.field1_0x4 = 0; + // mxEventLog_0044e5d8.field2_0x8 = 0; + // _memset(mxEventLog_0044e5d8.field6_0x18, 0, 0x330); + // mxEventLog_0044e5d8.init = 1; + // uVar5 = extraout_ECX; + // param_2 = extraout_EDX; + // } + e_pcpa_t err; + + do { + err = pcpaOpenServerWithBinary(&mxMaster->m_pcp, mxMaster->m_openMode, + mxMaster->m_controlPort, mxMaster->m_dataPort, 60000); + if (err != e_pcpa_ok) { + if (mxMaster->m_pcpaHasInit) { + pcpaClose(&mxMaster->m_pcp); + mxMaster->m_pcpaHasInit = false; + } + mxMasterInitPcp(mxMaster); + amiDebugLog("Error : Not Open Server. Code %d", err); + } + } while (err != e_pcpa_ok); + mxMaster->m_field23_0x3f4 = 1; + + appLauncherAppInfo_t appInfo[3]; + + while (1) { + err = pcpaServer(&mxMaster->m_pcp, 16); + + if (err != e_pcpa_ok && err != e_pcpa_to && err != e_pcpa_closed) { + if (mxMaster->m_pcpaHasInit) { + pcpaClose(&mxMaster->m_pcp); + mxMaster->m_pcpaHasInit = false; + } + mxMasterInitPcp(mxMaster); + do { + err = + pcpaOpenServerWithBinary(&mxMaster->m_pcp, mxMaster->m_openMode, + mxMaster->m_controlPort, mxMaster->m_dataPort, 60000); + if (err != e_pcpa_ok) { + if (mxMaster->m_pcpaHasInit) { + pcpaClose(&mxMaster->m_pcp); + mxMaster->m_pcpaHasInit = false; + } + mxMasterInitPcp(mxMaster); + amiDebugLog("Error : Not Open Server. Code %d", err); + } + } while (err != e_pcpa_ok); + } + + appLauncher_t* appLauncher; + if (mxMaster->m_field4_0x10 != 0) { + appLauncher = mxMaster->m_appLauncher; + if (appLauncher->m_createdThread) goto code_r0x004056a9; + goto LAB_004056db; + } + + goto LAB_0040574e; + code_r0x004056a9: + if (WaitForSingleObject(appLauncher->m_hThread, 0) != WAIT_TIMEOUT) { + CloseHandle(appLauncher->m_hThread); + appLauncher->m_hThread = NULL; + appLauncher->m_createdThread = false; + LAB_004056db: + if (!mxMaster->m_develop || mxMaster->m_field5_0x14) { + appInfo[0].m_mode = mxMaster->m_current; + mxMaster->m_field5_0x14 = 0; + if (appInfo[0].m_mode == 2) { + sprintf_s(appInfo[0].m_path, sizeof appInfo[0].m_path, "%s", + mxMaster->m_nextPath); + } + switch (appInfo[0].m_mode) { + case 1: + case 5: + case 6: + mxMaster->m_countSystemBoot++; + break; + case 2: + mxMaster->m_countGameBoot++; + break; + case 3: + mxMaster->m_countSystemTest++; + break; + case 4: + mxMaster->m_countGameTest++; + } + appLauncherCreateThread(appInfo, mxMaster->m_appLauncher); + } + mxMaster->m_field4_0x10 = 0; + LAB_0040574e: + if (mxMaster->m_backupMetadataChanged) { + // dVar3 = mxMaster->m_clearCount; + // dVar4 = mxMaster->m_interval; + // if (mxEventLog_0044e5d8.init != 0) { + // mxEventLog_0044e5d8.backup_count = mxMaster->backup_count; + // mxEventLog_0044e5d8.clear_count = dVar3; + // mxEventLog_0044e5d8.interval = dVar4; + // } + mxMaster->m_backupMetadataChanged = false; + } + // if ((mxEventLog_0044e5d8.init != 0) && (mxEventLog_0044e5d8.field2_0x8 != 0)) { + // iVar5 = 0; + // do { + // uVar6 = mxmBackupEventlog(dVar3, dVar4, iVar5); + // dVar4 = (dword)((ulonglong)uVar6 >> 0x20); + // if ((int)uVar6 != 0) break; + // iVar5 += 1; + // dVar3 = extraout_ECX_03; + // } while (iVar5 < 3); + // } + } + } + + // mxMaster->m_serverState = 2; + // while (1) { + // err = mxmPcpServer(mxMaster); + // if (err != e_pcpp_ok) amiDebugLog("Server tick: %d", err); + // } +} + +int main() { + load_micemaster_config(); + + // Enable colour + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode = 0; + if (GetConsoleMode(hConsole, &dwMode)) + SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + + WSADATA wsaData; + int err = WSAStartup(2, &wsaData); + if (err) return -1; + + MX_MASTER* mxMaster = malloc(sizeof *mxMaster); + if (mxMaster == NULL) { + amiDebugLog("Unable to allocate MX_MASTER"); + return -1; + } + ZeroMemory(mxMaster, sizeof *mxMaster); + appLauncher_t appLauncher; + ZeroMemory(&appLauncher, sizeof appLauncher); + pcpaInitStream(&appLauncher.m_pcp); + appLauncher.m_appInfo.m_appLauncher = &appLauncher; + mxMaster->m_appLauncher = &appLauncher; + + if (!mxMasterInit(mxMaster)) { + amiDebugLog("Error mxMasterInit"); + return -1; + } + mxMaster->m_controlPort = 40100; + mxMaster->m_dataPort = 40101; + mxMaster->m_openMode = OPEN_MODE_LOCAL; + + // if (!mxMasterOpen(mxMaster)) { + // amiDebugLog("Error mxMasterOpen"); + // return -1; + // } + + mxMasterSysProcessesStart(mxMaster); + mxMasterFdcProcessesStart(mxMaster); + mxMasterFirstFgProcessesStart(mxMaster); + mxMasterMainLoop(mxMaster); +} diff --git a/src/micetools/micemaster/meson.build b/src/micetools/micemaster/meson.build new file mode 100644 index 0000000..900ef2d --- /dev/null +++ b/src/micetools/micemaster/meson.build @@ -0,0 +1,25 @@ +rc = import('windows').compile_resources('micemaster.rc', depend_files: micekeychip_ico) +executable( + 'micemaster', + win_subsystem: subsystem, + sources: [ + 'config.c', + 'main.c', + 'mxm.c', + 'mxmEventLog.c', + 'appLauncher.c', + 'callbacks/foreground.c', + 'callbacks/logs.c', + 'callbacks/misc.c', + rc, + ], + link_with: [ + inih.get_variable('lib_inih'), + libpcp, + amiDebug, + amDongle, + amInstall, + ], + include_directories: incdir, + dependencies: [], +) diff --git a/src/micetools/micemaster/micemaster.rc b/src/micetools/micemaster/micemaster.rc new file mode 100644 index 0000000..92a9204 --- /dev/null +++ b/src/micetools/micemaster/micemaster.rc @@ -0,0 +1,3 @@ +#include + +0 ICON "../../assets/micekeychip.ico" diff --git a/src/micetools/micemaster/mxm.c b/src/micetools/micemaster/mxm.c new file mode 100644 index 0000000..b2221c4 --- /dev/null +++ b/src/micetools/micemaster/mxm.c @@ -0,0 +1,42 @@ +#include "mxm.h" + +#define TICK_MS 16 + +void mxmBeforeBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster) { + pcpaSetSendBinaryBuffer(stream, mxMaster->m_binaryMessage, mxMaster->m_binaryMessageLen); +} +void mxmAfterBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster) { + mxMaster->m_binaryMessage[0] = '\0'; + mxMaster->m_binaryMessageLen = 0; +} + +int mxmInit(MX_MASTER* mxMaster) { + +} + +e_pcpa_t mxmPcpStreamInit(MX_MASTER* mxMaster) { return 0; } + +e_pcpa_t mxmPcpServer(MX_MASTER* mxMaster) { + int err; + if (mxMaster->m_serverState == 1) { + err = mxmPcpStreamInit(mxMaster); + if (err == 0) { + mxMaster->m_serverState = 2; + return err; + } + } else { + if (mxMaster->m_serverState != 2) { + return (mxMaster->m_serverState == 0) ? e_pcpa_cannot_open : e_pcpa_not_open; + } + err = pcpaServer(&mxMaster->m_pcp, TICK_MS); + if (err == e_pcpa_to || err == e_pcpa_closed) err = e_pcpa_ok; + + if (err) { + amiDebugLog("Error pcpaServer. Code %d", err); + pcpaClose(&mxMaster->m_pcp); + mxMaster->m_serverState = 1; + } + } + + return err; +} diff --git a/src/micetools/micemaster/mxm.h b/src/micetools/micemaster/mxm.h new file mode 100644 index 0000000..cb1e20f --- /dev/null +++ b/src/micetools/micemaster/mxm.h @@ -0,0 +1,74 @@ +#include + +#include "appLauncher.h" +#include "callbacks/callbacks.h" +#include "config.h" +#include "lib/am/amDongle.h" +#include "lib/libpcp/libpcp.h" + +typedef enum { + mxMasterStartType_0 = 0, + mxMasterStartType_1 = 1, // Stores system message + mxMasterStartType_2 = 2, // Stores "path" into m_nextPath + mxMasterStartType_3 = 3, + mxMasterStartType_4 = 4, + mxMasterStartType_5 = 5, + + // Segaboot: 1, 5, 6 + // Gameboot: 2 + // Systemtest: 3 + +} mxMasterStartType_t; + +typedef struct MX_MASTER_ { + ushort m_controlPort; + ushort m_dataPort; + int m_openMode; + + // TODO: What are these? + unsigned int m_field4_0x10; + unsigned int m_field5_0x14; + bool m_backupMetadataChanged; + + unsigned int m_current; + unsigned int m_next; + bool m_develop; + bool m_fault; + + bool m_loggingAvailable; + bool m_backupCount; + bool m_clearCount; + bool m_interval; + char m_nextPath[128]; + char m_gameId[8]; + char m_platformId[8]; + char m_message[256]; + char m_keychipId[32]; + IN_ADDR m_networkAddr; + int m_countSystemBoot; + int m_countGameBoot; + int m_countSystemTest; + int m_countGameTest; + unsigned char m_binaryMessage[512]; + size_t m_binaryMessageLen; + + // TODO: What is this? + unsigned int m_field23_0x3f4; + + int m_serverState; // TODO: Remove once unneeded + + unsigned int m_kcReady; + bool m_pcpaHasInit; + appLauncher_t* m_appLauncher; + pcpa_cb_table_t m_pcpCallbacks[11]; + pcpa_t m_pcp; + +} MX_MASTER; + +void mxmBeforeBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster); +void mxmAfterBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster); + +// void mxmBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster); +int mxmInit(MX_MASTER* mxMaster); +e_pcpa_t mxmPcpStreamInit(MX_MASTER* mxMaster); +e_pcpa_t mxmPcpServer(MX_MASTER* mxMaster); diff --git a/src/micetools/micemaster/mxmEventLog.c b/src/micetools/micemaster/mxmEventLog.c new file mode 100644 index 0000000..034af1e --- /dev/null +++ b/src/micetools/micemaster/mxmEventLog.c @@ -0,0 +1,49 @@ +#include "mxmEventLog.h" + +#include + +mxmEventLog_t MxmEventLog; + +#define LOG_DRIVE "L:\\" +#define LOG_VOLUME "\\\\.\\L:\\" +#define LOG_DRIVE_NAME "SEGA_AM_LOG" + +bool mxmEventLogGetLogDrive(char *logPath) { + char volumeName[264]; + if (GetVolumeInformationA(LOG_VOLUME, volumeName, 264, NULL, NULL, NULL, NULL, 0)) { + if (strcmp(volumeName, LOG_DRIVE_NAME) == 0) { + strncpy_s(logPath, MAX_PATH, LOG_DRIVE, _TRUNCATE); + return true; + } + } + return false; +} + +int mxmEventLogSetDestination(char *name, unsigned int which) { + char *type_names[3]; + SYSTEMTIME now; + + type_names[0] = "application"; + type_names[1] = "security"; + type_names[2] = "system"; + + if (name == NULL || which >= 3) return -1; + + GetLocalTime(&now); + _snprintf_s(MxmEventLog.m_desinations[which].m_filename, MAX_PATH, _TRUNCATE, + "%s%s%04d%02d%02d%02d%02d%02d.evt", name, type_names[which], now.wYear, now.wMonth, + now.wDay, now.wHour, now.wMinute, now.wSecond); + return 0; +} + +void mxmEventLogInit(void) { + if (MxmEventLog.m_filenamesSet) return; + + char name[268]; + name[0] = '\0'; + MxmEventLog.m_logDriveFound = mxmEventLogGetLogDrive(name); + if (MxmEventLog.m_logDriveFound) { + for (int i = 0; i < 3; i++) mxmEventLogSetDestination(name, i); + MxmEventLog.m_filenamesSet = true; + } +} diff --git a/src/micetools/micemaster/mxmEventLog.h b/src/micetools/micemaster/mxmEventLog.h new file mode 100644 index 0000000..6f347c9 --- /dev/null +++ b/src/micetools/micemaster/mxmEventLog.h @@ -0,0 +1,25 @@ +#include +#include + +typedef struct { + unsigned int Rsv00; + unsigned int Rsv04; + unsigned int m_numRecords; + char m_filename[MAX_PATH]; +} mxmEventLogDesination_t; + +typedef struct { + bool m_init; + bool m_logDriveFound; + bool m_filenamesSet; + unsigned int m_backupCount; + unsigned int m_clearCount; + unsigned int m_interval; + mxmEventLogDesination_t m_desinations[3]; +} mxmEventLog_t; + +extern mxmEventLog_t MxmEventLog; + +bool mxmEventLogGetLogDrive(char *logPath); +int mxmEventLogSetDestination(char *name, unsigned int which); +void mxmEventLogInit(void); diff --git a/src/micetools/micepatch/meson.build b/src/micetools/micepatch/meson.build index 09dc2cb..91c68d2 100644 --- a/src/micetools/micepatch/meson.build +++ b/src/micetools/micepatch/meson.build @@ -1,16 +1,16 @@ rc = import('windows').compile_resources('micepatch.rc', depend_files: micepatch_ico) -micepatch = executable( - 'micepatch', - win_subsystem: subsystem, - sources: [ - 'main.c', - rc, - ], - link_with: [ - mice_lib, - ], - link_args: [ - '/MANIFEST:EMBED', - '/MANIFESTUAC:level="asInvoker" uiAccess="false"', - ] -) +# micepatch = executable( +# 'micepatch', +# win_subsystem: subsystem, +# sources: [ +# 'main.c', +# rc, +# ], +# link_with: [ +# mice_lib, +# ], +# link_args: [ +# '/MANIFEST:EMBED', +# '/MANIFESTUAC:level="asInvoker" uiAccess="false"', +# ] +# ) diff --git a/src/micetools/util/meson.build b/src/micetools/util/meson.build index d3cb510..8c6fa6f 100644 --- a/src/micetools/util/meson.build +++ b/src/micetools/util/meson.build @@ -2,11 +2,25 @@ executable( 'micedump', win_subsystem: subsystem, sources: [ - 'micedump.c', + 'micedump/main.c', + 'micedump/dmi.c', + 'micedump/eeprom.c', + 'micedump/kc_mxkeychip.c', + # 'micedump/kc_n2.c', + # 'micedump/kc_pic.c', + 'micedump/platform.c', + 'micedump/sram.c', + # 'micedump/superio.c', ], link_with: [ - amlib, mxklib, + amiTimer, + amOemstring, + amEeprom, + amSram, + amPlatform, + amDongle, + amSerialId, ], ) @@ -17,7 +31,8 @@ executable( 'micetinker.c', ], link_with: [ - amlib + amiTimer, + amEeprom, ], ) @@ -28,11 +43,3 @@ executable( 'micemonitor.c', ], ) - -executable( - 'kcproxy', - win_subsystem: subsystem, - sources: [ - 'proxy.c', - ], -) diff --git a/src/micetools/util/micedump.c b/src/micetools/util/micedump.c index 0d9afd6..8f05007 100644 --- a/src/micetools/util/micedump.c +++ b/src/micetools/util/micedump.c @@ -5,9 +5,8 @@ #include #include #include -#pragma comment(lib, "Setupapi.lib") -#include "../lib/am/amEeprom.h" +#include "../lib/amEeprom/amEeprom.h" #include "../lib/mxk/mxk.h" #define OpenDriver(x) \ @@ -21,111 +20,7 @@ puts(RULE); \ puts(""); -typedef struct { - uint64_t physAddr; - DWORD dType; - DWORD size; -} columba_request_t; -void scan_for_dmi(HANDLE columba, DWORD *stable_addr) { - DWORD bytesOut; - // short *stable_len; - columba_request_t request; - unsigned char readBuf[0x8010]; - - uint64_t search_addr = 0xf0000; - while (1) { - request.physAddr = search_addr; - request.dType = 1; - request.size = sizeof readBuf; - - BOOL succ = DeviceIoControl(columba, IOCTL_COLUMBA_READ, &request, sizeof request, &readBuf, - sizeof readBuf, &bytesOut, NULL); - if (succ && bytesOut == sizeof readBuf) { - for (unsigned int offset = 0; offset < 0x8008; offset++) { - if (readBuf[offset] == '_' && readBuf[offset + 1] == 'D' && - readBuf[offset + 2] == 'M' && readBuf[offset + 3] == 'I' && - readBuf[offset + 4] == '_') { - *stable_addr = *(DWORD *)&readBuf[offset + 8]; - - return; - } - } - } - - search_addr += 0x7ff0; - if (search_addr > 0xfffdf) return; - } -} - -BOOL dump_columba() { - SECTION_HEAD("columba"); - - HANDLE columba = OpenDriver("columba"); - if (columba == INVALID_HANDLE_VALUE) return FALSE; - - DWORD stable_addr = 0; - scan_for_dmi(columba, &stable_addr); - if (stable_addr == 0) { - CloseHandle(columba); - return FALSE; - } - - columba_request_t request; - unsigned char readBuf[0x10000]; - - printf("Found DMI at: %d\n", stable_addr); - - request.physAddr = stable_addr; - request.dType = 1; - if (stable_addr + 0x10000 < 0x100001) { - request.size = 0x10000; - } else { - request.size = 0x100000 - stable_addr; - } - DWORD bytesReturned; - - BOOL s = DeviceIoControl(columba, IOCTL_COLUMBA_READ, &request, sizeof request, readBuf, - sizeof readBuf, &bytesReturned, NULL); - if (!s || bytesReturned != sizeof readBuf) { - CloseHandle(columba); - return FALSE; - } - - puts("DMI read sucessful."); - FILE *dmi; - fopen_s(&dmi, "dmi.bin", "wb"); - fwrite(readBuf, 1, sizeof readBuf, dmi); - fclose(dmi); - puts(" -> Written to dmi.bin"); - - CloseHandle(columba); - return TRUE; -} - -BOOL dump_eeprom() { - SECTION_HEAD("mxSMBus"); - - HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0); - if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE; - - DWORD _dummy; - DWORD version; - DeviceIoControl(mxsmbus, IOCTL_MXSMBUS_GET_VERSION, NULL, 0, &version, sizeof version, &_dummy, - NULL); - printf("mxSMBus version: %08x\n", version); - - BYTE data[0x20]; - for (WORD reg = 0; reg < 256; reg++) { - if (!amEepromReadBlock(mxsmbus, reg & 0xFF, 0x20, data)) continue; - printf("%02x: ", reg); - for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]); - puts(""); - } - - CloseHandle(mxsmbus); - return TRUE; -} unsigned char sram_buf[1024 * 2048]; BOOL dump_sram() { diff --git a/src/micetools/util/micedump/dmi.c b/src/micetools/util/micedump/dmi.c new file mode 100644 index 0000000..7ac7ce4 --- /dev/null +++ b/src/micetools/util/micedump/dmi.c @@ -0,0 +1,45 @@ +#include +#include + +#include "../lib/am/amOemstring.h" + +BOOL miceDumpDMI() { + amOemstringDebugLevel = 1; + + fprintf(stderr, "Dumping DMI using %s\n", amOemstringVersion); + + char oemstring[32]; + int err = 0; + + err = amOemstringGetManufacturer(oemstring); + if (err) { + fprintf(stderr, "amOemstringGetManufacturer error: %d\n", err); + return FALSE; + } + printf("Manufacturer: %s\n", oemstring); + + puts("OEM Strings:"); + for (int which = 0; which < 5; which++) { + err = amOemstringGetOemstring(oemstring, which); + if (err) { + fprintf(stderr, "amOemstringGetOemstring error: %d\n", err); + return FALSE; + } + printf(" %d: %s\n", which + 1, oemstring); + } + err = amOemstringGetSBiosVer(oemstring); + if (err) { + fprintf(stderr, "amOemstringGetSBiosVer error: %d\n", err); + return FALSE; + } + printf("BIOS Version: %s\n", oemstring); + + err = amOemstringGetSBiosReleaseDate(oemstring); + if (err) { + fprintf(stderr, "amOemstringGetSBiosReleaseDate error: %d\n", err); + return FALSE; + } + printf("BIOS Date: %s\n", oemstring); + + return TRUE; +} diff --git a/src/micetools/util/micedump/eeprom.c b/src/micetools/util/micedump/eeprom.c new file mode 100644 index 0000000..05f6d7d --- /dev/null +++ b/src/micetools/util/micedump/eeprom.c @@ -0,0 +1,34 @@ +#include +#include + +#include "../lib/am/amEeprom.h" + +#define EEPROM_SIZE 0x2000 + +BOOL miceDumpEEPROM() { + amEepromDebugLevel = 1; + + fprintf(stderr, "Dumping EEPROM using %s\n", amEepromVersion); + + if (amEepromInit(NULL) != AM_EEPROM_STATUS_OK) { + puts("amEepromInit failed"); + return FALSE; + } + + BYTE data[0x20]; + for (WORD addr = 0; addr < EEPROM_SIZE; addr += sizeof data) { + if (amEepromRead(addr, data, sizeof data) != AM_EEPROM_STATUS_OK) continue; + printf("%04x: ", addr); + for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]); + printf(" "); + for (int i = 0; i < 0x20; i++) { + if (' ' <= data[i] && data[i] <= '~') printf("%c", data[i]); + else printf("."); + } + + puts(""); + } + + amEepromExit(); + return TRUE; +} diff --git a/src/micetools/util/micedump/kc_mxkeychip.c b/src/micetools/util/micedump/kc_mxkeychip.c new file mode 100644 index 0000000..6e53719 --- /dev/null +++ b/src/micetools/util/micedump/kc_mxkeychip.c @@ -0,0 +1,98 @@ +#include +#include + +#include "../lib/am/amDongle.h" +#include "../lib/am/amSerialId.h" + +struct { + char keychipId[17]; + char keychipSid[12]; + char gameId[5]; + unsigned char systemflag; + unsigned char modelType; + unsigned char region; + char networkAddress[16]; +} amlibDongle; + +AM_DONGLE_STATUS amlib_init_dongle(void) { + AM_DONGLE_STATUS err; + if ((err = amDongleInit()) != AM_DONGLE_STATUS_OK) return err; + + do { + err = amDongleSetupKeychip(); + } while (err == AM_DONGLE_STATUS_PENDING); + if (err != AM_DONGLE_STATUS_OK) return err; + + if ((err = amDongleSetupKeychip()) != AM_DONGLE_STATUS_OK) return err; + if (!amDongleIsAvailable()) return AM_DONGLE_STATUS_NG; + if ((err = amDongleSetAuthConfig("toolmode")) != AM_DONGLE_STATUS_OK) return err; + if ((err = amDongleBillingGetKeychipId(amlibDongle.keychipId, AM_DONGLE_BLOCK)) != + AM_DONGLE_STATUS_OK) + return err; + if (!amSerialIdConvert(amlibDongle.keychipId, amlibDongle.keychipSid)) + return AM_DONGLE_STATUS_NG; + if ((err = amDongleGetGameId(amlibDongle.gameId, AM_DONGLE_BLOCK)) != AM_DONGLE_STATUS_OK) + return err; + if ((err = amDongleGetSystemFlag(&amlibDongle.systemflag, AM_DONGLE_BLOCK)) != + AM_DONGLE_STATUS_OK) + return err; + if ((err = amDongleGetModelType(&amlibDongle.modelType, AM_DONGLE_BLOCK)) != + AM_DONGLE_STATUS_OK) + return err; + if ((err = amDongleGetRegion(&amlibDongle.region, AM_DONGLE_BLOCK)) != AM_DONGLE_STATUS_OK) + return err; + + unsigned int iNetworkAddress; + if ((err = amDongleGetNetworkAddress(&iNetworkAddress, AM_DONGLE_BLOCK)) != AM_DONGLE_STATUS_OK) + return err; + + sprintf(amlibDongle.networkAddress, "%d.%d.%d.%d", iNetworkAddress & 0xff, + (iNetworkAddress >> 8) & 0xff, (iNetworkAddress >> 16) & 0xff, + (iNetworkAddress >> 24) & 0xff); + + return AM_DONGLE_STATUS_OK; +} + +void miceDumpKCMxkeychip(void) { + amDongleDebugLevel = 1; + + fprintf(stderr, "Dumping dongle using %s\n", amDongleVersion); + + WSADATA wsaData; + if (WSAStartup(2, &wsaData)) { + puts("Failed to WSAStartup"); + return; + } + + AM_DONGLE_STATUS err; + err = amlib_init_dongle(); + if (err != AM_DONGLE_STATUS_OK) { + printf("Failed to init dongle:%d\n", err); + amDongleExit(); + return; + } + + printf("Keychip ID: %s\n", amlibDongle.keychipId); + printf(" SID: %s\n", amlibDongle.keychipSid); + printf(" Game ID: %s\n", amlibDongle.gameId); + printf("Systemflag: %02x\n", amlibDongle.systemflag); + printf("Model type: %02x\n", amlibDongle.modelType); + printf(" Region: %02x\n", amlibDongle.region); + printf(" Net addr: %s\n", amlibDongle.networkAddress); + + unsigned short version; + amDongleGetPicVersion(&version, AM_DONGLE_BLOCK); + printf(" Version: %04x\n", version); + amDongleGetVersion(&version, AM_DONGLE_BLOCK); + printf("N2 Version: %04x\n", version); + + unsigned int billingData; + amDongleBillingGetPlayCount(&billingData, AM_DONGLE_BLOCK); + printf("Play Count: %08x\n", billingData); + amDongleBillingGetPlayLimit(&billingData, AM_DONGLE_BLOCK); + printf("Play Limit: %08x\n", billingData); + amDongleBillingGetNearfull(&billingData, AM_DONGLE_BLOCK); + printf(" Nearfull: %08x\n", billingData); + + amDongleExit(); +} diff --git a/src/micetools/util/micedump/kc_n2.c b/src/micetools/util/micedump/kc_n2.c new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/util/micedump/kc_pic.c b/src/micetools/util/micedump/kc_pic.c new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/util/micedump/main.c b/src/micetools/util/micedump/main.c new file mode 100644 index 0000000..72070bd --- /dev/null +++ b/src/micetools/util/micedump/main.c @@ -0,0 +1,23 @@ +#include +#include + +#include "micedump.h" + +int main(int argc, char** argv) { + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "dmi") == 0) + miceDumpDMI(); + else if (strcmp(argv[i], "eeprom") == 0) + miceDumpEEPROM(); + else if (strcmp(argv[i], "platform") == 0) + miceDumpPlatform(); + else if (strcmp(argv[i], "sram") == 0) + miceDumpSRAM(); + else if (strcmp(argv[i], "dongle") == 0) + miceDumpKCMxkeychip(); + else + printf("Unknown dump type: %s\n", argv[i]); + } + + return 0; +} diff --git a/src/micetools/util/micedump/micedump.h b/src/micetools/util/micedump/micedump.h new file mode 100644 index 0000000..dcd5a3d --- /dev/null +++ b/src/micetools/util/micedump/micedump.h @@ -0,0 +1,8 @@ +void miceDumpDMI(void); +void miceDumpEEPROM(void); +void miceDumpKCMxkeychip(void); +void miceDumpKCN2(void); +void miceDumpKCPIC(void); +void miceDumpPlatform(void); +void miceDumpSRAM(void); +void miceDumpSuperIO(void); diff --git a/src/micetools/util/micedump/platform.c b/src/micetools/util/micedump/platform.c new file mode 100644 index 0000000..b2dc9d8 --- /dev/null +++ b/src/micetools/util/micedump/platform.c @@ -0,0 +1,16 @@ +#include +#include + +#include "../lib/am/amPlatform.h" + +void miceDumpPlatform(void) { + fprintf(stderr, "Dumping platform information using %s\n", amPlatformVersion); + + AM_PLATFORM_BOARD_TYPE boardType; + amPlatformGetBoardType(&boardType); + AM_PLATFORM_PLATFORM_ID platformId; + amPlatformGetPlatformId(&platformId); + + printf("Board type: %d\n", boardType); + printf("Platform ID: %s\n", platformId.strPlatformId); +} \ No newline at end of file diff --git a/src/micetools/util/micedump/sram.c b/src/micetools/util/micedump/sram.c new file mode 100644 index 0000000..3d149cb --- /dev/null +++ b/src/micetools/util/micedump/sram.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#include "../lib/am/amSram.h" + +#define DUMP_FILE "micedump-sram.bin" + +BOOL miceDumpSRAM() { + amSramDebugLevel = 1; + + fprintf(stderr, "Dumping SRAM using %s\n", amSramVersion); + + AM_SRAM_STATUS err = amSramInit(); + if (err != AM_SRAM_STATUS_OK) { + printf("amSramInit failed: %d\n", err); + return FALSE; + } + + DISK_GEOMETRY geom; + DWORD bytesReturned; + BOOL s = DeviceIoControl(amSram.m_handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geom, + sizeof geom, &bytesReturned, NULL); + if (!s) { + puts("IOCTL_DISK_GET_DRIVE_GEOMETRY failed"); + amSramExit(); + return FALSE; + } + puts("SRAM geometry:"); + printf(":: Cylinders: %lld\n", geom.Cylinders.QuadPart); + printf(":: MediaType: %d\n", geom.MediaType); + printf(":: TracksPerCylinder: %d\n", geom.TracksPerCylinder); + printf(":: SectorsPerTrack: %d\n", geom.SectorsPerTrack); + printf(":: BytesPerSector: %d\n", geom.BytesPerSector); + + puts("amSram computed values:"); + printf(":: amSram.m_size: %lld\n", amSram.m_size.QuadPart); + printf(":: amSram.m_sectorSize: %d\n", amSram.m_sectorSize); + + DWORD toRead = amSram.m_size.QuadPart & 0xffffffff; + + LPBYTE dump_buffer = malloc(toRead); + if (!dump_buffer) { + printf("Failed to malloc %ld bytes for buffer!\n", toRead); + return FALSE; + } + amSramRead(0, dump_buffer, toRead); + + FILE *sramFile; + fopen_s(&sramFile, DUMP_FILE, "wb"); + fwrite(dump_buffer, 1, toRead, sramFile); + fclose(sramFile); + printf(" -> Written to %s\n", DUMP_FILE); + + amSramExit(); + + return TRUE; +} diff --git a/src/micetools/util/micedump/superio.c b/src/micetools/util/micedump/superio.c new file mode 100644 index 0000000..e69de29 diff --git a/src/micetools/util/micetinker.c b/src/micetools/util/micetinker.c index 2fbb5f5..5a14329 100644 --- a/src/micetools/util/micetinker.c +++ b/src/micetools/util/micetinker.c @@ -5,30 +5,26 @@ #include #include #include -#pragma comment(lib, "Setupapi.lib") #include "../lib/am/amEeprom.h" BYTE get_region() { - HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0); - if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE; - + amEepromInit(NULL); BYTE data[0x20]; - amEepromReadBlock(mxsmbus, 0, sizeof data, data); - - CloseHandle(mxsmbus); + amEepromRead(0, data, sizeof data); + amEepromExit(); return data[12]; } BOOL change_region(BYTE region) { - HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0); - if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE; + if (amEepromInit(NULL) != AM_EEPROM_STATUS_OK) return FALSE; BYTE data[0x20]; - if (!amEepromReadBlock(mxsmbus, 0, sizeof data, data)) { + if (amEepromRead(0, data, sizeof data) != AM_EEPROM_STATUS_OK) { printf("Failed to read block 0"); - goto fail; + amEepromExit(); + return FALSE; } puts("Original content:"); @@ -36,20 +32,18 @@ BOOL change_region(BYTE region) { puts(""); data[12] = region; - amEepromRepairChecksum(data); + amCrc32RCreateTable(); + ((DWORD*)data)[0] = amCrc32RGet(sizeof data - 4, data + 4, 0); - amEepromWriteBlock(mxsmbus, 0, sizeof data, data); - amEepromReadBlock(mxsmbus, 0, sizeof data, data); + amEepromWrite(0, data, sizeof data); + amEepromRead(0, data, sizeof data); puts("Tinkered content:"); for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]); puts(""); - CloseHandle(mxsmbus); + amEepromExit(); return TRUE; -fail: - CloseHandle(mxsmbus); - return FALSE; } int main(int argc, char** argv) { diff --git a/src/micetools/util/proxy.c b/src/micetools/util/proxy.c deleted file mode 100644 index ed77bd3..0000000 --- a/src/micetools/util/proxy.c +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#pragma comment(lib, "Ws2_32.lib") -#pragma comment(lib, "Psapi.lib") - -#define UPSTREAM_HOST "127.0.0.1" -#define UPSTREAM_PORT 6969 - -FILE *log_file; -SOCKET upstream; - -void client_worker(SOCKET sock) { - char recv_buf[512]; - while (1) { - // Prompt - int nout = recv(upstream, recv_buf, sizeof recv_buf, 0); - send(sock, recv_buf, nout, 0); - - int nin = recv(sock, recv_buf, sizeof recv_buf, 0); - if (nin == -1) break; - - fprintf(log_file, "sys->kc %d:", nin); - for (int i = 0; i < nin; i++) { - fprintf(log_file, " %02x", recv_buf[i]); - } - fprintf(log_file, ": %.*s", nin, recv_buf); - fprintf(log_file, "\n"); - - send(upstream, recv_buf, nin, 0); - // Response - nout = recv(upstream, recv_buf, sizeof recv_buf, 0); - - fprintf(log_file, "kc->sys %d:", nout); - for (int i = 0; i < nout; i++) { - fprintf(log_file, " %02x", recv_buf[i]); - } - fprintf(log_file, ": %.*s", nout, recv_buf); - fprintf(log_file, "\n"); - - send(sock, recv_buf, nout, 0); - } -} - -void killProcessByName(const char *exeName) { - DWORD procList[0xffff]; - DWORD procCount; - char processName[MAX_PATH]; - - if (!EnumProcesses(procList, sizeof(procList), &procCount)) return; - - procCount = procCount / sizeof(DWORD); - - for (DWORD procIdx = 0; procIdx < procCount; procIdx++) { - HANDLE procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procList[procIdx]); - GetProcessImageFileName(procHandle, processName, sizeof(processName)); - if (strstr(processName, exeName)) TerminateProcess(procHandle, 0); - CloseHandle(procHandle); - } -} -int main() { - STARTUPINFO si = { sizeof si }; - PROCESS_INFORMATION pi; - killProcessByName("mxkeychip-port-patched.exe"); - if (!CreateProcessA(NULL, "S:/mxkeychip-port-patched.exe", NULL, NULL, FALSE, 0, NULL, NULL, - &si, &pi)) { - printf("Failed to spawn mxkc: %03x\n", GetLastError()); - } - struct sockaddr_in name; - - WSADATA wsaData; - WSAStartup(MAKEWORD(2, 2), &wsaData); - - name.sin_family = AF_INET; - name.sin_addr.s_addr = inet_addr(UPSTREAM_HOST); - name.sin_port = htons(UPSTREAM_PORT); - while (1) { - SOCKET upstream = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (connect(upstream, &name, sizeof name) < 0) { - closesocket(upstream); - printf("Still waiting %d\n", GetLastError()); - continue; - } - puts("Connected!"); - closesocket(upstream); - break; - } - - SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - name.sin_family = AF_INET; - name.sin_addr.s_addr = inet_addr("127.0.0.1"); - name.sin_port = htons(40106); - bind(s, &name, sizeof name); - - listen(s, 1); - - while (1) { - if (fopen_s(&log_file, "E:\\kc.log", "a")) - if (fopen_s(&log_file, "D:\\kc.log", "a")) - if (fopen_s(&log_file, "kc.log", "a")) printf("Failed to open log %d\n", errno); - - struct sockaddr_in addr; - int addr_len; - SOCKET sock = accept(s, &addr, &addr_len); - fprintf(log_file, "Connection open %s:%d\n", inet_ntoa(addr.sin_addr), addr.sin_port); - printf("Connection open %s:%d\n", inet_ntoa(addr.sin_addr), addr.sin_port); - - if (addr.sin_addr.s_addr == inet_addr("127.0.0.1")) { - upstream = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - name.sin_family = AF_INET; - name.sin_addr.s_addr = inet_addr(UPSTREAM_HOST); - name.sin_port = htons(UPSTREAM_PORT); - if (connect(upstream, &name, sizeof name) < 0) - puts("mxkc connect failed!"); - else - client_worker(sock); - - closesocket(upstream); - } - - fprintf(log_file, "Connection close %s:%d\n", inet_ntoa(addr.sin_addr), addr.sin_port); - printf("Connection close %s:%d\n", inet_ntoa(addr.sin_addr), addr.sin_port); - - closesocket(sock); - fclose(log_file); - } - - closesocket(s); - WSACleanup(); - - HANDLE mxkeychip = OpenProcess(PROCESS_TERMINATE, FALSE, pi.dwProcessId); - TerminateProcess(mxkeychip, 1); - CloseHandle(mxkeychip); - return 0; -} diff --git a/src/patches/ALLNetProc.patch b/src/patches/ALLNetProc.patch new file mode 100644 index 0000000..97a72f5 --- /dev/null +++ b/src/patches/ALLNetProc.patch @@ -0,0 +1,13 @@ +*004f48b0: 00000000 > 01000000 # LOG_EN_DONGLE +*004f989c: 00000000 > 01000000 # LOG_EN_PCP +*004f7d04: 00000000 > 01000000 # LOG_EN_EEPROM +*004f7d08: 00000000 > 01000000 # LOG_EN_BACKUP +*004f8118: 00000000 > 01000000 # LOG_EN_RTC +*004f96dc: 00000000 > 01000000 # LOG_EN_GFETCHER +*004f8338: 00000000 > 01000000 # LOG_EN_NETWORK +*004f88c0: 00000000 > 01000000 # LOG_EN_MASTER +*004f88b0: 00000000 > 01000000 # LOG_EN_HM +*004f8330: 00000000 > 01000000 # LOG_EN_SRAM +*004f9728: 00000000 > 01000000 # LOG_EN_PLATFORM +*004f9e7c: 00000000 > 01000000 # LOG_EN_ASSERTS (We use ALPB_LOG_LEVEL instead) +*004e884c: 01000000 > 0a000000 # ALPB_LOG_LEVEL (0=None, 1=Error, 2=Warning, 3=Most, 4=Debug) diff --git a/src/patches/ALLNetProc.patch.json b/src/patches/ALLNetProc.patch.json deleted file mode 100644 index d8291d9..0000000 --- a/src/patches/ALLNetProc.patch.json +++ /dev/null @@ -1,93 +0,0 @@ -[ - { - "name": "LOG_EN_DONGLE", - "at": "004f48b0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PCP", - "at": "004f989c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_EEPROM", - "at": "004f7d04", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_BACKUP", - "at": "004f7d08", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_RTC", - "at": "004f8118", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_GFETCHER", - "at": "004f96dc", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_NETWORK", - "at": "004f8338", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_MASTER", - "at": "004f88c0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_HM", - "at": "004f88b0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_SRAM", - "at": "004f8330", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PLATFORM", - "at": "004f9728", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_ASSERTS (We use ALPB_LOG_LEVEL instead)", - "at": "004f9e7c", - "from": "00000000", - "to": "01000000", - "count": 0 - }, - { - "name": "ALPB_LOG_LEVEL (0=None, 1=Error, 2=Warning, 3=Most, 4=Debug)", - "at": "004e884c", - "from": "01000000", - "to": "0a000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/Game.patch b/src/patches/Game.patch new file mode 100644 index 0000000..ffba335 --- /dev/null +++ b/src/patches/Game.patch @@ -0,0 +1,16 @@ +*008717a0: 00000000 > 01000000 +*00871728: 00000000 > 01000000 +*00871cd8: 00000000 > 01000000 +*00872660: 00000000 > 01000000 +*0087297c: 00000000 > 01000000 +*00872980: 00000000 > 01000000 +*00872988: 00000000 > 01000000 +*00873540: 00000000 > 01000000 +*00873538: 00000000 > 01000000 +*0087f890: 00000000 > 01000000 +*00882ce4: 00000000 > 01000000 +*00882cec: 00000000 > 01000000 +*00883018: 00000000 > 01000000 +*00886ff8: 00000000 > 01000000 +*0088b1b8: 00000000 > 01000000 +*0088b1c0: 00000000 > 01000000 diff --git a/src/patches/Game.patch.json b/src/patches/Game.patch.json deleted file mode 100644 index 20bd6c6..0000000 --- a/src/patches/Game.patch.json +++ /dev/null @@ -1,98 +0,0 @@ -[ - { - "at": "008717a0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00871728", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00871cd8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00872660", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "0087297c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00872980", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00872988", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00873540", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00873538", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "0087f890", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00882ce4", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00882cec", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00883018", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "00886ff8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "0088b1b8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "at": "0088b1c0", - "from": "00000000", - "to": "01000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/InitialD8_GLW_RE_SBZZ.patch b/src/patches/InitialD8_GLW_RE_SBZZ.patch new file mode 100644 index 0000000..dce644c --- /dev/null +++ b/src/patches/InitialD8_GLW_RE_SBZZ.patch @@ -0,0 +1,17 @@ +*01b20630 : 00000000 > 01000000 # LOG_EN_ATA +*01b0e638 : 00000000 > 01000000 # LOG_EN_BACKUP +*01b0ef68 : 00000000 > 01000000 # LOG_EN_DIPSW +*01b0ef70 : 00000000 > 01000000 # LOG_EN_DONGLE +*01b1415c : 00000000 > 01000000 # LOG_EN_EEPROM +*01b1333c : 00000000 > 01000000 # LOG_EN_GDELIVER +*01b12dfc : 00000000 > 01000000 # LOG_EN_GFETCHER +*01b123c4 : 00000000 > 01000000 # LOG_EN_HM +*01b123d0 : 00000000 > 01000000 # LOG_EN_INSTALL +*01b20524 : 00000000 > 01000000 # LOG_EN_JVSP +*01b24618 : 00000000 > 01000000 # LOG_EN_JVST +*01b13390 : 00000000 > 01000000 # LOG_EN_MASTER +*01b0e0c0 : 00000000 > 01000000 # LOG_EN_NETWORK +*01b28bfc : 00000000 > 01000000 # LOG_EN_PCP +*01b204b0 : 00000000 > 01000000 # LOG_EN_PLATFORM +*01b13f40 : 00000000 > 01000000 # LOG_EN_RTC +*01b14158 : 00000000 > 01000000 # LOG_EN_SRAM diff --git a/src/patches/InitialD8_GLW_RE_SBZZ.patch.json b/src/patches/InitialD8_GLW_RE_SBZZ.patch.json deleted file mode 100644 index 3f66e3a..0000000 --- a/src/patches/InitialD8_GLW_RE_SBZZ.patch.json +++ /dev/null @@ -1,121 +0,0 @@ -[ - { - "name": "LOG_EN_ATA", - "at": "01b20630", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_BACKUP", - "at": "01b0e638", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_DIPSW", - "at": "01b0ef68", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_DONGLE", - "at": "01b0ef70", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_EEPROM", - "at": "01b1415c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_GDELIVER", - "at": "01b1333c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_GFETCHER", - "at": "01b12dfc", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_HM", - "at": "01b123c4", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_INSTALL", - "at": "01b123d0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVSP", - "at": "01b20524", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVST", - "at": "01b24618", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_MASTER", - "at": "01b13390", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_NETWORK", - "at": "01b0e0c0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PCP", - "at": "01b28bfc", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PLATFORM", - "at": "01b204b0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_RTC", - "at": "01b13f40", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_SRAM", - "at": "01b14158", - "from": "00000000", - "to": "01000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/UnderNightInBirthExLate[st].patch b/src/patches/UnderNightInBirthExLate[st].patch new file mode 100644 index 0000000..d5fb053 --- /dev/null +++ b/src/patches/UnderNightInBirthExLate[st].patch @@ -0,0 +1,14 @@ +*00843b9c: 00000000 > 01000000 # amiTimerDebugLevel +*00843bd8: 00000000 > 01000000 # amCreditDebugLevel +*00843fc0: 00000000 > 01000000 # amBackupDebugLevel +*008443d0: 00000000 > 01000000 # amAuthDebugLevel +*008448d8: 00000000 > 01000000 # amDipswDebugLevel +*008448e0: 00000000 > 01000000 # amJvsDebugLevel +*00850c30: 00000000 > 01000000 # amMasterDebugLevel +*00851550: 00000000 > 01000000 # amAimeDebugLevel +*00851a78: 00000000 > 01000000 # amEepromDebugLevel +*00851d10: 00000000 > 01000000 # amJvspDebugLevel +*00851d1c: 00000000 > 01000000 # amSramDebugLevel +*00851d20: 00000000 > 01000000 # amPlatformDebugLevel +*00851da0: 00000000 > 01000000 # pcpDebugLevel +*00855fd8: 00000000 > 01000000 # amJvstDebugLevel diff --git a/src/patches/maimai_dump_.patch b/src/patches/maimai_dump_.patch new file mode 100644 index 0000000..5aa4f64 --- /dev/null +++ b/src/patches/maimai_dump_.patch @@ -0,0 +1,21 @@ +*00c8ab7c : 00000000 > 01000000 # amSramDebugLevel +*00f406f0 : 00000000 > 01000000 # LOG_EN_CABINET_DL +*00c88680 : 00000000 > 01000000 # amInstallDebugLevel +*00c8ab78 : 00000000 > 01000000 # amEepromDebugLevel +*00c88608 : 00000000 > 01000000 # amPlatformDebugLevel +*00c88dd0 : 00000000 > 01000000 # amStorageDebugLevel +*00ca25ec : 00000000 > 01000000 # pcpDebugLevel +*00c96ed0 : 00000000 > 01000000 # amHmDebugLevel +*00f406ec : 00000000 > 01000000 # LOG_EN_HTTP +*00c89ca8 : 00000000 > 01000000 # amDipswDebugLevel +*00c96ed8 : 00000000 > 01000000 # amDongleDebugLevel +*00c9a83c : 00000000 > 01000000 # amJvspDebugLevel +*00c89730 : 00000000 > 01000000 # amNetworkDebugLevel +*00c9a440 : 00000000 > 01000000 # amJvstThreadDebugLevel +*00c8ab80 : 00000000 > 01000000 # amJvsDebugLevel +*00c89fc8 : 00000000 > 01000000 # amMasterDebugLevel +*00c88bb8 : 00000000 > 01000000 # amRtcDebugLevel +*00c9e420 : 00000000 > 01000000 # amJvstDriverDebugLevel +*00c89320 : 00000000 > 01000000 # amBackupDebugLevel +*00c88bb4 : 00000000 > 01000000 # amHwResetDebugLevel +*00c830e8 : 00000000 > 01000000 # LOG_EN diff --git a/src/patches/maimai_dump_.patch.json b/src/patches/maimai_dump_.patch.json deleted file mode 100644 index 12c0a7a..0000000 --- a/src/patches/maimai_dump_.patch.json +++ /dev/null @@ -1,149 +0,0 @@ -[ - { - "name": "LOG_EN_SRAM", - "at": "00c8ab7c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_CABINET_DL", - "at": "00f406f0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_INSTALL", - "at": "00c88680", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_EEPROM", - "at": "00c8ab78", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PLATFORM", - "at": "00c88608", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_STORAGE", - "at": "00c88dd0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PCP", - "at": "00ca25ec", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_HM", - "at": "00c96ed0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_HTTP", - "at": "00f406ec", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_DIPSW", - "at": "00c89ca8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_DONGLE", - "at": "00c96ed8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVSP", - "at": "00c9a83c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_NETWORK", - "at": "00c89730", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVST_THREAD", - "at": "00c9a440", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVS", - "at": "00c8ab80", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_MASTER", - "at": "00c89fc8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_RTC", - "at": "00c88bb8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVST_DRIVER", - "at": "00c9e420", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_BACKUP", - "at": "00c89320", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_HWRESET", - "at": "00c88bb4", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN", - "at": "00c830e8", - "from": "00000000", - "to": "01000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/mxgfetcher.patch b/src/patches/mxgfetcher.patch new file mode 100644 index 0000000..e7f0018 --- /dev/null +++ b/src/patches/mxgfetcher.patch @@ -0,0 +1 @@ +*00465e54: 00000000 > 01000000 # LOG_EN_AMSRAM diff --git a/src/patches/mxgfetcher.patch.json b/src/patches/mxgfetcher.patch.json deleted file mode 100644 index a4aaeac..0000000 --- a/src/patches/mxgfetcher.patch.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "name": "LOG_EN_AMSRAM", - "at": "00465e54", - "from": "00000000", - "to": "01000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/mxmaster.patch b/src/patches/mxmaster.patch new file mode 100644 index 0000000..d9b0e8a --- /dev/null +++ b/src/patches/mxmaster.patch @@ -0,0 +1 @@ +*00431270: 00000000 > 01000000 # amDongleDebugLevel diff --git a/src/patches/mxmaster.patch.json b/src/patches/mxmaster.patch.json deleted file mode 100644 index 71defd4..0000000 --- a/src/patches/mxmaster.patch.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "name": "LOG_EN_DONGLE", - "at": "00431270", - "from": "00000000", - "to": "01000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/mxnetwork.patch b/src/patches/mxnetwork.patch new file mode 100644 index 0000000..0f7ae2c --- /dev/null +++ b/src/patches/mxnetwork.patch @@ -0,0 +1,2 @@ +*004438e0: 00000000 > 01000000 # pcpDebugLevel +*004433f8: 00000000 > 01000000 # amUtilDebugLevel diff --git a/src/patches/mxnetwork.patch.json b/src/patches/mxnetwork.patch.json deleted file mode 100644 index a90fd3c..0000000 --- a/src/patches/mxnetwork.patch.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "name": "LOG_EN_PCP", - "at": "004438e0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_UTL", - "at": "004433f8", - "from": "00000000", - "to": "01000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/mxsegaboot.patch b/src/patches/mxsegaboot.patch new file mode 100644 index 0000000..98ce246 --- /dev/null +++ b/src/patches/mxsegaboot.patch @@ -0,0 +1,23 @@ +*0054fcd8: 00000000 > 01000000 # LOG_EN_JVS_DRIVER +*00538810: 00000000 > 01000000 # LOG_EN_DIPSW +*0054afc8: 00000000 > 01000000 # LOG_EN_ATA +*00544b78: 00000000 > 01000000 # LOG_EN_DONGLE +*00536c98: 00000000 > 01000000 # LOG_EN_EEPROM +*00537834: 00000000 > 01000000 # LOG_EN_GCATCHER +*00537d4c: 00000000 > 01000000 # LOG_EN_GDELIVER +*0053828c: 00000000 > 01000000 # LOG_EN_GFETCHER +*00547fd0: 00000000 > 01000000 # LOG_EN_HWRESET +*00547fd8: 00000000 > 01000000 # LOG_EN_PLATFORM +*00548268: 00000000 > 01000000 # LOG_EN_HM +*00536f30: 00000000 > 01000000 # LOG_EN_BACKUP +*00547fcc: 00000000 > 01000000 # LOG_EN_CMOS +*005382d8: 00000000 > 01000000 # LOG_EN_INSTALL +*00538818: 00000000 > 01000000 # LOG_EN_JVS +*00544b68: 00000000 > 01000000 # LOG_EN_JVSP +*0054b3d8: 00000000 > 01000000 # LOG_EN_MASTER +*00548280: 00000000 > 01000000 # LOG_EN_NETWORK +*00548050: 00000000 > 01000000 # LOG_EN_RTC +*00536c94: 00000000 > 01000000 # LOG_EN_SRAM +*005487f8: 00000000 > 01000000 # LOG_EN_STORAGE +*00536c90: 00000000 > 01000000 # LOG_EN_SYS +*00536c70: 00000000 > 01000000 # LOG_EN_PCPT diff --git a/src/patches/mxsegaboot.patch.json b/src/patches/mxsegaboot.patch.json deleted file mode 100644 index d3c7804..0000000 --- a/src/patches/mxsegaboot.patch.json +++ /dev/null @@ -1,163 +0,0 @@ -[ - { - "name": "LOG_EN_JVS_DRIVER", - "at": "0054fcd8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_DIPSW", - "at": "00538810", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_ATA", - "at": "0054afc8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_DONGLE", - "at": "00544b78", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_EEPROM", - "at": "00536c98", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_GCATCHER", - "at": "00537834", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_GDELIVER", - "at": "00537d4c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_GFETCHER", - "at": "0053828c", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_HWRESET", - "at": "00547fd0", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PLATFORM", - "at": "00547fd8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_HM", - "at": "00548268", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_BACKUP", - "at": "00536f30", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_CMOS", - "at": "00547fcc", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_INSTALL", - "at": "005382d8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVS", - "at": "00538818", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_JVSP", - "at": "00544b68", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_MASTER", - "at": "0054b3d8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_NETWORK", - "at": "00548280", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_RTC", - "at": "00548050", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_SRAM", - "at": "00536c94", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_STORAGE", - "at": "005487f8", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_SYS", - "at": "00536c90", - "from": "00000000", - "to": "01000000", - "count": 4 - }, - { - "name": "LOG_EN_PCPT", - "at": "00536c70", - "from": "00000000", - "to": "01000000", - "count": 4 - } -] \ No newline at end of file diff --git a/src/patches/patches.index b/src/patches/patches.index new file mode 100644 index 0000000..c8ac3fc --- /dev/null +++ b/src/patches/patches.index @@ -0,0 +1,12 @@ +InitialD8_GLW_RE_SBZZ_dumped.exe: InitialD8_GLW_RE_SBZZ.patch +InitialD8_GLW_RE_SBZZ.exe: InitialD8_GLW_RE_SBZZ.patch +mxmaster.exe: mxmaster.patch +mxgfetcher.exe: mxgfetcher.patch +ORIG_mxsegaboot.exe: mxsegaboot.patch +mxsegaboot.exe: mxsegaboot.patch +ALLNetProc_win.exe: ALLNetProc.patch +ALLNetProc.exe: ALLNetProc.patch +Game.exe: Game.patch +mxnetwork.exe: mxnetwork.patch +maimai_dump_.exe: maimai_dump_.patch +RingGame.exe: UnderNightInBirthExLate[st].patch \ No newline at end of file diff --git a/src/patches/patches.json b/src/patches/patches.json deleted file mode 100644 index 3d2079d..0000000 --- a/src/patches/patches.json +++ /dev/null @@ -1,79 +0,0 @@ -[ - { - "name": "maimai Finale logs", - "description": "Enable logging facilities", - "binary_name": "maimai_dump_.exe", - "apply": true, - "patches_file": "maimai_dump_.patch.json" - }, - { - "name": "mxnetwork logs", - "description": "Enable logging facilities", - "binary_name": "mxnetwork.exe", - "apply": true, - "patches_file": "mxnetwork.patch.json" - }, - { - "name": "maimai 1.00 logs", - "description": "Enable logging facilities", - "binary_name": "Game.exe", - "apply": true, - "patches_file": "Game.patch.json" - }, - { - "name": "ALLNetProc logs", - "description": "Enable logging facilities", - "binary_name": "ALLNetProc.exe", - "apply": true, - "patches_file": "ALLNetProc.patch.json" - }, - { - "name": "ALLNetProc logs", - "description": "Enable logging facilities (alt filename)", - "binary_name": "ALLNetProc_win.exe", - "apply": true, - "patches_file": "ALLNetProc.patch.json" - }, - { - "name": "mxsegaboot logs", - "description": "Enable logging facilities", - "binary_name": "mxsegaboot.exe", - "apply": true, - "patches_file": "mxsegaboot.patch.json" - }, - { - "name": "mxsegaboot logs", - "description": "Enable logging facilities (alt filename)", - "binary_name": "ORIG_mxsegaboot.exe", - "apply": true, - "patches_file": "mxsegaboot.patch.json" - }, - { - "name": "mxgfetcher logs", - "description": "Enable logging facilities", - "binary_name": "mxgfetcher.exe", - "apply": true, - "patches_file": "mxgfetcher.patch.json" - }, - { - "name": "mxmaster logs", - "description": "Enable logging facilities", - "binary_name": "mxmaster.exe", - "apply": true, - "patches_file": "mxmaster.patch.json" - }, - { - "name": "InitialD8_GLW_RE_SBZZ logs", - "description": "Enable logging facilities", - "binary_name": "InitialD8_GLW_RE_SBZZ.exe", - "apply": true, - "patches_file": "InitialD8_GLW_RE_SBZZ.patch.json" - }, - { - "name": "InitialD8_GLW_RE_SBZZ logs", - "description": "Enable logging facilities", - "binary_name": "InitialD8_GLW_RE_SBZZ_dumped.exe", - "apply": true, - "patches_file": "InitialD8_GLW_RE_SBZZ.patch.json" - } -] \ No newline at end of file