summary refs log tree commit diff stats
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/alpha/cpu.c15
-rw-r--r--target/alpha/cpu.h3
-rw-r--r--target/arm/cpu.h3
-rw-r--r--target/cris/cpu.h3
-rw-r--r--target/hppa/cpu.c15
-rw-r--r--target/hppa/cpu.h2
-rw-r--r--target/i386/cpu.c15
-rw-r--r--target/i386/cpu.h3
-rw-r--r--target/lm32/cpu.c15
-rw-r--r--target/lm32/cpu.h3
-rw-r--r--target/m68k/cpu.h3
-rw-r--r--target/microblaze/cpu.h2
-rw-r--r--target/mips/cpu.h3
-rw-r--r--target/moxie/cpu.h3
-rw-r--r--target/nios2/cpu.h2
-rw-r--r--target/openrisc/cpu.h3
-rw-r--r--target/ppc/cpu.h3
-rw-r--r--target/ppc/translate.c9
-rw-r--r--target/riscv/cpu.c12
-rw-r--r--target/riscv/cpu.h1
-rw-r--r--target/s390x/cpu.h3
-rw-r--r--target/s390x/cpu_models.c2
-rw-r--r--target/sh4/cpu.c15
-rw-r--r--target/sh4/cpu.h3
-rw-r--r--target/sparc/cpu.h5
-rw-r--r--target/tilegx/cpu.h2
-rw-r--r--target/tricore/cpu.h3
-rw-r--r--target/tricore/helper.c2
-rw-r--r--target/unicore32/cpu.h3
-rw-r--r--target/xtensa/Makefile.objs3
-rw-r--r--target/xtensa/cpu.c26
-rw-r--r--target/xtensa/cpu.h63
-rw-r--r--target/xtensa/gdbstub.c14
-rw-r--r--target/xtensa/helper.c59
-rw-r--r--target/xtensa/helper.h4
-rw-r--r--target/xtensa/op_helper.c50
-rw-r--r--target/xtensa/overlay_tool.h11
-rw-r--r--target/xtensa/translate.c99
38 files changed, 302 insertions, 183 deletions
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
index 55675ce419..b08078e7fc 100644
--- a/target/alpha/cpu.c
+++ b/target/alpha/cpu.c
@@ -71,18 +71,6 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)
     acc->parent_realize(dev, errp);
 }
 
-/* Sort alphabetically by type name. */
-static gint alpha_cpu_list_compare(gconstpointer a, gconstpointer b)
-{
-    ObjectClass *class_a = (ObjectClass *)a;
-    ObjectClass *class_b = (ObjectClass *)b;
-    const char *name_a, *name_b;
-
-    name_a = object_class_get_name(class_a);
-    name_b = object_class_get_name(class_b);
-    return strcmp(name_a, name_b);
-}
-
 static void alpha_cpu_list_entry(gpointer data, gpointer user_data)
 {
     ObjectClass *oc = data;
@@ -100,8 +88,7 @@ void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     };
     GSList *list;
 
-    list = object_class_get_list(TYPE_ALPHA_CPU, false);
-    list = g_slist_sort(list, alpha_cpu_list_compare);
+    list = object_class_get_list_sorted(TYPE_ALPHA_CPU, false);
     (*cpu_fprintf)(f, "Available CPUs:\n");
     g_slist_foreach(list, alpha_cpu_list_entry, &s);
     g_slist_free(list);
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index a79fc2e780..7b50be785d 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -466,10 +466,9 @@ enum {
 
 void alpha_translate_init(void);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_ALPHA_CPU, cpu_model)
-
 #define ALPHA_CPU_TYPE_SUFFIX "-" TYPE_ALPHA_CPU
 #define ALPHA_CPU_TYPE_NAME(model) model ALPHA_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_ALPHA_CPU
 
 void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 1e7e1f8a7e..19a0c03f9b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2302,10 +2302,9 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
     return unmasked || pstate_unmasked;
 }
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_ARM_CPU, cpu_model)
-
 #define ARM_CPU_TYPE_SUFFIX "-" TYPE_ARM_CPU
 #define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
+#define CPU_RESOLVING_TYPE TYPE_ARM_CPU
 
 #define cpu_signal_handler cpu_arm_signal_handler
 #define cpu_list arm_cpu_list
diff --git a/target/cris/cpu.h b/target/cris/cpu.h
index 764b35cbae..8bb1dbc989 100644
--- a/target/cris/cpu.h
+++ b/target/cris/cpu.h
@@ -267,10 +267,9 @@ enum {
 #define TARGET_PHYS_ADDR_SPACE_BITS 32
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_CRIS_CPU, cpu_model)
-
 #define CRIS_CPU_TYPE_SUFFIX "-" TYPE_CRIS_CPU
 #define CRIS_CPU_TYPE_NAME(name) (name CRIS_CPU_TYPE_SUFFIX)
+#define CPU_RESOLVING_TYPE TYPE_CRIS_CPU
 
 #define cpu_signal_handler cpu_cris_signal_handler
 
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index 969f628f0a..c261b6b090 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -110,18 +110,6 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)
 #endif
 }
 
-/* Sort hppabetically by type name. */
-static gint hppa_cpu_list_compare(gconstpointer a, gconstpointer b)
-{
-    ObjectClass *class_a = (ObjectClass *)a;
-    ObjectClass *class_b = (ObjectClass *)b;
-    const char *name_a, *name_b;
-
-    name_a = object_class_get_name(class_a);
-    name_b = object_class_get_name(class_b);
-    return strcmp(name_a, name_b);
-}
-
 static void hppa_cpu_list_entry(gpointer data, gpointer user_data)
 {
     ObjectClass *oc = data;
@@ -138,8 +126,7 @@ void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     };
     GSList *list;
 
-    list = object_class_get_list(TYPE_HPPA_CPU, false);
-    list = g_slist_sort(list, hppa_cpu_list_compare);
+    list = object_class_get_list_sorted(TYPE_HPPA_CPU, false);
     (*cpu_fprintf)(f, "Available CPUs:\n");
     g_slist_foreach(list, hppa_cpu_list_entry, &s);
     g_slist_free(list);
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index c88d844938..19dd12a93e 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -266,7 +266,7 @@ static inline int cpu_mmu_index(CPUHPPAState *env, bool ifetch)
 
 void hppa_translate_init(void);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_HPPA_CPU, cpu_model)
+#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
 
 void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 6bb4ce8719..555ae79d29 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -195,6 +195,8 @@
  * bit[02]: Support Single-Range Output scheme;
  */
 #define INTEL_PT_MINIMAL_ECX     0x7
+/* generated packets which contain IP payloads have LIP values */
+#define INTEL_PT_IP_LIP          (1 << 31)
 #define INTEL_PT_ADDR_RANGES_NUM 0x2 /* Number of configurable address ranges */
 #define INTEL_PT_ADDR_RANGES_NUM_MASK 0x3
 #define INTEL_PT_MTC_BITMAP      (0x0249 << 16) /* Support ART(0,3,6,9) */
