]> git.proxmox.com Git - mirror_qemu.git/blobdiff - linux-user/main.c
hw/mips: Use object_initialize() on MIPSCPSState
[mirror_qemu.git] / linux-user / main.c
index 7f6cfa5548c15fe720308d9fb726ad50cfc43d28..689bcf436d266ab77632656738f7174995ea6dfc 100644 (file)
@@ -17,6 +17,7 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "qemu/osdep.h"
+#include "qemu/units.h"
 #include "qemu-version.h"
 #include <sys/syscall.h>
 #include <sys/resource.h>
 #include "qemu/path.h"
 #include "qemu/config-file.h"
 #include "qemu/cutils.h"
+#include "qemu/error-report.h"
 #include "qemu/help_option.h"
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "tcg.h"
 #include "qemu/timer.h"
 #include "qemu/envlist.h"
+#include "qemu/guest-random.h"
 #include "elf.h"
 #include "trace/control.h"
 #include "target_elf.h"
 #include "cpu_loop-common.h"
+#include "crypto/init.h"
 
 char *exec_path;
 
@@ -46,6 +50,7 @@ static int gdbstub_port;
 static envlist_t *envlist;
 static const char *cpu_model;
 static const char *cpu_type;
+static const char *seed_optarg;
 unsigned long mmap_min_addr;
 unsigned long guest_base;
 int have_guest_base;
@@ -77,14 +82,7 @@ int have_guest_base;
 # endif
 #endif
 
-/* That said, reserving *too* much vm space via mmap can run into problems
-   with rlimits, oom due to page table creation, etc.  We will still try it,
-   if directed by the command-line option, but not by default.  */
-#if HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32
-unsigned long reserved_va = MAX_RESERVED_VA;
-#else
 unsigned long reserved_va;
-#endif
 
 static void usage(int exitcode);
 
@@ -120,7 +118,6 @@ void fork_start(void)
 {
     start_exclusive();
     mmap_fork_start();
-    qemu_mutex_lock(&tb_ctx.tb_lock);
     cpu_list_lock();
 }
 
@@ -133,794 +130,20 @@ void fork_end(int child)
            Discard information about the parent threads.  */
         CPU_FOREACH_SAFE(cpu, next_cpu) {
             if (cpu != thread_cpu) {
-                QTAILQ_REMOVE(&cpus, cpu, node);
+                QTAILQ_REMOVE_RCU(&cpus, cpu, node);
             }
         }
-        qemu_mutex_init(&tb_ctx.tb_lock);
         qemu_init_cpu_list();
         gdbserver_fork(thread_cpu);
         /* qemu_init_cpu_list() takes care of reinitializing the
          * exclusive state, so we don't need to end_exclusive() here.
          */
     } else {
-        qemu_mutex_unlock(&tb_ctx.tb_lock);
         cpu_list_unlock();
         end_exclusive();
     }
 }
 
