From patchwork Sat Mar 23 19:09:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 160972 Delivered-To: patch@linaro.org Received: by 2002:a02:c6d8:0:0:0:0:0 with SMTP id r24csp2187769jan; Sat, 23 Mar 2019 12:33:38 -0700 (PDT) X-Google-Smtp-Source: APXvYqzMHTiJbRvRmAQZh9eoLn4XY58OlvmBrwLupOpEXZ4gBuBt67Mt95Vw3mqB89ew5/hN3jyl X-Received: by 2002:a25:4a88:: with SMTP id x130mr14093873yba.328.1553369618315; Sat, 23 Mar 2019 12:33:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1553369618; cv=none; d=google.com; s=arc-20160816; b=o/ms1yS3hdBadgSlYtqGNwCZUsP822fVr0xrIVaYt7Qgf2YJrj2Hw/A04L+xWUDOOM hIc3MW+VZpkBGcXSmP+RQsbonhpcCSBzRgkg/I9nVI5YQ6Q22BLxRp0OKfB77KUXIWT3 f+r5iay1mL7g/20Rw39JAdT/Nilp2sz8yJy0w/aeFEdZEuX/GHchaE5CfSZGz9x70CSZ MVeZL0Dvm/Q05vUmgSeYDcUoaQNfiYOXAHbeGt/WAu4qyy3Op1r9yo1xl41xj6oaIaTq Vt20SCKfkYbxotH7/fPTqCpOcHuTKx3AtONh6Fy+Dr5qNQufXZRsuA8KftEbv/6pEWom ANuw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=toOtnD54ZccAFcJcl4uO7OB9/pZ9I+Gvs8rhEDtsDuI=; b=htZ+v5S8eHsi5M7zep0kYaT7WGCJ05G4iryjUH3zNkWa/+1ly+BYF28bDuefvFIe2v pC/pHFhigkOwxH7fpE0d81m2//sq5ZirgVB7PFdo0Oj06Ub/Z2RH3R5jDaIhjigYpqhz ytrbwksYw4tQwKgJlPG7ty+hKe5jPNty2B37OQ8eTYIUCTLFdN99il0F24s6EMKwLn5o UYELw7b5yprG/8OnvxLnUDjOG0kZbMkggp98AOC+iknV2spxeGCxjGgi6kV5x6ddvRsd AtPgk6Wi6s3zeyln6LoxYSqYw0tv1fOMqLRLx3ZWRir8NJva8rP1TPbN2JxPQwbNY2F3 lRdg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=ohrAHOEY; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id y14si1238131ybr.368.2019.03.23.12.33.38 for (version=TLS1 cipher=AES128-SHA bits=128/128); Sat, 23 Mar 2019 12:33:38 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=ohrAHOEY; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:47063 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h7mOf-0006gU-Pi for patch@linaro.org; Sat, 23 Mar 2019 15:33:37 -0400 Received: from eggs.gnu.org ([209.51.188.92]:50919) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h7mFi-0007mr-FH for qemu-devel@nongnu.org; Sat, 23 Mar 2019 15:24:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h7m2Z-0007Yf-3C for qemu-devel@nongnu.org; Sat, 23 Mar 2019 15:10:51 -0400 Received: from mail-pf1-x434.google.com ([2607:f8b0:4864:20::434]:37193) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1h7m2V-00079T-CN for qemu-devel@nongnu.org; Sat, 23 Mar 2019 15:10:45 -0400 Received: by mail-pf1-x434.google.com with SMTP id 8so3685556pfr.4 for ; Sat, 23 Mar 2019 12:10:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=toOtnD54ZccAFcJcl4uO7OB9/pZ9I+Gvs8rhEDtsDuI=; b=ohrAHOEYEwh5u2yrQj+dkFSgJgt01CxNCWheoBYseZm//IaVglk4OzyLNELMrcXr3m 0HAfNSSwsj8WT2n8j9Un+EWsr6wHbh4LhMMYl8CqycmcBRJ2TSz36AGaJECM1QSpwKdb qYO6kF7/5E4/awbbIm+yt6eGktblszmGtwJu+A+Vlkr4J1ctgBQTzTe+yZ7vYq5IKKTx XRPYw4tCRAxz2xgpzzM+Rm+DVYIcWtIyzgxC5PUolqgphnhpl5Ioy463sWGccPIEIfBg xKcvkpRlmoyjzO4268+JH89OEx++dONVeH9HKXDQwIzh8gz3SqnDs9j2QylP6og1o9b7 E6bA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=toOtnD54ZccAFcJcl4uO7OB9/pZ9I+Gvs8rhEDtsDuI=; b=lEJNwTxob3bVmczrUFdBIh24Le10qxaIKdo42ovwjrR5UVBReofT4b/NEFf9d9rt6p xy1BRGK009SEy4FXzH4XtyY0gOFmGjK2Vc820pNPNyUET1nYPSVm6OPnrYkLMP5hPyWB /y9x3CzjS1fK1fyFcQsGqO8YgTjT2TzAEoXRJOkuTsaXWmC/0Y/WN9UoALhmmlRFDas4 zHYSN87jpqmAhwj7DfzVSFuy1/obKoge1Tbc2zxEM+V1RYCoH4tggFNQXXBWXsMfHVFl ThEtd+1AwVSYQxXdSjAnqEE1U3dudJMy3/v81KokEyLLcNO1RZ7iRNxyAUnPdswEyUXq KXkQ== X-Gm-Message-State: APjAAAUCaxBdiIb+4p4I05ZsxjQSWg5KAgK4NvG6d972FmFrvbwvHyay 0RKcH4zAC2hxYbMpPsjkhEihYC/8SmQ= X-Received: by 2002:a17:902:15a8:: with SMTP id m37mr16949982pla.178.1553368208581; Sat, 23 Mar 2019 12:10:08 -0700 (PDT) Received: from localhost.localdomain (174-21-5-201.tukw.qwest.net. [174.21.5.201]) by smtp.gmail.com with ESMTPSA id h184sm25990703pfc.78.2019.03.23.12.10.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 23 Mar 2019 12:10:06 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Sat, 23 Mar 2019 12:09:21 -0700 Message-Id: <20190323190925.21324-32-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190323190925.21324-1-richard.henderson@linaro.org> References: <20190323190925.21324-1-richard.henderson@linaro.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::434 Subject: [Qemu-devel] [PATCH 31/35] cpu: Move icount_decr to CPUNegativeOffsetState X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , =?utf-8?q?Andreas_F=C3=A4rber?= Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Amusingly, we had already ignored the comment to keep this value at the end of CPUState. This restores the minimum negative offset from TCG_AREG0 for code generation. This is slightly complicated for qom/cpu.c and tcg-all.c, in that they are compiled once. This means we need an out of line helper to access the icount_decr value. Cc: Paolo Bonzini Cc: Andreas Färber Signed-off-by: Richard Henderson --- RFC: I had problems with the build system moving qom/cpu.c from common-obj-y to obj-y. Then I tried just splitting out a piece of it, and ran into odder build system issues. Then I hacked Makefile.target in a way that doesn't look right, but works. Question: Should I bother splitting qom/cpu.c at all? Just move the whole thing to obj-y (with non-broken build changes, obviously, whatever that might be). r~ --- Makefile.target | 1 + include/exec/cpu-defs.h | 3 +- include/exec/gen-icount.h | 16 +- include/qom/cpu.h | 28 +-- accel/tcg/cpu-exec.c | 23 ++- accel/tcg/tcg-all.c | 6 +- accel/tcg/translate-all.c | 8 +- cpus.c | 9 +- qom/cpu-common.c | 425 ++++++++++++++++++++++++++++++++++++++ qom/cpu.c | 408 +----------------------------------- qom/Makefile.objs | 2 +- 11 files changed, 480 insertions(+), 449 deletions(-) create mode 100644 qom/cpu-common.c -- 2.17.1 diff --git a/Makefile.target b/Makefile.target index ae02495951..1fe3594768 100644 --- a/Makefile.target +++ b/Makefile.target @@ -117,6 +117,7 @@ obj-$(CONFIG_TCG) += fpu/softfloat.o obj-y += target/$(TARGET_BASE_ARCH)/ obj-y += disas.o obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o +obj-y += qom/cpu.o ######################################################### # Linux user emulator target diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ad97991faf..73de706342 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -33,6 +33,7 @@ #include "exec/hwaddr.h" #endif #include "exec/memattrs.h" +#include "qom/cpu.h" #include "cpu-param.h" @@ -232,7 +233,7 @@ typedef struct CPUTLB { * before CPUArchState, as a field named "neg". */ typedef struct CPUNegativeOffsetState { - /* Empty */ + icount_decr icount_decr; } CPUNegativeOffsetState; #endif diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 9cfa6ccce5..f7669b6841 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -5,8 +5,6 @@ /* Helpers for instruction counting code generation. */ -#define ENV_OFFSET offsetof(ArchCPU, env) - static TCGOp *icount_start_insn; static inline void gen_tb_start(TranslationBlock *tb) @@ -21,7 +19,8 @@ static inline void gen_tb_start(TranslationBlock *tb) } tcg_gen_ld_i32(count, cpu_env, - -ENV_OFFSET + offsetof(CPUState, icount_decr.u32)); + offsetof(ArchCPU, neg.icount_decr.u32) - + offsetof(ArchCPU, env)); if (tb_cflags(tb) & CF_USE_ICOUNT) { imm = tcg_temp_new_i32(); @@ -39,7 +38,8 @@ static inline void gen_tb_start(TranslationBlock *tb) if (tb_cflags(tb) & CF_USE_ICOUNT) { tcg_gen_st16_i32(count, cpu_env, - -ENV_OFFSET + offsetof(CPUState, icount_decr.u16.low)); + offsetof(ArchCPU, neg.icount_decr.u16.low) - + offsetof(ArchCPU, env)); } tcg_temp_free_i32(count); @@ -60,14 +60,18 @@ static inline void gen_tb_end(TranslationBlock *tb, int num_insns) static inline void gen_io_start(void) { TCGv_i32 tmp = tcg_const_i32(1); - tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io)); + tcg_gen_st_i32(tmp, cpu_env, + offsetof(ArchCPU, parent_obj.can_do_io) - + offsetof(ArchCPU, env)); tcg_temp_free_i32(tmp); } static inline void gen_io_end(void) { TCGv_i32 tmp = tcg_const_i32(0); - tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io)); + tcg_gen_st_i32(tmp, cpu_env, + offsetof(ArchCPU, parent_obj.can_do_io) - + offsetof(ArchCPU, env)); tcg_temp_free_i32(tmp); } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 1d6099e5d4..ee0159c97d 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -241,6 +241,18 @@ typedef struct icount_decr_u16 { } icount_decr_u16; #endif +/* + * Low 16 bits: number of cycles left, used only in icount mode. + * High 16 bits: Set to -1 to force TCG to stop executing linked TBs + * for this CPU and return to its top level loop (even in non-icount mode). + * This allows a single read-compare-cbranch-write sequence to test + * for both decrementer underflow and exceptions. + */ +typedef union icount_decr { + uint32_t u32; + icount_decr_u16 u16; +} icount_decr; + typedef struct CPUBreakpoint { vaddr pc; int flags; /* BP_* */ @@ -311,11 +323,6 @@ struct qemu_work_item; * @crash_occurred: Indicates the OS reported a crash (panic) for this CPU * @singlestep_enabled: Flags for single-stepping. * @icount_extra: Instructions until next timer event. - * @icount_decr: Low 16 bits: number of cycles left, only used in icount mode. - * High 16 bits: Set to -1 to force TCG to stop executing linked TBs for this - * CPU and return to its top level loop (even in non-icount mode). - * This allows a single read-compare-cbranch-write sequence to test - * for both decrementer underflow and exceptions. * @can_do_io: Nonzero if memory-mapped IO is safe. Deterministic execution * requires that IO only be performed on the last instruction of a TB * so that interrupts take effect immediately. @@ -437,15 +444,6 @@ struct CPUState { bool ignore_memory_transaction_failures; - /* Note that this is accessed at the start of every TB via a negative - offset from AREG0. Leave this field at the end so as to make the - (absolute value) offset as small as possible. This reduces code - size, especially for hosts without large memory offsets. */ - union { - uint32_t u32; - icount_decr_u16 u16; - } icount_decr; - struct hax_vcpu_state *hax_vcpu; int hvf_fd; @@ -1110,6 +1108,8 @@ void cpu_exec_unrealizefn(CPUState *cpu); */ bool target_words_bigendian(void); +void cpu_common_reset(CPUState *cpu); + #ifdef NEED_CPU_H #ifdef CONFIG_SOFTMMU diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 45ef41ebb2..032a62672e 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -54,7 +54,7 @@ typedef struct SyncClocks { #define MAX_DELAY_PRINT_RATE 2000000000LL #define MAX_NB_PRINTS 100 -static void align_clocks(SyncClocks *sc, const CPUState *cpu) +static void align_clocks(SyncClocks *sc, CPUState *cpu) { int64_t cpu_icount; @@ -62,7 +62,7 @@ static void align_clocks(SyncClocks *sc, const CPUState *cpu) return; } - cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low; + cpu_icount = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; sc->diff_clk += cpu_icount_to_ns(sc->last_cpu_icount - cpu_icount); sc->last_cpu_icount = cpu_icount; @@ -105,15 +105,15 @@ static void print_delay(const SyncClocks *sc) } } -static void init_delay_params(SyncClocks *sc, - const CPUState *cpu) +static void init_delay_params(SyncClocks *sc, CPUState *cpu) { if (!icount_align_option) { return; } sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sc->realtime_clock; - sc->last_cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low; + sc->last_cpu_icount + = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; if (sc->diff_clk < max_delay) { max_delay = sc->diff_clk; } @@ -467,7 +467,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) if (cpu->exception_index < 0) { #ifndef CONFIG_USER_ONLY if (replay_has_exception() - && cpu->icount_decr.u16.low + cpu->icount_extra == 0) { + && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) { /* try to cause an exception pending in the log */ cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0, curr_cflags()), true); } @@ -525,7 +525,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, * Ensure zeroing happens before reading cpu->exit_request or * cpu->interrupt_request (see also smp_wmb in cpu_exit()) */ - atomic_mb_set(&cpu->icount_decr.u16.high, 0); + atomic_mb_set(&cpu_neg(cpu)->icount_decr.u16.high, 0); if (unlikely(atomic_read(&cpu->interrupt_request))) { int interrupt_request; @@ -596,8 +596,9 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, } /* Finally, check if we need to exit to the main loop. */ - if (unlikely(atomic_read(&cpu->exit_request) - || (use_icount && cpu->icount_decr.u16.low + cpu->icount_extra == 0))) { + if (unlikely(atomic_read(&cpu->exit_request)) + || (use_icount + && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) { atomic_set(&cpu->exit_request, 0); if (cpu->exception_index == -1) { cpu->exception_index = EXCP_INTERRUPT; @@ -624,7 +625,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, } *last_tb = NULL; - insns_left = atomic_read(&cpu->icount_decr.u32); + insns_left = atomic_read(&cpu_neg(cpu)->icount_decr.u32); if (insns_left < 0) { /* Something asked us to stop executing chained TBs; just * continue round the main loop. Whatever requested the exit @@ -643,7 +644,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, cpu_update_icount(cpu); /* Refill decrementer and continue execution. */ insns_left = MIN(0xffff, cpu->icount_budget); - cpu->icount_decr.u16.low = insns_left; + cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu->icount_extra = cpu->icount_budget - insns_left; if (!cpu->icount_extra) { /* Execute any remaining instructions, then let the main loop diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 3d25bdcc17..9b215dcc5a 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -28,13 +28,12 @@ #include "sysemu/sysemu.h" #include "qom/object.h" #include "qemu-common.h" -#include "qom/cpu.h" +#include "cpu.h" #include "sysemu/cpus.h" #include "qemu/main-loop.h" unsigned long tcg_tb_size; -#ifndef CONFIG_USER_ONLY /* mask must never be zero, except for A20 change call */ static void tcg_handle_interrupt(CPUState *cpu, int mask) { @@ -51,7 +50,7 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask) if (!qemu_cpu_is_self(cpu)) { qemu_cpu_kick(cpu); } else { - atomic_set(&cpu->icount_decr.u16.high, -1); + atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); if (use_icount && !cpu->can_do_io && (mask & ~old_mask) != 0) { @@ -59,7 +58,6 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask) } } } -#endif static int tcg_init(MachineState *ms) { diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 2cc5d3c59f..ed19a41d55 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -363,7 +363,7 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, assert(use_icount); /* Reset the cycle counter to the start of the block and shift if to the number of actually executed instructions */ - cpu->icount_decr.u16.low += num_insns - i; + cpu_neg(cpu)->icount_decr.u16.low += num_insns - i; } restore_state_to_opc(env, tb, data); @@ -2162,7 +2162,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && env->active_tc.PC != tb->pc) { env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); - cpu->icount_decr.u16.low++; + cpu_neg(cpu)->icount_decr.u16.low++; env->hflags &= ~MIPS_HFLAG_BMASK; n = 2; } @@ -2170,7 +2170,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 && env->pc != tb->pc) { env->pc -= 2; - cpu->icount_decr.u16.low++; + cpu_neg(cpu)->icount_decr.u16.low++; env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); n = 2; } @@ -2344,7 +2344,7 @@ void cpu_interrupt(CPUState *cpu, int mask) { g_assert(qemu_mutex_iothread_locked()); cpu->interrupt_request |= mask; - atomic_set(&cpu->icount_decr.u16.high, -1); + atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); } /* diff --git a/cpus.c b/cpus.c index e83f72b48b..b123ef541e 100644 --- a/cpus.c +++ b/cpus.c @@ -237,7 +237,8 @@ void qemu_tcg_configure(QemuOpts *opts, Error **errp) */ static int64_t cpu_get_icount_executed(CPUState *cpu) { - return cpu->icount_budget - (cpu->icount_decr.u16.low + cpu->icount_extra); + return (cpu->icount_budget - + (cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra)); } /* @@ -1385,12 +1386,12 @@ static void prepare_icount_for_run(CPUState *cpu) * each vCPU execution. However u16.high can be raised * asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt */ - g_assert(cpu->icount_decr.u16.low == 0); + g_assert(cpu_neg(cpu)->icount_decr.u16.low == 0); g_assert(cpu->icount_extra == 0); cpu->icount_budget = tcg_get_icount_limit(); insns_left = MIN(0xffff, cpu->icount_budget); - cpu->icount_decr.u16.low = insns_left; + cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu->icount_extra = cpu->icount_budget - insns_left; replay_mutex_lock(); @@ -1404,7 +1405,7 @@ static void process_icount_data(CPUState *cpu) cpu_update_icount(cpu); /* Reset the counters */ - cpu->icount_decr.u16.low = 0; + cpu_neg(cpu)->icount_decr.u16.low = 0; cpu->icount_extra = 0; cpu->icount_budget = 0; diff --git a/qom/cpu-common.c b/qom/cpu-common.c new file mode 100644 index 0000000000..81d3821899 --- /dev/null +++ b/qom/cpu-common.c @@ -0,0 +1,425 @@ +/* + * QEMU CPU model + * + * Copyright (c) 2012-2014 SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "qom/cpu.h" +#include "sysemu/hw_accel.h" +#include "qemu/notify.h" +#include "qemu/log.h" +#include "exec/log.h" +#include "exec/cpu-common.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "trace-root.h" + +CPUInterruptHandler cpu_interrupt_handler; + +CPUState *cpu_by_arch_id(int64_t id) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->get_arch_id(cpu) == id) { + return cpu; + } + } + return NULL; +} + +bool cpu_exists(int64_t id) +{ + return !!cpu_by_arch_id(id); +} + +CPUState *cpu_create(const char *typename) +{ + Error *err = NULL; + CPUState *cpu = CPU(object_new(typename)); + object_property_set_bool(OBJECT(cpu), true, "realized", &err); + if (err != NULL) { + error_report_err(err); + object_unref(OBJECT(cpu)); + exit(EXIT_FAILURE); + } + return cpu; +} + +bool cpu_paging_enabled(const CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return cc->get_paging_enabled(cpu); +} + +static bool cpu_common_get_paging_enabled(const CPUState *cpu) +{ + return false; +} + +void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, + Error **errp) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + cc->get_memory_mapping(cpu, list, errp); +} + +static void cpu_common_get_memory_mapping(CPUState *cpu, + MemoryMappingList *list, + Error **errp) +{ + error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); +} + +/* Resetting the IRQ comes from across the code base so we take the + * BQL here if we need to. cpu_interrupt assumes it is held.*/ +void cpu_reset_interrupt(CPUState *cpu, int mask) +{ + bool need_lock = !qemu_mutex_iothread_locked(); + + if (need_lock) { + qemu_mutex_lock_iothread(); + } + cpu->interrupt_request &= ~mask; + if (need_lock) { + qemu_mutex_unlock_iothread(); + } +} + +int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf32_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return 0; +} + +int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf32_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf32_note(WriteCoreDumpFunction f, + CPUState *cpu, int cpuid, + void *opaque) +{ + return -1; +} + +int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf64_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return 0; +} + +int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf64_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf64_note(WriteCoreDumpFunction f, + CPUState *cpu, int cpuid, + void *opaque) +{ + return -1; +} + + +static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg) +{ + return 0; +} + +static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) +{ + return 0; +} + +static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp) +{ + /* If no extra check is required, QEMU watchpoint match can be considered + * as an architectural match. + */ + return true; +} + +static bool cpu_common_virtio_is_big_endian(CPUState *cpu) +{ + return target_words_bigendian(); +} + +static void cpu_common_noop(CPUState *cpu) +{ +} + +static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req) +{ + return false; +} + +GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + GuestPanicInformation *res = NULL; + + if (cc->get_crash_info) { + res = cc->get_crash_info(cpu); + } + return res; +} + +void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->dump_state) { + cpu_synchronize_state(cpu); + cc->dump_state(cpu, f, cpu_fprintf, flags); + } +} + +void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->dump_statistics) { + cc->dump_statistics(cpu, f, cpu_fprintf, flags); + } +} + +void cpu_reset(CPUState *cpu) +{ + CPUClass *klass = CPU_GET_CLASS(cpu); + + if (klass->reset != NULL) { + (*klass->reset)(cpu); + } + + trace_guest_cpu_reset(cpu); +} + +static bool cpu_common_has_work(CPUState *cs) +{ + return false; +} + +ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) +{ + CPUClass *cc = CPU_CLASS(object_class_by_name(typename)); + + assert(cpu_model && cc->class_by_name); + return cc->class_by_name(cpu_model); +} + +static void cpu_common_parse_features(const char *typename, char *features, + Error **errp) +{ + char *val; + static bool cpu_globals_initialized; + /* Single "key=value" string being parsed */ + char *featurestr = features ? strtok(features, ",") : NULL; + + /* should be called only once, catch invalid users */ + assert(!cpu_globals_initialized); + cpu_globals_initialized = true; + + while (featurestr) { + val = strchr(featurestr, '='); + if (val) { + GlobalProperty *prop = g_new0(typeof(*prop), 1); + *val = 0; + val++; + prop->driver = typename; + prop->property = g_strdup(featurestr); + prop->value = g_strdup(val); + qdev_prop_register_global(prop); + } else { + error_setg(errp, "Expected key=value format, found %s.", + featurestr); + return; + } + featurestr = strtok(NULL, ","); + } +} + +static void cpu_common_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cpu = CPU(dev); + Object *machine = qdev_get_machine(); + + /* qdev_get_machine() can return something that's not TYPE_MACHINE + * if this is one of the user-only emulators; in that case there's + * no need to check the ignore_memory_transaction_failures board flag. + */ + if (object_dynamic_cast(machine, TYPE_MACHINE)) { + ObjectClass *oc = object_get_class(machine); + MachineClass *mc = MACHINE_CLASS(oc); + + if (mc) { + cpu->ignore_memory_transaction_failures = + mc->ignore_memory_transaction_failures; + } + } + + if (dev->hotplugged) { + cpu_synchronize_post_init(cpu); + cpu_resume(cpu); + } + + /* NOTE: latest generic point where the cpu is fully realized */ + trace_init_vcpu(cpu); +} + +static void cpu_common_unrealizefn(DeviceState *dev, Error **errp) +{ + CPUState *cpu = CPU(dev); + /* NOTE: latest generic point before the cpu is fully unrealized */ + trace_fini_vcpu(cpu); + cpu_exec_unrealizefn(cpu); +} + +static void cpu_common_initfn(Object *obj) +{ + CPUState *cpu = CPU(obj); + CPUClass *cc = CPU_GET_CLASS(obj); + + cpu->cpu_index = UNASSIGNED_CPU_INDEX; + cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX; + cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; + /* *-user doesn't have configurable SMP topology */ + /* the default value is changed by qemu_init_vcpu() for softmmu */ + cpu->nr_cores = 1; + cpu->nr_threads = 1; + + qemu_mutex_init(&cpu->work_mutex); + QTAILQ_INIT(&cpu->breakpoints); + QTAILQ_INIT(&cpu->watchpoints); + + cpu_exec_initfn(cpu); +} + +static void cpu_common_finalize(Object *obj) +{ + CPUState *cpu = CPU(obj); + + qemu_mutex_destroy(&cpu->work_mutex); +} + +static int64_t cpu_common_get_arch_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + +static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len) +{ + return addr; +} + +static void generic_handle_interrupt(CPUState *cpu, int mask) +{ + cpu->interrupt_request |= mask; + + if (!qemu_cpu_is_self(cpu)) { + qemu_cpu_kick(cpu); + } +} + +CPUInterruptHandler cpu_interrupt_handler = generic_handle_interrupt; + +static void cpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + CPUClass *k = CPU_CLASS(klass); + + k->parse_features = cpu_common_parse_features; + k->reset = cpu_common_reset; + k->get_arch_id = cpu_common_get_arch_id; + k->has_work = cpu_common_has_work; + k->get_paging_enabled = cpu_common_get_paging_enabled; + k->get_memory_mapping = cpu_common_get_memory_mapping; + k->write_elf32_qemunote = cpu_common_write_elf32_qemunote; + k->write_elf32_note = cpu_common_write_elf32_note; + k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; + k->write_elf64_note = cpu_common_write_elf64_note; + k->gdb_read_register = cpu_common_gdb_read_register; + k->gdb_write_register = cpu_common_gdb_write_register; + k->virtio_is_big_endian = cpu_common_virtio_is_big_endian; + k->debug_excp_handler = cpu_common_noop; + k->debug_check_watchpoint = cpu_common_debug_check_watchpoint; + k->cpu_exec_enter = cpu_common_noop; + k->cpu_exec_exit = cpu_common_noop; + k->cpu_exec_interrupt = cpu_common_exec_interrupt; + k->adjust_watchpoint_address = cpu_adjust_watchpoint_address; + set_bit(DEVICE_CATEGORY_CPU, dc->categories); + dc->realize = cpu_common_realizefn; + dc->unrealize = cpu_common_unrealizefn; + dc->props = cpu_common_props; + /* + * Reason: CPUs still need special care by board code: wiring up + * IRQs, adding reset handlers, halting non-first CPUs, ... + */ + dc->user_creatable = false; +} + +static const TypeInfo cpu_type_info = { + .name = TYPE_CPU, + .parent = TYPE_DEVICE, + .instance_size = sizeof(CPUState), + .instance_init = cpu_common_initfn, + .instance_finalize = cpu_common_finalize, + .abstract = true, + .class_size = sizeof(CPUClass), + .class_init = cpu_class_init, +}; + +static void cpu_register_types(void) +{ + type_register_static(&cpu_type_info); +} + +type_init(cpu_register_types) diff --git a/qom/cpu.c b/qom/cpu.c index a8d2958956..830291a976 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -21,237 +21,18 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" -#include "qom/cpu.h" -#include "sysemu/hw_accel.h" -#include "qemu/notify.h" -#include "qemu/log.h" +#include "cpu.h" #include "exec/log.h" -#include "exec/cpu-common.h" -#include "qemu/error-report.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/qdev-properties.h" -#include "trace-root.h" - -CPUInterruptHandler cpu_interrupt_handler; - -CPUState *cpu_by_arch_id(int64_t id) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - CPUClass *cc = CPU_GET_CLASS(cpu); - - if (cc->get_arch_id(cpu) == id) { - return cpu; - } - } - return NULL; -} - -bool cpu_exists(int64_t id) -{ - return !!cpu_by_arch_id(id); -} - -CPUState *cpu_create(const char *typename) -{ - Error *err = NULL; - CPUState *cpu = CPU(object_new(typename)); - object_property_set_bool(OBJECT(cpu), true, "realized", &err); - if (err != NULL) { - error_report_err(err); - object_unref(OBJECT(cpu)); - exit(EXIT_FAILURE); - } - return cpu; -} - -bool cpu_paging_enabled(const CPUState *cpu) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return cc->get_paging_enabled(cpu); -} - -static bool cpu_common_get_paging_enabled(const CPUState *cpu) -{ - return false; -} - -void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, - Error **errp) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - cc->get_memory_mapping(cpu, list, errp); -} - -static void cpu_common_get_memory_mapping(CPUState *cpu, - MemoryMappingList *list, - Error **errp) -{ - error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); -} - -/* Resetting the IRQ comes from across the code base so we take the - * BQL here if we need to. cpu_interrupt assumes it is held.*/ -void cpu_reset_interrupt(CPUState *cpu, int mask) -{ - bool need_lock = !qemu_mutex_iothread_locked(); - - if (need_lock) { - qemu_mutex_lock_iothread(); - } - cpu->interrupt_request &= ~mask; - if (need_lock) { - qemu_mutex_unlock_iothread(); - } -} void cpu_exit(CPUState *cpu) { atomic_set(&cpu->exit_request, 1); /* Ensure cpu_exec will see the exit request after TCG has exited. */ smp_wmb(); - atomic_set(&cpu->icount_decr.u16.high, -1); + atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); } -int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf32_qemunote)(f, cpu, opaque); -} - -static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f, - CPUState *cpu, void *opaque) -{ - return 0; -} - -int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf32_note)(f, cpu, cpuid, opaque); -} - -static int cpu_common_write_elf32_note(WriteCoreDumpFunction f, - CPUState *cpu, int cpuid, - void *opaque) -{ - return -1; -} - -int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf64_qemunote)(f, cpu, opaque); -} - -static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f, - CPUState *cpu, void *opaque) -{ - return 0; -} - -int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf64_note)(f, cpu, cpuid, opaque); -} - -static int cpu_common_write_elf64_note(WriteCoreDumpFunction f, - CPUState *cpu, int cpuid, - void *opaque) -{ - return -1; -} - - -static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg) -{ - return 0; -} - -static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) -{ - return 0; -} - -static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp) -{ - /* If no extra check is required, QEMU watchpoint match can be considered - * as an architectural match. - */ - return true; -} - -static bool cpu_common_virtio_is_big_endian(CPUState *cpu) -{ - return target_words_bigendian(); -} - -static void cpu_common_noop(CPUState *cpu) -{ -} - -static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req) -{ - return false; -} - -GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - GuestPanicInformation *res = NULL; - - if (cc->get_crash_info) { - res = cc->get_crash_info(cpu); - } - return res; -} - -void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - if (cc->dump_state) { - cpu_synchronize_state(cpu); - cc->dump_state(cpu, f, cpu_fprintf, flags); - } -} - -void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - if (cc->dump_statistics) { - cc->dump_statistics(cpu, f, cpu_fprintf, flags); - } -} - -void cpu_reset(CPUState *cpu) -{ - CPUClass *klass = CPU_GET_CLASS(cpu); - - if (klass->reset != NULL) { - (*klass->reset)(cpu); - } - - trace_guest_cpu_reset(cpu); -} - -static void cpu_common_reset(CPUState *cpu) +void cpu_common_reset(CPUState *cpu) { CPUClass *cc = CPU_GET_CLASS(cpu); @@ -265,7 +46,7 @@ static void cpu_common_reset(CPUState *cpu) cpu->mem_io_pc = 0; cpu->mem_io_vaddr = 0; cpu->icount_extra = 0; - atomic_set(&cpu->icount_decr.u32, 0); + atomic_set(&cpu_neg(cpu)->icount_decr.u32, 0); cpu->can_do_io = 1; cpu->exception_index = -1; cpu->crash_occurred = false; @@ -277,184 +58,3 @@ static void cpu_common_reset(CPUState *cpu) tcg_flush_softmmu_tlb(cpu); } } - -static bool cpu_common_has_work(CPUState *cs) -{ - return false; -} - -ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) -{ - CPUClass *cc = CPU_CLASS(object_class_by_name(typename)); - - assert(cpu_model && cc->class_by_name); - return cc->class_by_name(cpu_model); -} - -static void cpu_common_parse_features(const char *typename, char *features, - Error **errp) -{ - char *val; - static bool cpu_globals_initialized; - /* Single "key=value" string being parsed */ - char *featurestr = features ? strtok(features, ",") : NULL; - - /* should be called only once, catch invalid users */ - assert(!cpu_globals_initialized); - cpu_globals_initialized = true; - - while (featurestr) { - val = strchr(featurestr, '='); - if (val) { - GlobalProperty *prop = g_new0(typeof(*prop), 1); - *val = 0; - val++; - prop->driver = typename; - prop->property = g_strdup(featurestr); - prop->value = g_strdup(val); - qdev_prop_register_global(prop); - } else { - error_setg(errp, "Expected key=value format, found %s.", - featurestr); - return; - } - featurestr = strtok(NULL, ","); - } -} - -static void cpu_common_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cpu = CPU(dev); - Object *machine = qdev_get_machine(); - - /* qdev_get_machine() can return something that's not TYPE_MACHINE - * if this is one of the user-only emulators; in that case there's - * no need to check the ignore_memory_transaction_failures board flag. - */ - if (object_dynamic_cast(machine, TYPE_MACHINE)) { - ObjectClass *oc = object_get_class(machine); - MachineClass *mc = MACHINE_CLASS(oc); - - if (mc) { - cpu->ignore_memory_transaction_failures = - mc->ignore_memory_transaction_failures; - } - } - - if (dev->hotplugged) { - cpu_synchronize_post_init(cpu); - cpu_resume(cpu); - } - - /* NOTE: latest generic point where the cpu is fully realized */ - trace_init_vcpu(cpu); -} - -static void cpu_common_unrealizefn(DeviceState *dev, Error **errp) -{ - CPUState *cpu = CPU(dev); - /* NOTE: latest generic point before the cpu is fully unrealized */ - trace_fini_vcpu(cpu); - cpu_exec_unrealizefn(cpu); -} - -static void cpu_common_initfn(Object *obj) -{ - CPUState *cpu = CPU(obj); - CPUClass *cc = CPU_GET_CLASS(obj); - - cpu->cpu_index = UNASSIGNED_CPU_INDEX; - cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX; - cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; - /* *-user doesn't have configurable SMP topology */ - /* the default value is changed by qemu_init_vcpu() for softmmu */ - cpu->nr_cores = 1; - cpu->nr_threads = 1; - - qemu_mutex_init(&cpu->work_mutex); - QTAILQ_INIT(&cpu->breakpoints); - QTAILQ_INIT(&cpu->watchpoints); - - cpu_exec_initfn(cpu); -} - -static void cpu_common_finalize(Object *obj) -{ - CPUState *cpu = CPU(obj); - - qemu_mutex_destroy(&cpu->work_mutex); -} - -static int64_t cpu_common_get_arch_id(CPUState *cpu) -{ - return cpu->cpu_index; -} - -static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len) -{ - return addr; -} - -static void generic_handle_interrupt(CPUState *cpu, int mask) -{ - cpu->interrupt_request |= mask; - - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - } -} - -CPUInterruptHandler cpu_interrupt_handler = generic_handle_interrupt; - -static void cpu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - CPUClass *k = CPU_CLASS(klass); - - k->parse_features = cpu_common_parse_features; - k->reset = cpu_common_reset; - k->get_arch_id = cpu_common_get_arch_id; - k->has_work = cpu_common_has_work; - k->get_paging_enabled = cpu_common_get_paging_enabled; - k->get_memory_mapping = cpu_common_get_memory_mapping; - k->write_elf32_qemunote = cpu_common_write_elf32_qemunote; - k->write_elf32_note = cpu_common_write_elf32_note; - k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; - k->write_elf64_note = cpu_common_write_elf64_note; - k->gdb_read_register = cpu_common_gdb_read_register; - k->gdb_write_register = cpu_common_gdb_write_register; - k->virtio_is_big_endian = cpu_common_virtio_is_big_endian; - k->debug_excp_handler = cpu_common_noop; - k->debug_check_watchpoint = cpu_common_debug_check_watchpoint; - k->cpu_exec_enter = cpu_common_noop; - k->cpu_exec_exit = cpu_common_noop; - k->cpu_exec_interrupt = cpu_common_exec_interrupt; - k->adjust_watchpoint_address = cpu_adjust_watchpoint_address; - set_bit(DEVICE_CATEGORY_CPU, dc->categories); - dc->realize = cpu_common_realizefn; - dc->unrealize = cpu_common_unrealizefn; - dc->props = cpu_common_props; - /* - * Reason: CPUs still need special care by board code: wiring up - * IRQs, adding reset handlers, halting non-first CPUs, ... - */ - dc->user_creatable = false; -} - -static const TypeInfo cpu_type_info = { - .name = TYPE_CPU, - .parent = TYPE_DEVICE, - .instance_size = sizeof(CPUState), - .instance_init = cpu_common_initfn, - .instance_finalize = cpu_common_finalize, - .abstract = true, - .class_size = sizeof(CPUClass), - .class_init = cpu_class_init, -}; - -static void cpu_register_types(void) -{ - type_register_static(&cpu_type_info); -} - -type_init(cpu_register_types) diff --git a/qom/Makefile.objs b/qom/Makefile.objs index 516349eec3..14506e0c2f 100644 --- a/qom/Makefile.objs +++ b/qom/Makefile.objs @@ -1,4 +1,4 @@ qom-obj-y = object.o container.o qom-qobject.o qom-obj-y += object_interfaces.o -common-obj-y = cpu.o +common-obj-y = cpu-common.o