From nobody Thu May 2 10:18:52 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1673712891; cv=none; d=zohomail.com; s=zohoarc; b=YwU+ZLxYjFCIHvPHay9fPzU6FpPYWBLvYYAyexM2c0XgS6sJE/GYjzR6MY8OpBAvMFMlZnV9syVW6ynC74yjcxB92YuGyLz3L484lXH5JEYOKNS19glyBchAp6VCJ5yTXb4kCyKr/1nRdWh2m5TGCG5ZS3z6ecQD1/YBjFo+p7g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1673712891; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=CNvD4W7gDzrm+GYmfk2E2CKCrUpAtRNGhMEJjb9L08I=; b=dL1u2Mrv5asbYRJlLJJj01YAg/1ooM7XjCw77Z1ZwQbVlbi4iBGXpS3/QEbVxUjIlWLM/2GhTkRPVb5Wq16ef3yyXuUwbxxaPTBSiWOMW4HQRIE+Pxnj1Nztw923NRrNa5ZdIpyPyBwd9ZxTQy49rH9fsIGqrJQ4R3KQofH6X4c= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1673712891126788.488141385044; Sat, 14 Jan 2023 08:14:51 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pGjAJ-0008C0-MY; Sat, 14 Jan 2023 11:13:55 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pGjAI-0008Bc-NI; Sat, 14 Jan 2023 11:13:54 -0500 Received: from mail-wr1-x429.google.com ([2a00:1450:4864:20::429]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pGjAF-0005zG-U9; Sat, 14 Jan 2023 11:13:54 -0500 Received: by mail-wr1-x429.google.com with SMTP id r9so864979wrw.4; Sat, 14 Jan 2023 08:13:51 -0800 (PST) Received: from omega.lan (194.46.205.77.rev.sfr.net. [77.205.46.194]) by smtp.gmail.com with ESMTPSA id y18-20020a5d6152000000b002425be3c9e2sm21330040wrt.60.2023.01.14.08.13.48 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 14 Jan 2023 08:13:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CNvD4W7gDzrm+GYmfk2E2CKCrUpAtRNGhMEJjb9L08I=; b=PW3AmaW+1DqSZZ9+zIf85KU5OJwEexzoR2Ba7uteCjwu4A7cmwdmFpeHaUnV04kTKs adYarFxllWUe2SRgzd22ZNnFPYAB0fInsm+RDl1wyXjOb2Za4PFKA9t0Nz2SCwRoDTUd Z8+nuF8mOYttGy3E921vMqhIxHB5OiJQV5bDANhfhh5YI3tB+DRs/GCc+7tLlXF459cA jLtnVp9oPAfqj9OrfvUn9XoTl14yJT8IWNMrmV/D08be5d1pgxlwwANEa7d0MOrFC185 3a33+k5tNa37g7jeiO8VW+gNX9kTDY6nZqgLZwRiOY42lF+8NfOX64FlCHkP0tyqNu8M fVPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CNvD4W7gDzrm+GYmfk2E2CKCrUpAtRNGhMEJjb9L08I=; b=aaPySY4KYuA5QwX//3JNSY7jGi5zb68MQqDEo5XPKPG47X1JndnD1ds8EU0zgul9nj xpCjJ2V+Srd+rfmQfX1zVMiwpOynRJ6oy96LFOFmLHZVYK5MOfv0OwhARIso0lrzwo2Q l8swP8Xj3JiQXSen1M2R3EpUOdH3D165/A7UZM4Riok9z51fIcqLzQQnibzUh02WUMo8 dOrohNKFUwadO0rW99U7EK39oZez0T+WZaG9OfKZfLhwQT51TLiDKiw15/qYiNqrtsfv oyTkSumxsQJKXUvUVxVk6l9FASG7zysZbJ5Ujd/0b2jivPpRMnqDVHf5EeeI7rgZ1TF6 Xz1Q== X-Gm-Message-State: AFqh2krlwbysGRfDOfmac0VKzqD2DLM/MyOEVFdbyJeROKZgbJGJiYmE hwDCMBlaOZ05pCWIA9rCF/URtjjHabpW2Q== X-Google-Smtp-Source: AMrXdXvrXG3vnD4HACRuSiod7YzHTZhKgfPwC7vUfmOp9valBYEGnK4vg2zczGPd8fyYsz1sVa7HoA== X-Received: by 2002:adf:ea12:0:b0:2bd:c097:848b with SMTP id q18-20020adfea12000000b002bdc097848bmr11073222wrm.16.1673712830028; Sat, 14 Jan 2023 08:13:50 -0800 (PST) From: francesco.cagnin@gmail.com X-Google-Original-From: fcagnin@quarkslab.com To: qemu-devel@nongnu.org Cc: mads@ynddal.dk, dirty@apple.com, peter.maydell@linaro.org, qemu-arm@nongnu.org, agraf@csgraf.de, pbonzini@redhat.com, alex.bennee@linaro.org, Francesco Cagnin Subject: [PATCH v3 1/3] arm: move KVM breakpoints helpers Date: Sat, 14 Jan 2023 17:13:00 +0100 Message-Id: <20230114161302.94595-2-fcagnin@quarkslab.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230114161302.94595-1-fcagnin@quarkslab.com> References: <20230114161302.94595-1-fcagnin@quarkslab.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::429; envelope-from=francesco.cagnin@gmail.com; helo=mail-wr1-x429.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer2=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1673712893287100003 Content-Type: text/plain; charset="utf-8" From: Francesco Cagnin These helpers will be also used for HVF. Aside from reformatting a couple of comments for 'checkpatch.pl' and updating meson to compile 'hyp_gdbstub.c', this is just code motion. Signed-off-by: Francesco Cagnin Reviewed-by: Alex Benn=C3=A9e Reviewed-by: Peter Maydell --- target/arm/hyp_gdbstub.c | 242 ++++++++++++++++++++++++++++++++++ target/arm/internals.h | 50 +++++++ target/arm/kvm64.c | 276 --------------------------------------- target/arm/meson.build | 3 +- 4 files changed, 294 insertions(+), 277 deletions(-) create mode 100644 target/arm/hyp_gdbstub.c diff --git a/target/arm/hyp_gdbstub.c b/target/arm/hyp_gdbstub.c new file mode 100644 index 0000000000..22b2b7de7b --- /dev/null +++ b/target/arm/hyp_gdbstub.c @@ -0,0 +1,242 @@ +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" +#include "exec/gdbstub.h" + +/* Maximum and current break/watch point counts */ +int max_hw_bps, max_hw_wps; +GArray *hw_breakpoints, *hw_watchpoints; + +/** + * insert_hw_breakpoint() + * @addr: address of breakpoint + * + * See ARM ARM D2.9.1 for details but here we are only going to create + * simple un-linked breakpoints (i.e. we don't chain breakpoints + * together to match address and context or vmid). The hardware is + * capable of fancier matching but that will require exposing that + * fanciness to GDB's interface + * + * DBGBCR_EL1, Debug Breakpoint Control Registers + * + * 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0 + * +------+------+-------+-----+----+------+-----+------+-----+---+ + * | RES0 | BT | LBN | SSC | HMC| RES0 | BAS | RES0 | PMC | E | + * +------+------+-------+-----+----+------+-----+------+-----+---+ + * + * BT: Breakpoint type (0 =3D unlinked address match) + * LBN: Linked BP number (0 =3D unused) + * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12) + * BAS: Byte Address Select (RES1 for AArch64) + * E: Enable bit + * + * DBGBVR_EL1, Debug Breakpoint Value Registers + * + * 63 53 52 49 48 2 1 0 + * +------+-----------+----------+-----+ + * | RESS | VA[52:49] | VA[48:2] | 0 0 | + * +------+-----------+----------+-----+ + * + * Depending on the addressing mode bits the top bits of the register + * are a sign extension of the highest applicable VA bit. Some + * versions of GDB don't do it correctly so we ensure they are correct + * here so future PC comparisons will work properly. + */ + +int insert_hw_breakpoint(target_ulong addr) +{ + HWBreakpoint brk =3D { + .bcr =3D 0x1, /* BCR E=3D1, enable */ + .bvr =3D sextract64(addr, 0, 53) + }; + + if (cur_hw_bps >=3D max_hw_bps) { + return -ENOBUFS; + } + + brk.bcr =3D deposit32(brk.bcr, 1, 2, 0x3); /* PMC =3D 11 */ + brk.bcr =3D deposit32(brk.bcr, 5, 4, 0xf); /* BAS =3D RES1 */ + + g_array_append_val(hw_breakpoints, brk); + + return 0; +} + +/** + * delete_hw_breakpoint() + * @pc: address of breakpoint + * + * Delete a breakpoint and shuffle any above down + */ + +int delete_hw_breakpoint(target_ulong pc) +{ + int i; + for (i =3D 0; i < hw_breakpoints->len; i++) { + HWBreakpoint *brk =3D get_hw_bp(i); + if (brk->bvr =3D=3D pc) { + g_array_remove_index(hw_breakpoints, i); + return 0; + } + } + return -ENOENT; +} + +/** + * insert_hw_watchpoint() + * @addr: address of watch point + * @len: size of area + * @type: type of watch point + * + * See ARM ARM D2.10. As with the breakpoints we can do some advanced + * stuff if we want to. The watch points can be linked with the break + * points above to make them context aware. However for simplicity + * currently we only deal with simple read/write watch points. + * + * D7.3.11 DBGWCR_EL1, Debug Watchpoint Control Registers + * + * 31 29 28 24 23 21 20 19 16 15 14 13 12 5 4 3 2 1 0 + * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+ + * | RES0 | MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E | + * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+ + * + * MASK: num bits addr mask (0=3Dnone,01/10=3Dres,11=3D3 bits (8 bytes)) + * WT: 0 - unlinked, 1 - linked (not currently used) + * LBN: Linked BP number (not currently used) + * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11) + * BAS: Byte Address Select + * LSC: Load/Store control (01: load, 10: store, 11: both) + * E: Enable + * + * The bottom 2 bits of the value register are masked. Therefore to + * break on any sizes smaller than an unaligned word you need to set + * MASK=3D0, BAS=3Dbit per byte in question. For larger regions (^2) you + * need to ensure you mask the address as required and set BAS=3D0xff + */ + +int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type) +{ + HWWatchpoint wp =3D { + .wcr =3D R_DBGWCR_E_MASK, /* E=3D1, enable */ + .wvr =3D addr & (~0x7ULL), + .details =3D { .vaddr =3D addr, .len =3D len } + }; + + if (cur_hw_wps >=3D max_hw_wps) { + return -ENOBUFS; + } + + /* + * HMC=3D0 SSC=3D0 PAC=3D3 will hit EL0 or EL1, any security state, + * valid whether EL3 is implemented or not + */ + wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, PAC, 3); + + switch (type) { + case GDB_WATCHPOINT_READ: + wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, LSC, 1); + wp.details.flags =3D BP_MEM_READ; + break; + case GDB_WATCHPOINT_WRITE: + wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, LSC, 2); + wp.details.flags =3D BP_MEM_WRITE; + break; + case GDB_WATCHPOINT_ACCESS: + wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, LSC, 3); + wp.details.flags =3D BP_MEM_ACCESS; + break; + default: + g_assert_not_reached(); + break; + } + if (len <=3D 8) { + /* we align the address and set the bits in BAS */ + int off =3D addr & 0x7; + int bas =3D (1 << len) - 1; + + wp.wcr =3D deposit32(wp.wcr, 5 + off, 8 - off, bas); + } else { + /* For ranges above 8 bytes we need to be a power of 2 */ + if (is_power_of_2(len)) { + int bits =3D ctz64(len); + + wp.wvr &=3D ~((1 << bits) - 1); + wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, MASK, bits); + wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff); + } else { + return -ENOBUFS; + } + } + + g_array_append_val(hw_watchpoints, wp); + return 0; +} + +bool check_watchpoint_in_range(int i, target_ulong addr) +{ + HWWatchpoint *wp =3D get_hw_wp(i); + uint64_t addr_top, addr_bottom =3D wp->wvr; + int bas =3D extract32(wp->wcr, 5, 8); + int mask =3D extract32(wp->wcr, 24, 4); + + if (mask) { + addr_top =3D addr_bottom + (1 << mask); + } else { + /* + * BAS must be contiguous but can offset against the base + * address in DBGWVR + */ + addr_bottom =3D addr_bottom + ctz32(bas); + addr_top =3D addr_bottom + clo32(bas); + } + + if (addr >=3D addr_bottom && addr <=3D addr_top) { + return true; + } + + return false; +} + +/** + * delete_hw_watchpoint() + * @addr: address of breakpoint + * + * Delete a breakpoint and shuffle any above down + */ + +int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type) +{ + int i; + for (i =3D 0; i < cur_hw_wps; i++) { + if (check_watchpoint_in_range(i, addr)) { + g_array_remove_index(hw_watchpoints, i); + return 0; + } + } + return -ENOENT; +} + +bool find_hw_breakpoint(CPUState *cpu, target_ulong pc) +{ + int i; + + for (i =3D 0; i < cur_hw_bps; i++) { + HWBreakpoint *bp =3D get_hw_bp(i); + if (bp->bvr =3D=3D pc) { + return true; + } + } + return false; +} + +CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr) +{ + int i; + + for (i =3D 0; i < cur_hw_wps; i++) { + if (check_watchpoint_in_range(i, addr)) { + return &get_hw_wp(i)->details; + } + } + return NULL; +} diff --git a/target/arm/internals.h b/target/arm/internals.h index d9555309df..6b69d8c774 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1377,4 +1377,54 @@ static inline uint64_t arm_mdcr_el2_eff(CPUARMState = *env) ((1 << (1 - 1)) | (1 << (2 - 1)) | \ (1 << (4 - 1)) | (1 << (8 - 1)) | (1 << (16 - 1))) =20 +/* + * Although the ARM implementation of hardware assisted debugging + * allows for different breakpoints per-core, the current GDB + * interface treats them as a global pool of registers (which seems to + * be the case for x86, ppc and s390). As a result we store one copy + * of registers which is used for all active cores. + * + * Write access is serialised by virtue of the GDB protocol which + * updates things. Read access (i.e. when the values are copied to the + * vCPU) is also gated by GDB's run control. + * + * This is not unreasonable as most of the time debugging kernels you + * never know which core will eventually execute your function. + */ + +typedef struct { + uint64_t bcr; + uint64_t bvr; +} HWBreakpoint; + +/* + * The watchpoint registers can cover more area than the requested + * watchpoint so we need to store the additional information + * somewhere. We also need to supply a CPUWatchpoint to the GDB stub + * when the watchpoint is hit. + */ +typedef struct { + uint64_t wcr; + uint64_t wvr; + CPUWatchpoint details; +} HWWatchpoint; + +/* Maximum and current break/watch point counts */ +extern int max_hw_bps, max_hw_wps; +extern GArray *hw_breakpoints, *hw_watchpoints; + +#define cur_hw_wps (hw_watchpoints->len) +#define cur_hw_bps (hw_breakpoints->len) +#define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i)) +#define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i)) + +bool find_hw_breakpoint(CPUState *cpu, target_ulong pc); +int insert_hw_breakpoint(target_ulong pc); +int delete_hw_breakpoint(target_ulong pc); + +bool check_watchpoint_in_range(int i, target_ulong addr); +CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr); +int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type); +int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type); + #endif diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 1197253d12..fb7bb65947 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -34,46 +34,6 @@ =20 static bool have_guest_debug; =20 -/* - * Although the ARM implementation of hardware assisted debugging - * allows for different breakpoints per-core, the current GDB - * interface treats them as a global pool of registers (which seems to - * be the case for x86, ppc and s390). As a result we store one copy - * of registers which is used for all active cores. - * - * Write access is serialised by virtue of the GDB protocol which - * updates things. Read access (i.e. when the values are copied to the - * vCPU) is also gated by GDB's run control. - * - * This is not unreasonable as most of the time debugging kernels you - * never know which core will eventually execute your function. - */ - -typedef struct { - uint64_t bcr; - uint64_t bvr; -} HWBreakpoint; - -/* The watchpoint registers can cover more area than the requested - * watchpoint so we need to store the additional information - * somewhere. We also need to supply a CPUWatchpoint to the GDB stub - * when the watchpoint is hit. - */ -typedef struct { - uint64_t wcr; - uint64_t wvr; - CPUWatchpoint details; -} HWWatchpoint; - -/* Maximum and current break/watch point counts */ -int max_hw_bps, max_hw_wps; -GArray *hw_breakpoints, *hw_watchpoints; - -#define cur_hw_wps (hw_watchpoints->len) -#define cur_hw_bps (hw_breakpoints->len) -#define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i)) -#define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i)) - /** * kvm_arm_init_debug() - check for guest debug capabilities * @cs: CPUState @@ -97,217 +57,6 @@ static void kvm_arm_init_debug(CPUState *cs) return; } =20 -/** - * insert_hw_breakpoint() - * @addr: address of breakpoint - * - * See ARM ARM D2.9.1 for details but here we are only going to create - * simple un-linked breakpoints (i.e. we don't chain breakpoints - * together to match address and context or vmid). The hardware is - * capable of fancier matching but that will require exposing that - * fanciness to GDB's interface - * - * DBGBCR_EL1, Debug Breakpoint Control Registers - * - * 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0 - * +------+------+-------+-----+----+------+-----+------+-----+---+ - * | RES0 | BT | LBN | SSC | HMC| RES0 | BAS | RES0 | PMC | E | - * +------+------+-------+-----+----+------+-----+------+-----+---+ - * - * BT: Breakpoint type (0 =3D unlinked address match) - * LBN: Linked BP number (0 =3D unused) - * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12) - * BAS: Byte Address Select (RES1 for AArch64) - * E: Enable bit - * - * DBGBVR_EL1, Debug Breakpoint Value Registers - * - * 63 53 52 49 48 2 1 0 - * +------+-----------+----------+-----+ - * | RESS | VA[52:49] | VA[48:2] | 0 0 | - * +------+-----------+----------+-----+ - * - * Depending on the addressing mode bits the top bits of the register - * are a sign extension of the highest applicable VA bit. Some - * versions of GDB don't do it correctly so we ensure they are correct - * here so future PC comparisons will work properly. - */ - -static int insert_hw_breakpoint(target_ulong addr) -{ - HWBreakpoint brk =3D { - .bcr =3D 0x1, /* BCR E=3D1, enable */ - .bvr =3D sextract64(addr, 0, 53) - }; - - if (cur_hw_bps >=3D max_hw_bps) { - return -ENOBUFS; - } - - brk.bcr =3D deposit32(brk.bcr, 1, 2, 0x3); /* PMC =3D 11 */ - brk.bcr =3D deposit32(brk.bcr, 5, 4, 0xf); /* BAS =3D RES1 */ - - g_array_append_val(hw_breakpoints, brk); - - return 0; -} - -/** - * delete_hw_breakpoint() - * @pc: address of breakpoint - * - * Delete a breakpoint and shuffle any above down - */ - -static int delete_hw_breakpoint(target_ulong pc) -{ - int i; - for (i =3D 0; i < hw_breakpoints->len; i++) { - HWBreakpoint *brk =3D get_hw_bp(i); - if (brk->bvr =3D=3D pc) { - g_array_remove_index(hw_breakpoints, i); - return 0; - } - } - return -ENOENT; -} - -/** - * insert_hw_watchpoint() - * @addr: address of watch point - * @len: size of area - * @type: type of watch point - * - * See ARM ARM D2.10. As with the breakpoints we can do some advanced - * stuff if we want to. The watch points can be linked with the break - * points above to make them context aware. However for simplicity - * currently we only deal with simple read/write watch points. - * - * D7.3.11 DBGWCR_EL1, Debug Watchpoint Control Registers - * - * 31 29 28 24 23 21 20 19 16 15 14 13 12 5 4 3 2 1 0 - * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+ - * | RES0 | MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E | - * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+ - * - * MASK: num bits addr mask (0=3Dnone,01/10=3Dres,11=3D3 bits (8 bytes)) - * WT: 0 - unlinked, 1 - linked (not currently used) - * LBN: Linked BP number (not currently used) - * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11) - * BAS: Byte Address Select - * LSC: Load/Store control (01: load, 10: store, 11: both) - * E: Enable - * - * The bottom 2 bits of the value register are masked. Therefore to - * break on any sizes smaller than an unaligned word you need to set - * MASK=3D0, BAS=3Dbit per byte in question. For larger regions (^2) you - * need to ensure you mask the address as required and set BAS=3D0xff - */ - -static int insert_hw_watchpoint(target_ulong addr, - target_ulong len, int type) -{ - HWWatchpoint wp =3D { - .wcr =3D R_DBGWCR_E_MASK, /* E=3D1, enable */ - .wvr =3D addr & (~0x7ULL), - .details =3D { .vaddr =3D addr, .len =3D len } - }; - - if (cur_hw_wps >=3D max_hw_wps) { - return -ENOBUFS; - } - - /* - * HMC=3D0 SSC=3D0 PAC=3D3 will hit EL0 or EL1, any security state, - * valid whether EL3 is implemented or not - */ - wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, PAC, 3); - - switch (type) { - case GDB_WATCHPOINT_READ: - wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, LSC, 1); - wp.details.flags =3D BP_MEM_READ; - break; - case GDB_WATCHPOINT_WRITE: - wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, LSC, 2); - wp.details.flags =3D BP_MEM_WRITE; - break; - case GDB_WATCHPOINT_ACCESS: - wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, LSC, 3); - wp.details.flags =3D BP_MEM_ACCESS; - break; - default: - g_assert_not_reached(); - break; - } - if (len <=3D 8) { - /* we align the address and set the bits in BAS */ - int off =3D addr & 0x7; - int bas =3D (1 << len) - 1; - - wp.wcr =3D deposit32(wp.wcr, 5 + off, 8 - off, bas); - } else { - /* For ranges above 8 bytes we need to be a power of 2 */ - if (is_power_of_2(len)) { - int bits =3D ctz64(len); - - wp.wvr &=3D ~((1 << bits) - 1); - wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, MASK, bits); - wp.wcr =3D FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff); - } else { - return -ENOBUFS; - } - } - - g_array_append_val(hw_watchpoints, wp); - return 0; -} - - -static bool check_watchpoint_in_range(int i, target_ulong addr) -{ - HWWatchpoint *wp =3D get_hw_wp(i); - uint64_t addr_top, addr_bottom =3D wp->wvr; - int bas =3D extract32(wp->wcr, 5, 8); - int mask =3D extract32(wp->wcr, 24, 4); - - if (mask) { - addr_top =3D addr_bottom + (1 << mask); - } else { - /* BAS must be contiguous but can offset against the base - * address in DBGWVR */ - addr_bottom =3D addr_bottom + ctz32(bas); - addr_top =3D addr_bottom + clo32(bas); - } - - if (addr >=3D addr_bottom && addr <=3D addr_top) { - return true; - } - - return false; -} - -/** - * delete_hw_watchpoint() - * @addr: address of breakpoint - * - * Delete a breakpoint and shuffle any above down - */ - -static int delete_hw_watchpoint(target_ulong addr, - target_ulong len, int type) -{ - int i; - for (i =3D 0; i < cur_hw_wps; i++) { - if (check_watchpoint_in_range(i, addr)) { - g_array_remove_index(hw_watchpoints, i); - return 0; - } - } - return -ENOENT; -} - - int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type) { @@ -372,31 +121,6 @@ bool kvm_arm_hw_debug_active(CPUState *cs) return ((cur_hw_wps > 0) || (cur_hw_bps > 0)); } =20 -static bool find_hw_breakpoint(CPUState *cpu, target_ulong pc) -{ - int i; - - for (i =3D 0; i < cur_hw_bps; i++) { - HWBreakpoint *bp =3D get_hw_bp(i); - if (bp->bvr =3D=3D pc) { - return true; - } - } - return false; -} - -static CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr) -{ - int i; - - for (i =3D 0; i < cur_hw_wps; i++) { - if (check_watchpoint_in_range(i, addr)) { - return &get_hw_wp(i)->details; - } - } - return NULL; -} - static bool kvm_arm_set_device_attr(CPUState *cs, struct kvm_device_attr *= attr, const char *name) { diff --git a/target/arm/meson.build b/target/arm/meson.build index 87e911b27f..63f5d30dd8 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -40,7 +40,8 @@ arm_ss.add(files( )) arm_ss.add(zlib) =20 -arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c', 'kvm64.c'), if_fals= e: files('kvm-stub.c')) +arm_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c', 'k= vm64.c'), if_false: files('kvm-stub.c')) +arm_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) =20 arm_ss.add(when: 'TARGET_AARCH64', if_true: files( 'cpu64.c', --=20 2.39.0 From nobody Thu May 2 10:18:52 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1673712919; cv=none; d=zohomail.com; s=zohoarc; b=dq+AuHdhyByEzNj9dVWDNIucc3jMajfRd96Ewb0+4rsBB+oD48sxbiqVT/q4p1ecpt+GEVMPaJuMd/RTnJkECgfbSBsL0QA8jWxJZznaYU13pFvPapdsW3FZfy/qSX44yOHOAWtLn45f70dJEF9+7SI13/jOzO+5wqVBa7RBLiI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1673712919; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=g0m8c3zD35Rh8jN697QlkJTzBkwPaUq+dtz2zKp3crs=; b=PvbdpbH6UpHGrK2t3pozsJQD5S+EmAlwx/1y6OwHVgc2WkKyANUv11ZeK7KRSIK+OuxlSQTm3KLgHe/mp+p8uKEO5wP8kT2ZD3yARVRbcmP28jafuAwzTXI+jcfuxcSYuNHRo46mcC2ze4ebwiuLUBYoFSGdsWALojuDGSIA2ao= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1673712919195651.7360076053429; Sat, 14 Jan 2023 08:15:19 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pGjAN-0008E6-HJ; Sat, 14 Jan 2023 11:13:59 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pGjAL-0008Cj-Dl; Sat, 14 Jan 2023 11:13:57 -0500 Received: from mail-wr1-x42f.google.com ([2a00:1450:4864:20::42f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pGjAH-0005zg-VJ; Sat, 14 Jan 2023 11:13:57 -0500 Received: by mail-wr1-x42f.google.com with SMTP id bs20so23663329wrb.3; Sat, 14 Jan 2023 08:13:53 -0800 (PST) Received: from omega.lan (194.46.205.77.rev.sfr.net. [77.205.46.194]) by smtp.gmail.com with ESMTPSA id y18-20020a5d6152000000b002425be3c9e2sm21330040wrt.60.2023.01.14.08.13.50 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 14 Jan 2023 08:13:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=g0m8c3zD35Rh8jN697QlkJTzBkwPaUq+dtz2zKp3crs=; b=hA5l/VIc5kFYcTU5FHAD6Lrri3SgZJSs1rmEou4G9Ix/JMbDdWg7+nUYUeDCU0KIaa TZs7FQSCpwisYF5JUcQpe2iNUI3p6/WVqDF0qb0x6uuheT812aqSCQqJUue7kFV0mh3b ouP7N4u+6I0ZBE/r+LIs8QED2LqpgL6EKti1DRNnKnf4ht+Q8bP+P9NoSPeZnx4solv1 gQxAmH4CSNBEu9CfktSMQM2Hq8ZwXBzPRFSWpxNKnjxcblcIGhJt9RAEuFv0hCAo5EQs Zm3RXEb40USncJWZJ1QgC2xJFpVn/GogMJI8YajD+/zLStsAlHUvX9Wa7RnZT1+KHN2S 3yNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=g0m8c3zD35Rh8jN697QlkJTzBkwPaUq+dtz2zKp3crs=; b=07qdCrmbozKfzKcoe40BcxqZ51Lw+5jex87NDostQUy2pYXXz6rTDnssyuwnR2Y/14 nb8NGMZAp+eqtNHK0KJlpDgI6svTFaIlrKRslJ3Q+ApmiOyu7vGCc7JAz+MrtXTkQwtF PPNOahJNmduYj9rr3uytfs10wApfMwXjgSuwE1hQPv8fnBWC5Ia+bDV7eDOsG9Arfxqm NvPJDbpxjiIoWuwOpXRONB+gjgwZeOWUD6PdgwmNMwGjKeDrsRDETKtHxgM+acr7qWfa nuPNpR+Jy31yT1j5CF9Afwa/69X28t2Ko+YBNvV59ozGt6ugjU4IfdvyeYEg2/5QdjWr dorw== X-Gm-Message-State: AFqh2kpZ2L78Q7cuL7jpqHRZBfeSQm2v69tUyp4h7TnAiV0jiQzkXXUb 2neO/iQBK+EA37Ap/arTCGg02H96tirK6g== X-Google-Smtp-Source: AMrXdXseXrRHSgi6URLeHdzyptRQRPQ05+ZH54krfxmH6jMQN9+j5Ut1KN3wNh6/IssroAI385YdnA== X-Received: by 2002:a5d:4351:0:b0:256:ff7d:2346 with SMTP id u17-20020a5d4351000000b00256ff7d2346mr48748732wrr.51.1673712832115; Sat, 14 Jan 2023 08:13:52 -0800 (PST) From: francesco.cagnin@gmail.com X-Google-Original-From: fcagnin@quarkslab.com To: qemu-devel@nongnu.org Cc: mads@ynddal.dk, dirty@apple.com, peter.maydell@linaro.org, qemu-arm@nongnu.org, agraf@csgraf.de, pbonzini@redhat.com, alex.bennee@linaro.org, Francesco Cagnin Subject: [PATCH v3 2/3] hvf: implement guest debugging on Apple Silicon hosts Date: Sat, 14 Jan 2023 17:13:01 +0100 Message-Id: <20230114161302.94595-3-fcagnin@quarkslab.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230114161302.94595-1-fcagnin@quarkslab.com> References: <20230114161302.94595-1-fcagnin@quarkslab.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::42f; envelope-from=francesco.cagnin@gmail.com; helo=mail-wr1-x42f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer2=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1673712919494100001 Content-Type: text/plain; charset="utf-8" From: Francesco Cagnin Support is added for single-stepping, software breakpoints, hardware breakpoints and watchpoints. The code has been structured like the KVM counterpart (and many parts are basically identical). Guests can be debugged through the gdbstub. While guest debugging is enabled, the guest can still read and write the DBG*_EL1 registers but they don't have any effect. Signed-off-by: Francesco Cagnin --- accel/hvf/hvf-accel-ops.c | 123 ++++++++ accel/hvf/hvf-all.c | 24 ++ cpu.c | 3 + include/sysemu/hvf.h | 29 ++ include/sysemu/hvf_int.h | 1 + target/arm/hvf/hvf.c | 631 +++++++++++++++++++++++++++++++++++++- 6 files changed, 809 insertions(+), 2 deletions(-) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 24913ca9c4..1ce0f94a64 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -52,6 +52,7 @@ #include "qemu/main-loop.h" #include "exec/address-spaces.h" #include "exec/exec-all.h" +#include "exec/gdbstub.h" #include "sysemu/cpus.h" #include "sysemu/hvf.h" #include "sysemu/hvf_int.h" @@ -340,12 +341,18 @@ static int hvf_accel_init(MachineState *ms) return hvf_arch_init(); } =20 +static int hvf_gdbstub_sstep_flags(void) +{ + return SSTEP_ENABLE | SSTEP_NOIRQ; +} + static void hvf_accel_class_init(ObjectClass *oc, void *data) { AccelClass *ac =3D ACCEL_CLASS(oc); ac->name =3D "HVF"; ac->init_machine =3D hvf_accel_init; ac->allowed =3D &hvf_allowed; + ac->gdbstub_supported_sstep_flags =3D hvf_gdbstub_sstep_flags; } =20 static const TypeInfo hvf_accel_type =3D { @@ -462,6 +469,117 @@ static void hvf_start_vcpu_thread(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } =20 +static bool hvf_supports_guest_debug(void) +{ +#ifdef TARGET_AARCH64 + return true; +#else + return false; +#endif +} + +static int hvf_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwa= ddr len) +{ + struct hvf_sw_breakpoint *bp; + int err; + + if (type =3D=3D GDB_BREAKPOINT_SW) { + bp =3D hvf_find_sw_breakpoint(cpu, addr); + if (bp) { + bp->use_count++; + return 0; + } + + bp =3D g_new(struct hvf_sw_breakpoint, 1); + bp->pc =3D addr; + bp->use_count =3D 1; + err =3D hvf_arch_insert_sw_breakpoint(cpu, bp); + if (err) { + g_free(bp); + return err; + } + + QTAILQ_INSERT_HEAD(&cpu->hvf->hvf_sw_breakpoints, bp, entry); + } else { + err =3D hvf_arch_insert_hw_breakpoint(addr, len, type); + if (err) { + return err; + } + } + + CPU_FOREACH(cpu) { + err =3D hvf_update_guest_debug(cpu); + if (err) { + return err; + } + } + return 0; +} + +static int hvf_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwa= ddr len) +{ + struct hvf_sw_breakpoint *bp; + int err; + + if (type =3D=3D GDB_BREAKPOINT_SW) { + bp =3D hvf_find_sw_breakpoint(cpu, addr); + if (!bp) { + return -ENOENT; + } + + if (bp->use_count > 1) { + bp->use_count--; + return 0; + } + + err =3D hvf_arch_remove_sw_breakpoint(cpu, bp); + if (err) { + return err; + } + + QTAILQ_REMOVE(&cpu->hvf->hvf_sw_breakpoints, bp, entry); + g_free(bp); + } else { + err =3D hvf_arch_remove_hw_breakpoint(addr, len, type); + if (err) { + return err; + } + } + + CPU_FOREACH(cpu) { + err =3D hvf_update_guest_debug(cpu); + if (err) { + return err; + } + } + return 0; +} + +static void hvf_remove_all_breakpoints(CPUState *cpu) +{ + struct hvf_sw_breakpoint *bp, *next; + CPUState *tmpcpu; + + QTAILQ_FOREACH_SAFE(bp, &cpu->hvf->hvf_sw_breakpoints, entry, next) { + if (hvf_arch_remove_sw_breakpoint(cpu, bp) !=3D 0) { + /* Try harder to find a CPU that currently sees the breakpoint= . */ + CPU_FOREACH(tmpcpu) + { + if (hvf_arch_remove_sw_breakpoint(tmpcpu, bp) =3D=3D 0) { + break; + } + } + } + QTAILQ_REMOVE(&cpu->hvf->hvf_sw_breakpoints, bp, entry); + g_free(bp); + } + hvf_arch_remove_all_hw_breakpoints(); + + CPU_FOREACH(cpu) { + hvf_update_guest_debug(cpu); + } +} + static void hvf_accel_ops_class_init(ObjectClass *oc, void *data) { AccelOpsClass *ops =3D ACCEL_OPS_CLASS(oc); @@ -473,6 +591,11 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, = void *data) ops->synchronize_post_init =3D hvf_cpu_synchronize_post_init; ops->synchronize_state =3D hvf_cpu_synchronize_state; ops->synchronize_pre_loadvm =3D hvf_cpu_synchronize_pre_loadvm; + + ops->supports_guest_debug =3D hvf_supports_guest_debug; + ops->insert_breakpoint =3D hvf_insert_breakpoint; + ops->remove_breakpoint =3D hvf_remove_breakpoint; + ops->remove_all_breakpoints =3D hvf_remove_all_breakpoints; }; static const TypeInfo hvf_accel_ops_type =3D { .name =3D ACCEL_OPS_NAME("hvf"), diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c index 0043f4d308..3f02c090b1 100644 --- a/accel/hvf/hvf-all.c +++ b/accel/hvf/hvf-all.c @@ -10,6 +10,7 @@ =20 #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "exec/gdbstub.h" #include "sysemu/hvf.h" #include "sysemu/hvf_int.h" =20 @@ -44,3 +45,26 @@ void assert_hvf_ok(hv_return_t ret) =20 abort(); } + +struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, target_ulo= ng pc) +{ + struct hvf_sw_breakpoint *bp; + + QTAILQ_FOREACH(bp, &cpu->hvf->hvf_sw_breakpoints, entry) { + if (bp->pc =3D=3D pc) { + return bp; + } + } + return NULL; +} + +int hvf_sw_breakpoints_active(CPUState *cpu) +{ + return !QTAILQ_EMPTY(&cpu->hvf->hvf_sw_breakpoints); +} + +int hvf_update_guest_debug(CPUState *cpu) +{ + hvf_arch_update_guest_debug(cpu); + return 0; +} diff --git a/cpu.c b/cpu.c index 4a7d865427..1fd531aabd 100644 --- a/cpu.c +++ b/cpu.c @@ -33,6 +33,7 @@ #endif #include "sysemu/tcg.h" #include "sysemu/kvm.h" +#include "sysemu/hvf.h" #include "sysemu/replay.h" #include "exec/cpu-common.h" #include "exec/exec-all.h" @@ -389,6 +390,8 @@ void cpu_single_step(CPUState *cpu, int enabled) cpu->singlestep_enabled =3D enabled; if (kvm_enabled()) { kvm_update_guest_debug(cpu, 0); + } else if (hvf_enabled()) { + hvf_update_guest_debug(cpu); } trace_breakpoint_singlestep(cpu->cpu_index, enabled); } diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index bb70082e45..3e99c80416 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -36,4 +36,33 @@ typedef struct HVFState HVFState; DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE, TYPE_HVF_ACCEL) =20 +#ifdef NEED_CPU_H +#include "cpu.h" + +int hvf_update_guest_debug(CPUState *cpu); + +struct hvf_sw_breakpoint { + target_ulong pc; + target_ulong saved_insn; + int use_count; + QTAILQ_ENTRY(hvf_sw_breakpoint) entry; +}; + +struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, + target_ulong pc); + +int hvf_sw_breakpoints_active(CPUState *cpu); + +int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint = *bp); +int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint = *bp); +int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, + int type); +int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, + int type); +void hvf_arch_remove_all_hw_breakpoints(void); + +void hvf_arch_update_guest_debug(CPUState *cpu); + +#endif /* NEED_CPU_H */ + #endif diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h index 6545f7cd61..a7957d046b 100644 --- a/include/sysemu/hvf_int.h +++ b/include/sysemu/hvf_int.h @@ -53,6 +53,7 @@ struct hvf_vcpu_state { void *exit; bool vtimer_masked; sigset_t unblock_ipi_mask; + QTAILQ_HEAD(, hvf_sw_breakpoint) hvf_sw_breakpoints; }; =20 void assert_hvf_ok(hv_return_t ret); diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 060aa0ccf4..c63e8da6a5 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -31,6 +31,99 @@ #include "trace/trace-target_arm_hvf.h" #include "migration/vmstate.h" =20 +#include "exec/gdbstub.h" + +#define MDSCR_EL1_SS_SHIFT 0 +#define MDSCR_EL1_MDE_SHIFT 15 + +static bool guest_debug_enabled; + +static uint16_t dbgbcr_regs[] =3D { + HV_SYS_REG_DBGBCR0_EL1, + HV_SYS_REG_DBGBCR1_EL1, + HV_SYS_REG_DBGBCR2_EL1, + HV_SYS_REG_DBGBCR3_EL1, + HV_SYS_REG_DBGBCR4_EL1, + HV_SYS_REG_DBGBCR5_EL1, + HV_SYS_REG_DBGBCR6_EL1, + HV_SYS_REG_DBGBCR7_EL1, + HV_SYS_REG_DBGBCR8_EL1, + HV_SYS_REG_DBGBCR9_EL1, + HV_SYS_REG_DBGBCR10_EL1, + HV_SYS_REG_DBGBCR11_EL1, + HV_SYS_REG_DBGBCR12_EL1, + HV_SYS_REG_DBGBCR13_EL1, + HV_SYS_REG_DBGBCR14_EL1, + HV_SYS_REG_DBGBCR15_EL1, +}; +static uint16_t dbgbvr_regs[] =3D { + HV_SYS_REG_DBGBVR0_EL1, + HV_SYS_REG_DBGBVR1_EL1, + HV_SYS_REG_DBGBVR2_EL1, + HV_SYS_REG_DBGBVR3_EL1, + HV_SYS_REG_DBGBVR4_EL1, + HV_SYS_REG_DBGBVR5_EL1, + HV_SYS_REG_DBGBVR6_EL1, + HV_SYS_REG_DBGBVR7_EL1, + HV_SYS_REG_DBGBVR8_EL1, + HV_SYS_REG_DBGBVR9_EL1, + HV_SYS_REG_DBGBVR10_EL1, + HV_SYS_REG_DBGBVR11_EL1, + HV_SYS_REG_DBGBVR12_EL1, + HV_SYS_REG_DBGBVR13_EL1, + HV_SYS_REG_DBGBVR14_EL1, + HV_SYS_REG_DBGBVR15_EL1, +}; +static uint16_t dbgwcr_regs[] =3D { + HV_SYS_REG_DBGWCR0_EL1, + HV_SYS_REG_DBGWCR1_EL1, + HV_SYS_REG_DBGWCR2_EL1, + HV_SYS_REG_DBGWCR3_EL1, + HV_SYS_REG_DBGWCR4_EL1, + HV_SYS_REG_DBGWCR5_EL1, + HV_SYS_REG_DBGWCR6_EL1, + HV_SYS_REG_DBGWCR7_EL1, + HV_SYS_REG_DBGWCR8_EL1, + HV_SYS_REG_DBGWCR9_EL1, + HV_SYS_REG_DBGWCR10_EL1, + HV_SYS_REG_DBGWCR11_EL1, + HV_SYS_REG_DBGWCR12_EL1, + HV_SYS_REG_DBGWCR13_EL1, + HV_SYS_REG_DBGWCR14_EL1, + HV_SYS_REG_DBGWCR15_EL1, +}; +static uint16_t dbgwvr_regs[] =3D { + HV_SYS_REG_DBGWVR0_EL1, + HV_SYS_REG_DBGWVR1_EL1, + HV_SYS_REG_DBGWVR2_EL1, + HV_SYS_REG_DBGWVR3_EL1, + HV_SYS_REG_DBGWVR4_EL1, + HV_SYS_REG_DBGWVR5_EL1, + HV_SYS_REG_DBGWVR6_EL1, + HV_SYS_REG_DBGWVR7_EL1, + HV_SYS_REG_DBGWVR8_EL1, + HV_SYS_REG_DBGWVR9_EL1, + HV_SYS_REG_DBGWVR10_EL1, + HV_SYS_REG_DBGWVR11_EL1, + HV_SYS_REG_DBGWVR12_EL1, + HV_SYS_REG_DBGWVR13_EL1, + HV_SYS_REG_DBGWVR14_EL1, + HV_SYS_REG_DBGWVR15_EL1, +}; + +static void hvf_arm_init_debug(CPUState *cpu) +{ + ARMCPU *arm_cpu =3D ARM_CPU(cpu); + + max_hw_bps =3D arm_num_brps(arm_cpu); + hw_breakpoints =3D + g_array_sized_new(true, true, sizeof(HWBreakpoint), max_hw_bps); + + max_hw_wps =3D arm_num_wrps(arm_cpu); + hw_watchpoints =3D + g_array_sized_new(true, true, sizeof(HWWatchpoint), max_hw_wps); +} + #define HVF_SYSREG(crn, crm, op0, op1, op2) \ ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2) #define PL1_WRITE_MASK 0x4 @@ -79,6 +172,71 @@ #define SYSREG_PMCEID1_EL0 SYSREG(3, 3, 9, 12, 7) #define SYSREG_PMCCNTR_EL0 SYSREG(3, 3, 9, 13, 0) #define SYSREG_PMCCFILTR_EL0 SYSREG(3, 3, 14, 15, 7) +#define SYSREG_MDSCR_EL1 SYSREG(2, 0, 0, 2, 2) +#define SYSREG_DBGBVR0_EL1 SYSREG(2, 0, 0, 0, 4) +#define SYSREG_DBGBCR0_EL1 SYSREG(2, 0, 0, 0, 5) +#define SYSREG_DBGWVR0_EL1 SYSREG(2, 0, 0, 0, 6) +#define SYSREG_DBGWCR0_EL1 SYSREG(2, 0, 0, 0, 7) +#define SYSREG_DBGBVR1_EL1 SYSREG(2, 0, 0, 1, 4) +#define SYSREG_DBGBCR1_EL1 SYSREG(2, 0, 0, 1, 5) +#define SYSREG_DBGWVR1_EL1 SYSREG(2, 0, 0, 1, 6) +#define SYSREG_DBGWCR1_EL1 SYSREG(2, 0, 0, 1, 7) +#define SYSREG_DBGBVR2_EL1 SYSREG(2, 0, 0, 2, 4) +#define SYSREG_DBGBCR2_EL1 SYSREG(2, 0, 0, 2, 5) +#define SYSREG_DBGWVR2_EL1 SYSREG(2, 0, 0, 2, 6) +#define SYSREG_DBGWCR2_EL1 SYSREG(2, 0, 0, 2, 7) +#define SYSREG_DBGBVR3_EL1 SYSREG(2, 0, 0, 3, 4) +#define SYSREG_DBGBCR3_EL1 SYSREG(2, 0, 0, 3, 5) +#define SYSREG_DBGWVR3_EL1 SYSREG(2, 0, 0, 3, 6) +#define SYSREG_DBGWCR3_EL1 SYSREG(2, 0, 0, 3, 7) +#define SYSREG_DBGBVR4_EL1 SYSREG(2, 0, 0, 4, 4) +#define SYSREG_DBGBCR4_EL1 SYSREG(2, 0, 0, 4, 5) +#define SYSREG_DBGWVR4_EL1 SYSREG(2, 0, 0, 4, 6) +#define SYSREG_DBGWCR4_EL1 SYSREG(2, 0, 0, 4, 7) +#define SYSREG_DBGBVR5_EL1 SYSREG(2, 0, 0, 5, 4) +#define SYSREG_DBGBCR5_EL1 SYSREG(2, 0, 0, 5, 5) +#define SYSREG_DBGWVR5_EL1 SYSREG(2, 0, 0, 5, 6) +#define SYSREG_DBGWCR5_EL1 SYSREG(2, 0, 0, 5, 7) +#define SYSREG_DBGBVR6_EL1 SYSREG(2, 0, 0, 6, 4) +#define SYSREG_DBGBCR6_EL1 SYSREG(2, 0, 0, 6, 5) +#define SYSREG_DBGWVR6_EL1 SYSREG(2, 0, 0, 6, 6) +#define SYSREG_DBGWCR6_EL1 SYSREG(2, 0, 0, 6, 7) +#define SYSREG_DBGBVR7_EL1 SYSREG(2, 0, 0, 7, 4) +#define SYSREG_DBGBCR7_EL1 SYSREG(2, 0, 0, 7, 5) +#define SYSREG_DBGWVR7_EL1 SYSREG(2, 0, 0, 7, 6) +#define SYSREG_DBGWCR7_EL1 SYSREG(2, 0, 0, 7, 7) +#define SYSREG_DBGBVR8_EL1 SYSREG(2, 0, 0, 8, 4) +#define SYSREG_DBGBCR8_EL1 SYSREG(2, 0, 0, 8, 5) +#define SYSREG_DBGWVR8_EL1 SYSREG(2, 0, 0, 8, 6) +#define SYSREG_DBGWCR8_EL1 SYSREG(2, 0, 0, 8, 7) +#define SYSREG_DBGBVR9_EL1 SYSREG(2, 0, 0, 9, 4) +#define SYSREG_DBGBCR9_EL1 SYSREG(2, 0, 0, 9, 5) +#define SYSREG_DBGWVR9_EL1 SYSREG(2, 0, 0, 9, 6) +#define SYSREG_DBGWCR9_EL1 SYSREG(2, 0, 0, 9, 7) +#define SYSREG_DBGBVR10_EL1 SYSREG(2, 0, 0, 10, 4) +#define SYSREG_DBGBCR10_EL1 SYSREG(2, 0, 0, 10, 5) +#define SYSREG_DBGWVR10_EL1 SYSREG(2, 0, 0, 10, 6) +#define SYSREG_DBGWCR10_EL1 SYSREG(2, 0, 0, 10, 7) +#define SYSREG_DBGBVR11_EL1 SYSREG(2, 0, 0, 11, 4) +#define SYSREG_DBGBCR11_EL1 SYSREG(2, 0, 0, 11, 5) +#define SYSREG_DBGWVR11_EL1 SYSREG(2, 0, 0, 11, 6) +#define SYSREG_DBGWCR11_EL1 SYSREG(2, 0, 0, 11, 7) +#define SYSREG_DBGBVR12_EL1 SYSREG(2, 0, 0, 12, 4) +#define SYSREG_DBGBCR12_EL1 SYSREG(2, 0, 0, 12, 5) +#define SYSREG_DBGWVR12_EL1 SYSREG(2, 0, 0, 12, 6) +#define SYSREG_DBGWCR12_EL1 SYSREG(2, 0, 0, 12, 7) +#define SYSREG_DBGBVR13_EL1 SYSREG(2, 0, 0, 13, 4) +#define SYSREG_DBGBCR13_EL1 SYSREG(2, 0, 0, 13, 5) +#define SYSREG_DBGWVR13_EL1 SYSREG(2, 0, 0, 13, 6) +#define SYSREG_DBGWCR13_EL1 SYSREG(2, 0, 0, 13, 7) +#define SYSREG_DBGBVR14_EL1 SYSREG(2, 0, 0, 14, 4) +#define SYSREG_DBGBCR14_EL1 SYSREG(2, 0, 0, 14, 5) +#define SYSREG_DBGWVR14_EL1 SYSREG(2, 0, 0, 14, 6) +#define SYSREG_DBGWCR14_EL1 SYSREG(2, 0, 0, 14, 7) +#define SYSREG_DBGBVR15_EL1 SYSREG(2, 0, 0, 15, 4) +#define SYSREG_DBGBCR15_EL1 SYSREG(2, 0, 0, 15, 5) +#define SYSREG_DBGWVR15_EL1 SYSREG(2, 0, 0, 15, 6) +#define SYSREG_DBGWCR15_EL1 SYSREG(2, 0, 0, 15, 7) =20 #define WFX_IS_WFE (1 << 0) =20 @@ -370,6 +528,82 @@ int hvf_get_registers(CPUState *cpu) continue; } =20 + if (guest_debug_enabled) { + switch (hvf_sreg_match[i].reg) { + case HV_SYS_REG_DBGBVR0_EL1: + case HV_SYS_REG_DBGBCR0_EL1: + case HV_SYS_REG_DBGWVR0_EL1: + case HV_SYS_REG_DBGWCR0_EL1: + case HV_SYS_REG_DBGBVR1_EL1: + case HV_SYS_REG_DBGBCR1_EL1: + case HV_SYS_REG_DBGWVR1_EL1: + case HV_SYS_REG_DBGWCR1_EL1: + case HV_SYS_REG_DBGBVR2_EL1: + case HV_SYS_REG_DBGBCR2_EL1: + case HV_SYS_REG_DBGWVR2_EL1: + case HV_SYS_REG_DBGWCR2_EL1: + case HV_SYS_REG_DBGBVR3_EL1: + case HV_SYS_REG_DBGBCR3_EL1: + case HV_SYS_REG_DBGWVR3_EL1: + case HV_SYS_REG_DBGWCR3_EL1: + case HV_SYS_REG_DBGBVR4_EL1: + case HV_SYS_REG_DBGBCR4_EL1: + case HV_SYS_REG_DBGWVR4_EL1: + case HV_SYS_REG_DBGWCR4_EL1: + case HV_SYS_REG_DBGBVR5_EL1: + case HV_SYS_REG_DBGBCR5_EL1: + case HV_SYS_REG_DBGWVR5_EL1: + case HV_SYS_REG_DBGWCR5_EL1: + case HV_SYS_REG_DBGBVR6_EL1: + case HV_SYS_REG_DBGBCR6_EL1: + case HV_SYS_REG_DBGWVR6_EL1: + case HV_SYS_REG_DBGWCR6_EL1: + case HV_SYS_REG_DBGBVR7_EL1: + case HV_SYS_REG_DBGBCR7_EL1: + case HV_SYS_REG_DBGWVR7_EL1: + case HV_SYS_REG_DBGWCR7_EL1: + case HV_SYS_REG_DBGBVR8_EL1: + case HV_SYS_REG_DBGBCR8_EL1: + case HV_SYS_REG_DBGWVR8_EL1: + case HV_SYS_REG_DBGWCR8_EL1: + case HV_SYS_REG_DBGBVR9_EL1: + case HV_SYS_REG_DBGBCR9_EL1: + case HV_SYS_REG_DBGWVR9_EL1: + case HV_SYS_REG_DBGWCR9_EL1: + case HV_SYS_REG_DBGBVR10_EL1: + case HV_SYS_REG_DBGBCR10_EL1: + case HV_SYS_REG_DBGWVR10_EL1: + case HV_SYS_REG_DBGWCR10_EL1: + case HV_SYS_REG_DBGBVR11_EL1: + case HV_SYS_REG_DBGBCR11_EL1: + case HV_SYS_REG_DBGWVR11_EL1: + case HV_SYS_REG_DBGWCR11_EL1: + case HV_SYS_REG_DBGBVR12_EL1: + case HV_SYS_REG_DBGBCR12_EL1: + case HV_SYS_REG_DBGWVR12_EL1: + case HV_SYS_REG_DBGWCR12_EL1: + case HV_SYS_REG_DBGBVR13_EL1: + case HV_SYS_REG_DBGBCR13_EL1: + case HV_SYS_REG_DBGWVR13_EL1: + case HV_SYS_REG_DBGWCR13_EL1: + case HV_SYS_REG_DBGBVR14_EL1: + case HV_SYS_REG_DBGBCR14_EL1: + case HV_SYS_REG_DBGWVR14_EL1: + case HV_SYS_REG_DBGWCR14_EL1: + case HV_SYS_REG_DBGBVR15_EL1: + case HV_SYS_REG_DBGBCR15_EL1: + case HV_SYS_REG_DBGWVR15_EL1: + case HV_SYS_REG_DBGWCR15_EL1: { + const ARMCPRegInfo *ri; + ri =3D get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_sreg_match= [i].key); + val =3D read_raw_cp_reg(env, ri); + + arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] =3D val; + continue; + } + } + } + ret =3D hv_vcpu_get_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, &= val); assert_hvf_ok(ret); =20 @@ -421,6 +655,76 @@ int hvf_put_registers(CPUState *cpu) continue; } =20 + if (guest_debug_enabled) { + switch (hvf_sreg_match[i].reg) { + case HV_SYS_REG_DBGBVR0_EL1: + case HV_SYS_REG_DBGBCR0_EL1: + case HV_SYS_REG_DBGWVR0_EL1: + case HV_SYS_REG_DBGWCR0_EL1: + case HV_SYS_REG_DBGBVR1_EL1: + case HV_SYS_REG_DBGBCR1_EL1: + case HV_SYS_REG_DBGWVR1_EL1: + case HV_SYS_REG_DBGWCR1_EL1: + case HV_SYS_REG_DBGBVR2_EL1: + case HV_SYS_REG_DBGBCR2_EL1: + case HV_SYS_REG_DBGWVR2_EL1: + case HV_SYS_REG_DBGWCR2_EL1: + case HV_SYS_REG_DBGBVR3_EL1: + case HV_SYS_REG_DBGBCR3_EL1: + case HV_SYS_REG_DBGWVR3_EL1: + case HV_SYS_REG_DBGWCR3_EL1: + case HV_SYS_REG_DBGBVR4_EL1: + case HV_SYS_REG_DBGBCR4_EL1: + case HV_SYS_REG_DBGWVR4_EL1: + case HV_SYS_REG_DBGWCR4_EL1: + case HV_SYS_REG_DBGBVR5_EL1: + case HV_SYS_REG_DBGBCR5_EL1: + case HV_SYS_REG_DBGWVR5_EL1: + case HV_SYS_REG_DBGWCR5_EL1: + case HV_SYS_REG_DBGBVR6_EL1: + case HV_SYS_REG_DBGBCR6_EL1: + case HV_SYS_REG_DBGWVR6_EL1: + case HV_SYS_REG_DBGWCR6_EL1: + case HV_SYS_REG_DBGBVR7_EL1: + case HV_SYS_REG_DBGBCR7_EL1: + case HV_SYS_REG_DBGWVR7_EL1: + case HV_SYS_REG_DBGWCR7_EL1: + case HV_SYS_REG_DBGBVR8_EL1: + case HV_SYS_REG_DBGBCR8_EL1: + case HV_SYS_REG_DBGWVR8_EL1: + case HV_SYS_REG_DBGWCR8_EL1: + case HV_SYS_REG_DBGBVR9_EL1: + case HV_SYS_REG_DBGBCR9_EL1: + case HV_SYS_REG_DBGWVR9_EL1: + case HV_SYS_REG_DBGWCR9_EL1: + case HV_SYS_REG_DBGBVR10_EL1: + case HV_SYS_REG_DBGBCR10_EL1: + case HV_SYS_REG_DBGWVR10_EL1: + case HV_SYS_REG_DBGWCR10_EL1: + case HV_SYS_REG_DBGBVR11_EL1: + case HV_SYS_REG_DBGBCR11_EL1: + case HV_SYS_REG_DBGWVR11_EL1: + case HV_SYS_REG_DBGWCR11_EL1: + case HV_SYS_REG_DBGBVR12_EL1: + case HV_SYS_REG_DBGBCR12_EL1: + case HV_SYS_REG_DBGWVR12_EL1: + case HV_SYS_REG_DBGWCR12_EL1: + case HV_SYS_REG_DBGBVR13_EL1: + case HV_SYS_REG_DBGBCR13_EL1: + case HV_SYS_REG_DBGWVR13_EL1: + case HV_SYS_REG_DBGWCR13_EL1: + case HV_SYS_REG_DBGBVR14_EL1: + case HV_SYS_REG_DBGBCR14_EL1: + case HV_SYS_REG_DBGWVR14_EL1: + case HV_SYS_REG_DBGWCR14_EL1: + case HV_SYS_REG_DBGBVR15_EL1: + case HV_SYS_REG_DBGBCR15_EL1: + case HV_SYS_REG_DBGWVR15_EL1: + case HV_SYS_REG_DBGWCR15_EL1: + continue; + } + } + val =3D arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx]; ret =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, v= al); assert_hvf_ok(ret); @@ -621,6 +925,8 @@ int hvf_arch_init_vcpu(CPUState *cpu) &arm_cpu->isar.id_aa64mmfr0); assert_hvf_ok(ret); =20 + hvf_arm_init_debug(cpu); + return 0; } =20 @@ -839,6 +1145,78 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t re= g, uint32_t rt) case SYSREG_OSDLR_EL1: /* Dummy register */ break; + case SYSREG_DBGBVR0_EL1: + case SYSREG_DBGBVR1_EL1: + case SYSREG_DBGBVR2_EL1: + case SYSREG_DBGBVR3_EL1: + case SYSREG_DBGBVR4_EL1: + case SYSREG_DBGBVR5_EL1: + case SYSREG_DBGBVR6_EL1: + case SYSREG_DBGBVR7_EL1: + case SYSREG_DBGBVR8_EL1: + case SYSREG_DBGBVR9_EL1: + case SYSREG_DBGBVR10_EL1: + case SYSREG_DBGBVR11_EL1: + case SYSREG_DBGBVR12_EL1: + case SYSREG_DBGBVR13_EL1: + case SYSREG_DBGBVR14_EL1: + case SYSREG_DBGBVR15_EL1: + val =3D env->cp15.dbgbvr[SYSREG_CRM(reg)]; + break; + case SYSREG_DBGBCR0_EL1: + case SYSREG_DBGBCR1_EL1: + case SYSREG_DBGBCR2_EL1: + case SYSREG_DBGBCR3_EL1: + case SYSREG_DBGBCR4_EL1: + case SYSREG_DBGBCR5_EL1: + case SYSREG_DBGBCR6_EL1: + case SYSREG_DBGBCR7_EL1: + case SYSREG_DBGBCR8_EL1: + case SYSREG_DBGBCR9_EL1: + case SYSREG_DBGBCR10_EL1: + case SYSREG_DBGBCR11_EL1: + case SYSREG_DBGBCR12_EL1: + case SYSREG_DBGBCR13_EL1: + case SYSREG_DBGBCR14_EL1: + case SYSREG_DBGBCR15_EL1: + val =3D env->cp15.dbgbcr[SYSREG_CRM(reg)]; + break; + case SYSREG_DBGWVR0_EL1: + case SYSREG_DBGWVR1_EL1: + case SYSREG_DBGWVR2_EL1: + case SYSREG_DBGWVR3_EL1: + case SYSREG_DBGWVR4_EL1: + case SYSREG_DBGWVR5_EL1: + case SYSREG_DBGWVR6_EL1: + case SYSREG_DBGWVR7_EL1: + case SYSREG_DBGWVR8_EL1: + case SYSREG_DBGWVR9_EL1: + case SYSREG_DBGWVR10_EL1: + case SYSREG_DBGWVR11_EL1: + case SYSREG_DBGWVR12_EL1: + case SYSREG_DBGWVR13_EL1: + case SYSREG_DBGWVR14_EL1: + case SYSREG_DBGWVR15_EL1: + val =3D env->cp15.dbgwvr[SYSREG_CRM(reg)]; + break; + case SYSREG_DBGWCR0_EL1: + case SYSREG_DBGWCR1_EL1: + case SYSREG_DBGWCR2_EL1: + case SYSREG_DBGWCR3_EL1: + case SYSREG_DBGWCR4_EL1: + case SYSREG_DBGWCR5_EL1: + case SYSREG_DBGWCR6_EL1: + case SYSREG_DBGWCR7_EL1: + case SYSREG_DBGWCR8_EL1: + case SYSREG_DBGWCR9_EL1: + case SYSREG_DBGWCR10_EL1: + case SYSREG_DBGWCR11_EL1: + case SYSREG_DBGWCR12_EL1: + case SYSREG_DBGWCR13_EL1: + case SYSREG_DBGWCR14_EL1: + case SYSREG_DBGWCR15_EL1: + val =3D env->cp15.dbgwcr[SYSREG_CRM(reg)]; + break; default: if (is_id_sysreg(reg)) { /* ID system registers read as RES0 */ @@ -1021,6 +1399,81 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t = reg, uint64_t val) case SYSREG_OSDLR_EL1: /* Dummy register */ break; + case SYSREG_MDSCR_EL1: + env->cp15.mdscr_el1 =3D val; + break; + case SYSREG_DBGBVR0_EL1: + case SYSREG_DBGBVR1_EL1: + case SYSREG_DBGBVR2_EL1: + case SYSREG_DBGBVR3_EL1: + case SYSREG_DBGBVR4_EL1: + case SYSREG_DBGBVR5_EL1: + case SYSREG_DBGBVR6_EL1: + case SYSREG_DBGBVR7_EL1: + case SYSREG_DBGBVR8_EL1: + case SYSREG_DBGBVR9_EL1: + case SYSREG_DBGBVR10_EL1: + case SYSREG_DBGBVR11_EL1: + case SYSREG_DBGBVR12_EL1: + case SYSREG_DBGBVR13_EL1: + case SYSREG_DBGBVR14_EL1: + case SYSREG_DBGBVR15_EL1: + env->cp15.dbgbvr[SYSREG_CRM(reg)] =3D val; + break; + case SYSREG_DBGBCR0_EL1: + case SYSREG_DBGBCR1_EL1: + case SYSREG_DBGBCR2_EL1: + case SYSREG_DBGBCR3_EL1: + case SYSREG_DBGBCR4_EL1: + case SYSREG_DBGBCR5_EL1: + case SYSREG_DBGBCR6_EL1: + case SYSREG_DBGBCR7_EL1: + case SYSREG_DBGBCR8_EL1: + case SYSREG_DBGBCR9_EL1: + case SYSREG_DBGBCR10_EL1: + case SYSREG_DBGBCR11_EL1: + case SYSREG_DBGBCR12_EL1: + case SYSREG_DBGBCR13_EL1: + case SYSREG_DBGBCR14_EL1: + case SYSREG_DBGBCR15_EL1: + env->cp15.dbgbcr[SYSREG_CRM(reg)] =3D val; + break; + case SYSREG_DBGWVR0_EL1: + case SYSREG_DBGWVR1_EL1: + case SYSREG_DBGWVR2_EL1: + case SYSREG_DBGWVR3_EL1: + case SYSREG_DBGWVR4_EL1: + case SYSREG_DBGWVR5_EL1: + case SYSREG_DBGWVR6_EL1: + case SYSREG_DBGWVR7_EL1: + case SYSREG_DBGWVR8_EL1: + case SYSREG_DBGWVR9_EL1: + case SYSREG_DBGWVR10_EL1: + case SYSREG_DBGWVR11_EL1: + case SYSREG_DBGWVR12_EL1: + case SYSREG_DBGWVR13_EL1: + case SYSREG_DBGWVR14_EL1: + case SYSREG_DBGWVR15_EL1: + env->cp15.dbgwvr[SYSREG_CRM(reg)] =3D val; + break; + case SYSREG_DBGWCR0_EL1: + case SYSREG_DBGWCR1_EL1: + case SYSREG_DBGWCR2_EL1: + case SYSREG_DBGWCR3_EL1: + case SYSREG_DBGWCR4_EL1: + case SYSREG_DBGWCR5_EL1: + case SYSREG_DBGWCR6_EL1: + case SYSREG_DBGWCR7_EL1: + case SYSREG_DBGWCR8_EL1: + case SYSREG_DBGWCR9_EL1: + case SYSREG_DBGWCR10_EL1: + case SYSREG_DBGWCR11_EL1: + case SYSREG_DBGWCR12_EL1: + case SYSREG_DBGWCR13_EL1: + case SYSREG_DBGWCR14_EL1: + case SYSREG_DBGWCR15_EL1: + env->cp15.dbgwcr[SYSREG_CRM(reg)] =3D val; + break; default: cpu_synchronize_state(cpu); trace_hvf_unhandled_sysreg_write(env->pc, reg, @@ -1166,11 +1619,12 @@ int hvf_vcpu_exec(CPUState *cpu) { ARMCPU *arm_cpu =3D ARM_CPU(cpu); CPUARMState *env =3D &arm_cpu->env; + int ret; hv_vcpu_exit_t *hvf_exit =3D cpu->hvf->exit; hv_return_t r; bool advance_pc =3D false; =20 - if (hvf_inject_interrupts(cpu)) { + if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) && hvf_inject_interrupts(= cpu)) { return EXCP_INTERRUPT; } =20 @@ -1188,6 +1642,7 @@ int hvf_vcpu_exec(CPUState *cpu) uint64_t syndrome =3D hvf_exit->exception.syndrome; uint32_t ec =3D syn_get_ec(syndrome); =20 + ret =3D 0; qemu_mutex_lock_iothread(); switch (exit_reason) { case HV_EXIT_REASON_EXCEPTION: @@ -1207,6 +1662,47 @@ int hvf_vcpu_exec(CPUState *cpu) hvf_sync_vtimer(cpu); =20 switch (ec) { + case EC_SOFTWARESTEP: { + ret =3D EXCP_DEBUG; + + if (!cpu->singlestep_enabled) { + error_report("EC_SOFTWARESTEP but single-stepping not enabled"= ); + } + break; + } + case EC_AA64_BKPT: { + ret =3D EXCP_DEBUG; + + cpu_synchronize_state(cpu); + + if (!hvf_find_sw_breakpoint(cpu, env->pc)) { + error_report("EC_AA64_BKPT but unknown sw breakpoint"); + } + break; + } + case EC_BREAKPOINT: { + ret =3D EXCP_DEBUG; + + cpu_synchronize_state(cpu); + + if (!find_hw_breakpoint(cpu, env->pc)) { + error_report("EC_BREAKPOINT but unknown hw breakpoint"); + } + break; + } + case EC_WATCHPOINT: { + ret =3D EXCP_DEBUG; + + cpu_synchronize_state(cpu); + + CPUWatchpoint *wp =3D + find_hw_watchpoint(cpu, hvf_exit->exception.virtual_address); + if (!wp) { + error_report("EXCP_DEBUG but unknown hw watchpoint"); + } + cpu->watchpoint_hit =3D wp; + break; + } case EC_DATAABORT: { bool isv =3D syndrome & ARM_EL_ISV; bool iswrite =3D (syndrome >> 6) & 1; @@ -1313,7 +1809,7 @@ int hvf_vcpu_exec(CPUState *cpu) assert_hvf_ok(r); } =20 - return 0; + return ret; } =20 static const VMStateDescription vmstate_hvf_vtimer =3D { @@ -1347,3 +1843,134 @@ int hvf_arch_init(void) qemu_add_vm_change_state_handler(hvf_vm_state_change, &vtimer); return 0; } + +static inline bool hvf_arm_hw_debug_active(CPUState *cpu) +{ + return ((cur_hw_wps > 0) || (cur_hw_bps > 0)); +} + +static const uint32_t brk_insn =3D 0xd4200000; + +int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint = *bp) +{ + if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0)= || + cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { + return -EINVAL; + } + return 0; +} + +int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint = *bp) +{ + static uint32_t brk; + + if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&brk, 4, 0) || + brk !=3D brk_insn || + cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)= ) { + return -EINVAL; + } + return 0; +} + +int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int= type) +{ + switch (type) { + case GDB_BREAKPOINT_HW: + return insert_hw_breakpoint(addr); + case GDB_WATCHPOINT_READ: + case GDB_WATCHPOINT_WRITE: + case GDB_WATCHPOINT_ACCESS: + return insert_hw_watchpoint(addr, len, type); + default: + return -ENOSYS; + } +} + +int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int= type) +{ + switch (type) { + case GDB_BREAKPOINT_HW: + return delete_hw_breakpoint(addr); + case GDB_WATCHPOINT_READ: + case GDB_WATCHPOINT_WRITE: + case GDB_WATCHPOINT_ACCESS: + return delete_hw_watchpoint(addr, len, type); + default: + return -ENOSYS; + } +} + +void hvf_arch_remove_all_hw_breakpoints(void) +{ + if (cur_hw_wps > 0) { + g_array_remove_range(hw_watchpoints, 0, cur_hw_wps); + } + if (cur_hw_bps > 0) { + g_array_remove_range(hw_breakpoints, 0, cur_hw_bps); + } +} + +void hvf_arch_update_guest_debug(CPUState *cpu) +{ + ARMCPU *arm_cpu =3D ARM_CPU(cpu); + CPUARMState *env =3D &arm_cpu->env; + hv_return_t r =3D HV_SUCCESS; + + guest_debug_enabled =3D cpu->singlestep_enabled || + hvf_sw_breakpoints_active(cpu) || + hvf_arm_hw_debug_active(cpu); + + cpu_synchronize_state(cpu); + + if (cpu->singlestep_enabled) { + env->cp15.mdscr_el1 =3D + deposit64(env->cp15.mdscr_el1, MDSCR_EL1_SS_SHIFT, 1, 1); + pstate_write(env, pstate_read(env) | PSTATE_SS); + } else { + env->cp15.mdscr_el1 =3D + deposit64(env->cp15.mdscr_el1, MDSCR_EL1_SS_SHIFT, 1, 0); + } + + if (hvf_arm_hw_debug_active(cpu)) { + env->cp15.mdscr_el1 =3D + deposit64(env->cp15.mdscr_el1, MDSCR_EL1_MDE_SHIFT, 1, 1); + + int i; + for (i =3D 0; i < cur_hw_bps; i++) { + HWBreakpoint *bp =3D get_hw_bp(i); + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i], bp->bc= r); + assert_hvf_ok(r); + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i], bp->bv= r); + assert_hvf_ok(r); + } + for (i =3D 0; i < cur_hw_wps; i++) { + HWWatchpoint *bp =3D get_hw_wp(i); + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i], bp->wc= r); + assert_hvf_ok(r); + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i], bp->wv= r); + assert_hvf_ok(r); + } + } else { + env->cp15.mdscr_el1 =3D + deposit64(env->cp15.mdscr_el1, MDSCR_EL1_MDE_SHIFT, 1, 0); + + int i; + for (i =3D 0; i < max_hw_bps; i++) { + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i], env->c= p15.dbgbcr[i]); + assert_hvf_ok(r); + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i], env->c= p15.dbgbvr[i]); + assert_hvf_ok(r); + } + for (i =3D 0; i < max_hw_wps; i++) { + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i], env->c= p15.dbgwcr[i]); + assert_hvf_ok(r); + r =3D hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i], env->c= p15.dbgwvr[i]); + assert_hvf_ok(r); + } + } + + r =3D hv_vcpu_set_trap_debug_exceptions(cpu->hvf->fd, guest_debug_enab= led); + assert_hvf_ok(r); + r =3D hv_vcpu_set_trap_debug_reg_accesses(cpu->hvf->fd, guest_debug_en= abled); + assert_hvf_ok(r); +} --=20 2.39.0 From nobody Thu May 2 10:18:52 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1673712886; cv=none; d=zohomail.com; s=zohoarc; b=RWw3uEKh45TSaAGispa1BL+2YMauJirffTifrYam8lMrhdJgn2ucDpIvi70Lom/uBtaf/d9/pkrRGVyZV6Nxtoa3jB6cAHV4AAP7ID66pBdDpzfw/iH2x950zWZkx2foZgDAvRtu33DTqXyZWn6O2j4k4wmFmrEglDvuW/oi1JQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1673712886; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=roNn3SpXSMUmx447vswU4kZUnjYahKbuV9DtjkyBlJM=; b=A9pWjmqeem19a2Ig8IVFugMDIRlx3XNxvLpyASibUN35kBcYl+wGxEI/4/u3SlB5Hb6AVxDghPRgC/MOvgjXMf6t3fgCTMgCDSt2Ky1DW4dbjAXwPplCnwW8q5Bwbocs1EVMSFa/HFXkLex3Pl113oVXc/z0AakwhsR1xyM0Cls= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 16737128861961023.8694257366035; Sat, 14 Jan 2023 08:14:46 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pGjAM-0008Cw-63; Sat, 14 Jan 2023 11:13:58 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pGjAK-0008CY-UQ; Sat, 14 Jan 2023 11:13:56 -0500 Received: from mail-wr1-x42a.google.com ([2a00:1450:4864:20::42a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pGjAJ-0005zp-Fk; Sat, 14 Jan 2023 11:13:56 -0500 Received: by mail-wr1-x42a.google.com with SMTP id e3so14438561wru.13; Sat, 14 Jan 2023 08:13:54 -0800 (PST) Received: from omega.lan (194.46.205.77.rev.sfr.net. [77.205.46.194]) by smtp.gmail.com with ESMTPSA id y18-20020a5d6152000000b002425be3c9e2sm21330040wrt.60.2023.01.14.08.13.52 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 14 Jan 2023 08:13:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=roNn3SpXSMUmx447vswU4kZUnjYahKbuV9DtjkyBlJM=; b=R1edhttxRmW5MGnOPQsODqzst+ujrIYeE1qUoqgVH7ypmUKosxp1NlsomEPtBqudtD FthPxl1epjxrjQyT6q5RLLspxyJb1maNdcwQLClnw0VlxdsPkHUA74ajAciIfhh29V8I WMmTmvuZJZC64ubkXICyfvQaj93QT1CF2MnHHxXEO7bANt9eXA2GElJktJFpS4jsC3YL LXsTQedQtSGh/P+UTDGAx9ykJGl1w2o+gZzpcmY3XoVr4pE6WnKHySqmyRmRJ41nWH68 mpAkdqi9+3hNYoImi6CvLOKKVXMI2Uh/7XGdEr5uW/kbRTOIKA0rkm1qcEzkMR1a6be+ o/wQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=roNn3SpXSMUmx447vswU4kZUnjYahKbuV9DtjkyBlJM=; b=IKuhOiyZGz2+/Ntw1yZEIuXC68ztlN9AbwrWUTshHLjxeo4vB8FVyJQOiFNIJzA+i3 YKR8k6mwuqN8SyXQOOD8kE80SRvC5R4KJCJpxHregSOCG2aVMcB/3xRjmfrUTZWxZbXh Y4qssqrwIPL9X7Bjcc/cjRghmZ5AuMcpcDQsqnY46XWBltFppLnbhw8Y/0YnzMkQf6GK WN/9Q1xJT0Bq+jWSGhsQIbXc5UIYR703RwyerGyqqYsfDKFHLP/Vpnhwqfe/lNjbheo8 Upm/vQmywvCbgWoNQniOdoL1sJsnZvJh5hdCRh4EG9zMNIPBP9+Va4Su7LaEdCADd3aV nIXw== X-Gm-Message-State: AFqh2koLuCLv2NknDt/U4dc7uQFkLZXzCQrsqwfYNrxtUpCI71AgB3/E MJjvwq4Mg7sEbQ/yzIZP6ow+am/muJCPGg== X-Google-Smtp-Source: AMrXdXt7SmpRyXNGYqQG44mXxmQdlMc8cbVxZSvTGVccTJ0tIa8yWiCdsxbnVeptCgmE9maJ1Wr63A== X-Received: by 2002:adf:c70b:0:b0:2bd:ef73:3b6e with SMTP id k11-20020adfc70b000000b002bdef733b6emr2074901wrg.35.1673712833827; Sat, 14 Jan 2023 08:13:53 -0800 (PST) From: francesco.cagnin@gmail.com X-Google-Original-From: fcagnin@quarkslab.com To: qemu-devel@nongnu.org Cc: mads@ynddal.dk, dirty@apple.com, peter.maydell@linaro.org, qemu-arm@nongnu.org, agraf@csgraf.de, pbonzini@redhat.com, alex.bennee@linaro.org, Francesco Cagnin Subject: [PATCH v3 3/3] hvf: handle singlestepping over instructions which trigger a VM exit Date: Sat, 14 Jan 2023 17:13:02 +0100 Message-Id: <20230114161302.94595-4-fcagnin@quarkslab.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230114161302.94595-1-fcagnin@quarkslab.com> References: <20230114161302.94595-1-fcagnin@quarkslab.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::42a; envelope-from=francesco.cagnin@gmail.com; helo=mail-wr1-x42a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer2=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1673712887677100001 Content-Type: text/plain; charset="utf-8" From: Francesco Cagnin Signed-off-by: Francesco Cagnin --- target/arm/hvf/hvf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index c63e8da6a5..87c531508e 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1807,6 +1807,10 @@ int hvf_vcpu_exec(CPUState *cpu) pc +=3D 4; r =3D hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_PC, pc); assert_hvf_ok(r); + + if (cpu->singlestep_enabled) { + ret =3D EXCP_DEBUG; + } } =20 return ret; --=20 2.39.0