-#ifdef TARGET_TILEGX
-
-static void gen_sigill_reg(CPUTLGState *env)
-{
-    target_siginfo_t info;
-
-    info.si_signo = TARGET_SIGILL;
-    info.si_errno = 0;
-    info.si_code = TARGET_ILL_PRVREG;
-    info._sifields._sigfault._addr = env->pc;
-    queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-}
-
-static void do_signal(CPUTLGState *env, int signo, int sigcode)
-{
-    target_siginfo_t info;
-
-    info.si_signo = signo;
-    info.si_errno = 0;
-    info._sifields._sigfault._addr = env->pc;
-
-    if (signo == TARGET_SIGSEGV) {
-        /* The passed in sigcode is a dummy; check for a page mapping
-           and pass either MAPERR or ACCERR.  */
-        target_ulong addr = env->excaddr;
-        info._sifields._sigfault._addr = addr;
-        if (page_check_range(addr, 1, PAGE_VALID) < 0) {
-            sigcode = TARGET_SEGV_MAPERR;
-        } else {
-            sigcode = TARGET_SEGV_ACCERR;
-        }
-    }
-    info.si_code = sigcode;
-
-    queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-}
-
-static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr)
-{
-    env->excaddr = addr;
-    do_signal(env, TARGET_SIGSEGV, 0);
-}
-
-static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
-{
-    if (unlikely(reg >= TILEGX_R_COUNT)) {
-        switch (reg) {
-        case TILEGX_R_SN:
-        case TILEGX_R_ZERO:
-            return;
-        case TILEGX_R_IDN0:
-        case TILEGX_R_IDN1:
-        case TILEGX_R_UDN0:
-        case TILEGX_R_UDN1:
-        case TILEGX_R_UDN2:
-        case TILEGX_R_UDN3:
-            gen_sigill_reg(env);
-            return;
-        default:
-            g_assert_not_reached();
-        }
-    }
-    env->regs[reg] = val;
-}
-
-/*
- * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in
- * memory at the address held in the first source register. If the values are
- * not equal, then no memory operation is performed. If the values are equal,
- * the 8-byte quantity from the second source register is written into memory
- * at the address held in the first source register. In either case, the result
- * of the instruction is the value read from memory. The compare and write to
- * memory are atomic and thus can be used for synchronization purposes. This
- * instruction only operates for addresses aligned to a 8-byte boundary.
- * Unaligned memory access causes an Unaligned Data Reference interrupt.
- *
- * Functional Description (64-bit)
- *       uint64_t memVal = memoryReadDoubleWord (rf[SrcA]);
- *       rf[Dest] = memVal;
- *       if (memVal == SPR[CmpValueSPR])
- *           memoryWriteDoubleWord (rf[SrcA], rf[SrcB]);
- *
- * Functional Description (32-bit)
- *       uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA]));
- *       rf[Dest] = memVal;
- *       if (memVal == signExtend32 (SPR[CmpValueSPR]))
- *           memoryWriteWord (rf[SrcA], rf[SrcB]);
- *
- *
- * This function also processes exch and exch4 which need not process SPR.
- */
-static void do_exch(CPUTLGState *env, bool quad, bool cmp)
-{
-    target_ulong addr;
-    target_long val, sprval;
-
-    start_exclusive();
-
-    addr = env->atomic_srca;
-    if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
-        goto sigsegv_maperr;
-    }
-
-    if (cmp) {
-        if (quad) {
-            sprval = env->spregs[TILEGX_SPR_CMPEXCH];
-        } else {
-            sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32);
-        }
-    }
-
-    if (!cmp || val == sprval) {
-        target_long valb = env->atomic_srcb;
-        if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
-            goto sigsegv_maperr;
-        }
-    }
-
-    set_regval(env, env->atomic_dstr, val);
-    end_exclusive();
-    return;
-
- sigsegv_maperr:
-    end_exclusive();
-    gen_sigsegv_maperr(env, addr);
-}
-
-static void do_fetch(CPUTLGState *env, int trapnr, bool quad)
-{
-    int8_t write = 1;
-    target_ulong addr;
-    target_long val, valb;
-
-    start_exclusive();
-
-    addr = env->atomic_srca;
-    valb = env->atomic_srcb;
-    if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
-        goto sigsegv_maperr;
-    }
-
-    switch (trapnr) {
-    case TILEGX_EXCP_OPCODE_FETCHADD:
-    case TILEGX_EXCP_OPCODE_FETCHADD4:
-        valb += val;
-        break;
-    case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
-        valb += val;
-        if (valb < 0) {
-            write = 0;
-        }
-        break;
-    case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
-        valb += val;
-        if ((int32_t)valb < 0) {
-            write = 0;
-        }
-        break;
-    case TILEGX_EXCP_OPCODE_FETCHAND:
-    case TILEGX_EXCP_OPCODE_FETCHAND4:
-        valb &= val;
-        break;
-    case TILEGX_EXCP_OPCODE_FETCHOR:
-    case TILEGX_EXCP_OPCODE_FETCHOR4:
-        valb |= val;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    if (write) {
-        if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
-            goto sigsegv_maperr;
-        }
-    }
-
-    set_regval(env, env->atomic_dstr, val);
-    end_exclusive();
-    return;
-
- sigsegv_maperr:
-    end_exclusive();
-    gen_sigsegv_maperr(env, addr);
-}
-
-void cpu_loop(CPUTLGState *env)
-{
-    CPUState *cs = CPU(tilegx_env_get_cpu(env));
-    int trapnr;
-
-    while (1) {
-        cpu_exec_start(cs);
-        trapnr = cpu_exec(cs);
-        cpu_exec_end(cs);
-        process_queued_cpu_work(cs);
-
-        switch (trapnr) {
-        case TILEGX_EXCP_SYSCALL:
-        {
-            abi_ulong ret = do_syscall(env, env->regs[TILEGX_R_NR],
-                                       env->regs[0], env->regs[1],
-                                       env->regs[2], env->regs[3],
-                                       env->regs[4], env->regs[5],
-                                       env->regs[6], env->regs[7]);
-            if (ret == -TARGET_ERESTARTSYS) {
-                env->pc -= 8;
-            } else if (ret != -TARGET_QEMU_ESIGRETURN) {
-                env->regs[TILEGX_R_RE] = ret;
-                env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(ret) ? -ret : 0;
-            }
-            break;
-        }
-        case TILEGX_EXCP_OPCODE_EXCH:
-            do_exch(env, true, false);
-            break;
-        case TILEGX_EXCP_OPCODE_EXCH4:
-            do_exch(env, false, false);
-            break;
-        case TILEGX_EXCP_OPCODE_CMPEXCH:
-            do_exch(env, true, true);
-            break;
-        case TILEGX_EXCP_OPCODE_CMPEXCH4:
-            do_exch(env, false, true);
-            break;
-        case TILEGX_EXCP_OPCODE_FETCHADD:
-        case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
-        case TILEGX_EXCP_OPCODE_FETCHAND:
-        case TILEGX_EXCP_OPCODE_FETCHOR:
-            do_fetch(env, trapnr, true);
-            break;
-        case TILEGX_EXCP_OPCODE_FETCHADD4:
-        case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
-        case TILEGX_EXCP_OPCODE_FETCHAND4:
-        case TILEGX_EXCP_OPCODE_FETCHOR4:
-            do_fetch(env, trapnr, false);
-            break;
-        case TILEGX_EXCP_SIGNAL:
-            do_signal(env, env->signo, env->sigcode);
-            break;
-        case TILEGX_EXCP_REG_IDN_ACCESS:
-        case TILEGX_EXCP_REG_UDN_ACCESS:
-            gen_sigill_reg(env);
-            break;
-        case EXCP_ATOMIC:
-            cpu_exec_step_atomic(cs);
-            break;
-        default:
-            fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
-            g_assert_not_reached();
-        }
-        process_pending_signals(env);
-    }
-}
-
-#endif
-
-#ifdef TARGET_RISCV
-
-void cpu_loop(CPURISCVState *env)
-{
-    CPUState *cs = CPU(riscv_env_get_cpu(env));
-    int trapnr, signum, sigcode;
-    target_ulong sigaddr;
-    target_ulong ret;
-
-    for (;;) {
-        cpu_exec_start(cs);
-        trapnr = cpu_exec(cs);
-        cpu_exec_end(cs);
-        process_queued_cpu_work(cs);
-
-        signum = 0;
-        sigcode = 0;
-        sigaddr = 0;
-
-        switch (trapnr) {
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-        case EXCP_ATOMIC:
-            cpu_exec_step_atomic(cs);
-            break;
-        case RISCV_EXCP_U_ECALL:
-            env->pc += 4;
-            if (env->gpr[xA7] == TARGET_NR_arch_specific_syscall + 15) {
-                /* riscv_flush_icache_syscall is a no-op in QEMU as
-                   self-modifying code is automatically detected */
-                ret = 0;
-            } else {
-                ret = do_syscall(env,
-                                 env->gpr[xA7],
-                                 env->gpr[xA0],
-                                 env->gpr[xA1],
-                                 env->gpr[xA2],
-                                 env->gpr[xA3],
-                                 env->gpr[xA4],
-                                 env->gpr[xA5],
-                                 0, 0);
-            }
-            if (ret == -TARGET_ERESTARTSYS) {
-                env->pc -= 4;
-            } else if (ret != -TARGET_QEMU_ESIGRETURN) {
-                env->gpr[xA0] = ret;
-            }
-            if (cs->singlestep_enabled) {
-                goto gdbstep;
-            }
-            break;
-        case RISCV_EXCP_ILLEGAL_INST:
-            signum = TARGET_SIGILL;
-            sigcode = TARGET_ILL_ILLOPC;
-            break;
-        case RISCV_EXCP_BREAKPOINT:
-            signum = TARGET_SIGTRAP;
-            sigcode = TARGET_TRAP_BRKPT;
-            sigaddr = env->pc;
-            break;
-        case RISCV_EXCP_INST_PAGE_FAULT:
-        case RISCV_EXCP_LOAD_PAGE_FAULT:
-        case RISCV_EXCP_STORE_PAGE_FAULT:
-            signum = TARGET_SIGSEGV;
-            sigcode = TARGET_SEGV_MAPERR;
-            break;
-        case EXCP_DEBUG:
-        gdbstep:
-            signum = gdb_handlesig(cs, TARGET_SIGTRAP);
-            sigcode = TARGET_TRAP_BRKPT;
-            break;
-        default:
-            EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
-                     trapnr);
-            exit(EXIT_FAILURE);
-        }
-
-        if (signum) {
-            target_siginfo_t info = {
-                .si_signo = signum,
-                .si_errno = 0,
-                .si_code = sigcode,
-                ._sifields._sigfault._addr = sigaddr
-            };
-            queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
-        }
-
-        process_pending_signals(env);
-    }
-}
-
-#endif /* TARGET_RISCV */
-
-#ifdef TARGET_HPPA
-
-static abi_ulong hppa_lws(CPUHPPAState *env)
-{
-    uint32_t which = env->gr[20];
-    abi_ulong addr = env->gr[26];
-    abi_ulong old = env->gr[25];
-    abi_ulong new = env->gr[24];
-    abi_ulong size, ret;
-
-    switch (which) {
-    default:
-        return -TARGET_ENOSYS;
-
-    case 0: /* elf32 atomic 32bit cmpxchg */
-        if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
-            return -TARGET_EFAULT;
-        }
-        old = tswap32(old);
-        new = tswap32(new);
-        ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
-        ret = tswap32(ret);
-        break;
-
-    case 2: /* elf32 atomic "new" cmpxchg */
-        size = env->gr[23];
-        if (size >= 4) {
-            return -TARGET_ENOSYS;
-        }
-        if (((addr | old | new) & ((1 << size) - 1))
-            || !access_ok(VERIFY_WRITE, addr, 1 << size)
-            || !access_ok(VERIFY_READ, old, 1 << size)
-            || !access_ok(VERIFY_READ, new, 1 << size)) {
-            return -TARGET_EFAULT;
-        }
-        /* Note that below we use host-endian loads so that the cmpxchg
-           can be host-endian as well.  */
-        switch (size) {
-        case 0:
-            old = *(uint8_t *)g2h(old);
-            new = *(uint8_t *)g2h(new);
-            ret = atomic_cmpxchg((uint8_t *)g2h(addr), old, new);
-            ret = ret != old;
-            break;
-        case 1:
-            old = *(uint16_t *)g2h(old);
-            new = *(uint16_t *)g2h(new);
-            ret = atomic_cmpxchg((uint16_t *)g2h(addr), old, new);
-            ret = ret != old;
-            break;
-        case 2:
-            old = *(uint32_t *)g2h(old);
-            new = *(uint32_t *)g2h(new);
-            ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
-            ret = ret != old;
-            break;
-        case 3:
-            {
-                uint64_t o64, n64, r64;
-                o64 = *(uint64_t *)g2h(old);
-                n64 = *(uint64_t *)g2h(new);
-#ifdef CONFIG_ATOMIC64
-                r64 = atomic_cmpxchg__nocheck((uint64_t *)g2h(addr), o64, n64);
-                ret = r64 != o64;
-#else
-                start_exclusive();
-                r64 = *(uint64_t *)g2h(addr);
-                ret = 1;
-                if (r64 == o64) {
-                    *(uint64_t *)g2h(addr) = n64;
-                    ret = 0;
-                }
-                end_exclusive();
-#endif
-            }
-            break;
-        }
-        break;
-    }
-
-    env->gr[28] = ret;
-    return 0;
-}
-
-void cpu_loop(CPUHPPAState *env)
-{
-    CPUState *cs = CPU(hppa_env_get_cpu(env));
-    target_siginfo_t info;
-    abi_ulong ret;
-    int trapnr;
-
-    while (1) {
-        cpu_exec_start(cs);
-        trapnr = cpu_exec(cs);
-        cpu_exec_end(cs);
-        process_queued_cpu_work(cs);
-
-        switch (trapnr) {
-        case EXCP_SYSCALL:
-            ret = do_syscall(env, env->gr[20],
-                             env->gr[26], env->gr[25],
-                             env->gr[24], env->gr[23],
-                             env->gr[22], env->gr[21], 0, 0);
-            switch (ret) {
-            default:
-                env->gr[28] = ret;
-                /* We arrived here by faking the gateway page.  Return.  */
-                env->iaoq_f = env->gr[31];
-                env->iaoq_b = env->gr[31] + 4;
-                break;
-            case -TARGET_ERESTARTSYS:
-            case -TARGET_QEMU_ESIGRETURN:
-                break;
-            }
-            break;
-        case EXCP_SYSCALL_LWS:
-            env->gr[21] = hppa_lws(env);
-            /* We arrived here by faking the gateway page.  Return.  */
-            env->iaoq_f = env->gr[31];
-            env->iaoq_b = env->gr[31] + 4;
-            break;
-        case EXCP_ITLB_MISS:
-        case EXCP_DTLB_MISS:
-        case EXCP_NA_ITLB_MISS:
-        case EXCP_NA_DTLB_MISS:
-        case EXCP_IMP:
-        case EXCP_DMP:
-        case EXCP_DMB:
-        case EXCP_PAGE_REF:
-        case EXCP_DMAR:
-        case EXCP_DMPI:
-            info.si_signo = TARGET_SIGSEGV;
-            info.si_errno = 0;
-            info.si_code = TARGET_SEGV_ACCERR;
-            info._sifields._sigfault._addr = env->cr[CR_IOR];
-            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-            break;
-        case EXCP_UNALIGN:
-            info.si_signo = TARGET_SIGBUS;
-            info.si_errno = 0;
-            info.si_code = 0;
-            info._sifields._sigfault._addr = env->cr[CR_IOR];
-            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-            break;
-        case EXCP_ILL:
-        case EXCP_PRIV_OPR:
-        case EXCP_PRIV_REG:
-            info.si_signo = TARGET_SIGILL;
-            info.si_errno = 0;
-            info.si_code = TARGET_ILL_ILLOPN;
-            info._sifields._sigfault._addr = env->iaoq_f;
-            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-            break;
-        case EXCP_OVERFLOW:
-        case EXCP_COND:
-        case EXCP_ASSIST:
-            info.si_signo = TARGET_SIGFPE;
-            info.si_errno = 0;
-            info.si_code = 0;
-            info._sifields._sigfault._addr = env->iaoq_f;
-            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-            break;
-        case EXCP_DEBUG:
-            trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
-            if (trapnr) {
-                info.si_signo = trapnr;
-                info.si_errno = 0;
-                info.si_code = TARGET_TRAP_BRKPT;
-                queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
-            }
-            break;
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-        default:
-            g_assert_not_reached();
-        }
-        process_pending_signals(env);
-    }
-}
-
-#endif /* TARGET_HPPA */
-
-#ifdef TARGET_XTENSA
-
-static void xtensa_rfw(CPUXtensaState *env)
-{
-    xtensa_restore_owb(env);
-    env->pc = env->sregs[EPC1];
-}
-
-static void xtensa_rfwu(CPUXtensaState *env)
-{
-    env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]);
-    xtensa_rfw(env);
-}
-
-static void xtensa_rfwo(CPUXtensaState *env)
-{
-    env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]);
-    xtensa_rfw(env);
-}
-
-static void xtensa_overflow4(CPUXtensaState *env)
-{
-    put_user_ual(env->regs[0], env->regs[5] - 16);
-    put_user_ual(env->regs[1], env->regs[5] - 12);
-    put_user_ual(env->regs[2], env->regs[5] -  8);
-    put_user_ual(env->regs[3], env->regs[5] -  4);
-    xtensa_rfwo(env);
-}
-
-static void xtensa_underflow4(CPUXtensaState *env)
-{
-    get_user_ual(env->regs[0], env->regs[5] - 16);
-    get_user_ual(env->regs[1], env->regs[5] - 12);
-    get_user_ual(env->regs[2], env->regs[5] -  8);
-    get_user_ual(env->regs[3], env->regs[5] -  4);
-    xtensa_rfwu(env);
-}
-
-static void xtensa_overflow8(CPUXtensaState *env)
-{
-    put_user_ual(env->regs[0], env->regs[9] - 16);
-    get_user_ual(env->regs[0], env->regs[1] - 12);
-    put_user_ual(env->regs[1], env->regs[9] - 12);
-    put_user_ual(env->regs[2], env->regs[9] -  8);
-    put_user_ual(env->regs[3], env->regs[9] -  4);
-    put_user_ual(env->regs[4], env->regs[0] - 32);
-    put_user_ual(env->regs[5], env->regs[0] - 28);
-    put_user_ual(env->regs[6], env->regs[0] - 24);
-    put_user_ual(env->regs[7], env->regs[0] - 20);
-    xtensa_rfwo(env);
-}
-
-static void xtensa_underflow8(CPUXtensaState *env)
-{
-    get_user_ual(env->regs[0], env->regs[9] - 16);
-    get_user_ual(env->regs[1], env->regs[9] - 12);
-    get_user_ual(env->regs[2], env->regs[9] -  8);
-    get_user_ual(env->regs[7], env->regs[1] - 12);
-    get_user_ual(env->regs[3], env->regs[9] -  4);
-    get_user_ual(env->regs[4], env->regs[7] - 32);
-    get_user_ual(env->regs[5], env->regs[7] - 28);
-    get_user_ual(env->regs[6], env->regs[7] - 24);
-    get_user_ual(env->regs[7], env->regs[7] - 20);
-    xtensa_rfwu(env);
-}
-
-static void xtensa_overflow12(CPUXtensaState *env)
-{
-    put_user_ual(env->regs[0],  env->regs[13] - 16);
-    get_user_ual(env->regs[0],  env->regs[1]  - 12);
-    put_user_ual(env->regs[1],  env->regs[13] - 12);
-    put_user_ual(env->regs[2],  env->regs[13] -  8);
-    put_user_ual(env->regs[3],  env->regs[13] -  4);
-    put_user_ual(env->regs[4],  env->regs[0]  - 48);
-    put_user_ual(env->regs[5],  env->regs[0]  - 44);
-    put_user_ual(env->regs[6],  env->regs[0]  - 40);
-    put_user_ual(env->regs[7],  env->regs[0]  - 36);
-    put_user_ual(env->regs[8],  env->regs[0]  - 32);
-    put_user_ual(env->regs[9],  env->regs[0]  - 28);
-    put_user_ual(env->regs[10], env->regs[0]  - 24);
-    put_user_ual(env->regs[11], env->regs[0]  - 20);
-    xtensa_rfwo(env);
-}
-
-static void xtensa_underflow12(CPUXtensaState *env)
-{
-    get_user_ual(env->regs[0],  env->regs[13] - 16);
-    get_user_ual(env->regs[1],  env->regs[13] - 12);
-    get_user_ual(env->regs[2],  env->regs[13] -  8);
-    get_user_ual(env->regs[11], env->regs[1]  - 12);
-    get_user_ual(env->regs[3],  env->regs[13] -  4);
-    get_user_ual(env->regs[4],  env->regs[11] - 48);
-    get_user_ual(env->regs[5],  env->regs[11] - 44);
-    get_user_ual(env->regs[6],  env->regs[11] - 40);
-    get_user_ual(env->regs[7],  env->regs[11] - 36);
-    get_user_ual(env->regs[8],  env->regs[11] - 32);
-    get_user_ual(env->regs[9],  env->regs[11] - 28);
-    get_user_ual(env->regs[10], env->regs[11] - 24);
-    get_user_ual(env->regs[11], env->regs[11] - 20);
-    xtensa_rfwu(env);
-}
-
-void cpu_loop(CPUXtensaState *env)
-{
-    CPUState *cs = CPU(xtensa_env_get_cpu(env));
-    target_siginfo_t info;
-    abi_ulong ret;
-    int trapnr;
-
-    while (1) {
-        cpu_exec_start(cs);
-        trapnr = cpu_exec(cs);
-        cpu_exec_end(cs);
-        process_queued_cpu_work(cs);
-
-        env->sregs[PS] &= ~PS_EXCM;
-        switch (trapnr) {
-        case EXCP_INTERRUPT:
-            break;
-
-        case EXC_WINDOW_OVERFLOW4:
-            xtensa_overflow4(env);
-            break;
-        case EXC_WINDOW_UNDERFLOW4:
-            xtensa_underflow4(env);
-            break;
-        case EXC_WINDOW_OVERFLOW8:
-            xtensa_overflow8(env);
-            break;
-        case EXC_WINDOW_UNDERFLOW8:
-            xtensa_underflow8(env);
-            break;
-        case EXC_WINDOW_OVERFLOW12:
-            xtensa_overflow12(env);
-            break;
-        case EXC_WINDOW_UNDERFLOW12:
-            xtensa_underflow12(env);
-            break;
-
-        case EXC_USER:
-            switch (env->sregs[EXCCAUSE]) {
-            case ILLEGAL_INSTRUCTION_CAUSE:
-            case PRIVILEGED_CAUSE:
-                info.si_signo = TARGET_SIGILL;
-                info.si_errno = 0;
-                info.si_code =
-                    env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
-                    TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
-                info._sifields._sigfault._addr = env->sregs[EPC1];
-                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-                break;
-
-            case SYSCALL_CAUSE:
-                env->pc += 3;
-                ret = do_syscall(env, env->regs[2],
-                                 env->regs[6], env->regs[3],
-                                 env->regs[4], env->regs[5],
-                                 env->regs[8], env->regs[9], 0, 0);
-                switch (ret) {
-                default:
-                    env->regs[2] = ret;
-                    break;
-
-                case -TARGET_ERESTARTSYS:
-                    env->pc -= 3;
-                    break;
-
-                case -TARGET_QEMU_ESIGRETURN:
-                    break;
-                }
-                break;
-
-            case ALLOCA_CAUSE:
-                env->sregs[PS] = deposit32(env->sregs[PS],
-                                           PS_OWB_SHIFT,
-                                           PS_OWB_LEN,
-                                           env->sregs[WINDOW_BASE]);
-
-                switch (env->regs[0] & 0xc0000000) {
-                case 0x00000000:
-                case 0x40000000:
-                    xtensa_rotate_window(env, -1);
-                    xtensa_underflow4(env);
-                    break;
-
-                case 0x80000000:
-                    xtensa_rotate_window(env, -2);
-                    xtensa_underflow8(env);
-                    break;
-
-                case 0xc0000000:
-                    xtensa_rotate_window(env, -3);
-                    xtensa_underflow12(env);
-                    break;
-                }
-                break;
-
-            case INTEGER_DIVIDE_BY_ZERO_CAUSE:
-                info.si_signo = TARGET_SIGFPE;
-                info.si_errno = 0;
-                info.si_code = TARGET_FPE_INTDIV;
-                info._sifields._sigfault._addr = env->sregs[EPC1];
-                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-                break;
-
-            case LOAD_PROHIBITED_CAUSE:
-            case STORE_PROHIBITED_CAUSE:
-                info.si_signo = TARGET_SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SEGV_ACCERR;
-                info._sifields._sigfault._addr = env->sregs[EXCVADDR];
-                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-                break;
-
-            default:
-                fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
-                g_assert_not_reached();
-            }
-            break;
-        case EXCP_DEBUG:
-            trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
-            if (trapnr) {
-                info.si_signo = trapnr;
-                info.si_errno = 0;
-                info.si_code = TARGET_TRAP_BRKPT;
-                queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
-            }
-            break;
-        case EXC_DEBUG:
-        default:
-            fprintf(stderr, "trapnr = %d\n", trapnr);
-            g_assert_not_reached();
-        }
-        process_pending_signals(env);
-    }
-}
-
-#endif /* TARGET_XTENSA */
-
 __thread CPUState *thread_cpu;
 
 bool qemu_cpu_is_self(CPUState *cpu)