@@ -781,13 +783,7 @@ static char *x86_cpu_type_name(const char *model_name)
 static ObjectClass *x86_cpu_class_by_name(const char *cpu_model)
 {
     ObjectClass *oc;
-    char *typename;
-
-    if (cpu_model == NULL) {
-        return NULL;
-    }
-
-    typename = x86_cpu_type_name(cpu_model);
+    char *typename = x86_cpu_type_name(cpu_model);
     oc = object_class_by_name(typename);
     g_free(typename);
     return oc;
@@ -3141,7 +3137,7 @@ arch_query_cpu_model_expansion(CpuModelExpansionType type,
 
     xc = x86_cpu_from_model(model->name,
                             model->has_props ?
-                                qobject_to_qdict(model->props) :
+                                qobject_to(QDict, model->props) :
                                 NULL, &err);
     if (err) {
         goto out;
@@ -4173,7 +4169,8 @@ static int x86_cpu_filter_features(X86CPU *cpu)
            ((eax_1 & INTEL_PT_ADDR_RANGES_NUM_MASK) <
                                            INTEL_PT_ADDR_RANGES_NUM) ||
            ((ebx_1 & (INTEL_PT_PSB_BITMAP | INTEL_PT_CYCLE_BITMAP)) !=
-                (INTEL_PT_PSB_BITMAP | INTEL_PT_CYCLE_BITMAP))) {
+                (INTEL_PT_PSB_BITMAP | INTEL_PT_CYCLE_BITMAP)) ||
+           (ecx_0 & INTEL_PT_IP_LIP)) {
             /*
              * Processor Trace capabilities aren't configurable, so if the
              * host can't emulate the capabilities we report on
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 2e2bab5ff3..78db1b833a 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1589,10 +1589,9 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 
 #define PHYS_ADDR_MASK MAKE_64BIT_MASK(0, TCG_PHYS_ADDR_BITS)
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_X86_CPU, cpu_model)
-
 #define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU
 #define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
+#define CPU_RESOLVING_TYPE TYPE_X86_CPU
 
 #ifdef TARGET_X86_64
 #define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu64")
diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c
index 96c2499d0b..0003152469 100644
--- a/target/lm32/cpu.c
+++ b/target/lm32/cpu.c
@@ -32,18 +32,6 @@ static void lm32_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
-/* Sort alphabetically by type name. */
-static gint lm32_cpu_list_compare(gconstpointer a, gconstpointer b)
-{
-    ObjectClass *class_a = (ObjectClass *)a;
-    ObjectClass *class_b = (ObjectClass *)b;
-    const char *name_a, *name_b;
-
-    name_a = object_class_get_name(class_a);
-    name_b = object_class_get_name(class_b);
-    return strcmp(name_a, name_b);
-}
-
 static void lm32_cpu_list_entry(gpointer data, gpointer user_data)
 {
     ObjectClass *oc = data;
@@ -65,8 +53,7 @@ void lm32_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     };
     GSList *list;
 
-    list = object_class_get_list(TYPE_LM32_CPU, false);
-    list = g_slist_sort(list, lm32_cpu_list_compare);
+    list = object_class_get_list_sorted(TYPE_LM32_CPU, false);
     (*cpu_fprintf)(f, "Available CPUs:\n");
     g_slist_foreach(list, lm32_cpu_list_entry, &s);
     g_slist_free(list);
diff --git a/target/lm32/cpu.h b/target/lm32/cpu.h
index ce0a2f24c4..66157eefe9 100644
--- a/target/lm32/cpu.h
+++ b/target/lm32/cpu.h
@@ -255,10 +255,9 @@ void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address,
 void lm32_watchpoint_remove(CPULM32State *env, int index);
 bool lm32_cpu_do_semihosting(CPUState *cs);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_LM32_CPU, cpu_model)
-
 #define LM32_CPU_TYPE_SUFFIX "-" TYPE_LM32_CPU
 #define LM32_CPU_TYPE_NAME(model) model LM32_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_LM32_CPU
 
 #define cpu_list lm32_cpu_list
 #define cpu_signal_handler cpu_lm32_signal_handler
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 2259bf22dc..c63adf772f 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -527,10 +527,9 @@ enum {
 #define TARGET_PHYS_ADDR_SPACE_BITS 32
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_M68K_CPU, cpu_model)
-
 #define M68K_CPU_TYPE_SUFFIX "-" TYPE_M68K_CPU
 #define M68K_CPU_TYPE_NAME(model) model M68K_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_M68K_CPU
 
 #define cpu_signal_handler cpu_m68k_signal_handler
 #define cpu_list m68k_cpu_list
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 1fe21c8539..5be71bc320 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -343,7 +343,7 @@ int cpu_mb_signal_handler(int host_signum, void *pinfo,
 #define TARGET_PHYS_ADDR_SPACE_BITS 32
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_MICROBLAZE_CPU, cpu_model)
+#define CPU_RESOLVING_TYPE TYPE_MICROBLAZE_CPU
 
 #define cpu_signal_handler cpu_mb_signal_handler
 
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 7f8ba5ff3e..cfe1735e0e 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -739,10 +739,9 @@ enum {
 
 int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_MIPS_CPU, cpu_model)
-
 #define MIPS_CPU_TYPE_SUFFIX "-" TYPE_MIPS_CPU
 #define MIPS_CPU_TYPE_NAME(model) model MIPS_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_MIPS_CPU
 
 bool cpu_supports_cps_smp(const char *cpu_type);
 bool cpu_supports_isa(const char *cpu_type, unsigned int isa);
diff --git a/target/moxie/cpu.h b/target/moxie/cpu.h
index d85e1fc061..d40f1e6c45 100644
--- a/target/moxie/cpu.h
+++ b/target/moxie/cpu.h
@@ -119,10 +119,9 @@ void moxie_translate_init(void);
 int cpu_moxie_signal_handler(int host_signum, void *pinfo,
                              void *puc);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_MOXIE_CPU, cpu_model)
-
 #define MOXIE_CPU_TYPE_SUFFIX "-" TYPE_MOXIE_CPU
 #define MOXIE_CPU_TYPE_NAME(model) model MOXIE_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_MOXIE_CPU
 
 #define cpu_signal_handler cpu_moxie_signal_handler
 
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index cd4e40d1b4..145796e8ce 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -230,7 +230,7 @@ void nios2_check_interrupts(CPUNios2State *env);
 # define TARGET_VIRT_ADDR_SPACE_BITS 32
 #endif
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_NIOS2_CPU, cpu_model)
+#define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU
 
 #define cpu_gen_code cpu_nios2_gen_code
 #define cpu_signal_handler cpu_nios2_signal_handler
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 5050b1135c..35cab65f11 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -389,10 +389,9 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
                                int *prot, target_ulong address, int rw);
 #endif
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_OPENRISC_CPU, cpu_model)
-
 #define OPENRISC_CPU_TYPE_SUFFIX "-" TYPE_OPENRISC_CPU
 #define OPENRISC_CPU_TYPE_NAME(model) model OPENRISC_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_OPENRISC_CPU
 
 #include "exec/cpu-all.h"
 
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7bde1884a1..c621a6bd5e 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1375,10 +1375,9 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
 int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp);
 int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_POWERPC_CPU, cpu_model)
