Skip to content

Commit

Permalink
Added emuctrl tool
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas-jonsson committed Dec 18, 2023
1 parent 499697d commit f86e2fe
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 23 deletions.
13 changes: 11 additions & 2 deletions front/common/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,21 @@ struct frontend_keyboard_controller {
};

enum frontend_ctrl_command {
FRONTEND_CTRL_SHUTDOWN = 0x1
FRONTEND_CTRL_RESET,
FRONTEND_CTRL_SHUTDOWN,
FRONTEND_CTRL_HAS_DATA,
FRONTEND_CTRL_READ_DATA,
FRONTEND_CTRL_WRITE_DATA,
FRONTEND_CTRL_POPEN,
FRONTEND_CTRL_PCLOSE,
FRONTEND_CTRL_FCLOSE,
FRONTEND_CTRL_PUSH,
FRONTEND_CTRL_PULL
};

struct frontend_ctrl_interface {
void *userdata;
vxt_byte (*callback)(enum frontend_ctrl_command cmd, void *userdata);
vxt_byte (*callback)(enum frontend_ctrl_command cmd, vxt_byte data, void *userdata);
};

struct frontend_disk_interface {
Expand Down
96 changes: 92 additions & 4 deletions front/sdl/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ char new_floppy_image_path[FILENAME_MAX] = {0};

bool config_updated = false;

#define EMUCTRL_BUFFER_SIZE 1024
vxt_byte emuctrl_buffer[EMUCTRL_BUFFER_SIZE] = {0};
int emuctrl_buffer_len = 0;
FILE *emuctrl_file_handle = NULL;
bool emuctrl_is_popen_handle = false;

int str_buffer_len = 0;
char *str_buffer = NULL;

Expand Down Expand Up @@ -404,11 +410,93 @@ static const char *resolve_path(enum frontend_path_type type, const char *path)
return buffer;
}