@@ -1049,9 +272,9 @@ static void handle_arg_stack_size(const char *arg)
     }
 
     if (*p == 'M') {
-        guest_stack_size *= 1024 * 1024;
+        guest_stack_size *= MiB;
     } else if (*p == 'k' || *p == 'K') {
-        guest_stack_size *= 1024;
+        guest_stack_size *= KiB;
     }
 }
 
@@ -1070,15 +293,9 @@ static void handle_arg_pagesize(const char *arg)
     }
 }
 
-static void handle_arg_randseed(const char *arg)
+static void handle_arg_seed(const char *arg)
 {
-    unsigned long long seed;
-
-    if (parse_uint_full(arg, &seed, 0) != 0 || seed > UINT_MAX) {
-        fprintf(stderr, "Invalid seed number: %s\n", arg);
-        exit(EXIT_FAILURE);
-    }
-    srand(seed);
+    seed_optarg = arg;
 }
 
 static void handle_arg_gdb(const char *arg)
@@ -1097,7 +314,7 @@ static void handle_arg_cpu(const char *arg)
     if (cpu_model == NULL || is_help_option(cpu_model)) {
         /* XXX: implement xxx_cpu_list for targets that still miss it */
 #if defined(cpu_list)
-        cpu_list(stdout, &fprintf);
+        cpu_list();
 #endif
         exit(EXIT_FAILURE);
     }