-
 #define POWERPC_CPU_TYPE_SUFFIX "-" TYPE_POWERPC_CPU
 #define POWERPC_CPU_TYPE_NAME(model) model POWERPC_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_POWERPC_CPU
 
 #define cpu_signal_handler cpu_ppc_signal_handler
 #define cpu_list ppc_cpu_list
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 0a0c090c99..218665b408 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4526,7 +4526,7 @@ static void gen_tlbie(DisasContext *ctx)
     TCGv_i32 t1;
 
     if (ctx->gtse) {
-        CHK_SV; /* If gtse is set then tblie is supervisor privileged */
+        CHK_SV; /* If gtse is set then tlbie is supervisor privileged */
     } else {
         CHK_HV; /* Else hypervisor privileged */
     }
@@ -4553,7 +4553,12 @@ static void gen_tlbsync(DisasContext *ctx)
 #if defined(CONFIG_USER_ONLY)
     GEN_PRIV;
 #else
-    CHK_HV;
+
+    if (ctx->gtse) {
+        CHK_SV; /* If gtse is set then tlbsync is supervisor privileged */
+    } else {
+        CHK_HV; /* Else hypervisor privileged */
+    }
 
     /* BookS does both ptesync and tlbsync make tlbsync a nop for server */
     if (ctx->insns_flags & PPC_BOOKE) {
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 4851890844..9de34d7099 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -391,16 +391,16 @@ static const TypeInfo riscv_cpu_type_info = {
 char *riscv_isa_string(RISCVCPU *cpu)
 {
     int i;
-    size_t maxlen = 5 + ctz32(cpu->env.misa);
-    char *isa_string = g_new0(char, maxlen);
-    snprintf(isa_string, maxlen, "rv%d", TARGET_LONG_BITS);
+    const size_t maxlen = sizeof("rv128") + sizeof(riscv_exts) + 1;
+    char *isa_str = g_new(char, maxlen);
+    char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS);
     for (i = 0; i < sizeof(riscv_exts); i++) {
         if (cpu->env.misa & RV(riscv_exts[i])) {
-            isa_string[strlen(isa_string)] = riscv_exts[i] - 'A' + 'a';
-
+            *p++ = qemu_tolower(riscv_exts[i]);
         }
     }
-    return isa_string;
+    *p = '\0';
+    return isa_str;
 }
 
 void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index cff02a2857..41e06ac0f9 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -46,6 +46,7 @@
 
 #define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU
 #define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX)
+#define CPU_RESOLVING_TYPE TYPE_RISCV_CPU
 
 #define TYPE_RISCV_CPU_ANY              RISCV_CPU_TYPE_NAME("any")
 #define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1")
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 5f357a4e2d..3ee40f08b7 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -719,10 +719,9 @@ void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga,
 
 
 /* helper.c */
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_S390_CPU, cpu_model)
-
 #define S390_CPU_TYPE_SUFFIX "-" TYPE_S390_CPU
 #define S390_CPU_TYPE_NAME(name) (name S390_CPU_TYPE_SUFFIX)
+#define CPU_RESOLVING_TYPE TYPE_S390_CPU
 
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 1d5f0da4fe..2741b6803f 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -453,7 +453,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
     Object *obj;
 
     if (info->props) {
-        qdict = qobject_to_qdict(info->props);
+        qdict = qobject_to(QDict, info->props);
         if (!qdict) {
             error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
             return;
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index 6302cfda3a..541ffc2d97 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -85,18 +85,6 @@ typedef struct SuperHCPUListState {
     FILE *file;
 } SuperHCPUListState;
 
-/* Sort alphabetically by type name. */
-static gint superh_cpu_list_compare(gconstpointer a, gconstpointer b)
-{
-    ObjectClass *class_a = (ObjectClass *)a;
-    ObjectClass *class_b = (ObjectClass *)b;
-    const char *name_a, *name_b;
-
-    name_a = object_class_get_name(class_a);
-    name_b = object_class_get_name(class_b);
-    return strcmp(name_a, name_b);
-}
-
 static void superh_cpu_list_entry(gpointer data, gpointer user_data)
 {
     SuperHCPUListState *s = user_data;
@@ -114,8 +102,7 @@ void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     };
     GSList *list;
 
-    list = object_class_get_list(TYPE_SUPERH_CPU, false);
-    list = g_slist_sort(list, superh_cpu_list_compare);
+    list = object_class_get_list_sorted(TYPE_SUPERH_CPU, false);
     g_slist_foreach(list, superh_cpu_list_entry, &s);
     g_slist_free(list);
 }
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index a649b68d78..775b5743bf 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -272,10 +272,9 @@ int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr);
 
 void cpu_load_tlb(CPUSH4State * env);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_SUPERH_CPU, cpu_model)
-
 #define SUPERH_CPU_TYPE_SUFFIX "-" TYPE_SUPERH_CPU
 #define SUPERH_CPU_TYPE_NAME(model) model SUPERH_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_SUPERH_CPU
 
 #define cpu_signal_handler cpu_sh4_signal_handler
 #define cpu_list sh4_cpu_list
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 9724134a5b..4972ebcfd4 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -652,12 +652,9 @@ hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
 #endif
 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 
-#ifndef NO_CPU_IO_DEFS
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_SPARC_CPU, cpu_model)
-#endif
-
 #define SPARC_CPU_TYPE_SUFFIX "-" TYPE_SPARC_CPU
 #define SPARC_CPU_TYPE_NAME(model) model SPARC_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_SPARC_CPU
 
 #define cpu_signal_handler cpu_sparc_signal_handler
 #define cpu_list sparc_cpu_list
diff --git a/target/tilegx/cpu.h b/target/tilegx/cpu.h
index 71cea04589..238f8d36d7 100644
--- a/target/tilegx/cpu.h
+++ b/target/tilegx/cpu.h
@@ -164,7 +164,7 @@ static inline TileGXCPU *tilegx_env_get_cpu(CPUTLGState *env)
 void tilegx_tcg_init(void);
 int cpu_tilegx_signal_handler(int host_signum, void *pinfo, void *puc);
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_TILEGX_CPU, cpu_model)
+#define CPU_RESOLVING_TYPE TYPE_TILEGX_CPU
 
 #define cpu_signal_handler cpu_tilegx_signal_handler
 
diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h
index 07b8b59f58..c3665c6ddd 100644
--- a/target/tricore/cpu.h
+++ b/target/tricore/cpu.h
@@ -413,10 +413,9 @@ static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc,
     *flags = 0;
 }
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_TRICORE_CPU, cpu_model)
-
 #define TRICORE_CPU_TYPE_SUFFIX "-" TYPE_TRICORE_CPU
 #define TRICORE_CPU_TYPE_NAME(model) model TRICORE_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_TRICORE_CPU
 
 /* helpers.c */
 int cpu_tricore_handle_mmu_fault(CPUState *cpu, target_ulong address,
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
index 45276d3782..dad7eea085 100644
--- a/target/tricore/helper.c
+++ b/target/tricore/helper.c
@@ -101,7 +101,7 @@ void tricore_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     };
     GSList *list;
 
-    list = object_class_get_list(TYPE_TRICORE_CPU, false);
+    list = object_class_get_list_sorted(TYPE_TRICORE_CPU, false);
     (*cpu_fprintf)(f, "Available CPUs:\n");
     g_slist_foreach(list, tricore_cpu_list_entry, &s);
     g_slist_free(list);
diff --git a/target/unicore32/cpu.h b/target/unicore32/cpu.h
index 42e1d52478..735d3ae9dc 100644
--- a/target/unicore32/cpu.h
+++ b/target/unicore32/cpu.h
@@ -164,10 +164,9 @@ static inline int cpu_mmu_index(CPUUniCore32State *env, bool ifetch)
 
 #include "exec/cpu-all.h"
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_UNICORE32_CPU, cpu_model)
-
 #define UNICORE32_CPU_TYPE_SUFFIX "-" TYPE_UNICORE32_CPU
 #define UNICORE32_CPU_TYPE_NAME(model) model UNICORE32_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_UNICORE32_CPU
 
 static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc,
                                         target_ulong *cs_base, uint32_t *flags)
diff --git a/target/xtensa/Makefile.objs b/target/xtensa/Makefile.objs
index e15851521f..2fae785cb2 100644
--- a/target/xtensa/Makefile.objs
+++ b/target/xtensa/Makefile.objs
@@ -1,10 +1,9 @@
-obj-y += xtensa-semi.o
 obj-y += core-dc232b.o
 obj-y += core-dc233c.o
 obj-y += core-de212.o
 obj-y += core-fsf.o
 obj-y += core-sample_controller.o
-obj-$(CONFIG_SOFTMMU) += monitor.o
+obj-$(CONFIG_SOFTMMU) += monitor.o xtensa-semi.o
 obj-y += xtensa-isa.o
 obj-y += translate.o op_helper.o helper.o cpu.o
 obj-y += gdbstub.o
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index 4573388a45..2b5b537222 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -45,9 +45,13 @@ static void xtensa_cpu_set_pc(CPUState *cs, vaddr value)
 
 static bool xtensa_cpu_has_work(CPUState *cs)
 {
+#ifndef CONFIG_USER_ONLY
     XtensaCPU *cpu = XTENSA_CPU(cs);
 
     return !cpu->env.runstall && cpu->env.pending_irq_level;
+#else
+    return true;
+#endif
 }
 
 /* CPUClass::reset() */
@@ -62,8 +66,16 @@ static void xtensa_cpu_reset(CPUState *s)
     env->exception_taken = 0;
     env->pc = env->config->exception_vector[EXC_RESET0 + env->static_vectors];
     env->sregs[LITBASE] &= ~1;
+#ifndef CONFIG_USER_ONLY
     env->sregs[PS] = xtensa_option_enabled(env->config,
             XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+    env->pending_irq_level = 0;
+#else
+    env->sregs[PS] =
+        (xtensa_option_enabled(env->config,
+                               XTENSA_OPTION_WINDOWED_REGISTER) ? PS_WOE : 0) |
+        PS_UM | (3 << PS_RING_SHIFT);
+#endif
     env->sregs[VECBASE] = env->config->vecbase;
     env->sregs[IBREAKENABLE] = 0;
     env->sregs[MEMCTL] = MEMCTL_IL0EN & env->config->memctl_mask;
@@ -73,9 +85,10 @@ static void xtensa_cpu_reset(CPUState *s)
     env->sregs[CONFIGID0] = env->config->configid[0];
     env->sregs[CONFIGID1] = env->config->configid[1];
 
-    env->pending_irq_level = 0;
+#ifndef CONFIG_USER_ONLY
     reset_mmu(env);
     s->halted = env->runstall;
+#endif
 }
 
 static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
@@ -104,11 +117,12 @@ static void xtensa_cpu_disas_set_info(CPUState *cs, disassemble_info *info)
 static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
-    XtensaCPU *cpu = XTENSA_CPU(dev);
     XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev);
     Error *local_err = NULL;
 
