Received: by 10.192.165.148 with SMTP id m20csp2337472imm; Sun, 6 May 2018 12:21:34 -0700 (PDT) X-Google-Smtp-Source: AB8JxZoCtKkIBoS67FUGlWcqdlSzVY4WJ+DJc/XKF5DK0DLi1syuNLFOeSXrtNqFf03eeEx7xhQy X-Received: by 2002:a63:6f46:: with SMTP id k67-v6mr27687942pgc.303.1525634494546; Sun, 06 May 2018 12:21:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525634494; cv=none; d=google.com; s=arc-20160816; b=kkz0nIXRiQZfXNotBikZi+UKBmXUGt6t+0FT6f4JstVSszhqr9FwbbO+QRAWqeOdmf bKihaiDMN4RJw/K0Or2FAO77zjgKKbo0EFqRws4EfdlT8FwehTS8j49uO4F6503iAYFb 9/Z5vTLY1P6Sq/T5yzUA3pHlD3IAKvSwDy8fq5OFWNsUFqqogQeyAOhkvFmsbkAGnwZW UV/dQt9wiRXAvLccNe2UwzVtYBmGFgyPS0zHHY9bm5MDKKS52ADuvY0/Rj7oFJWEj6Xs PFsnxABoULfATPda1NqxVAu/e9gyOe8KzeZ1bDhCM/Nx2B7yM3swWJHhWN3H7eTZWuXz 3Egg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=YcrnySpKJhBsFaKXSAq6HasKde5A7v2p53Z7nO5DqAQ=; b=LhOn0jtssIVvlQkx4FnTwTHFAglubvMmhrsFocv46FCPXuaSKZ1BtqvoO6O1BWJKul A7WpWMVBtTUPRYqoNCFoNVDvofBG0bn8I+oxFJgFe0nQ0/RUJUIBKMh5Bxy0zLhJ+eLQ cslqmjjKYVqjdm2CcvF5QW6kcv/uZ4Zj99rKKNguifL4bXJNTTma8FlaZBy8ZrvUMJRr osWZFmAAcESf8BW1vEH3InGk1eH9xQMkgmrwV2uoHHkMxfUrPr/78lyLrWqpxwuj9/y9 2Hg1kNDBwBrFybCT1uzQilkvh5AdAaTG1zb+Osnh6q08bPY+UG803J/ZB1IiABQaW8Uz zY+A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=1NXkB/a4; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h16-v6si20757582pli.493.2018.05.06.12.21.10; Sun, 06 May 2018 12:21:34 -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; dkim=pass header.i=@kernel.org header.s=default header.b=1NXkB/a4; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751991AbeEFTUn (ORCPT + 99 others); Sun, 6 May 2018 15:20:43 -0400 Received: from mail.kernel.org ([198.145.29.99]:38930 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751825AbeEFTUk (ORCPT ); Sun, 6 May 2018 15:20:40 -0400 Received: from lerouge.home (LFbn-NCY-1-193-82.w83-194.abo.wanadoo.fr [83.194.41.82]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 68DC62183D; Sun, 6 May 2018 19:20:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1525634439; bh=0MDjmtPXawBvWj2vybMzgmgPrE0fD19pGLt4Azqnkxg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=1NXkB/a4qrtQbDxEtElWMN2bTCRZF9Tqx2fjxaAEBgNupCSRVBL2d8A0cl+f2PxdK yIqSMeCM1bgxp2Zt1QGmbT1bv8HG30x6tllzvVjey2LBXjBWelCY4Ftt9Hp+NR2aZf rvrIEmBlhBmSolaGinlRUww3Q9A81IxRwyXDLmfw= From: Frederic Weisbecker To: LKML Cc: Frederic Weisbecker , 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 , Mark Rutland , Alexander Shishkin , Andy Lutomirski , Arnaldo Carvalho de Melo , Max Filippov Subject: [PATCH 6/9] arm64: Split breakpoint validation into "check" and "commit" Date: Sun, 6 May 2018 21:19:52 +0200 Message-Id: <1525634395-23380-7-git-send-email-frederic@kernel.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1525634395-23380-1-git-send-email-frederic@kernel.org> References: <1525634395-23380-1-git-send-email-frederic@kernel.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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. 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/arm64/kernel/hw_breakpoint.c | 183 +++++++++++++++++++++++++------------- 1 file changed, 122 insertions(+), 61 deletions(-) diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index 74bb56f..fa02995 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -419,15 +419,114 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, return 0; } +static int hw_breakpoint_arch_check(struct perf_event *bp, + const struct perf_event_attr *attr) +{ + u64 addr = attr->bp_addr, len = attr->bp_len; + u32 type = attr->bp_type; + + /* Type */ + switch (type) { + case HW_BREAKPOINT_X: + case HW_BREAKPOINT_R: + case HW_BREAKPOINT_W: + case HW_BREAKPOINT_RW: + break; + default: + return -EINVAL; + } + + /* Len */ + switch (len) { + case HW_BREAKPOINT_LEN_1: + case HW_BREAKPOINT_LEN_2: + case HW_BREAKPOINT_LEN_3: + case HW_BREAKPOINT_LEN_4: + case HW_BREAKPOINT_LEN_5: + case HW_BREAKPOINT_LEN_6: + case HW_BREAKPOINT_LEN_7: + case HW_BREAKPOINT_LEN_8: + break; + default: + return -EINVAL; + } + + /* + * On AArch64, we only permit breakpoints of length 4, whereas + * AArch32 also requires breakpoints of length 2 for Thumb. + * Watchpoints can be of length 1, 2, 4 or 8 bytes. + */ + if (type == HW_BREAKPOINT_X) { + if (is_compat_bp(bp)) { + if (len != HW_BREAKPOINT_LEN_2 && + len != HW_BREAKPOINT_LEN_4) + return -EINVAL; + } else if (len != HW_BREAKPOINT_LEN_4) { + /* + * FIXME: Some tools (I'm looking at you perf) assume + * that breakpoints should be sizeof(long). This + * is nonsense. For now, we fix up the parameter + * but we should probably return -EINVAL instead. + */ + len = HW_BREAKPOINT_LEN_4; + } + } + + /* + * Check address alignment. + * We don't do any clever alignment correction for watchpoints + * because using 64-bit unaligned addresses is deprecated for + * AArch64. + * + * AArch32 tasks expect some simple alignment fixups, so emulate + * that here. + */ + if (is_compat_bp(bp)) { + u64 alignment_mask, offset; + + if (len == HW_BREAKPOINT_LEN_8) + alignment_mask = 0x7; + else + alignment_mask = 0x3; + offset = addr & alignment_mask; + switch (offset) { + case 0: + /* Aligned */ + break; + case 1: + /* Allow single byte watchpoint. */ + if (len == HW_BREAKPOINT_LEN_1) + break; + case 2: + /* Allow halfword watchpoints and breakpoints. */ + if (len == HW_BREAKPOINT_LEN_2) + break; + default: + return -EINVAL; + } + } + + /* + * Disallow per-task kernel breakpoints since these would + * complicate the stepping code. + */ + if (arch_check_bp_in_kernelspace(bp) && bp->hw.target) + return -EINVAL; + + return 0; +} + /* * Construct an arch_hw_breakpoint from a perf_event. */ -static int arch_build_bp_info(struct perf_event *bp) +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; + u64 alignment_mask, offset; /* Type */ - switch (bp->attr.bp_type) { + switch (attr->bp_type) { case HW_BREAKPOINT_X: info->ctrl.type = ARM_BREAKPOINT_EXECUTE; break; @@ -441,11 +540,11 @@ static int arch_build_bp_info(struct perf_event *bp) info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; break; default: - return -EINVAL; + WARN_ON_ONCE(1); } /* Len */ - switch (bp->attr.bp_len) { + switch (attr->bp_len) { case HW_BREAKPOINT_LEN_1: info->ctrl.len = ARM_BREAKPOINT_LEN_1; break; @@ -471,7 +570,7 @@ static int arch_build_bp_info(struct perf_event *bp) info->ctrl.len = ARM_BREAKPOINT_LEN_8; break; default: - return -EINVAL; + WARN_ON_ONCE(1); } /* @@ -480,11 +579,7 @@ static int arch_build_bp_info(struct perf_event *bp) * Watchpoints can be of length 1, 2, 4 or 8 bytes. */ if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { - if (is_compat_bp(bp)) { - if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 && - info->ctrl.len != ARM_BREAKPOINT_LEN_4) - return -EINVAL; - } else if (info->ctrl.len != ARM_BREAKPOINT_LEN_4) { + if (!is_compat_bp(bp) && info->ctrl.len != ARM_BREAKPOINT_LEN_4) { /* * FIXME: Some tools (I'm looking at you perf) assume * that breakpoints should be sizeof(long). This @@ -496,7 +591,7 @@ static int arch_build_bp_info(struct perf_event *bp) } /* Address */ - info->address = bp->attr.bp_addr; + info->address = attr->bp_addr; /* * Privilege @@ -509,72 +604,38 @@ static int arch_build_bp_info(struct perf_event *bp) info->ctrl.privilege = AARCH64_BREAKPOINT_EL0; /* Enabled? */ - info->ctrl.enabled = !bp->attr.disabled; + info->ctrl.enabled = !attr->disabled; - 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; - u64 alignment_mask, offset; - - /* Build the arch_hw_breakpoint. */ - ret = arch_build_bp_info(bp); - if (ret) - return ret; - - /* - * Check address alignment. - * We don't do any clever alignment correction for watchpoints - * because using 64-bit unaligned addresses is deprecated for - * AArch64. - * - * AArch32 tasks expect some simple alignment fixups, so emulate - * that here. - */ if (is_compat_bp(bp)) { if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) alignment_mask = 0x7; else alignment_mask = 0x3; - offset = info->address & alignment_mask; - switch (offset) { - case 0: - /* Aligned */ - break; - case 1: - /* Allow single byte watchpoint. */ - if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) - break; - case 2: - /* Allow halfword watchpoints and breakpoints. */ - if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) - break; - default: - return -EINVAL; - } } else { if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) alignment_mask = 0x3; else alignment_mask = 0x7; - offset = info->address & alignment_mask; } + offset = info->address & alignment_mask; + info->address &= ~alignment_mask; info->ctrl.len <<= offset; +} - /* - * Disallow per-task kernel breakpoints since these would - * complicate the stepping code. - */ - if (info->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target) - return -EINVAL; +/* + * 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