diff --git a/MAINTAINERS b/MAINTAINERS
index 8f5681f..615df35 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -91,6 +91,11 @@ M: Aurelien Jarno <aurelien@aurel32.net>
 S: Odd Fixes
 F: target-mips/
 
+NiosII
+M: Chris Wulff <crwulff@gmail.com>
+S: Odd Fixes
+F: target-nios2/
+
 PowerPC
 M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
diff --git a/arch_init.c b/arch_init.c
index e6effe8..0aafe8e 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -84,6 +84,8 @@ int graphic_depth = 15;
 #define QEMU_ARCH QEMU_ARCH_MICROBLAZE
 #elif defined(TARGET_MIPS)
 #define QEMU_ARCH QEMU_ARCH_MIPS
+#elif defined(TARGET_NIOS2)
+#define QEMU_ARCH QEMU_ARCH_NIOS2
 #elif defined(TARGET_OPENRISC)
 #define QEMU_ARCH QEMU_ARCH_OPENRISC
 #elif defined(TARGET_PPC)
diff --git a/arch_init.h b/arch_init.h
index 5fc780c..b2d736a 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -20,6 +20,7 @@ enum {
     QEMU_ARCH_XTENSA = 4096,
     QEMU_ARCH_OPENRISC = 8192,
     QEMU_ARCH_UNICORE32 = 0x4000,
+    QEMU_ARCH_NIOS2 = 0x8000,
 };
 
 extern const uint32_t arch_type;
diff --git a/configure b/configure
index 7290f50..554e44a 100755
--- a/configure
+++ b/configure
@@ -924,6 +924,7 @@ mips-softmmu \
 mipsel-softmmu \
 mips64-softmmu \
 mips64el-softmmu \
+nios2-softmmu \
 or32-softmmu \
 ppc-softmmu \
 ppcemb-softmmu \
@@ -952,6 +953,7 @@ microblaze-linux-user \
 microblazeel-linux-user \
 mips-linux-user \
 mipsel-linux-user \
+nios2-linux-user \
 or32-linux-user \
 ppc-linux-user \
 ppc64-linux-user \
@@ -3808,6 +3810,11 @@ case "$target_arch2" in
     echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
     target_long_alignment=8
   ;;
+  nios2)
+    target_nptl="yes"
+    target_phys_bits=32
+    target_libs_softmmu="$fdt_libs"
+  ;;
   or32)
     TARGET_ARCH=openrisc
     TARGET_BASE_ARCH=openrisc
@@ -4061,6 +4068,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
     echo "CONFIG_MIPS_DIS=y"  >> $config_target_mak
     echo "CONFIG_MIPS_DIS=y"  >> $libdis_config_mak
   ;;
+  nios2)
+    echo "CONFIG_NIOS2_DIS=y"  >> $config_target_mak
+    echo "CONFIG_NIOS2_DIS=y"  >> $libdis_config_mak
+  ;;
   or32)
     echo "CONFIG_OPENRISC_DIS=y"  >> $config_target_mak
     echo "CONFIG_OPENRISC_DIS=y"  >> $libdis_config_mak
diff --git a/cpu-exec.c b/cpu-exec.c
index 904ee73..f9da4d1 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -220,6 +220,7 @@ int cpu_exec(CPUArchState *env)
 #elif defined(TARGET_LM32)
 #elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
+#elif defined(TARGET_NIOS2)
 #elif defined(TARGET_OPENRISC)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
@@ -275,7 +276,8 @@ int cpu_exec(CPUArchState *env)
                     }
 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
-    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
+    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || \
+    defined(TARGET_UNICORE32) || defined(TARGET_NIOS2)
                     if (interrupt_request & CPU_INTERRUPT_HALT) {
                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                         env->halted = 1;
@@ -529,6 +531,13 @@ int cpu_exec(CPUArchState *env)
                         do_interrupt(env);
                         next_tb = 0;
                     }