-    xtensa_irq_init(&cpu->env);
+#ifndef CONFIG_USER_ONLY
+    xtensa_irq_init(&XTENSA_CPU(dev)->env);
+#endif
 
     cpu_exec_realizefn(cs, &local_err);
     if (local_err != NULL) {
@@ -133,11 +147,13 @@ static void xtensa_cpu_initfn(Object *obj)
     cs->env_ptr = env;
     env->config = xcc->config;
 
+#ifndef CONFIG_USER_ONLY
     env->address_space_er = g_malloc(sizeof(*env->address_space_er));
     env->system_er = g_malloc(sizeof(*env->system_er));
     memory_region_init_io(env->system_er, NULL, NULL, env, "er",
                           UINT64_C(0x100000000));
     address_space_init(env->address_space_er, env->system_er, "ER");
+#endif
 }
 
 static const VMStateDescription vmstate_xtensa_cpu = {
@@ -166,7 +182,9 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
     cc->gdb_read_register = xtensa_cpu_gdb_read_register;
     cc->gdb_write_register = xtensa_cpu_gdb_write_register;
     cc->gdb_stop_before_watchpoint = true;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = xtensa_cpu_handle_mmu_fault;
+#else
     cc->do_unaligned_access = xtensa_cpu_do_unaligned_access;
     cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
     cc->do_unassigned_access = xtensa_cpu_do_unassigned_access;
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 49c2e3cf9a..e9d2e109f7 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -31,6 +31,9 @@
 #define ALIGNED_ONLY
 #define TARGET_LONG_BITS 32
 
+/* Xtensa processors have a weak memory model */
+#define TCG_GUEST_DEFAULT_MO      (0)
+
 #define CPUArchState struct CPUXtensaState
 
 #include "qemu-common.h"
@@ -41,7 +44,11 @@
 #define NB_MMU_MODES 4
 
 #define TARGET_PHYS_ADDR_SPACE_BITS 32
+#ifdef CONFIG_USER_ONLY
+#define TARGET_VIRT_ADDR_SPACE_BITS 30
+#else
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
 #define TARGET_PAGE_BITS 12
 
 enum {
@@ -173,6 +180,7 @@ enum {
 
 #define PS_OWB 0xf00
 #define PS_OWB_SHIFT 8
+#define PS_OWB_LEN 4
 
 #define PS_CALLINC 0x30000
 #define PS_CALLINC_SHIFT 16
@@ -310,6 +318,7 @@ typedef struct xtensa_tlb {
 
 typedef struct XtensaGdbReg {
     int targno;
+    unsigned flags;
     int type;
     int group;
     unsigned size;
@@ -434,6 +443,7 @@ typedef struct CPUXtensaState {
     } fregs[16];
     float_status fp_status;
 
+#ifndef CONFIG_USER_ONLY
     xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
     xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE];
     unsigned autorefill_idx;
@@ -446,6 +456,7 @@ typedef struct CPUXtensaState {
     uint64_t time_base;
     uint64_t ccount_time;
     uint32_t ccount_base;
+#endif
 
     int exception_taken;
     int yield_needed;
@@ -480,6 +491,9 @@ static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env)
 
 #define ENV_OFFSET offsetof(XtensaCPU, env)
 
+
+int xtensa_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int size,
+                                int mmu_idx);
 void xtensa_cpu_do_interrupt(CPUState *cpu);
 bool xtensa_cpu_exec_interrupt(CPUState *cpu, int interrupt_request);
 void xtensa_cpu_do_unassigned_access(CPUState *cpu, hwaddr addr,
@@ -499,6 +513,7 @@ void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
 
 #define XTENSA_CPU_TYPE_SUFFIX "-" TYPE_XTENSA_CPU
 #define XTENSA_CPU_TYPE_NAME(model) model XTENSA_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_XTENSA_CPU
 
 #ifdef TARGET_WORDS_BIGENDIAN
 #define XTENSA_DEFAULT_CPU_MODEL "fsf"
@@ -512,8 +527,6 @@ void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
 #define XTENSA_DEFAULT_CPU_NOMMU_TYPE \
     XTENSA_CPU_TYPE_NAME(XTENSA_DEFAULT_CPU_NOMMU_MODEL)
 
-#define cpu_init(cpu_model) cpu_generic_init(TYPE_XTENSA_CPU, cpu_model)
-
 void xtensa_translate_init(void);
 void xtensa_breakpoint_handler(CPUState *cs);
 void xtensa_finalize_config(XtensaConfig *config);
@@ -527,26 +540,9 @@ int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 void xtensa_sync_window_from_phys(CPUXtensaState *env);
 void xtensa_sync_phys_from_window(CPUXtensaState *env);
-uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t way);
-void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
-        uint32_t *vpn, uint32_t wi, uint32_t *ei);
-int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
-        uint32_t *pwi, uint32_t *pei, uint8_t *pring);
-void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
-        xtensa_tlb_entry *entry, bool dtlb,
-        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
-void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
-        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
-int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
-        uint32_t vaddr, int is_write, int mmu_idx,
-        uint32_t *paddr, uint32_t *page_size, unsigned *access);
-void reset_mmu(CPUXtensaState *env);
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env);
+void xtensa_rotate_window(CPUXtensaState *env, uint32_t delta);
+void xtensa_restore_owb(CPUXtensaState *env);
 void debug_exception_env(CPUXtensaState *new_env, uint32_t cause);
-static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env)
-{
-    return env->system_er;
-}
 
 static inline void xtensa_select_static_vectors(CPUXtensaState *env,
                                                 unsigned n)
@@ -600,6 +596,29 @@ static inline int xtensa_get_cring(const CPUXtensaState *env)
     }
 }
 
+#ifndef CONFIG_USER_ONLY
+uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env,
+                                  bool dtlb, uint32_t way);
+void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t wi, uint32_t *ei);
+int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
+        uint32_t *pwi, uint32_t *pei, uint8_t *pring);
+void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
+        xtensa_tlb_entry *entry, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
+void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
+int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access);
+void reset_mmu(CPUXtensaState *env);
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env);
+
+static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env)
+{
+    return env->system_er;
+}
+
 static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
         bool dtlb, unsigned wi, unsigned ei)
 {
@@ -607,6 +626,7 @@ static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
         env->dtlb[wi] + ei :
         env->itlb[wi] + ei;
 }
+#endif
 
 static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env)
 {
@@ -619,6 +639,7 @@ static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env)
 #define MMU_MODE1_SUFFIX _ring1
 #define MMU_MODE2_SUFFIX _ring2
 #define MMU_MODE3_SUFFIX _ring3
+#define MMU_USER_IDX 3
 
 static inline int cpu_mmu_index(CPUXtensaState *env, bool ifetch)
 {
diff --git a/target/xtensa/gdbstub.c b/target/xtensa/gdbstub.c
index d78a1b437d..a8ea98d03f 100644
--- a/target/xtensa/gdbstub.c
+++ b/target/xtensa/gdbstub.c
@@ -28,9 +28,14 @@ int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
     XtensaCPU *cpu = XTENSA_CPU(cs);
     CPUXtensaState *env = &cpu->env;
     const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+#ifdef CONFIG_USER_ONLY
+    int num_regs = env->config->gdb_regmap.num_core_regs;
+#else
+    int num_regs = env->config->gdb_regmap.num_regs;
+#endif
     unsigned i;
 
-    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+    if (n < 0 || n >= num_regs) {
         return 0;
     }
 
@@ -81,8 +86,13 @@ int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     CPUXtensaState *env = &cpu->env;
     uint32_t tmp;
     const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+#ifdef CONFIG_USER_ONLY
+    int num_regs = env->config->gdb_regmap.num_core_regs;
+#else
+    int num_regs = env->config->gdb_regmap.num_regs;
+#endif
 
-    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+    if (n < 0 || n >= num_regs) {
         return 0;
     }
 
diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c
index 5009fecedc..34844eead3 100644
--- a/target/xtensa/helper.c
+++ b/target/xtensa/helper.c
@@ -88,19 +88,31 @@ static void init_libisa(XtensaConfig *config)
 
 void xtensa_finalize_config(XtensaConfig *config)
 {
-    unsigned i, n = 0;
-
     if (config->isa_internal) {
         init_libisa(config);
     }
-    if (config->gdb_regmap.num_regs) {
-        return;
-    }
 
-    for (i = 0; config->gdb_regmap.reg[i].targno >= 0; ++i) {
-        n += (config->gdb_regmap.reg[i].type != 6);
+    if (config->gdb_regmap.num_regs == 0 ||
+        config->gdb_regmap.num_core_regs == 0) {
+        unsigned i;
+        unsigned n_regs = 0;
+        unsigned n_core_regs = 0;
+
+        for (i = 0; config->gdb_regmap.reg[i].targno >= 0; ++i) {
+            if (config->gdb_regmap.reg[i].type != 6) {
+                ++n_regs;
+                if ((config->gdb_regmap.reg[i].flags & 0x1) == 0) {
+                    ++n_core_regs;
+                }
+            }
+        }
+        if (config->gdb_regmap.num_regs == 0) {
+            config->gdb_regmap.num_regs = n_regs;
+        }
+        if (config->gdb_regmap.num_core_regs == 0) {
+            config->gdb_regmap.num_core_regs = n_core_regs;
+        }
     }
-    config->gdb_regmap.num_regs = n;
 }
 
 void xtensa_register_core(XtensaConfigList *node)
@@ -161,6 +173,7 @@ void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 
 hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 {
+#ifndef CONFIG_USER_ONLY
     XtensaCPU *cpu = XTENSA_CPU(cs);
     uint32_t paddr;
     uint32_t page_size;
@@ -175,8 +188,13 @@ hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
         return paddr;
     }
     return ~0;
+#else
+    return addr;
+#endif
 }
 
+#ifndef CONFIG_USER_ONLY
+
 static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
 {
     if (xtensa_option_enabled(env->config,
@@ -286,6 +304,11 @@ void xtensa_cpu_do_interrupt(CPUState *cs)
     }
     check_interrupts(env);
 }
+#else
+void xtensa_cpu_do_interrupt(CPUState *cs)
+{
+}
+#endif
 
 bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
@@ -297,6 +320,25 @@ bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     return false;
 }
 
+#ifdef CONFIG_USER_ONLY
+
+int xtensa_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
+                                int mmu_idx)
+{
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+    CPUXtensaState *env = &cpu->env;
+
+    qemu_log_mask(CPU_LOG_INT,
+                  "%s: rw = %d, address = 0x%08" VADDR_PRIx ", size = %d\n",
+                  __func__, rw, address, size);
+    env->sregs[EXCVADDR] = address;
+    env->sregs[EXCCAUSE] = rw ? STORE_PROHIBITED_CAUSE : LOAD_PROHIBITED_CAUSE;
+    cs->exception_index = EXC_USER;
+    return 1;
+}
+
+#else
+
 static void reset_tlb_mmu_all_ways(CPUXtensaState *env,
         const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
 {
@@ -757,3 +799,4 @@ void xtensa_runstall(CPUXtensaState *env, bool runstall)
         cpu_reset_interrupt(cpu, CPU_INTERRUPT_HALT);
     }
 }
