235 lines
6.0 KiB
C
235 lines
6.0 KiB
C
typedef unsigned int u32;
|
|
typedef unsigned char u8;
|
|
typedef int i32;
|
|
|
|
__declspec(dllimport) void *__stdcall CreateFileA(const char *name, u32 access, u32 share,
|
|
void *security, u32 creation,
|
|
u32 flags, void *template_file);
|
|
__declspec(dllimport) u32 __stdcall SetFilePointer(void *file, i32 distance,
|
|
i32 *distance_high, u32 method);
|
|
__declspec(dllimport) int __stdcall WriteFile(void *file, const void *buffer, u32 bytes,
|
|
u32 *written, void *overlapped);
|
|
__declspec(dllimport) int __stdcall CloseHandle(void *object);
|
|
|
|
#define GENERIC_WRITE 0x40000000u
|
|
#define FILE_SHARE_READ_WRITE 0x00000003u
|
|
#define OPEN_ALWAYS 4u
|
|
#define FILE_ATTRIBUTE_NORMAL 0x00000080u
|
|
#define FILE_END 2u
|
|
#define INVALID_HANDLE_VALUE ((void *)-1)
|
|
|
|
static u32 g_handle = 0x49444d43u; /* "IDMC" */
|
|
static u32 g_status = 0;
|
|
static u32 g_regs[0x2000] = {
|
|
[0x4150 >> 2] = 0x0000825cu,
|
|
[0x4140 >> 2] = 0x80000004u,
|
|
[0x41a4 >> 2] = 0x80000005u,
|
|
};
|
|
static u8 g_buffer[0x8000];
|
|
static u32 g_log_count;
|
|
|
|
static char *append_char(char *p, char c)
|
|
{
|
|
*p++ = c;
|
|
return p;
|
|
}
|
|
|
|
static char *append_text(char *p, const char *s)
|
|
{
|
|
while (*s) {
|
|
*p++ = *s++;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static char *append_hex(char *p, u32 value)
|
|
{
|
|
static const char digits[] = "0123456789abcdef";
|
|
int i;
|
|
p = append_text(p, "0x");
|
|
for (i = 7; i >= 0; --i) {
|
|
*p++ = digits[(value >> (i * 4)) & 0xf];
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static void log3(const char *name, u32 a, u32 b, u32 c)
|
|
{
|
|
char line[160];
|
|
char *p;
|
|
u32 written;
|
|
void *file;
|
|
|
|
if (g_log_count++ > 20000) {
|
|
return;
|
|
}
|
|
|
|
p = line;
|
|
p = append_text(p, name);
|
|
p = append_char(p, '(');
|
|
p = append_hex(p, a);
|
|
p = append_text(p, ", ");
|
|
p = append_hex(p, b);
|
|
p = append_text(p, ", ");
|
|
p = append_hex(p, c);
|
|
p = append_text(p, ")\r\n");
|
|
|
|
file = CreateFileA("Z:\\tmp\\idmac_shim.log", GENERIC_WRITE, FILE_SHARE_READ_WRITE,
|
|
0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
|
if (file == INVALID_HANDLE_VALUE) {
|
|
return;
|
|
}
|
|
SetFilePointer(file, 0, 0, FILE_END);
|
|
WriteFile(file, line, (u32)(p - line), &written, 0);
|
|
CloseHandle(file);
|
|
}
|
|
|
|
static u32 load_le32(const void *ptr)
|
|
{
|
|
const u8 *p = (const u8 *)ptr;
|
|
return ((u32)p[0]) | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
|
|
}
|
|
|
|
int __attribute__((stdcall)) DllMain(void *module, unsigned long reason, void *reserved)
|
|
{
|
|
(void)module;
|
|
(void)reason;
|
|
(void)reserved;
|
|
return 1;
|
|
}
|
|
|
|
int iDmacDrvOpen(u32 device, u32 *handle_out, u32 *status_out)
|
|
{
|
|
log3("Open", device, (u32)handle_out, (u32)status_out);
|
|
(void)device;
|
|
if (handle_out) {
|
|
*handle_out = g_handle;
|
|
}
|
|
if (status_out) {
|
|
*status_out = g_status;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int iDmacDrvClose(u32 handle, u32 *status_out)
|
|
{
|
|
log3("Close", handle, (u32)status_out, 0);
|
|
(void)handle;
|
|
if (status_out) {
|
|
*status_out = g_status;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int iDmacDrvRegisterRead(u32 handle, u32 address, u32 *value_out, u32 *status_out)
|
|
{
|
|
log3("RegisterRead", handle, address, (u32)value_out);
|
|
(void)handle;
|
|
if (status_out) {
|
|
*status_out = g_status;
|
|
}
|
|
if (!value_out) {
|
|
return 0x57;
|
|
}
|
|
|
|
switch (address) {
|
|
case 0x400:
|
|
*value_out = 0x01010313u;
|
|
break;
|
|
case 0x4000:
|
|
*value_out = 0x00ff00ffu;
|
|
break;
|
|
case 0x4004:
|
|
*value_out = 0x00ff0000u;
|
|
break;
|
|
default:
|
|
if ((address >> 2) < (sizeof(g_regs) / sizeof(g_regs[0]))) {
|
|
*value_out = g_regs[address >> 2];
|
|
} else {
|
|
*value_out = 0;
|
|
}
|
|
break;
|
|
}
|
|
log3("RegisterReadValue", address, *value_out, status_out ? *status_out : 0);
|
|
return 0;
|
|
}
|
|
|
|
int iDmacDrvRegisterWrite(u32 handle, u32 address, u32 value, u32 *status_out)
|
|
{
|
|
log3("RegisterWrite", handle, address, value);
|
|
(void)handle;
|
|
if (status_out) {
|
|
*status_out = g_status;
|
|
}
|
|
if ((address >> 2) < (sizeof(g_regs) / sizeof(g_regs[0]))) {
|
|
g_regs[address >> 2] = value;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int iDmacDrvRegisterBufferRead(u32 handle, u32 address, void *buffer, u32 bytes, u32 *status_out)
|
|
{
|
|
u32 i;
|
|
log3("BufferRead", handle, address, bytes);
|
|
(void)handle;
|
|
if (status_out) {
|
|
*status_out = g_status;
|
|
}
|
|
if (!buffer) {
|
|
return 0x57;
|
|
}
|
|
if (bytes >= 4) {
|
|
log3("BufferReadBefore", address, bytes, load_le32(buffer));
|
|
}
|
|
for (i = 0; i < bytes; i++) {
|
|
((u8 *)buffer)[i] = (address + i < sizeof(g_buffer)) ? g_buffer[address + i] : 0;
|
|
}
|
|
if (bytes >= 4) {
|
|
log3("BufferReadAfter", address, bytes, load_le32(buffer));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int iDmacDrvRegisterBufferWrite(u32 handle, u32 address, const void *buffer, u32 bytes, u32 *status_out)
|
|
{
|
|
u32 i;
|
|
log3("BufferWrite", handle, address, bytes);
|
|
(void)handle;
|
|
if (status_out) {
|
|
*status_out = g_status;
|
|
}
|
|
if (!buffer) {
|
|
return 0x57;
|
|
}
|
|
if (bytes >= 4) {
|
|
log3("BufferWriteData", address, bytes, load_le32(buffer));
|
|
}
|
|
for (i = 0; i < bytes; i++) {
|
|
if (address + i < sizeof(g_buffer)) {
|
|
g_buffer[address + i] = ((const u8 *)buffer)[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int iDmacDrvDmaRead(u32 handle, u32 address, void *buffer, u32 bytes, u32 *status_out)
|
|
{
|
|
return iDmacDrvRegisterBufferRead(handle, address, buffer, bytes, status_out);
|
|
}
|
|
|
|
int iDmacDrvDmaWrite(u32 handle, u32 address, const void *buffer, u32 bytes, u32 *status_out)
|
|
{
|
|
return iDmacDrvRegisterBufferWrite(handle, address, buffer, bytes, status_out);
|
|
}
|
|
|
|
int iDmacDrvProgramDownload(u32 handle, u32 command, u32 *status_out)
|
|
{
|
|
log3("ProgramDownload", handle, command, (u32)status_out);
|
|
(void)handle;
|
|
(void)command;
|
|
if (status_out) {
|
|
*status_out = g_status;
|
|
}
|
|
return 0;
|
|
}
|