+#elif defined(TARGET_NIOS2)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD)
+                        && (env->regs[CR_STATUS] & CR_STATUS_PIE)) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #endif
                    /* Don't use the cached interrupt_request value,
                       do_interrupt may have updated the EXITTB flag. */
@@ -654,6 +663,7 @@ int cpu_exec(CPUArchState *env)
               | env->cc_dest | (env->cc_x << 4);
 #elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
+#elif defined(TARGET_NIOS2)
 #elif defined(TARGET_OPENRISC)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_ALPHA)
diff --git a/default-configs/nios2-linux-user.mak b/default-configs/nios2-linux-user.mak
new file mode 100644
index 0000000..5be3eb7
--- /dev/null
+++ b/default-configs/nios2-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for nios2-linux-user
diff --git a/default-configs/nios2-softmmu.mak b/default-configs/nios2-softmmu.mak
new file mode 100644
index 0000000..a14708a
--- /dev/null
+++ b/default-configs/nios2-softmmu.mak
@@ -0,0 +1,5 @@
+# Default configuration for nios2-softmmu
+
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_ALTERA=y
diff --git a/dis-asm.h b/dis-asm.h
index 3944b3c..a7010bf 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -221,6 +221,8 @@ enum bfd_architecture
   bfd_arch_ia64,      /* HP/Intel ia64 */
 #define bfd_mach_ia64_elf64    64
 #define bfd_mach_ia64_elf32    32
+  bfd_arch_nios2,
+#define bfd_mach_nios2          1
   bfd_arch_lm32,       /* Lattice Mico32 */
 #define bfd_mach_lm32 1
   bfd_arch_last
@@ -407,6 +409,7 @@ int print_insn_crisv10          (bfd_vma, disassemble_info*);
 int print_insn_microblaze       (bfd_vma, disassemble_info*);
 int print_insn_ia64             (bfd_vma, disassemble_info*);
 int print_insn_lm32             (bfd_vma, disassemble_info*);
+int print_insn_nios2            (bfd_vma, disassemble_info*);
 
 #if 0
 /* Fetch the disassembler for a given BFD, if that support is available.  */
diff --git a/disas.c b/disas.c
index b801c8f..8469c2e 100644
--- a/disas.c
+++ b/disas.c
@@ -245,6 +245,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
 #elif defined(TARGET_MICROBLAZE)
     disasm_info.mach = bfd_arch_microblaze;
     print_insn = print_insn_microblaze;
+#elif defined(TARGET_NIOS2)
+    disasm_info.mach = bfd_arch_nios2;
+    print_insn = print_insn_nios2;
 #elif defined(TARGET_LM32)
     disasm_info.mach = bfd_mach_lm32;
     print_insn = print_insn_lm32;
diff --git a/elf.h b/elf.h
index a21ea53..e5e667b 100644
--- a/elf.h
+++ b/elf.h
@@ -124,6 +124,8 @@ typedef int64_t  Elf64_Sxword;
  */
 #define EM_S390_OLD     0xA390
 
+#define EM_ALTERA_NIOS2 113     /* Altera Nios II soft-core processor */
+
 #define EM_MICROBLAZE      189
 #define EM_MICROBLAZE_OLD  0xBAAB
 
diff --git a/exec.c b/exec.c
index af94f9c..e6faf0f 100644
--- a/exec.c
+++ b/exec.c
@@ -2860,7 +2860,8 @@ static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
 #endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || \
+    defined(TARGET_MICROBLAZE) || defined(TARGET_NIOS2)
     cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
 #endif
     return 0;
@@ -2872,7 +2873,8 @@ static void unassigned_mem_write(void *opaque, hwaddr addr,
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64"\n", addr, val);
 #endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || \
+    defined(TARGET_MICROBLAZE) || defined(TARGET_NIOS2)
     cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
 #endif
 }