@@ -1213,7 +430,7 @@ static const struct qemu_argument arg_table[] = {
      "",           "run in singlestep mode"},
     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
      "",           "log system calls"},
-    {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_randseed,
+    {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_seed,
      "",           "Seed for pseudo-random number generator"},
     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
@@ -1381,6 +598,7 @@ int main(int argc, char **argv, char **envp)
     int ret;
     int execfd;
 
+    error_init(argv[0]);
     module_call_init(MODULE_INIT_TRACE);
     qemu_init_cpu_list();
     module_call_init(MODULE_INIT_QOM);
@@ -1405,8 +623,6 @@ int main(int argc, char **argv, char **envp)
 
     cpu_model = NULL;
 
-    srand(time(NULL));
-
     qemu_add_opts(&qemu_trace_opts);
 
     optind = parse_args(argc, argv);
@@ -1441,11 +657,22 @@ int main(int argc, char **argv, char **envp)
     if (cpu_model == NULL) {
         cpu_model = cpu_get_model(get_elf_eflags(execfd));
     }
-    cpu_type = parse_cpu_model(cpu_model);
+    cpu_type = parse_cpu_option(cpu_model);
 
+    /* init tcg before creating CPUs and to get qemu_host_page_size */
     tcg_exec_init(0);
-    /* NOTE: we need to init the CPU at this stage to get
-       qemu_host_page_size */
+
+    /* Reserving *too* much vm space via mmap can run into problems
+       with rlimits, oom due to page table creation, etc.  We will still try it,
+       if directed by the command-line option, but not by default.  */
+    if (HOST_LONG_BITS == 64 &&
+        TARGET_VIRT_ADDR_SPACE_BITS <= 32 &&
+        reserved_va == 0) {
+        /* reserved_va must be aligned with the host page size
+         * as it is used with mmap()
+         */
+        reserved_va = MAX_RESERVED_VA & qemu_host_page_mask;
+    }
 
     cpu = cpu_create(cpu_type);
     env = cpu->env_ptr;
@@ -1457,15 +684,27 @@ int main(int argc, char **argv, char **envp)
         do_strace = 1;
     }
 
