Insane amount of stuff including a bunch of amlib

This commit is contained in:
Bottersnike 2023-01-21 18:51:13 +00:00
parent 52a66a2623
commit 60ccfbede6
198 changed files with 12831 additions and 4951 deletions

View File

@ -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"

View File

@ -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

View File

@ -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')

View File

@ -0,0 +1,212 @@
#include <stdint.h>
#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
*/

View File

@ -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;
}

View File

@ -23,3 +23,6 @@
#include "../lib/mice/mice.h"
#include "./util/_util.h"
extern WCHAR exePath[MAX_PATH + 1];
extern DWORD imageOffset;

View File

@ -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);
}

View File

@ -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();
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();

View File

@ -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',
)

View File

@ -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);
}

View File

@ -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
// ( <L/R> <sensor> <> <> )
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]);
// { <L/R> <sensor> t h }
log_misc("touch", "th-command recieved: %d", sensor);
// Sensor == '@': failed
// ( <L/R> <sensor> <> <threshold> )
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
// ( <L/R> <sensor> <> <> )
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]);
// { <L/R> <sensor> t h }
log_misc("touch", "th-command recieved: %d", sensor);
// Sensor == '@': failed
// ( <L/R> <sensor> <> <threshold> )
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);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,421 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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(<columba>, <read>, 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;
}

View File

@ -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) {

View File

@ -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);
}

View File

@ -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(<mxparallel>, 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);
}

View File

@ -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);

View File

@ -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 {

View File

@ -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(<mxsram>, <get sector size>, 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;

View File

@ -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;

View File

@ -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)

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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 <float.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#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);

View File

@ -1,3 +1,4 @@
gui_files = files(
'imgui_memory_editor.c',
'gui.c',
)

View File

@ -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() {

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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;
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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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];

View File

@ -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: [

View File

@ -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);

View File

@ -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);

View File

@ -1,6 +1,7 @@
#include "hook.h"
#include <memory.h>
#include <stdbool.h>
#include <stdlib.h>
#include "log.h"

View File

@ -1,13 +1,18 @@
#include "log.h"
#include <dbghelp.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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;
}
}
}

View File

@ -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();

View File

@ -0,0 +1,98 @@
#include <Windows.h>
#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';
}

View File

@ -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",
};

View File

@ -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);

10
src/micetools/lib/_am.h Normal file
View File

@ -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;

View File

@ -0,0 +1,6 @@
#pragma once
#include "amEeprom.h"
#include "amOemstring.h"
#include "amPlatform.h"
#include "amSram.h"

View File

@ -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);

View File

@ -0,0 +1,4 @@
void amAtaOpenDevice(void);
void amAtaCloseDevice(void);
void amAtaPioInCommand(void);
void amAtaPioOutCommand(void);

View File

@ -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);

View File

@ -0,0 +1 @@
void amAuthDiscRead(void);

View File

@ -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);

View File

@ -0,0 +1,3 @@
void amCmosReadByteInRearpart(void);
void amCmosSetPartition(void);
void amCmosWriteByteInRearpart(void);

View File

@ -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);

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,211 @@
#pragma once
#include <Windows.h>
#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);

View File

@ -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;
}

View File

@ -1,13 +1,59 @@
#pragma once
#include <Windows.h>
#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);

View File

@ -0,0 +1,4 @@
void amGcatcherInit(void);
void amGcatcherIsUpdate(void);
void amGcatcherReloadInfo(void);
void amGcatcherStartCatcher(void);

View File

@ -0,0 +1,3 @@
void amGdeliverInit(void);
void amGdeliverReadSegment(void);
void amGdeliverResSetThread(void);

View File

@ -0,0 +1,3 @@
void amGfetcherInit(void);
void amGfetcherReqIsReleaseEx(void);
void amGfetcherReqRestart(void);

View File

@ -0,0 +1 @@
void amHardwareReset(void);

View File

@ -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);

View File

@ -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();
}

View File

@ -0,0 +1,211 @@
#pragma once
#include <Windows.h>
#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*);

View File

@ -0,0 +1,2 @@
void amJvsInit(void);
void amJvsInitEx(void);

View File

@ -0,0 +1 @@
void amJvsUpdate(void);

View File

@ -0,0 +1,3 @@
void amJvspAckSwInput(void);
void amJvspGetReport(void);
void amJvspMakeReportIndex(void);

View File

View File

@ -0,0 +1,3 @@
void amJvstDriverExit(void);
void amJvstDriverSetup(void);
void amJvstDriverSetupComm(void);

View File

@ -0,0 +1 @@
void amJvstThreadInit(void);

View File

@ -0,0 +1,2 @@
void amLibSetErrorLog(void);
void amLibSetupErrorLogInfo(void);

View File

@ -0,0 +1,2 @@
void amLogInit(void);
void amLogSetEventOption(void);

View File

View File

@ -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);

View File

@ -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);

View File

@ -0,0 +1,190 @@
#include "amOemstring.h"
#include <stdio.h>
#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;
}

View File

@ -0,0 +1,41 @@
#pragma once
#include <Windows.h>
#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);

View File

@ -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;
}

View File

@ -0,0 +1,112 @@
#pragma once
#include <Windows.h>
#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);

View File

@ -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);

View File

@ -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;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <Windows.h>
#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);

View File

@ -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, &sectorSize,
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;
}

View File

@ -0,0 +1,56 @@
#pragma once
#include <Windows.h>
#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);

View File

@ -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);

View File

@ -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);

View File

@ -1,19 +0,0 @@
#include <amTimer.h>
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;
}

View File

@ -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,
],
)

View File

@ -0,0 +1,5 @@
#pragma once
#include "amiCrc.h"
#include "amiDebug.h"
#include "amiTimer.h"

View File

@ -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;
}

View File

@ -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))

View File

View File

@ -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; }

Some files were not shown because too many files have changed in this diff Show More