static vxt_byte emu_control(enum frontend_ctrl_command cmd, void *userdata) {
static vxt_byte emu_control(enum frontend_ctrl_command cmd, vxt_byte data, void *userdata) {
(void)userdata;
if (cmd == FRONTEND_CTRL_SHUTDOWN) {
printf("Guest OS shutdown!\n");
SDL_AtomicSet(&running, 0);

switch (cmd) {
case FRONTEND_CTRL_RESET:
emuctrl_buffer_len = 0;
if (emuctrl_file_handle) {
if (emuctrl_is_popen_handle)
#ifdef _WIN32
_pclose
#else
pclose
#endif
(emuctrl_file_handle);
else
fclose(emuctrl_file_handle);
}
emuctrl_file_handle = NULL;
emuctrl_is_popen_handle = false;
break;
case FRONTEND_CTRL_SHUTDOWN:
printf("Guest OS shutdown!\n");
SDL_AtomicSet(&running, 0);
break;
case FRONTEND_CTRL_HAS_DATA:
if (emuctrl_file_handle) {
int ch = fgetc(emuctrl_file_handle);
if (ch & ~0xFF) {
return 0;
} else {
ungetc(ch, emuctrl_file_handle);
return 1;
}
}
return emuctrl_buffer_len ? 1 : 0;
case FRONTEND_CTRL_READ_DATA:
if (emuctrl_file_handle)
return (vxt_byte)fgetc(emuctrl_file_handle);
else if (emuctrl_buffer_len)
return emuctrl_buffer[--emuctrl_buffer_len];
break;
case FRONTEND_CTRL_WRITE_DATA:
if (emuctrl_file_handle && !emuctrl_is_popen_handle)
return (fputc(data, emuctrl_file_handle) == data) ? 0 : 1;
if (emuctrl_buffer_len >= EMUCTRL_BUFFER_SIZE)
return 1;
emuctrl_buffer[emuctrl_buffer_len++] = data;
break;
case FRONTEND_CTRL_POPEN:
if (!(emuctrl_file_handle =
#ifdef _WIN32
_popen
#else
popen
#endif
((char*)emuctrl_buffer, "r"))
) {
printf("FRONTEND_CTRL_POPEN: popen failed!\n");
return 1;
}
printf("FRONTEND_CTRL_POPEN: \"%s\"\n", (char*)emuctrl_buffer);
emuctrl_buffer_len = 0;
emuctrl_is_popen_handle = true;
break;
case FRONTEND_CTRL_PCLOSE:
if (!emuctrl_is_popen_handle)
return 1;
if (emuctrl_file_handle)
pclose(emuctrl_file_handle);
emuctrl_file_handle = NULL;
emuctrl_is_popen_handle = false;
break;
case FRONTEND_CTRL_FCLOSE:
if (emuctrl_is_popen_handle)
return 1;
if (emuctrl_file_handle)
fclose(emuctrl_file_handle);
emuctrl_file_handle = NULL;
break;
case FRONTEND_CTRL_PUSH:
case FRONTEND_CTRL_PULL:
if (!(emuctrl_file_handle = fopen((char*)emuctrl_buffer, (cmd == FRONTEND_CTRL_PUSH) ? "wb" : "rb"))) {
printf("FRONTEND_CTRL_PUSH/PULL: fopen failed!\n");
return 1;
}
emuctrl_buffer_len = 0;
break;
}
return 0;
}
Expand Down
4 changes: 2 additions & 2 deletions front/web/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ static bool set_mouse_adapter(const struct frontend_mouse_adapter *adapter) {
return true;
}

static vxt_byte emu_control(enum frontend_ctrl_command cmd, void *userdata) {
(void)userdata;
static vxt_byte emu_control(enum frontend_ctrl_command cmd, vxt_byte data, void *userdata) {
(void)data; (void)userdata;
if (cmd == FRONTEND_CTRL_SHUTDOWN) {
LOG("Guest OS shutdown!");
js_shutdown();
Expand Down
26 changes: 11 additions & 15 deletions modules/ctrl/ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,29 @@

struct ctrl {
vxt_byte ret;
vxt_byte (*callback)(enum frontend_ctrl_command,void*);
vxt_byte (*callback)(enum frontend_ctrl_command,vxt_byte,void*);
void *userdata;

int state;
};

static vxt_byte in(struct ctrl *c, vxt_word port) {
(void)port;
vxt_byte r = c->ret;
c->ret = 0;
return r;
if (!c->callback) {
return 0;
}
return (port == 0xB5) ? c->callback(FRONTEND_CTRL_READ_DATA, 0, c->userdata) : c->ret;
}

static void out(struct ctrl *c, vxt_word port, vxt_byte data) {
(void)port;
if (!c->callback)
if (!c->callback) {
return;
switch (data) {
case 0: // Reset controller
c->ret = 0;
break;
case 1: // Shutdown
c->ret = c->callback(FRONTEND_CTRL_SHUTDOWN, c->userdata);
break;
}
}
c->ret = (port == 0xB5) ? c->callback(FRONTEND_CTRL_WRITE_DATA, data, c->userdata) : c->callback((enum frontend_ctrl_command)data, 0, c->userdata);
}

static vxt_error install(struct ctrl *c, vxt_system *s) {
vxt_system_install_io_at(s, VXT_GET_PIREPHERAL(c), 0xB4);
vxt_system_install_io(s, VXT_GET_PIREPHERAL(c), 0xB4, 0xB5);
return VXT_NO_ERROR;
}

Expand Down
4 changes: 4 additions & 0 deletions tools/emuctrl/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh

bcc -0 -Md -o emuctrl.com -ansi emuctrl.c
mv emuctrl.com ../../
176 changes: 176 additions & 0 deletions tools/emuctrl/emuctrl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

#if !defined(__BCC__) || !defined(__MSDOS__)
#error Use BCC to produce MSDOS executable!
#endif

#ifdef __FIST_ARG_IN_AX__
#error Unexpected calling convension!
#endif

/* Should be synced with frontend.h */
enum {
FRONTEND_CTRL_RESET,
FRONTEND_CTRL_SHUTDOWN,
FRONTEND_CTRL_HAS_DATA,
FRONTEND_CTRL_READ_DATA,
FRONTEND_CTRL_WRITE_DATA,
FRONTEND_CTRL_POPEN,
FRONTEND_CTRL_PCLOSE,
FRONTEND_CTRL_FCLOSE,
FRONTEND_CTRL_PUSH,
FRONTEND_CTRL_PULL
};

static int read_status(void) {
#asm
xor ax, ax
in al, 0xB4
#endasm
}

static void write_command_(unsigned char c) {
#asm
push bx
mov bx, sp
mov al, [bx+4]
out 0xB4, al
pop bx
#endasm
}

static int write_command(unsigned char c) {
write_command_(c);
return read_status();
}

static void reset(void) {
int status = write_command(FRONTEND_CTRL_RESET);
assert(!status);
}

static void write_data(unsigned char c) {
#asm
push bx
mov bx, sp
mov al, [bx+4]
out 0xB5, al
pop bx
#endasm
}

static unsigned char read_data(void) {
#asm
xor ax, ax
in al, 0xB5
#endasm
}

static void print_help(void) {
printf(
"Usage: emuctrl [cmd] <args...>\n\n"
" shutdown Terminates the emulator\n"
" popen <args...> Execute command on host and pipe input to guest\n"
" push [src] [dest] Upload file from guest to host\n"
" pull [src] [dest] Download file from host to guest\n"
"\n"
);
exit(-1);
}

char buffer[256] = {0};

int main(int argc, char *argv[]) {
int i;
char *ptr;
FILE *fp;

if (write_command(FRONTEND_CTRL_RESET) != 0) {
printf("Make sure the VirtualXT 'ctrl' module is loaded.\n");
return -1;
}

if (argc < 2)
print_help();

if (!strcmp(argv[1], "shutdown")) {
reset();
write_command(FRONTEND_CTRL_SHUTDOWN);
} else if (!strcmp(argv[1], "popen")) {
if (argc < 3) {
printf("Host Command: ");
gets(buffer);
} else for (i = 2; i < argc; i++) {
if (i > 2)
strcat(buffer, " ");
strcat(buffer, argv[i]);
}

reset();
for (ptr = buffer; *ptr; ptr++)
write_data(*ptr);
write_data(0);

if (write_command(FRONTEND_CTRL_POPEN)) {
printf("Could not open process: %s\n", argv[2]);
return -1;
}

while (write_command(FRONTEND_CTRL_HAS_DATA))
putc(read_data(), stdout);
write_command(FRONTEND_CTRL_PCLOSE);
} else if (!strcmp(argv[1], "push")) {
if (argc < 4)
print_help();

reset();
for (ptr = argv[3]; *ptr; ptr++)
write_data(*ptr);
write_data(0);

if (write_command(FRONTEND_CTRL_PUSH)) {
printf("Could not copy: %s -> %s\n", argv[2], argv[3]);
return -1;
}

if (!(fp = fopen(argv[2], "rb"))) {
printf("Could not open: %s\n", argv[2]);
return -1;
}

while ((i = fgetc(fp)) != EOF)
write_data(i);

write_command(FRONTEND_CTRL_FCLOSE);
fclose(fp);
} else if (!strcmp(argv[1], "pull")) {
if (argc < 4)
print_help();

reset();
for (ptr = argv[2]; *ptr; ptr++)
write_data(*ptr);
write_data(0);

if (write_command(FRONTEND_CTRL_PULL)) {
printf("Could not copy: %s -> %s\n", argv[2], argv[3]);
return -1;
}

if (!(fp = fopen(argv[3], "wb"))) {
printf("Could not open: %s\n", argv[3]);
return -1;
}

while (write_command(FRONTEND_CTRL_HAS_DATA))
fputc(read_data(), fp);

write_command(FRONTEND_CTRL_FCLOSE);
fclose(fp);
} else {
print_help();
}
return 0;
}

0 comments on commit f86e2fe

Please sign in to comment.