+#endif
diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h
index cc751c98fb..73444ae02c 100644
--- a/target/xtensa/helper.h
+++ b/target/xtensa/helper.h
@@ -12,9 +12,12 @@ DEF_HELPER_1(restore_owb, void, env)
 DEF_HELPER_2(movsp, void, env, i32)
 DEF_HELPER_2(wsr_lbeg, void, env, i32)
 DEF_HELPER_2(wsr_lend, void, env, i32)
+#ifndef CONFIG_USER_ONLY
 DEF_HELPER_1(simcall, void, env)
+#endif
 DEF_HELPER_1(dump_state, void, env)
 
+#ifndef CONFIG_USER_ONLY
 DEF_HELPER_3(waiti, void, env, i32, i32)
 DEF_HELPER_1(update_ccount, void, env)
 DEF_HELPER_2(wsr_ccount, void, env, i32)
@@ -35,6 +38,7 @@ DEF_HELPER_2(wsr_ibreakenable, void, env, i32)
 DEF_HELPER_3(wsr_ibreaka, void, env, i32, i32)
 DEF_HELPER_3(wsr_dbreaka, void, env, i32, i32)
 DEF_HELPER_3(wsr_dbreakc, void, env, i32, i32)
+#endif
 
 DEF_HELPER_2(wur_fcr, void, env, i32)
 DEF_HELPER_FLAGS_1(abs_s, TCG_CALL_NO_RWG_SE, f32, f32)
diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
index 7486b99799..d401105d09 100644
--- a/target/xtensa/op_helper.c
+++ b/target/xtensa/op_helper.c
@@ -36,6 +36,13 @@
 #include "qemu/timer.h"
 #include "fpu/softfloat.h"
 
+#ifdef CONFIG_USER_ONLY
+/* tb_invalidate_phys_range */
+#include "accel/tcg/translate-all.h"
+#endif
+
+#ifndef CONFIG_USER_ONLY
+
 void xtensa_cpu_do_unaligned_access(CPUState *cs,
         vaddr addr, MMUAccessType access_type,
         int mmu_idx, uintptr_t retaddr)
@@ -102,6 +109,17 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
     }
 }
 
+#else
+
+static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
+{
+    mmap_lock();
+    tb_invalidate_phys_range(vaddr, vaddr + 1);
+    mmap_unlock();
+}
+
+#endif
+
 void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
 {
     CPUState *cs = CPU(xtensa_env_get_cpu(env));
@@ -219,21 +237,21 @@ void xtensa_sync_phys_from_window(CPUXtensaState *env)
     copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
 }
 
-static void rotate_window_abs(CPUXtensaState *env, uint32_t position)
+static void xtensa_rotate_window_abs(CPUXtensaState *env, uint32_t position)
 {
     xtensa_sync_phys_from_window(env);
     env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
     xtensa_sync_window_from_phys(env);
 }
 
-static void rotate_window(CPUXtensaState *env, uint32_t delta)
+void xtensa_rotate_window(CPUXtensaState *env, uint32_t delta)
 {
-    rotate_window_abs(env, env->sregs[WINDOW_BASE] + delta);
+    xtensa_rotate_window_abs(env, env->sregs[WINDOW_BASE] + delta);
 }
 
 void HELPER(wsr_windowbase)(CPUXtensaState *env, uint32_t v)
 {
-    rotate_window_abs(env, v);
+    xtensa_rotate_window_abs(env, v);
 }
 
 void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
@@ -251,7 +269,7 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
             HELPER(window_check)(env, pc, callinc);
         }
         env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - imm;
-        rotate_window(env, callinc);
+        xtensa_rotate_window(env, callinc);
         env->sregs[WINDOW_START] |=
             windowstart_bit(env->sregs[WINDOW_BASE], env);
     }
@@ -266,7 +284,7 @@ void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
 
     assert(n <= w);
 
-    rotate_window(env, n);
+    xtensa_rotate_window(env, n);
     env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
         (windowbase << PS_OWB_SHIFT) | PS_EXCM;
     env->sregs[EPC1] = env->pc = pc;
@@ -311,7 +329,7 @@ uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc)
 
         ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
 
