Split libnu into libplatform, libamex

Going to add some ALLS stuff to libplatform and the ALLS hardware
does not contain an AMEX board.
This commit is contained in:
Tau
2019-03-04 17:22:38 -05:00
parent 727ce5171f
commit bc297b2480
26 changed files with 76 additions and 53 deletions

232
amex/ds.c Normal file
View File

@ -0,0 +1,232 @@
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#ifdef __GNUC__
#include <ntdef.h>
#else
#include <winnt.h>
#endif
#include <devioctl.h>
#include <ntdddisk.h>
#include <ntstatus.h>
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "amex/ds.h"
#include "amex/nvram.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "util/crc.h"
#include "util/dprintf.h"
#include "util/setupapi.h"
#pragma pack(push, 1)
enum {
DS_IOCTL_SETUP = 0x80006004,
DS_IOCTL_READ_SECTOR = 0x80006010,
};
struct ds_eeprom {
uint32_t crc32;
uint8_t unk_04[5];
char serial_no[17];
uint8_t unk_1A[6];
};
static_assert(sizeof(struct ds_eeprom) == 0x20, "DS EEPROM size");
#pragma pack(pop)
static HRESULT ds_handle_irp(struct irp *irp);
static HRESULT ds_handle_open(struct irp *irp);
static HRESULT ds_handle_close(struct irp *irp);
static HRESULT ds_handle_ioctl(struct irp *irp);
static HRESULT ds_ioctl_get_geometry(struct irp *irp);
static HRESULT ds_ioctl_setup(struct irp *irp);
static HRESULT ds_ioctl_read_sector(struct irp *irp);
static const char ds_serial_file[] = "DEVICE/ds.txt";
static struct ds_eeprom ds_eeprom;
static HANDLE ds_fd;
HRESULT ds_hook_init(void)
{
HRESULT hr;
FILE *f;
char c;
int i;
memset(&ds_eeprom, 0, sizeof(ds_eeprom));
f = fopen(ds_serial_file, "r");
if (f != NULL) {
i = 0;
for (;;) {
if (feof(f) || i >= sizeof(ds_eeprom.serial_no) - 1) {
break;
}
c = getc(f);
if (isspace(c)) {
break;
}
ds_eeprom.serial_no[i++] = c;
}
fclose(f);
} else {
dprintf("Failed to open %s\n", ds_serial_file);
}
ds_eeprom.crc32 = crc32(&ds_eeprom.unk_04, 0x1C, 0);
hr = iohook_push_handler(ds_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&ds_guid, L"$ds");
if (FAILED(hr)) {
return hr;
}
ds_fd = iohook_open_dummy_fd();
return S_OK;
}
static HRESULT ds_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != ds_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return ds_handle_open(irp);
case IRP_OP_CLOSE: return ds_handle_close(irp);
case IRP_OP_IOCTL: return ds_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT ds_handle_open(struct irp *irp)
{
if (wcscmp(irp->open_filename, L"$ds") != 0) {
return iohook_invoke_next(irp);
}
dprintf("DS: Open device\n");
irp->fd = ds_fd;
return S_OK;
}
static HRESULT ds_handle_close(struct irp *irp)
{
dprintf("DS: Close device\n");
return S_OK;
}
static HRESULT ds_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
return ds_ioctl_get_geometry(irp);
case DS_IOCTL_SETUP:
return ds_ioctl_setup(irp);
case DS_IOCTL_READ_SECTOR:
return ds_ioctl_read_sector(irp);
default:
dprintf("DS: Unknown ioctl %08x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT ds_ioctl_get_geometry(struct irp *irp)
{
DISK_GEOMETRY *out;
if (irp->read.nbytes < sizeof(*out)) {
dprintf("DS: Invalid ioctl response buffer size\n");
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dprintf("DS: Get geometry\n");
out = (DISK_GEOMETRY *) irp->read.bytes;
out->Cylinders.QuadPart = 1;
out->MediaType = 0;
out->TracksPerCylinder = 1;
out->SectorsPerTrack = 2;
out->BytesPerSector = 32;
irp->read.pos = sizeof(*out);
return S_OK;
}
static HRESULT ds_ioctl_setup(struct irp *irp)
{
dprintf("DS: Setup IOCTL\n");
return S_OK;
}
static HRESULT ds_ioctl_read_sector(struct irp *irp)
{
struct const_iobuf src;
uint32_t sector_no;
HRESULT hr;
hr = iobuf_read_le32(&irp->write, &sector_no);
if (FAILED(hr)) {
return hr;
}
dprintf("DS: Read sector %08x\n", sector_no);
src.bytes = (const uint8_t *) &ds_eeprom;
src.nbytes = sizeof(ds_eeprom);
src.pos = 0;
iobuf_move(&irp->read, &src);
if (irp->ovl != NULL) {
irp->ovl->Internal = STATUS_SUCCESS;
irp->ovl->InternalHigh = irp->read.pos;
if (irp->ovl->hEvent != NULL) {
SetEvent(irp->ovl->hEvent);
}
}
return S_OK;
}

12
amex/ds.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <windows.h>
DEFINE_GUID(
ds_guid,
0x279A9F67,
0x348F,
0x41C9,
0xA4, 0xC4, 0xDF, 0xDB, 0x8A, 0xE8, 0xE5, 0xE0);
HRESULT ds_hook_init(void);

164
amex/eeprom.c Normal file
View File

@ -0,0 +1,164 @@
#include <windows.h>
#ifdef __GNUC__
#include <ntdef.h>
#else
#include <winnt.h>
#endif
#include <devioctl.h>
#include <ntdddisk.h>
#include <assert.h>
#include "amex/eeprom.h"
#include "amex/nvram.h"
#include "hook/iohook.h"
#include "util/dprintf.h"
#include "util/setupapi.h"
static HRESULT eeprom_handle_irp(struct irp *irp);
static HRESULT eeprom_handle_open(struct irp *irp);
static HRESULT eeprom_handle_close(struct irp *irp);
static HRESULT eeprom_handle_ioctl(struct irp *irp);
static HRESULT eeprom_handle_read(struct irp *irp);
static HRESULT eeprom_handle_write(struct irp *irp);
static HRESULT eeprom_ioctl_get_geometry(struct irp *irp);
static HANDLE eeprom_file;
HRESULT eeprom_hook_init(void)
{
HRESULT hr;
hr = nvram_open_file(&eeprom_file, L"DEVICE\\eeprom.bin", 0x2000);
if (FAILED(hr)) {
return hr;
}
hr = iohook_push_handler(eeprom_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&eeprom_guid, L"$eeprom");
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT eeprom_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != eeprom_file) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return eeprom_handle_open(irp);
case IRP_OP_CLOSE: return eeprom_handle_close(irp);
case IRP_OP_IOCTL: return eeprom_handle_ioctl(irp);
case IRP_OP_READ: return eeprom_handle_read(irp);
case IRP_OP_WRITE: return eeprom_handle_write(irp);
default: return iohook_invoke_next(irp);
}
}
static HRESULT eeprom_handle_open(struct irp *irp)
{
if (wcscmp(irp->open_filename, L"$eeprom") != 0) {
return iohook_invoke_next(irp);
}
dprintf("EEPROM: Open device\n");
irp->fd = eeprom_file;
return S_OK;
}
static HRESULT eeprom_handle_close(struct irp *irp)
{
dprintf("EEPROM: Close device\n");
return S_OK;
}
static HRESULT eeprom_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
return eeprom_ioctl_get_geometry(irp);
default:
dprintf("EEPROM: Unknown ioctl %x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT eeprom_ioctl_get_geometry(struct irp *irp)
{
DISK_GEOMETRY *out;
if (irp->read.nbytes < sizeof(*out)) {
dprintf("EEPROM: Invalid ioctl response buffer size\n");
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dprintf("EEPROM: Get geometry\n");
/* Not the real values, just bullshitting something for now */
out = (DISK_GEOMETRY *) irp->read.bytes;
out->Cylinders.QuadPart = 0x800;
out->MediaType = 0;
out->TracksPerCylinder = 1;
out->SectorsPerTrack = 2;
out->BytesPerSector = 4;
irp->read.pos = sizeof(*out);
return S_OK;
}
static HRESULT eeprom_handle_read(struct irp *irp)
{
if (irp->ovl == NULL) {
dprintf("EEPROM: Synchronous read..?\n");
return E_UNEXPECTED;
}
dprintf("EEPROM: Read off %x len %x\n",
(int) irp->ovl->Offset,
(int) irp->read.nbytes);
return iohook_invoke_next(irp);
}
static HRESULT eeprom_handle_write(struct irp *irp)
{
if (irp->ovl == NULL) {
dprintf("EEPROM: Synchronous write..?\n");
return E_UNEXPECTED;
}
dprintf("EEPROM: Write off %x len %x\n",
(int) irp->ovl->Offset,
(int) irp->write.nbytes);
return iohook_invoke_next(irp);
}

12
amex/eeprom.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <windows.h>
DEFINE_GUID(
eeprom_guid,
0xB7970F0C,
0x31C4,
0x45FF,
0x96, 0x18, 0x0A, 0x24, 0x00, 0x94, 0xB2, 0x71);
HRESULT eeprom_hook_init(void);

184
amex/gpio.c Normal file
View File

@ -0,0 +1,184 @@
#include <windows.h>
#include <ntstatus.h>
#include <assert.h>
#include <string.h>
#include "amex/gpio.h"
#include "hook/iohook.h"
#include "util/dprintf.h"
#include "util/setupapi.h"
enum {
GPIO_IOCTL_SET_LEDS = 0x8000A004,
GPIO_IOCTL_GET_PSW = 0x80006008,
GPIO_IOCTL_GET_DIPSW = 0x8000600C,
GPIO_IOCTL_DESCRIBE = 0x80006014,
};
enum {
GPIO_TYPE_NONE = 0,
GPIO_TYPE_LED = 1,
GPIO_TYPE_DIPSW = 2,
GPIO_TYPE_PSW = 3,
};
#pragma pack(push, 1)
struct gpio_port {
uint8_t unknown;
/* Number of distinct instances of this thing..? */
uint8_t count;
/* Type of GPIO port */
uint16_t type;
};
struct gpio_ports {
uint8_t unknown; /* Maybe a count of valid items in the array idk */
struct gpio_port ports[32];
};
#pragma pack(pop)
static HRESULT gpio_handle_irp(struct irp *irp);
static HRESULT gpio_handle_open(struct irp *irp);
static HRESULT gpio_handle_close(struct irp *irp);
static HRESULT gpio_handle_ioctl(struct irp *irp);
static HRESULT gpio_ioctl_get_psw(struct irp *irp);
static HRESULT gpio_ioctl_get_dipsw(struct irp *irp);
static HRESULT gpio_ioctl_describe(struct irp *irp);
static HRESULT gpio_ioctl_set_leds(struct irp *irp);
static HANDLE gpio_fd;
static const struct gpio_ports gpio_ports = {
.ports = {
{
.type = GPIO_TYPE_LED,
.count = 2,
}, {
.type = GPIO_TYPE_DIPSW,
.count = 8,
}, {
.type = GPIO_TYPE_PSW,
.count = 2,
}
},
};
static_assert(sizeof(gpio_ports) == 129, "GPIO port map size");
void gpio_hook_init(void)
{
gpio_fd = iohook_open_dummy_fd();
iohook_push_handler(gpio_handle_irp);
setupapi_add_phantom_dev(&gpio_guid, L"$gpio");
}
static HRESULT gpio_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != gpio_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return gpio_handle_open(irp);
case IRP_OP_CLOSE: return gpio_handle_close(irp);
case IRP_OP_IOCTL: return gpio_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT gpio_handle_open(struct irp *irp)
{
if (wcscmp(irp->open_filename, L"$gpio") != 0) {
return iohook_invoke_next(irp);
}
dprintf("GPIO: Open device\n");
irp->fd = gpio_fd;
return S_OK;
}
static HRESULT gpio_handle_close(struct irp *irp)
{
dprintf("GPIO: Close device\n");
return S_OK;
}
static HRESULT gpio_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case GPIO_IOCTL_SET_LEDS:
return gpio_ioctl_set_leds(irp);
case GPIO_IOCTL_GET_PSW:
return gpio_ioctl_get_psw(irp);
case GPIO_IOCTL_GET_DIPSW:
return gpio_ioctl_get_dipsw(irp);
case GPIO_IOCTL_DESCRIBE:
return gpio_ioctl_describe(irp);
default:
dprintf("GPIO: Unknown ioctl %08x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT gpio_ioctl_get_dipsw(struct irp *irp)
{
uint32_t dipsw;
dipsw = 0xff;
//dprintf("GPIO: Get dipsw %08x\n", dipsw);
return iobuf_write_le32(&irp->read, dipsw);
}
static HRESULT gpio_ioctl_get_psw(struct irp *irp)
{
uint32_t result;
result = 0;
/* Bit 0 == SW1 == Alt. Test */
/* Bit 1 == SW2 == Alt. Service */
return iobuf_write_le32(&irp->read, result);
}
static HRESULT gpio_ioctl_describe(struct irp *irp)
{
dprintf("GPIO: Describe GPIO ports\n");
if (irp->read.nbytes < sizeof(gpio_ports)) {
dprintf("GPIO: Descriptor read buffer too small\n");
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
memcpy(irp->read.bytes, &gpio_ports, sizeof(gpio_ports));
irp->read.pos = sizeof(gpio_ports);
return S_OK;
}
static HRESULT gpio_ioctl_set_leds(struct irp *irp)
{
return S_OK;
}

12
amex/gpio.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <windows.h>
DEFINE_GUID(
gpio_guid,
0xE9A26688,
0xF522,
0x44FA,
0xBF, 0xEE, 0x59, 0xDD, 0x16, 0x15, 0x56, 0x6C);
void gpio_hook_init(void);

8
amex/guid.c Normal file
View File

@ -0,0 +1,8 @@
#include <windows.h>
#include <initguid.h>
#include "amex/ds.h"
#include "amex/eeprom.h"
#include "amex/gpio.h"
#include "amex/jvs.h"
#include "amex/sram.h"

175
amex/jvs.c Normal file
View File

@ -0,0 +1,175 @@
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#include <ntstatus.h>
#include <assert.h>
#include <stddef.h>
#include "amex/jvs.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "jvs/jvs-bus.h"
#include "util/dprintf.h"
#include "util/dump.h"
#include "util/setupapi.h"
enum {
JVS_IOCTL_HELLO = 0x80006004,
JVS_IOCTL_SENSE = 0x8000600C,
JVS_IOCTL_TRANSACT = 0x8000E008,
};
static HRESULT jvs_handle_irp(struct irp *irp);
static HRESULT jvs_handle_open(struct irp *irp);
static HRESULT jvs_handle_close(struct irp *irp);
static HRESULT jvs_handle_ioctl(struct irp *irp);
static HRESULT jvs_ioctl_hello(struct irp *irp);
static HRESULT jvs_ioctl_sense(struct irp *irp);
static HRESULT jvs_ioctl_transact(struct irp *irp);
static HANDLE jvs_fd;
static struct jvs_node *jvs_root;
void jvs_hook_init(void)
{
jvs_fd = iohook_open_dummy_fd();
iohook_push_handler(jvs_handle_irp);
setupapi_add_phantom_dev(&jvs_guid, L"$jvs");
}
void jvs_attach(struct jvs_node *root)
{
jvs_root = root;
}
static HRESULT jvs_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != jvs_fd) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return jvs_handle_open(irp);
case IRP_OP_CLOSE: return jvs_handle_close(irp);
case IRP_OP_IOCTL: return jvs_handle_ioctl(irp);
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT jvs_handle_open(struct irp *irp)
{
if (wcscmp(irp->open_filename, L"$jvs") != 0) {
return iohook_invoke_next(irp);
}
dprintf("JVS Controller: Open device\n");
irp->fd = jvs_fd;
return S_OK;
}
static HRESULT jvs_handle_close(struct irp *irp)
{
dprintf("JVS Controller: Close device\n");
return S_OK;
}
static HRESULT jvs_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case JVS_IOCTL_HELLO:
return jvs_ioctl_hello(irp);
case JVS_IOCTL_SENSE:
return jvs_ioctl_sense(irp);
case JVS_IOCTL_TRANSACT:
return jvs_ioctl_transact(irp);
default:
dprintf("JVS Controller: Unknown ioctl %#x\n", irp->ioctl);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT jvs_ioctl_hello(struct irp *irp)
{
HRESULT hr;
// uuh fucked if i know
dprintf("JVS Controller: Port startup (?)\n");
iobuf_write_8(&irp->read, 0);
hr = iobuf_write_8(&irp->read, 0);
return hr;
}
static HRESULT jvs_ioctl_sense(struct irp *irp)
{
uint8_t code;
bool sense;
if (jvs_root != NULL) {
sense = jvs_root->sense(jvs_root);
if (sense) {
dprintf("JVS Controller: Sense line 2.5 V (address unassigned)\n");
code = 3;
} else {
dprintf("JVS Controller: Sense line 0.0 V (address assigned)\n");
code = 2;
}
} else {
dprintf("JVS Controller: Sense line 5.0 V (no downstream PCB)\n");
code = 1;
}
return iobuf_write_8(&irp->read, code);
}
static HRESULT jvs_ioctl_transact(struct irp *irp)
{
#if 0
dprintf("\nJVS Controller: Outbound frame:\n");
dump_const_iobuf(&irp->write);
#endif
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read);
#if 0
dprintf("JVS Controller: Inbound frame:\n");
dump_iobuf(&irp->read);
dprintf("\n");
#endif
if (irp->read.pos == 0) {
/* The un-acked JVS reset command must return ERROR_NO_DATA_DETECTED,
and this error must always be returned asynchronously. And since
async I/O comes from the NT kernel, we have to return that win32
error as the equivalent NTSTATUS. */
if (irp->ovl == NULL || irp->ovl->hEvent == NULL) {
return HRESULT_FROM_WIN32(ERROR_NO_DATA_DETECTED);
}
irp->ovl->Internal = STATUS_NO_DATA_DETECTED;
SetEvent(irp->ovl->hEvent);
return HRESULT_FROM_WIN32(ERROR_IO_PENDING);
} else {
return S_OK;
}
}

15
amex/jvs.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <windows.h>
#include "jvs/jvs-bus.h"
DEFINE_GUID(
jvs_guid,
0xDB6BBB45,
0xCC96,
0x4288,
0xAA, 0x00, 0x6C, 0x00, 0xD7, 0x67, 0xBD, 0xBF);
void jvs_hook_init(void);
void jvs_attach(struct jvs_node *root);

27
amex/meson.build Normal file
View File

@ -0,0 +1,27 @@
amex_lib = static_library(
'amex',
include_directories : inc,
implicit_include_directories : false,
c_pch : [
'../precompiled.c',
'../precompiled.h',
],
dependencies : [
capnhook.get_variable('hook_dep'),
],
sources : [
'ds.c',
'ds.h',
'eeprom.c',
'eeprom.h',
'gpio.c',
'gpio.h',
'guid.c',
'jvs.c',
'jvs.h',
'nvram.c',
'nvram.h',
'sram.c',
'sram.h',
],
)

81
amex/nvram.c Normal file
View File

@ -0,0 +1,81 @@
#include <windows.h>
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include "amex/nvram.h"
#include "util/dprintf.h"
HRESULT nvram_open_file(HANDLE *out, wchar_t *path, size_t size)
{
LARGE_INTEGER cur_size;
LARGE_INTEGER pos;
HANDLE file;
HRESULT hr;
BOOL ok;
assert(out != NULL);
assert(path != NULL);
*out = NULL;
file = CreateFileW(
path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file == INVALID_HANDLE_VALUE) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: Error opening backing store: %x\n", path, (int) hr);
goto end;
}
ok = GetFileSizeEx(file, &cur_size);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: GetFileSizeEx failed: %x\n", path, (int) hr);
goto end;
}
if (cur_size.QuadPart != (uint64_t) size) {
pos.QuadPart = (uint64_t) size;
ok = SetFilePointerEx(file, pos, NULL, FILE_BEGIN);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: SetFilePointerEx failed: %x\n", path, (int) hr);
goto end;
}
ok = SetEndOfFile(file);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("%S: SetEndOfFile failed: %x\n", path, (int) hr);
goto end;
}
}
*out = file;
file = INVALID_HANDLE_VALUE;
hr = S_OK;
end:
if (file != INVALID_HANDLE_VALUE) {
CloseHandle(file);
}
return hr;
}

