Received: by 10.223.148.5 with SMTP id 5csp7694055wrq; Thu, 18 Jan 2018 08:26:43 -0800 (PST) X-Google-Smtp-Source: ACJfBouR+O3eSgJr7xcKT2QL1xLITcfnvnwH4vXpgrnqhNpdJgWY9xUk4iT+S3TuqaHjC+H1LgvL X-Received: by 10.101.90.71 with SMTP id z7mr27934009pgs.15.1516292803277; Thu, 18 Jan 2018 08:26:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516292803; cv=none; d=google.com; s=arc-20160816; b=WSXMuW9GRJFC+s5YX6rZ9LbTRuA7VsaEpyJ1mu5k4+BtJ/BZ3bacC0fAAx2+zxZ29K eyBVDDq552AuMArhqkjyAFUrDcMQyuHRMcxVimSB6ca4J1cOiNM2saInlea14Plo085G 7NEOOJsggv3gbIjm9pdzjiwSZKTuuRPYgykhJPd7cpPTL2YS7IlJHsQwlulKG062F8aQ gvPYwb26rqt76xdoAgXa8PCw/VmALRwQ9sp/qjtOw4xlOxmhc581GXpzfu80MYjpPkz8 Izm/JVRZWfWRvQLRoME1Ykiu+tLKijZteXRrOwk3ZTZPW7aPPOI1YxRK3X+p35/NPVh6 r4Jg== 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=ClTu6OyDc/gBge27wFHjWINEViMZtnt8UxVVasIYQVc=; b=FPvvbVT6CBQ2uFwnCk3idT1XhSr2e1ce3ilEO3kUa0HN1sDnnKumS3Mhe95PuPQdUx g1t5si/qvQHBPD9bsgotca7ym6SeSKDcEhMS3oyyyoruok9HIc8o8xjK7uzkcrW5aT5+ bniv7ZqveIY/fl/SGpy8LvnAhASJ9z6ltNohdn1bvt0D2JHIbpXnmn2DWLs/wsP6z06U O4pX4fcmjpLwc+GdMrwfqYEjs9EsVabm8jLyslRVqQ3c/7PTfsOAAS3d+aWeHN3L9J74 7NIjxwfXeACmsgl6XAOoAStE/HL3XqiZier+LEgvP7SJx24PW2kBtnvJxHLKM6Bvdb70 pW6Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=lFqreh+k; 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=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f64-v6si13034plf.473.2018.01.18.08.26.29; Thu, 18 Jan 2018 08:26:43 -0800 (PST) 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=@gmail.com header.s=20161025 header.b=lFqreh+k; 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=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932846AbeARPvp (ORCPT + 99 others); Thu, 18 Jan 2018 10:51:45 -0500 Received: from mail-pf0-f195.google.com ([209.85.192.195]:36210 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754875AbeARPve (ORCPT ); Thu, 18 Jan 2018 10:51:34 -0500 Received: by mail-pf0-f195.google.com with SMTP id 23so14900213pfp.3 for ; Thu, 18 Jan 2018 07:51:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ClTu6OyDc/gBge27wFHjWINEViMZtnt8UxVVasIYQVc=; b=lFqreh+kmlmAdrvmmJkJpxivgpz8gYLu2wAiq925THfC2lyRcZAIgspYOqOhsjYm/Q KjX9ZZ9L8VgxA3aLqdQGbZUiVjy4Aj4I5lSvtONiLycbNSUXvz7Ln68wVelDR9YPr8VE npirnBLmLVkiBgCY7ICt2CLyAo5d2iSjrI1A/xz8nGRhr9EuiAysGAATC+QpLjkkwFw4 wHJ5BVvMprhEyelavLEIyMVWsL+dHjTK8S2lAExnqcVfpyzexYuEbr/c8fnLNHsLn4VT /fgS6GWSRNugKlYaHeL7GkscCNPUmv1D/+hnp7nsjs04QanmLoeOx/8oULoHaYV7emGI HcTg== 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; bh=ClTu6OyDc/gBge27wFHjWINEViMZtnt8UxVVasIYQVc=; b=S2ecCSniEpvdVDb24JLgQyYNqGvE+pXTeWszRc9a9JcAVUKyIl5RekavCFUj3chOdb 8vjy0KIKzjR6iE6YnMb32E2Qy/iUGcwSE/hRezeaP0cTZoT8bxjU6WgzB8cVW05Mlizv 6qLQJRDWNi+Chg0TDz+5xuGSmTV4AIzumRBQf4FDSOPAbKrvEhSEbrw+bfVGMi8pkZ1P WVJ44d2R+jX7eUTfQDvNkR0yVTnqxWytLiT//NZoy6+3cHV7efUzNv+kXQdY9UTPKzPx mXumjILdU5UEamc+D/TKW0s0bqV98X7H2uKGElNJDpinz2jeWZ0j11oIbRfaPrcdw7Uc JOXw== X-Gm-Message-State: AKwxytcR/f+ZWOHwx8U08+dfaxutRblSWoNOgm5BBZ6qML7M0nEgu9wU yfRSNMMxdDDb2zz3DiYLdVs= X-Received: by 10.98.13.196 with SMTP id 65mr15857272pfn.155.1516290370080; Thu, 18 Jan 2018 07:46:10 -0800 (PST) Received: from localhost.localdomain (114-37-171-238.dynamic-ip.hinet.net. [114.37.171.238]) by smtp.gmail.com with ESMTPSA id f188sm14571465pfc.22.2018.01.18.07.46.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 18 Jan 2018 07:46:09 -0800 (PST) From: Alan Kao X-Google-Original-From: Alan Kao To: Palmer Dabbelt , Albert Ou , Steven Rostedt , Ingo Molnar , Masahiro Yamada , Kamil Rytarowski , Andrew Morton , patches@groups.riscv.org, linux-kernel@vger.kernel.org, Stefan O'Rear Cc: Alan Kao , Greentime Hu Subject: [PATCH v3 2/6] riscv/ftrace: Add dynamic function tracer support Date: Thu, 18 Jan 2018 23:45:41 +0800 Message-Id: <20180118154545.17987-3-alankao@andestech.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180118154545.17987-1-alankao@andestech.com> References: <20180118154545.17987-1-alankao@andestech.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org We now have dynamic ftrace with the following added items: * ftrace_make_call, ftrace_make_nop (in kernel/ftrace.c) The two functions turns any recorded call site of filtered functions into a call to ftrace_caller or nops * ftracce_update_ftrace_func (in kernel/ftrace.c) turns the stub call at ftrace_call into a call to a generic entry for function tracers. * ftrace_caller (in kernel/mcount-dyn.S) The entry where each _mcount call sites calls to once they are filtered to be traced. Also, this patch fixes the semantic problems in mcount.S, which will be treated as only a reference implementation once we have the dynamic ftrace. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ftrace.h | 45 ++++++++++++++++++ arch/riscv/kernel/Makefile | 5 +- arch/riscv/kernel/ftrace.c | 100 +++++++++++++++++++++++++++++++++++++++- arch/riscv/kernel/mcount-dyn.S | 50 ++++++++++++++++++++ arch/riscv/kernel/mcount.S | 22 +++++---- 6 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 arch/riscv/kernel/mcount-dyn.S diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 1f45a76f412e..a5c5c88700d4 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -118,6 +118,7 @@ config ARCH_RV64I select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_DYNAMIC_FTRACE endchoice diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 66d4175eb13e..acf0c7d001f3 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -8,3 +8,48 @@ #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) #define HAVE_FUNCTION_GRAPH_FP_TEST #endif + +#ifndef __ASSEMBLY__ +void _mcount(void); +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} + +struct dyn_arch_ftrace { +}; +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE +/* + * A general call in RISC-V is a pair of insts: + * 1) auipc: setting high-20 pc-related bits to ra register + * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to + * return address (original pc + 4) + * + * Dynamic ftrace generates probes to call sites, so we must deal with + * both auipc and jalr at the same time. + */ + +#define MCOUNT_ADDR ((unsigned long)_mcount) +#define JALR_SIGN_MASK (0x00000800) +#define JALR_OFFSET_MASK (0x00000fff) +#define AUIPC_OFFSET_MASK (0xfffff000) +#define AUIPC_PAD (0x00001000) +#define JALR_SHIFT 20 +#define JALR_BASIC (0x000080e7) +#define AUIPC_BASIC (0x00000097) +#define NOP4 (0x00000013) + +#define to_jalr_insn(_offset) \ + (((_offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_BASIC) + +#define to_auipc_insn(_offset) ((_offset & JALR_SIGN_MASK) ? \ + (((_offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_BASIC) : \ + ((_offset & AUIPC_OFFSET_MASK) | AUIPC_BASIC)) + +/* + * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here. + */ +#define MCOUNT_INSN_SIZE 8 +#endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 196f62ffc428..d7bdf888f1ca 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -34,7 +34,8 @@ CFLAGS_setup.o := -mcmodel=medany obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_FUNCTION_TRACER) += mcount.o -obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o + +obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o +obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o clean: diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index d0de68d144cb..311c287433c9 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -6,9 +6,107 @@ */ #include +#include +#include + +#ifdef CONFIG_DYNAMIC_FTRACE +static int ftrace_check_current_call(unsigned long hook_pos, + unsigned int *expected) +{ + unsigned int replaced[2]; + unsigned int nops[2] = {NOP4, NOP4}; + + /* we expect nops at the hook position */ + if (!expected) + expected = nops; + + /* + * Read the text we want to modify; + * return must be -EFAULT on read error + */ + if (probe_kernel_read(replaced, (void *)hook_pos, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* + * Make sure it is what we expect it to be; + * return must be -EINVAL on failed comparison + */ + if (memcmp(expected, replaced, sizeof(replaced))) { + pr_err("%p: expected (%08x %08x) but get (%08x %08x)", + (void *)hook_pos, expected[0], expected[1], replaced[0], + replaced[1]); + return -EINVAL; + } + + return 0; +} + +static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, + bool enable) +{ + unsigned int offset = (unsigned int)(target - hook_pos); + unsigned int auipc_call = to_auipc_insn(offset); + unsigned int jalr_call = to_jalr_insn(offset); + unsigned int calls[2] = {auipc_call, jalr_call}; + unsigned int nops[2] = {NOP4, NOP4}; + int ret = 0; + + /* when ftrace_make_nop is called */ + if (!enable) + ret = ftrace_check_current_call(hook_pos, calls); + + if (ret) + return ret; + + /* replace the auipc-jalr pair at once */ + ret = probe_kernel_write((void *)hook_pos, enable ? calls : nops, + MCOUNT_INSN_SIZE); + /* return must be -EPERM on write error */ + if (ret) + return -EPERM; + + smp_mb(); + flush_icache_range((void *)hook_pos, (void *)hook_pos + MCOUNT_INSN_SIZE); + + return 0; +} + +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + int ret = ftrace_check_current_call(rec->ip, NULL); + + if (ret) + return ret; + + return __ftrace_modify_call(rec->ip, addr, true); +} + +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, + unsigned long addr) +{ + return __ftrace_modify_call(rec->ip, addr, false); +} + +int ftrace_update_ftrace_func(ftrace_func_t func) +{ + int ret = __ftrace_modify_call((unsigned long)&ftrace_call, + (unsigned long)func, true); + if (!ret) { + ret = __ftrace_modify_call((unsigned long)&ftrace_regs_call, + (unsigned long)func, true); + } + + return ret; +} + +int __init ftrace_dyn_arch_init(void) +{ + return 0; +} +#endif /* - * Most of this file is copied from arm64. + * Most of this function is copied from arm64. */ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, unsigned long frame_pointer) diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S new file mode 100644 index 000000000000..5731d9f56142 --- /dev/null +++ b/arch/riscv/kernel/mcount-dyn.S @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2017 Andes Technology Corporation */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + .text + + .macro SAVE_ABI_STATE + addi sp, sp, -16 + sd s0, 0(sp) + sd ra, 8(sp) + addi s0, sp, 16 + .endm + + .macro RESTORE_ABI_STATE + ld ra, 8(sp) + ld s0, 0(sp) + addi sp, sp, 16 + .endm + +ENTRY(ftrace_caller) + /* + * a0: the address in the caller when calling ftrace_caller + * a1: the caller's return address + */ + ld a1, -8(s0) + addi a0, ra, -MCOUNT_INSN_SIZE + SAVE_ABI_STATE +ftrace_call: + .global ftrace_call + /* + * For the dynamic ftrace to work, here we should reserve at least + * 8 bytes for a functional auipc-jalr pair. The following call + * means nothing but the required 8 bytes. + * + * Calling ftrace_update_ftrace_func would overwrite the call below. + * Check ftrace_modify_all_code for details. + */ + call ftrace_stub + RESTORE_ABI_STATE + ret +ENDPROC(ftrace_caller) diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S index c46a778627be..ce9bdc57a2a1 100644 --- a/arch/riscv/kernel/mcount.S +++ b/arch/riscv/kernel/mcount.S @@ -32,13 +32,13 @@ addi s0, sp, 32 .endm - .macro STORE_ABI_STATE + .macro RESTORE_ABI_STATE ld ra, 8(sp) ld s0, 0(sp) addi sp, sp, 16 .endm - .macro STORE_RET_ABI_STATE + .macro RESTORE_RET_ABI_STATE ld ra, 24(sp) ld s0, 16(sp) ld a0, 8(sp) @@ -46,6 +46,10 @@ .endm ENTRY(ftrace_stub) +#ifdef CONFIG_DYNAMIC_FTRACE + .global _mcount + .set _mcount, ftrace_stub +#endif ret ENDPROC(ftrace_stub) @@ -66,15 +70,15 @@ ENTRY(return_to_handler) #ifdef HAVE_FUNCTION_GRAPH_FP_TEST mv a0, t6 #endif - la t0, ftrace_return_to_handler - jalr t0 + call ftrace_return_to_handler mv a1, a0 - STORE_RET_ABI_STATE + RESTORE_RET_ABI_STATE jalr a1 ENDPROC(return_to_handler) EXPORT_SYMBOL(return_to_handler) #endif +#ifndef CONFIG_DYNAMIC_FTRACE ENTRY(_mcount) la t4, ftrace_stub #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -104,9 +108,8 @@ do_ftrace_graph_caller: ld a2, -16(s0) #endif SAVE_ABI_STATE - la t0, prepare_ftrace_return - jalr t0 - STORE_ABI_STATE + call prepare_ftrace_return + RESTORE_ABI_STATE ret #endif @@ -120,7 +123,8 @@ do_trace: SAVE_ABI_STATE jalr t5 - STORE_ABI_STATE + RESTORE_ABI_STATE ret ENDPROC(_mcount) EXPORT_SYMBOL(_mcount) +#endif -- 2.15.1