Received: by 10.192.165.148 with SMTP id m20csp4168162imm; Tue, 8 May 2018 04:14:01 -0700 (PDT) X-Google-Smtp-Source: AB8JxZr4bd+VI9q4niB3f9zVw6JqmNx51D2kZSZu5ZpOwGBmCWJVz3OskU/sPT+WRRa3Yerg88oj X-Received: by 2002:a17:902:bb83:: with SMTP id m3-v6mr16504193pls.236.1525778041100; Tue, 08 May 2018 04:14:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525778041; cv=none; d=google.com; s=arc-20160816; b=QfviG4uYOK/fcWHJw1LyCRpX/PbdGVtuLThS5lTaT60t1GNIJZTr+m1yZ6gb1+tfIQ nyTg5tLqQWHPDt2CRsQ7a2ZG/1pDTRo6igPIBIWb1PpxyfKHbD3v4dshiH3H53uKMBiU oolxoHe0JfDvpyNhe0TblHv4jebqXByKAWP9OJRaXei7G4/S13C2Ne04YvtHmOXfXnvK TStboPUV1X4IPQoG+AtRvxWSA1Iq7FPiR8Jsw56NtRduokYAYfSJEq+hMEbaaYXbClzB BNGmmVcPOEX1KO34Zufr6VoxwzI+nGZL7Pea39GK70sIIA4x1c0FwAS+TkTjTDtCGVkV x+Bw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date:arc-authentication-results; bh=6R7RhA4pVO+MIjdbpfscJfEtnfu/DvdkIcDqUFoZKcs=; b=ZORgdS2bN7uMZ45HkQIWU8Tgm9kUaNhdXuNyV+el12UMegClHJml9QO9eCeirk2ap7 1t6KbSllwi2PGVMY/QoD4/nTC3uBfU5SXpyGUMR5iCz08TdjkrATTUtU17cT0dEyjqeP hmhl/ehVQuFjvLMgjZy0xpBIeVOeEY1MDDxPUdg+EHbzgpRGj0v2UrzaGUYlwCgXI+/+ L9MgjJ18Enas1yOUvNA/BuV3FI5zVFil6APRAOqU2s4WUPeEX03/SC40KRjGGnfCXd4k bTa0OXkLjhopZ8b4UAP9t/+rwREzSgrtsNrRs4dsGHIQSt0+NFZAQgsWwEtovsMcmMWx 7OOA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v64-v6si6250708pgv.528.2018.05.08.04.13.44; Tue, 08 May 2018 04:14:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752412AbeEHLNf (ORCPT + 99 others); Tue, 8 May 2018 07:13:35 -0400 Received: from foss.arm.com ([217.140.101.70]:56480 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751270AbeEHLNd (ORCPT ); Tue, 8 May 2018 07:13:33 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 06A2E1529; Tue, 8 May 2018 04:13:33 -0700 (PDT) Received: from lakrids.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C2D773F318; Tue, 8 May 2018 04:13:29 -0700 (PDT) Date: Tue, 8 May 2018 12:13:23 +0100 From: Mark Rutland To: Frederic Weisbecker Cc: LKML , Jiri Olsa , Namhyung Kim , Peter Zijlstra , Linus Torvalds , Yoshinori Sato , Benjamin Herrenschmidt , Catalin Marinas , Chris Zankel , Paul Mackerras , Thomas Gleixner , Will Deacon , Michael Ellerman , Rich Felker , Ingo Molnar , Alexander Shishkin , Andy Lutomirski , Arnaldo Carvalho de Melo , Max Filippov Subject: Re: [PATCH 4/9] arm: Split breakpoint validation into "check" and "commit" Message-ID: <20180508111323.mmjo4ky4txzi4gx4@lakrids.cambridge.arm.com> References: <1525634395-23380-1-git-send-email-frederic@kernel.org> <1525634395-23380-5-git-send-email-frederic@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1525634395-23380-5-git-send-email-frederic@kernel.org> User-Agent: NeoMutt/20170113 (1.7.2) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Frederick, On Sun, May 06, 2018 at 09:19:50PM +0200, Frederic Weisbecker wrote: > The breakpoint code mixes up attribute check and commit into a single > code entity. Therefore the validation may return an error due to > incorrect atributes while still leaving halfway modified architecture > breakpoint struct. > > Prepare fox fixing this misdesign and separate both logics. Could you elaborate on what the problem is? I would have expected that when arch_build_bp_info() returns an error code, we wouldn't subsequently use the arch_hw_breakpoint information. Where does that happen? I understand that there was a problem on x86 -- I'm just having difficulty figuring it out. I also see that the check and commit hooks have to duplicate a reasonable amount of logic, e.g. the switch on bp->attr.type. Can we instead refactor the existing arch_build_bp_info() hooks to use a temporary arch_hw_breakpoint, and then struct assign it after all the error cases, e.g. static int arch_build_bp_info(struct perf_event *bp) { struct arch_hw_breakpoint hbp; if (some_condition(bp)) hbp->field = 0xf00; switch (bp->attr.type) { case FOO: return -EINVAL; case BAR: hbp->other_field = 7; break; }; if (failure_case(foo)) return err; *counter_arch_bp(bp) = hbp; } ... or is that also problematic? Thanks, Mark. > Signed-off-by: Frederic Weisbecker > Cc: Linus Torvalds > Cc: Andy Lutomirski > Cc: Yoshinori Sato > Cc: Rich Felker > Cc: Ingo Molnar > Cc: Thomas Gleixner > Cc: Will Deacon > Cc: Mark Rutland > Cc: Max Filippov > Cc: Chris Zankel > Cc: Catalin Marinas > Cc: Benjamin Herrenschmidt > Cc: Paul Mackerras > Cc: Michael Ellerman > Cc: Peter Zijlstra > Cc: Arnaldo Carvalho de Melo > Cc: Alexander Shishkin > Cc: Jiri Olsa > Cc: Namhyung Kim > --- > arch/arm/kernel/hw_breakpoint.c | 176 +++++++++++++++++++++++----------------- > 1 file changed, 103 insertions(+), 73 deletions(-) > > diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c > index 629e251..1769d3a 100644 > --- a/arch/arm/kernel/hw_breakpoint.c > +++ b/arch/arm/kernel/hw_breakpoint.c > @@ -515,45 +515,33 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, > return 0; > } > > -/* > - * Construct an arch_hw_breakpoint from a perf_event. > - */ > -static int arch_build_bp_info(struct perf_event *bp) > +static int hw_breakpoint_arch_check(struct perf_event *bp, > + const struct perf_event_attr *attr) > { > - struct arch_hw_breakpoint *info = counter_arch_bp(bp); > + u32 offset, alignment_mask = 0x3; > + > + /* Ensure that we are in monitor debug mode. */ > + if (!monitor_mode_enabled()) > + return -ENODEV; > > /* Type */ > - switch (bp->attr.bp_type) { > + switch (attr->bp_type) { > case HW_BREAKPOINT_X: > - info->ctrl.type = ARM_BREAKPOINT_EXECUTE; > - break; > case HW_BREAKPOINT_R: > - info->ctrl.type = ARM_BREAKPOINT_LOAD; > - break; > case HW_BREAKPOINT_W: > - info->ctrl.type = ARM_BREAKPOINT_STORE; > - break; > case HW_BREAKPOINT_RW: > - info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; > break; > default: > return -EINVAL; > } > > /* Len */ > - switch (bp->attr.bp_len) { > + switch (attr->bp_len) { > case HW_BREAKPOINT_LEN_1: > - info->ctrl.len = ARM_BREAKPOINT_LEN_1; > - break; > case HW_BREAKPOINT_LEN_2: > - info->ctrl.len = ARM_BREAKPOINT_LEN_2; > - break; > case HW_BREAKPOINT_LEN_4: > - info->ctrl.len = ARM_BREAKPOINT_LEN_4; > - break; > case HW_BREAKPOINT_LEN_8: > - info->ctrl.len = ARM_BREAKPOINT_LEN_8; > - if ((info->ctrl.type != ARM_BREAKPOINT_EXECUTE) > + if ((attr->bp_type != HW_BREAKPOINT_X) > && max_watchpoint_len >= 8) > break; > default: > @@ -566,50 +554,17 @@ static int arch_build_bp_info(struct perf_event *bp) > * by the hardware and must be aligned to the appropriate number of > * bytes. > */ > - if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE && > - info->ctrl.len != ARM_BREAKPOINT_LEN_2 && > - info->ctrl.len != ARM_BREAKPOINT_LEN_4) > + if (attr->bp_type == HW_BREAKPOINT_X && > + attr->bp_len != HW_BREAKPOINT_LEN_2 && > + attr->bp_len != HW_BREAKPOINT_LEN_4) > return -EINVAL; > > - /* Address */ > - info->address = bp->attr.bp_addr; > - > - /* Privilege */ > - info->ctrl.privilege = ARM_BREAKPOINT_USER; > - if (arch_check_bp_in_kernelspace(bp)) > - info->ctrl.privilege |= ARM_BREAKPOINT_PRIV; > - > - /* Enabled? */ > - info->ctrl.enabled = !bp->attr.disabled; > - > - /* Mismatch */ > - info->ctrl.mismatch = 0; > - > - return 0; > -} > - > -/* > - * Validate the arch-specific HW Breakpoint register settings. > - */ > -int arch_validate_hwbkpt_settings(struct perf_event *bp) > -{ > - struct arch_hw_breakpoint *info = counter_arch_bp(bp); > - int ret = 0; > - u32 offset, alignment_mask = 0x3; > - > - /* Ensure that we are in monitor debug mode. */ > - if (!monitor_mode_enabled()) > - return -ENODEV; > - > - /* Build the arch_hw_breakpoint. */ > - ret = arch_build_bp_info(bp); > - if (ret) > - goto out; > - > /* Check address alignment. */ > - if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) > + if (attr->bp_len == HW_BREAKPOINT_LEN_8) > alignment_mask = 0x7; > - offset = info->address & alignment_mask; > + > + offset = attr->bp_addr & alignment_mask; > + > switch (offset) { > case 0: > /* Aligned */ > @@ -617,20 +572,16 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) > case 1: > case 2: > /* Allow halfword watchpoints and breakpoints. */ > - if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) > + if (attr->bp_len == HW_BREAKPOINT_LEN_2) > break; > case 3: > /* Allow single byte watchpoint. */ > - if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) > + if (attr->bp_len == HW_BREAKPOINT_LEN_1) > break; > default: > - ret = -EINVAL; > - goto out; > + return -EINVAL; > } > > - info->address &= ~alignment_mask; > - info->ctrl.len <<= offset; > - > if (is_default_overflow_handler(bp)) { > /* > * Mismatch breakpoints are required for single-stepping > @@ -655,13 +606,92 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) > * reports them. > */ > if (!debug_exception_updates_fsr() && > - (info->ctrl.type == ARM_BREAKPOINT_LOAD || > - info->ctrl.type == ARM_BREAKPOINT_STORE)) > + (attr->bp_type == HW_BREAKPOINT_R || > + attr->bp_type == HW_BREAKPOINT_W)) > return -EINVAL; > } > > -out: > - return ret; > + return 0; > +} > + > +static void hw_breakpoint_arch_commit(struct perf_event *bp) > +{ > + struct arch_hw_breakpoint *info = counter_arch_bp(bp); > + struct perf_event_attr *attr = &bp->attr; > + u32 offset, alignment_mask = 0x3; > + > + /* Type */ > + switch (attr->bp_type) { > + case HW_BREAKPOINT_X: > + info->ctrl.type = ARM_BREAKPOINT_EXECUTE; > + break; > + case HW_BREAKPOINT_R: > + info->ctrl.type = ARM_BREAKPOINT_LOAD; > + break; > + case HW_BREAKPOINT_W: > + info->ctrl.type = ARM_BREAKPOINT_STORE; > + break; > + case HW_BREAKPOINT_RW: > + info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; > + break; > + default: > + WARN_ON_ONCE(1); > + } > + > + /* Len */ > + switch (attr->bp_len) { > + case HW_BREAKPOINT_LEN_1: > + info->ctrl.len = ARM_BREAKPOINT_LEN_1; > + break; > + case HW_BREAKPOINT_LEN_2: > + info->ctrl.len = ARM_BREAKPOINT_LEN_2; > + break; > + case HW_BREAKPOINT_LEN_4: > + info->ctrl.len = ARM_BREAKPOINT_LEN_4; > + break; > + case HW_BREAKPOINT_LEN_8: > + info->ctrl.len = ARM_BREAKPOINT_LEN_8; > + break; > + default: > + WARN_ON_ONCE(1); > + } > + > + /* Address */ > + info->address = attr->bp_addr; > + > + /* Privilege */ > + info->ctrl.privilege = ARM_BREAKPOINT_USER; > + if (arch_check_bp_in_kernelspace(bp)) > + info->ctrl.privilege |= ARM_BREAKPOINT_PRIV; > + > + /* Enabled? */ > + info->ctrl.enabled = !attr->disabled; > + > + /* Mismatch */ > + info->ctrl.mismatch = 0; > + > + if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) > + alignment_mask = 0x7; > + > + offset = info->address & alignment_mask; > + info->address &= ~alignment_mask; > + info->ctrl.len <<= offset; > +} > + > +/* > + * Validate the arch-specific HW Breakpoint register settings. > + */ > +int arch_validate_hwbkpt_settings(struct perf_event *bp) > +{ > + int err; > + > + err = hw_breakpoint_arch_check(bp, &bp->attr); > + if (err) > + return err; > + > + hw_breakpoint_arch_commit(bp); > + > + return 0; > } > > /* > -- > 2.7.4 >