7
amex/nvram.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include <stddef.h>
HRESULT nvram_open_file(HANDLE *out, wchar_t *path, size_t size);

128
amex/sram.c Normal file
View File

@ -0,0 +1,128 @@
#include <windows.h>
#ifdef __GNUC__
#include <ntdef.h>
#else
#include <winnt.h>
#endif
#include <devioctl.h>
#include <ntdddisk.h>
#include <assert.h>
#include "amex/sram.h"
#include "amex/nvram.h"
#include "hook/iohook.h"
#include "util/dprintf.h"
#include "util/setupapi.h"
static HRESULT sram_handle_irp(struct irp *irp);
static HRESULT sram_handle_open(struct irp *irp);
static HRESULT sram_handle_close(struct irp *irp);
static HRESULT sram_handle_ioctl(struct irp *irp);
static HRESULT sram_ioctl_get_geometry(struct irp *irp);
static HANDLE sram_file;
HRESULT sram_hook_init(void)
{
HRESULT hr;
hr = nvram_open_file(&sram_file, L"DEVICE\\sram.bin", 0x80000);
if (FAILED(hr)) {
return hr;
}
hr = iohook_push_handler(sram_handle_irp);
if (FAILED(hr)) {
return hr;
}
hr = setupapi_add_phantom_dev(&sram_guid, L"$sram");
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
static HRESULT sram_handle_irp(struct irp *irp)
{
assert(irp != NULL);
if (irp->op != IRP_OP_OPEN && irp->fd != sram_file) {
return iohook_invoke_next(irp);
}
switch (irp->op) {
case IRP_OP_OPEN: return sram_handle_open(irp);
case IRP_OP_CLOSE: return sram_handle_close(irp);
case IRP_OP_IOCTL: return sram_handle_ioctl(irp);
default: return iohook_invoke_next(irp);
}
}
static HRESULT sram_handle_open(struct irp *irp)
{
if (wcscmp(irp->open_filename, L"$sram") != 0) {
return iohook_invoke_next(irp);
}
dprintf("SRAM: Open device\n");
irp->fd = sram_file;
return S_OK;
}
static HRESULT sram_handle_close(struct irp *irp)
{
dprintf("SRAM: Close device\n");
return S_OK;
}
static HRESULT sram_handle_ioctl(struct irp *irp)
{
switch (irp->ioctl) {
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
return sram_ioctl_get_geometry(irp);
default:
dprintf("SRAM: Unknown ioctl %x, write %i read %i\n",
irp->ioctl,
(int) irp->write.nbytes,
(int) irp->read.nbytes);
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
}
}
static HRESULT sram_ioctl_get_geometry(struct irp *irp)
{
DISK_GEOMETRY *out;
if (irp->read.nbytes < sizeof(*out)) {
dprintf("SRAM: Invalid ioctl response buffer size\n");
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dprintf("SRAM: Get geometry\n");
out = (DISK_GEOMETRY *) irp->read.bytes;
out->Cylinders.QuadPart = 0x20000;
out->MediaType = 0;
out->TracksPerCylinder = 1;
out->SectorsPerTrack = 1;
out->BytesPerSector = 4;
irp->read.pos = sizeof(*out);
return S_OK;
}

12
amex/sram.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <windows.h>
DEFINE_GUID(
sram_guid,
0x741B5FCA,
0x4635,
0x4443,
0xA7, 0xA0, 0x57, 0xCA, 0x7B, 0x50, 0x6A, 0x49);
HRESULT sram_hook_init(void);