-        rotate_window(env, -n);
+        xtensa_rotate_window(env, -n);
         if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
             env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
         } else {
@@ -334,12 +352,17 @@ uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc)
 
 void HELPER(rotw)(CPUXtensaState *env, uint32_t imm4)
 {
-    rotate_window(env, imm4);
+    xtensa_rotate_window(env, imm4);
+}
+
+void xtensa_restore_owb(CPUXtensaState *env)
+{
+    xtensa_rotate_window_abs(env, (env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
 }
 
 void HELPER(restore_owb)(CPUXtensaState *env)
 {
-    rotate_window_abs(env, (env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
+    xtensa_restore_owb(env);
 }
 
 void HELPER(movsp)(CPUXtensaState *env, uint32_t pc)
@@ -376,6 +399,8 @@ void HELPER(dump_state)(CPUXtensaState *env)
     cpu_dump_state(CPU(cpu), stderr, fprintf, 0);
 }
 
+#ifndef CONFIG_USER_ONLY
+
 void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
 {
     CPUState *cpu;
@@ -888,6 +913,7 @@ void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v)
     }
     env->sregs[DBREAKC + i] = v;
 }
+#endif
 
 void HELPER(wur_fcr)(CPUXtensaState *env, uint32_t v)
 {
@@ -1025,12 +1051,18 @@ void HELPER(ule_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
 uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr)
 {
+#ifndef CONFIG_USER_ONLY
     return address_space_ldl(env->address_space_er, addr,
                              MEMTXATTRS_UNSPECIFIED, NULL);
+#else
+    return 0;
+#endif
 }
 
 void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr)
 {
+#ifndef CONFIG_USER_ONLY
     address_space_stl(env->address_space_er, addr, data,
                       MEMTXATTRS_UNSPECIFIED, NULL);
+#endif
 }
diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h
index 589dd62850..b24ad11fec 100644
--- a/target/xtensa/overlay_tool.h
+++ b/target/xtensa/overlay_tool.h
@@ -25,9 +25,14 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#define XTREG(idx, ofs, bi, sz, al, no, flags, cp, typ, grp, name, \
-        a1, a2, a3, a4, a5, a6) \
-    { .targno = (no), .type = (typ), .group = (grp), .size = (sz) },
+#define XTREG(idx, ofs, bi, sz, al, no, fl, cp, typ, grp, name, \
+              a1, a2, a3, a4, a5, a6) { \
+    .targno = (no), \
+    .flags = (fl), \
+    .type = (typ), \
+    .group = (grp), \
+    .size = (sz), \
+},
 #define XTREG_END { .targno = -1 },
 
 #ifndef XCHAL_HAVE_DEPBITS
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 671d934ff4..4f6d03059f 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -345,12 +345,14 @@ static void gen_debug_exception(DisasContext *dc, uint32_t cause)
 
 static bool gen_check_privilege(DisasContext *dc)
 {
-    if (dc->cring) {
-        gen_exception_cause(dc, PRIVILEGED_CAUSE);
-        dc->is_jmp = DISAS_UPDATE;
-        return false;
+#ifndef CONFIG_USER_ONLY
+    if (!dc->cring) {
+        return true;
     }
-    return true;
+#endif
+    gen_exception_cause(dc, PRIVILEGED_CAUSE);
+    dc->is_jmp = DISAS_UPDATE;
+    return false;
 }
 
 static bool gen_check_cpenable(DisasContext *dc, unsigned cp)
@@ -498,6 +500,7 @@ static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access)
     return true;
 }
 
+#ifndef CONFIG_USER_ONLY
 static bool gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
 {
     if (tb_cflags(dc->tb) & CF_USE_ICOUNT) {
@@ -519,14 +522,17 @@ static bool gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
     tcg_gen_andi_i32(d, d, 0xfffffffc);
     return false;
 }
+#endif
 
 static bool gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
 {
     static bool (* const rsr_handler[256])(DisasContext *dc,
             TCGv_i32 d, uint32_t sr) = {
+#ifndef CONFIG_USER_ONLY
         [CCOUNT] = gen_rsr_ccount,
         [INTSET] = gen_rsr_ccount,
         [PTEVADDR] = gen_rsr_ptevaddr,
+#endif
     };
 
     if (rsr_handler[sr]) {
@@ -582,6 +588,7 @@ static bool gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
     return false;
 }
 
+#ifndef CONFIG_USER_ONLY
 static bool gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
 {
     gen_helper_wsr_windowbase(cpu_env, v);
@@ -797,6 +804,11 @@ static bool gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
     }
     return ret;
 }
+#else
+static void gen_check_interrupts(DisasContext *dc)
+{
+}
+#endif
 
 static bool gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 {
@@ -808,6 +820,7 @@ static bool gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [BR] = gen_wsr_br,
         [LITBASE] = gen_wsr_litbase,
         [ACCHI] = gen_wsr_acchi,
+#ifndef CONFIG_USER_ONLY
         [WINDOW_BASE] = gen_wsr_windowbase,
         [WINDOW_START] = gen_wsr_windowstart,
         [PTEVADDR] = gen_wsr_ptevaddr,
@@ -834,6 +847,7 @@ static bool gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [CCOMPARE] = gen_wsr_ccompare,
         [CCOMPARE + 1] = gen_wsr_ccompare,
         [CCOMPARE + 2] = gen_wsr_ccompare,
+#endif
     };
 
     if (wsr_handler[sr]) {
@@ -878,6 +892,7 @@ static void gen_load_store_alignment(DisasContext *dc, int shift,
     }
 }
 
+#ifndef CONFIG_USER_ONLY
 static void gen_waiti(DisasContext *dc, uint32_t imm4)
 {
     TCGv_i32 pc = tcg_const_i32(dc->next_pc);
@@ -894,6 +909,7 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4)
     tcg_temp_free(intlevel);
     gen_jumpi_check_loop_end(dc, 0);
 }
+#endif
 
 static bool gen_window_check1(DisasContext *dc, unsigned r1)
 {
@@ -1215,11 +1231,17 @@ void xtensa_cpu_dump_state(CPUState *cs, FILE *f,
                 (i % 4) == 3 ? '\n' : ' ');
     }
 
