* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+
#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/units.h"
+#include "sysemu/tcg.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 "qemu/module.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;
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;
# 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);
{
start_exclusive();
mmap_fork_start();
- qemu_mutex_lock(&tb_ctx.tb_lock);
cpu_list_lock();
}
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_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)
CPUArchState *cpu_copy(CPUArchState *env)
{
- CPUState *cpu = ENV_GET_CPU(env);
+ CPUState *cpu = env_cpu(env);
CPUState *new_cpu = cpu_create(cpu_type);
CPUArchState *new_env = new_cpu->env_ptr;
CPUBreakpoint *bp;
}
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;
}
}
}
}
-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)
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);
}
"", "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>]"},
int ret;
int execfd;
+ error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
qemu_init_cpu_list();
module_call_init(MODULE_INIT_QOM);
cpu_model = NULL;
- srand(time(NULL));
-
qemu_add_opts(&qemu_trace_opts);
optind = parse_args(argc, argv);
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;
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);
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);
}
/*
target_cpu_copy_regs(env, regs);
-#if 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",