diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 5845158..2dfe964 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -634,7 +634,13 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
 
     /* Second part of the bootloader */
     p = (uint32_t *) (base + 0x580);
-    stl_p(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
+
+    if (semihosting_enabled) {
+        /* Preserve a0 content when semihosting is enabled. */
+        stl_p(p++, 0x00000000);                         /* nop */
+    } else {
+        stl_p(p++, 0x24040002);                         /* addiu a0, zero, 2 */
+    }
     stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
     stl_p(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
     stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 1ab7063..7d63da2 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -125,6 +125,8 @@ extern int graphic_rotate;
 extern int no_quit;
 extern int no_shutdown;
 extern int semihosting_enabled;
+extern const char **semihosting_argv;
+extern int semihosting_argc;
 extern int old_param;
 extern int boot_menu;
 extern bool boot_strict;
diff --git a/qemu-options.hx b/qemu-options.hx
index 99ad1ae..bd058d0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3240,6 +3240,14 @@ Enable semihosting and define where the semihosting calls will be addressed,
 to QEMU (@code{native}) or to GDB (@code{gdb}). The default is @code{auto}, which means
 @code{gdb} during debug sessions and @code{native} otherwise (ARM, M68K, Xtensa only).
 ETEXI
+DEF("semihosting-arg", HAS_ARG, QEMU_OPTION_semihosting_arg,
+    "-semihosting-arg    arguments passed to the guest program\n",
+    QEMU_ARCH_MIPS)
+STEXI
+@item -semihosting-arg
+@findex -semihosting-arg
+Arguments passed to the guest program (MIPS only).
+ETEXI
 DEF("old-param", 0, QEMU_OPTION_old_param,
     "-old-param      old param mode\n", QEMU_ARCH_ARM)
 STEXI
diff --git a/target-mips/mips-semi.c b/target-mips/mips-semi.c
index 3bf7b2a..63f2700 100644
--- a/target-mips/mips-semi.c
+++ b/target-mips/mips-semi.c
@@ -21,6 +21,9 @@
 #include "cpu.h"
 #include "exec/helper-proto.h"
 #include "exec/softmmu-semi.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu/sysemu.h"
+#endif
 
 typedef enum UHIOp {
     UHI_exit = 1,
@@ -71,6 +74,12 @@ enum UHIOpenFlags {
     UHIOpen_EXCL   = 0x800
 };
 
+#ifdef CONFIG_USER_ONLY
+/* Suppress compiler errors in linux-user. */
+static const char **semihosting_argv;
+static int semihosting_argc;
+#endif
+
 static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
                                 target_ulong vaddr)
 {
@@ -169,6 +178,21 @@ static int read_from_file(CPUMIPSState *env, target_ulong fd,
     return num_of_bytes;
 }
 
+static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
+                               target_ulong vaddr)
+{
+    int strsize = strlen(semihosting_argv[arg_num]) + 1;
+    char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
+    if (!dst) {
+        return -1;
+    }
+
+    strcpy(dst, semihosting_argv[arg_num]);
+
+    unlock_user(dst, vaddr, strsize);
+    return 0;
+}
+
 #define GET_TARGET_STRING(p, addr)              \
     do {                                        \
         p = lock_user_string(addr);             \
@@ -248,9 +272,21 @@ void helper_do_semihosting(CPUMIPSState *env)
         }
         break;
     case UHI_argc:
+        gpr[2] = semihosting_argc;
+        break;
     case UHI_argnlen:
+        if (gpr[4] >= semihosting_argc) {
+            gpr[2] = -1;
+            goto uhi_done;
+        }
+        gpr[2] = strlen(semihosting_argv[gpr[4]]);
+        break;
     case UHI_argn:
-        /* TODO */
+        if (gpr[4] >= semihosting_argc) {
+            gpr[2] = -1;
+            goto uhi_done;
+        }
+        gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
         break;
     case UHI_plog:
         GET_TARGET_STRING(p, gpr[4]);
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 82fa5a4..678c3d5 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -19652,6 +19652,13 @@ void cpu_state_reset(CPUMIPSState *env)
     restore_rounding_mode(env);
     restore_flush_mode(env);
     cs->exception_index = EXCP_NONE;
+
+#ifndef CONFIG_USER_ONLY
+    if (semihosting_enabled) {
+        /* When $4 is -1 the UHI interface will be used for argc and argv */
+        env->active_tc.gpr[4] = -1;
+    }
+#endif
 }
 
 void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos)
diff --git a/vl.c b/vl.c
index e1ffd0a..b2d3422 100644
--- a/vl.c
+++ b/vl.c
@@ -169,6 +169,8 @@ const char *watchdog;
 QEMUOptionRom option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
 int semihosting_enabled = 0;
+const char **semihosting_argv;
+int semihosting_argc;
 int old_param = 0;
 const char *qemu_name;
 int alt_grab = 0;
@@ -3560,6 +3562,22 @@ int main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
+            case QEMU_OPTION_semihosting_arg:
+                if (semihosting_argc == 0) {
+                    /* If arguments are present then the first argument goes to
+                       argv[1] as argv[0] is reserved for the program name */
+                    semihosting_argc = 2;
+                    semihosting_argv =
+                        g_malloc(semihosting_argc * sizeof(void *));
+                    semihosting_argv[1] = optarg;
+                } else {
+                    semihosting_argc++;
+                    semihosting_argv =
+                        g_realloc(semihosting_argv,
+                                  semihosting_argc * sizeof(void *));
+                    semihosting_argv[semihosting_argc - 1] = optarg;
+                }
+                break;
             case QEMU_OPTION_tdf:
                 fprintf(stderr, "Warning: user space PIT time drift fix "
                                 "is no longer supported.\n");
@@ -4078,6 +4096,16 @@ int main(int argc, char **argv, char **envp)
         current_machine->kernel_cmdline = (char *)kernel_cmdline;
     }
 
+    if (semihosting_argc) {
+        if (kernel_filename) {
+            semihosting_argv[0] = kernel_filename;
+        } else if (bios_name) {
+            semihosting_argv[0] = bios_name;
+        } else {
+            semihosting_argv[0] = "";
+        }
+    }
+
     linux_boot = (kernel_filename != NULL);
 
     if (!linux_boot && *kernel_cmdline != '\0') {