-    if (getenv("QEMU_RAND_SEED")) {
-        handle_arg_randseed(getenv("QEMU_RAND_SEED"));
+    if (seed_optarg == NULL) {
+        seed_optarg = getenv("QEMU_RAND_SEED");
+    }
+    {
+        Error *err = NULL;
+        if (seed_optarg != NULL) {
+            qemu_guest_random_seed_main(seed_optarg, &err);
+        } else {
+            qcrypto_init(&err);
+        }
+        if (err) {
+            error_reportf_err(err, "cannot initialize crypto: ");
+            exit(1);
+        }
     }
 
     target_environ = envlist_to_environ(envlist, NULL);
     envlist_free(envlist);
 
     /*
-     * Now that page sizes are configured in cpu_init() we can do
+     * Now that page sizes are configured in tcg_exec_init() we can do
      * proper page alignment for guest_base.
      */
     guest_base = HOST_PAGE_ALIGN(guest_base);
@@ -1510,8 +749,8 @@ int main(int argc, char **argv, char **envp)
     target_argc = argc - optind;
     target_argv = calloc(target_argc + 1, sizeof (char *));
     if (target_argv == NULL) {
-       (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
-       exit(EXIT_FAILURE);
+        (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+        exit(EXIT_FAILURE);
     }
 
     /*
@@ -1578,42 +817,6 @@ int main(int argc, char **argv, char **envp)
 
     target_cpu_copy_regs(env, regs);
 
-#if defined(TARGET_RISCV)
-    {
-        env->pc = regs->sepc;
-        env->gpr[xSP] = regs->sp;
-    }
-#elif defined(TARGET_TILEGX)
-    {
-        int i;
-        for (i = 0; i < TILEGX_R_COUNT; i++) {
-            env->regs[i] = regs->regs[i];
-        }
-        for (i = 0; i < TILEGX_SPR_COUNT; i++) {
-            env->spregs[i] = 0;
-        }
-        env->pc = regs->pc;
-    }
-#elif defined(TARGET_HPPA)
-    {
-        int i;
-        for (i = 1; i < 32; i++) {
-            env->gr[i] = regs->gr[i];
-        }
-        env->iaoq_f = regs->iaoq[0];
-        env->iaoq_b = regs->iaoq[1];
-    }
-#elif defined(TARGET_XTENSA)
-    {
-        int i;
-        for (i = 0; i < 16; ++i) {
-            env->regs[i] = regs->areg[i];
-        }
-        env->sregs[WINDOW_START] = regs->windowstart;
-        env->pc = regs->pc;
-    }
-#endif
-
     if (gdbstub_port) {
         if (gdbserver_start(gdbstub_port) < 0) {
             fprintf(stderr, "qemu: could not open gdbserver on port %d\n",