From da43cc4580c011abd44a9d1fa2570806d223b6d0 Mon Sep 17 00:00:00 2001 From: Dreg Date: Sat, 26 Aug 2023 17:37:55 +0200 Subject: [PATCH] add port e9 hack support for all rings (#64) By enabling the 'all_rings' option, you can utilize the port e9 hack from ring3 IMO very useful for: - user-mode sandbox (ex Cuckoo) - malware analysis - API/SYSCALL logger with a simple hook from ring3 - automation + instrumentation from user mode code - ... So yes, from this PR a user-mode-sandbox can display on the console of the system running Bochs anything that is written to 0xE9 port ![porte9hackallrings](https://github.com/bochs-emu/Bochs/assets/9882181/ddbca3fa-729b-4a3e-95ad-078e44c7a17a) **This PR is 100% backward compatibility** btw, @stlintel I'm not certain if **bochs/config.cc** is the ideal location to define **bool port_e9_hack_all_rings** (unmapped io/dev is better?) --- bochs/.bochsrc | 4 ++- bochs/PARAM_TREE.txt | 1 + bochs/config.cc | 43 +++++++++++++++++++++++++++------ bochs/cpu/io.cc | 4 +++ bochs/doc/docbook/user/user.dbk | 6 ++++- bochs/param_names.h | 1 + 6 files changed, 49 insertions(+), 10 deletions(-) diff --git a/bochs/.bochsrc b/bochs/.bochsrc index 0c40400f1..67ef5ded5 100644 --- a/bochs/.bochsrc +++ b/bochs/.bochsrc @@ -1310,10 +1310,12 @@ speaker: enabled=1, mode=sound, volume=15 # very early when writing BIOS or OS code for example, without having to # bother with setting up a serial port or etc. Reading from port 0xE9 will # will return 0xe9 to let you know if the feature is available. -# Leave this 0 unless you have a reason to use it. +# Leave this 0 unless you have a reason to use it. By enabling the +# 'all_rings' option, you can utilize the port e9 hack from ring3. # # Example: # port_e9_hack: enabled=1 +# port_e9_hack: enabled=1, all_rings=1 #======================================================================= #port_e9_hack: enabled=1 diff --git a/bochs/PARAM_TREE.txt b/bochs/PARAM_TREE.txt index d60846685..d8f37d821 100644 --- a/bochs/PARAM_TREE.txt +++ b/bochs/PARAM_TREE.txt @@ -285,6 +285,7 @@ sound misc port_e9_hack + port_e9_hack_all_rings gdbstub port text_base diff --git a/bochs/config.cc b/bochs/config.cc index 6af2d4779..caef29812 100644 --- a/bochs/config.cc +++ b/bochs/config.cc @@ -1679,6 +1679,13 @@ void bx_init_options() "Debug messages written to i/o port 0xE9 will be displayed on console", 0); + // port e9 hack all rings + new bx_param_bool_c(misc, + "port_e9_hack_all_rings", + "Enable port 0xE9 hack for all rings", + "Debug messages written to i/o port 0xE9 from ring3 will be displayed on console", + 0); + // GDB stub menu = new bx_list_c(misc, "gdbstub", "GDB Stub Options"); menu->set_options(menu->SHOW_PARENT | menu->USE_BOX_TITLE); @@ -1763,6 +1770,7 @@ void bx_init_options() misc->add(SIM->get_param(BXPN_KBD_PASTE_DELAY)); misc->add(SIM->get_param(BXPN_USER_SHORTCUT)); misc->add(SIM->get_param(BXPN_PORT_E9_HACK)); + misc->add(SIM->get_param(BXPN_PORT_E9_HACK_ALL_RINGS)); misc->set_options(misc->SHOW_PARENT | misc->SHOW_GROUP_NAME); } @@ -2237,6 +2245,30 @@ static int parse_param_bool(const char *input, int len, const char *param) return -1; } +static int parse_port_e9_hack(const char *context, const char **params, int num_params) +{ + if (num_params > 2) { + PARSE_ERR(("%s: port_e9_hack directive: wrong # args.", context)); + } + if (strncmp(params[0], "enabled=", 8)) { + PARSE_ERR(("%s: port_e9_hack directive malformed.", context)); + } + if (parse_param_bool(params[0], 8, BXPN_PORT_E9_HACK) < 0) { + PARSE_ERR(("%s: port_e9_hack directive malformed.", context)); + } + if (num_params == 2) { + if (!strncmp(params[1], "all_rings=", 10)) { + if (parse_param_bool(params[1], 10, BXPN_PORT_E9_HACK_ALL_RINGS) < 0) { + PARSE_ERR(("%s: all_rings option malformed.", context)); + } + } else { + PARSE_ERR(("%s: port_e9_hack: invalid parameter %s", context, params[1])); + } + } + + return 0; +} + int bx_parse_param_from_list(const char *context, const char *input, bx_list_c *list) { char *propval, *property, *value; @@ -3186,14 +3218,8 @@ static int parse_line_formatted(const char *context, int num_params, char *param PARSE_ERR(("%s: print_timestamps directive malformed.", context)); } } else if (!strcmp(params[0], "port_e9_hack")) { - if (num_params != 2) { - PARSE_ERR(("%s: port_e9_hack directive: wrong # args.", context)); - } - if (strncmp(params[1], "enabled=", 8)) { - PARSE_ERR(("%s: port_e9_hack directive malformed.", context)); - } - if (parse_param_bool(params[1], 8, BXPN_PORT_E9_HACK) < 0) { - PARSE_ERR(("%s: port_e9_hack directive malformed.", context)); + if (parse_port_e9_hack(context, (const char **)(params + 1), num_params - 1) < 0) { + return -1; } } else if (!strcmp(params[0], "load32bitOSImage")) { PARSE_ERR(("%s: load32bitOSImage: This legacy feature is no longer supported.", context)); @@ -3550,6 +3576,7 @@ int bx_write_configuration(const char *rc, int overwrite) fprintf(fp, "print_timestamps: enabled=%d\n", bx_dbg.print_timestamps); bx_write_debugger_options(fp); fprintf(fp, "port_e9_hack: enabled=%d\n", SIM->get_param_bool(BXPN_PORT_E9_HACK)->get()); + fprintf(fp, "port_e9_hack_all_rings: enabled=%d\n", SIM->get_param_bool(BXPN_PORT_E9_HACK_ALL_RINGS)->get()); fprintf(fp, "private_colormap: enabled=%d\n", SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()); #if BX_WITH_AMIGAOS fprintf(fp, "fullscreen: enabled=%d\n", SIM->get_param_bool(BXPN_FULLSCREEN)->get()); diff --git a/bochs/cpu/io.cc b/bochs/cpu/io.cc index 538404440..89b8bf591 100644 --- a/bochs/cpu/io.cc +++ b/bochs/cpu/io.cc @@ -864,6 +864,10 @@ bool BX_CPP_AttrRegparmN(3) BX_CPU_C::allow_io(bxInstruction_c *i, Bit16u port, /* If CPL <= IOPL, then all IO portesses are accessible. * Otherwise, must check the IO permission map on >286. * On the 286, there is no IO permissions map */ + + static bool port_e9_hack_all_rings = SIM->get_param_bool(BXPN_PORT_E9_HACK_ALL_RINGS)->get(); + if (0xe9 == port && port_e9_hack_all_rings) + return(1); // port e9 hack can be used by unprivileged code if (BX_CPU_THIS_PTR cr0.get_PE() && (BX_CPU_THIS_PTR get_VM() || (CPL > BX_CPU_THIS_PTR get_IOPL()))) { diff --git a/bochs/doc/docbook/user/user.dbk b/bochs/doc/docbook/user/user.dbk index 2ddfa0322..b5bd606c4 100644 --- a/bochs/doc/docbook/user/user.dbk +++ b/bochs/doc/docbook/user/user.dbk @@ -5204,13 +5204,17 @@ Example: port_e9_hack: enabled=1 + + port_e9_hack: enabled=1, all_rings=1 + The 0xE9 port doesn't exists in normal ISA architecture. However, we define a convention here, to display on the console of the system running Bochs anything that is written to it. The idea is to provide debug output very early when writing BIOS or OS code for example, without having to bother with setting up a serial port or etc. Reading from port 0xE9 will will return 0xe9 to let you know if the feature is available. Leave -this 0 unless you have a reason to use it. +this 0 unless you have a reason to use it. By enabling the 'all_rings' +option, you can utilize the port e9 hack from ring3. diff --git a/bochs/param_names.h b/bochs/param_names.h index 3ae365f2a..96b6f4d69 100644 --- a/bochs/param_names.h +++ b/bochs/param_names.h @@ -175,6 +175,7 @@ #define BXPN_SOUND_SB16 "sound.sb16" #define BXPN_SOUND_ES1370 "sound.es1370" #define BXPN_PORT_E9_HACK "misc.port_e9_hack" +#define BXPN_PORT_E9_HACK_ALL_RINGS "misc.port_e9_hack_all_rings" #define BXPN_GDBSTUB "misc.gdbstub" #define BXPN_LOG_FILENAME "log.filename" #define BXPN_LOG_PREFIX "log.prefix"