diff --git a/gdbstub.c b/gdbstub.c
index d02ec75..3c741fb 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1367,6 +1367,33 @@ static int cpu_gdb_write_register(CPUMBState *env, uint8_t *mem_buf, int n)
     }
     return 4;
 }
+
+#elif defined(TARGET_NIOS2)
+
+static int cpu_gdb_read_register(CPUNios2State *env, uint8_t *mem_buf, int n)
+{
+    if (n > NUM_CORE_REGS) {
+        return 0;
+    }
+
+    GET_REG32(env->regs[n]);
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUNios2State *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n > NUM_CORE_REGS) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    env->regs[n] = tmp;
+    return 4;
+}
+
 #elif defined (TARGET_CRIS)
 
 #define NUM_CORE_REGS 49
@@ -2030,6 +2057,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
     }
 #elif defined (TARGET_MICROBLAZE)
     s->c_cpu->sregs[SR_PC] = pc;
+#elif defined(TARGET_NIOS2)
+    s->c_cpu->regs[R_PC] = pc;
 #elif defined(TARGET_OPENRISC)
     s->c_cpu->pc = pc;
 #elif defined (TARGET_CRIS)
diff --git a/hw/nios2/Makefile.objs b/hw/nios2/Makefile.objs
new file mode 100644
index 0000000..5a92c78
--- /dev/null
+++ b/hw/nios2/Makefile.objs
@@ -0,0 +1,3 @@
+obj-y += nios2_pic_cpu.o
+
+obj-y := $(addprefix ../,$(obj-y))
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 1d8bcb4..31e77a9 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -804,6 +804,35 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env
 
 #endif /* TARGET_MICROBLAZE */
 
+#ifdef TARGET_NIOS2
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_ARCH    EM_ALTERA_NIOS2
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    /* TODO */
+}
+
+#define ELF_EXEC_PAGESIZE        4096
+
+#define USE_ELF_CORE_DUMP
+/* TODO - #define ELF_NREG 38 */
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    /* TODO */
+}
+
+#endif /* TARGET_NIOS2 */
+
 #ifdef TARGET_OPENRISC
 
 #define ELF_START_MMAP 0x08000000
diff --git a/monitor.c b/monitor.c
index c0e32d6..ca93008 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1764,7 +1764,8 @@ static void tlb_info(Monitor *mon)
 
 #endif
 
-#if defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_XTENSA)
+#if defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_XTENSA) || \
+    defined(TARGET_NIOS2)
 static void tlb_info(Monitor *mon)
 {
     CPUArchState *env1 = mon_get_cpu();
@@ -2529,7 +2530,7 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.info = hmp_info_pci,
     },
 #if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
-    defined(TARGET_PPC) || defined(TARGET_XTENSA)
+    defined(TARGET_PPC) || defined(TARGET_XTENSA) || defined(TARGET_NIOS2)
     {
         .name       = "tlb",
         .args_type  = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 542e3ac..b7e72d9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2871,7 +2871,7 @@
 ##
 { 'enum': 'TargetType',
   'data': [ 'alpha', 'arm', 'cris', 'i386', 'lm32', 'm68k', 'microblazeel',
-            'microblaze', 'mips64el', 'mips64', 'mipsel', 'mips', 'or32',
+            'microblaze', 'mips64el', 'mips64', 'mipsel', 'mips', 'nios2', 'or32',
             'ppc64', 'ppcemb', 'ppc', 's390x', 'sh4eb', 'sh4', 'sparc64',
             'sparc', 'unicore32', 'x86_64', 'xtensaeb', 'xtensa' ] }
 
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 35cabbc..3515f15 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2475,6 +2475,9 @@ The binary format is detected automatically.
 @command{qemu-mips} TODO.
 @command{qemu-mipsel} TODO.
 
+@cindex user mode (NiosII)
+@command{qemu-nios2} TODO.
+
 @cindex user mode (PowerPC)
 @command{qemu-ppc64abi32} TODO.
 @command{qemu-ppc64} TODO.