+    xtensa_sync_phys_from_window(env);
     cpu_fprintf(f, "\n");
 
     for (i = 0; i < env->config->nareg; ++i) {
-        cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
-                (i % 4) == 3 ? '\n' : ' ');
+        cpu_fprintf(f, "AR%02d=%08x ", i, env->phys_regs[i]);
+        if (i % 4 == 3) {
+            bool ws = (env->sregs[WINDOW_START] & (1 << (i / 4))) != 0;
+            bool cw = env->sregs[WINDOW_BASE] == i / 4;
+
+            cpu_fprintf(f, "%c%c\n", ws ? '<' : ' ', cw ? '=' : ' ');
+        }
     }
 
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) {
@@ -1590,12 +1612,14 @@ static void translate_icache(DisasContext *dc, const uint32_t arg[],
 {
     if ((!par[0] || gen_check_privilege(dc)) &&
         gen_window_check1(dc, arg[0]) && par[1]) {
+#ifndef CONFIG_USER_ONLY
         TCGv_i32 addr = tcg_temp_new_i32();
 
         tcg_gen_movi_i32(cpu_pc, dc->pc);
         tcg_gen_addi_i32(addr, cpu_R[arg[0]], arg[1]);
         gen_helper_itlb_hit_test(cpu_env, addr);
         tcg_temp_free(addr);
+#endif
     }
 }
 
@@ -1604,12 +1628,14 @@ static void translate_itlb(DisasContext *dc, const uint32_t arg[],
 {
     if (gen_check_privilege(dc) &&
         gen_window_check1(dc, arg[0])) {
+#ifndef CONFIG_USER_ONLY
         TCGv_i32 dtlb = tcg_const_i32(par[0]);
 
         gen_helper_itlb(cpu_env, cpu_R[arg[0]], dtlb);
         /* This could change memory mapping, so exit tb */
         gen_jumpi_check_loop_end(dc, -1);
         tcg_temp_free(dtlb);
+#endif
     }
 }
 
@@ -1658,9 +1684,15 @@ static void translate_ldst(DisasContext *dc, const uint32_t arg[],
             gen_load_store_alignment(dc, par[0] & MO_SIZE, addr, par[1]);
         }
         if (par[2]) {
+            if (par[1]) {
+                tcg_gen_mb(TCG_BAR_STRL | TCG_MO_ALL);
+            }
             tcg_gen_qemu_st_tl(cpu_R[arg[0]], addr, dc->cring, par[0]);
         } else {
             tcg_gen_qemu_ld_tl(cpu_R[arg[0]], addr, dc->cring, par[0]);
+            if (par[1]) {
+                tcg_gen_mb(TCG_BAR_LDAQ | TCG_MO_ALL);
+            }
         }
         tcg_temp_free(addr);
     }
@@ -1817,6 +1849,12 @@ static void translate_mac16(DisasContext *dc, const uint32_t arg[],
     }
 }
 
+static void translate_memw(DisasContext *dc, const uint32_t arg[],
+                           const uint32_t par[])
+{
+    tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
+}
+
 static void translate_minmax(DisasContext *dc, const uint32_t arg[],
                              const uint32_t par[])
 {
@@ -1967,11 +2005,13 @@ static void translate_ptlb(DisasContext *dc, const uint32_t arg[],
 {
     if (gen_check_privilege(dc) &&
         gen_window_check2(dc, arg[0], arg[1])) {
+#ifndef CONFIG_USER_ONLY
         TCGv_i32 dtlb = tcg_const_i32(par[0]);
 
         tcg_gen_movi_i32(cpu_pc, dc->pc);
         gen_helper_ptlb(cpu_R[arg[0]], cpu_env, cpu_R[arg[1]], dtlb);
         tcg_temp_free(dtlb);
+#endif
     }
 }
 
@@ -2155,8 +2195,10 @@ static void translate_rtlb(DisasContext *dc, const uint32_t arg[],
 {
     static void (* const helper[])(TCGv_i32 r, TCGv_env env, TCGv_i32 a1,
                                    TCGv_i32 a2) = {
+#ifndef CONFIG_USER_ONLY
         gen_helper_rtlb0,
         gen_helper_rtlb1,
+#endif
     };
 
     if (gen_check_privilege(dc) &&
@@ -2187,29 +2229,33 @@ static void translate_setb_expstate(DisasContext *dc, const uint32_t arg[],
     tcg_gen_ori_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], 1u << arg[0]);
 }
 
+#ifdef CONFIG_USER_ONLY
+static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr)
+{
+}
+#else
+static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr)
+{
+    TCGv_i32 tpc = tcg_const_i32(dc->pc);
+
+    gen_helper_check_atomctl(cpu_env, tpc, addr);
+    tcg_temp_free(tpc);
+}
+#endif
+
 static void translate_s32c1i(DisasContext *dc, const uint32_t arg[],
                              const uint32_t par[])
 {
     if (gen_window_check2(dc, arg[0], arg[1])) {
-        TCGLabel *label = gen_new_label();
         TCGv_i32 tmp = tcg_temp_local_new_i32();
         TCGv_i32 addr = tcg_temp_local_new_i32();
-        TCGv_i32 tpc;
 
         tcg_gen_mov_i32(tmp, cpu_R[arg[0]]);
         tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]);
         gen_load_store_alignment(dc, 2, addr, true);
-
-        tpc = tcg_const_i32(dc->pc);
-        gen_helper_check_atomctl(cpu_env, tpc, addr);
-        tcg_gen_qemu_ld32u(cpu_R[arg[0]], addr, dc->cring);
-        tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[arg[0]],
-                           cpu_SR[SCOMPARE1], label);
-
-        tcg_gen_qemu_st32(tmp, addr, dc->cring);
-
-        gen_set_label(label);
-        tcg_temp_free(tpc);
+        gen_check_atomctl(dc, addr);
+        tcg_gen_atomic_cmpxchg_i32(cpu_R[arg[0]], addr, cpu_SR[SCOMPARE1],
+                                   tmp, dc->cring, MO_32);
         tcg_temp_free(addr);
         tcg_temp_free(tmp);
     }
@@ -2261,11 +2307,14 @@ static void translate_sext(DisasContext *dc, const uint32_t arg[],
 static void translate_simcall(DisasContext *dc, const uint32_t arg[],
                               const uint32_t par[])
 {
+#ifndef CONFIG_USER_ONLY
     if (semihosting_enabled()) {
         if (gen_check_privilege(dc)) {
             gen_helper_simcall(cpu_env);
         }
-    } else {
+    } else
+#endif
+    {
         qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n");
         gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
     }
@@ -2448,7 +2497,9 @@ static void translate_waiti(DisasContext *dc, const uint32_t arg[],
                             const uint32_t par[])
 {
     if (gen_check_privilege(dc)) {
+#ifndef CONFIG_USER_ONLY
         gen_waiti(dc, arg[0]);
+#endif
     }
 }
 
@@ -2457,12 +2508,14 @@ static void translate_wtlb(DisasContext *dc, const uint32_t arg[],
 {
     if (gen_check_privilege(dc) &&
         gen_window_check2(dc, arg[0], arg[1])) {
+#ifndef CONFIG_USER_ONLY
         TCGv_i32 dtlb = tcg_const_i32(par[0]);
 
         gen_helper_wtlb(cpu_env, cpu_R[arg[0]], cpu_R[arg[1]], dtlb);
         /* This could change memory mapping, so exit tb */
         gen_jumpi_check_loop_end(dc, -1);
         tcg_temp_free(dtlb);
+#endif
     }
 }
 
@@ -2822,7 +2875,7 @@ static const XtensaOpcodeOps core_ops[] = {
         .translate = translate_extui,
     }, {
         .name = "extw",
-        .translate = translate_nop,
+        .translate = translate_memw,
     }, {
         .name = "hwwdtlba",
         .translate = translate_ill,
@@ -2939,7 +2992,7 @@ static const XtensaOpcodeOps core_ops[] = {
         .par = (const uint32_t[]){TCG_COND_GEU},
     }, {
         .name = "memw",
-        .translate = translate_nop,
+        .translate = translate_memw,
     }, {
         .name = "min",
         .translate = translate_minmax,