From patchwork Fri Apr 10 22:17:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 214109 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8724C2BB86 for ; Fri, 10 Apr 2020 22:18:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 918292145D for ; Fri, 10 Apr 2020 22:18:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="STTfAg/5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726779AbgDJWSX (ORCPT ); Fri, 10 Apr 2020 18:18:23 -0400 Received: from mail-pg1-f193.google.com ([209.85.215.193]:41108 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726762AbgDJWSW (ORCPT ); Fri, 10 Apr 2020 18:18:22 -0400 Received: by mail-pg1-f193.google.com with SMTP id m13so1521433pgd.8 for ; Fri, 10 Apr 2020 15:18:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3LahRNEc8NZpH6NlGKTJK2B5A2bd6uVChU8p3hPZnzw=; b=STTfAg/5L1KOesfw7jIs6oFNooK9Uk19XuSGpBvcQqc/azMYWEFgleBbD3sjcN/bwf s7FvIKlaHfR38aKmYxpOBfhKK8pGSdFuZ0UPWiniE9vFXmpojXdwSd/DiZl7vrB8FCaZ N5Ioc4gW4S+wBKII3cqGgoJSfAOQABzaIYv9w= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3LahRNEc8NZpH6NlGKTJK2B5A2bd6uVChU8p3hPZnzw=; b=REqF1NXZBbPi0pMHVPp1IVX0xabkRlBfDlO2rjiqAbH1v8riE2+UbSeT6cm5cttp4n /CZNF3m15j1q7jHAlMdRffgqhBFBwoume1/cYrOS+RUByNEOQ2Bp8MAIB7RF9VLqI1+0 /YA6UM9O+CyS5m/7vZz0oHfjbzUF1CR8keF3X1hwGX/4bAv0JVM0ckV4Uo2VzY4cNVSZ N7xH8gykvRnYb0T3OckW8Pzu/EUob7wpxJ4ax/XqGoHSAeW5wxytdAug80usI/nli8Zd m3EbyRDBnY62lLwbZc/tinVL8/R8ryX8hqVjMxHnLGL6VOuN+M2XCZ4QPno8S1gcxE1K S0YQ== X-Gm-Message-State: AGi0PuY8Zbl6uf+tti9BKQRLv1iXEhhUF/fDu1TM/pIN7kaRCZuDsGwP UnuJPW3ohcEGfpUIFzRZPJbIWQ== X-Google-Smtp-Source: APiQypIiuN6UDZ0FydqXjZJ8s/J+IS48bp/hUfvF47JjI/mnhBmAWeU118kPEebv28h1d2XKICDUTw== X-Received: by 2002:a65:4107:: with SMTP id w7mr6124188pgp.438.1586557100792; Fri, 10 Apr 2020 15:18:20 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id x2sm2646600pfq.92.2020.04.10.15.18.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Apr 2020 15:18:20 -0700 (PDT) From: Douglas Anderson To: jason.wessel@windriver.com, daniel.thompson@linaro.org, gregkh@linuxfoundation.org Cc: hpa@zytor.com, kgdb-bugreport@lists.sourceforge.net, corbet@lwn.net, frowand.list@gmail.com, tglx@linutronix.de, jslaby@suse.com, linux-serial@vger.kernel.org, mingo@redhat.com, will@kernel.org, bjorn.andersson@linaro.org, agross@kernel.org, bp@alien8.de, catalin.marinas@arm.com, Douglas Anderson , linux-kernel@vger.kernel.org Subject: [PATCH 1/7] kgdboc: Use a platform device to handle tty drivers showing up late Date: Fri, 10 Apr 2020 15:17:20 -0700 Message-Id: <20200410151632.1.I4a493cfb0f9f740ce8fd2ab58e62dc92d18fed30@changeid> X-Mailer: git-send-email 2.26.0.110.g2183baf09c-goog In-Reply-To: <20200410221726.36442-1-dianders@chromium.org> References: <20200410221726.36442-1-dianders@chromium.org> MIME-Version: 1.0 Sender: linux-serial-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org If you build CONFIG_KGDB_SERIAL_CONSOLE into the kernel then you should be able to have KGDB init itself at bootup by specifying the "kgdboc=..." kernel command line parameter. This has worked OK for me for many years, but on a new device I switched to it stopped working. The problem is that on this new device the serial driver gets its probe deferred. Now when kgdb initializes it can't find the tty driver and when it gives up it never tries again. We could try to find ways to move up the initialization of the serial driver and such a thing might be worthwhile, but it's nice to be robust against serial drivers that load late. We could move kgdb to init itself later but that penalizes our ability to debug early boot code on systems where the driver inits early. We could roll our own system of detecting when new tty drivers get loaded and then use that to figure out when kgdb can init, but that's ugly. Instead, let's jump on the -EPROBE_DEFER bandwagon. We'll create a singleton instance of a "kgdboc" platform device. If we can't find our tty device when the singleton "kgdboc" probes we'll return -EPROBE_DEFER which means that the system will call us back later to try again when the tty device might be there. We won't fully transition all of the kgdboc to a platform device because early kgdb initialization (via the "ekgdboc" kernel command line parameter) still runs before the platform device has been created. The kgdb platform device is merely used as a convenient way to hook into the system's normal probe deferral mechanisms. As part of this, we'll ever-so-slightly change how the "kgdboc=..." kernel command line parameter works. Previously if you booted up and kgdb couldn't find the tty driver then later reading '/sys/module/kgdboc/parameters/kgdboc' would return a blank string. Now kgdb will keep track of the string that came as part of the command line and give it back to you. It's expected that this should be an OK change. Signed-off-by: Douglas Anderson --- drivers/tty/serial/kgdboc.c | 126 +++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 25 deletions(-) diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index c7d51b51898f..9ace39fc4f95 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -20,6 +20,7 @@ #include #include #include +#include #define MAX_CONFIG_LEN 40 @@ -27,6 +28,7 @@ static struct kgdb_io kgdboc_io_ops; /* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ static int configured = -1; +DEFINE_MUTEX(config_mutex); static char config[MAX_CONFIG_LEN]; static struct kparam_string kps = { @@ -38,6 +40,8 @@ static int kgdboc_use_kms; /* 1 if we use kernel mode switching */ static struct tty_driver *kgdb_tty_driver; static int kgdb_tty_line; +static struct platform_device *kgdboc_pdev; + #ifdef CONFIG_KDB_KEYBOARD static int kgdboc_reset_connect(struct input_handler *handler, struct input_dev *dev, @@ -133,11 +137,13 @@ static void kgdboc_unregister_kbd(void) static void cleanup_kgdboc(void) { + if (configured != 1) + return; + if (kgdb_unregister_nmi_console()) return; kgdboc_unregister_kbd(); - if (configured == 1) - kgdb_unregister_io_module(&kgdboc_io_ops); + kgdb_unregister_io_module(&kgdboc_io_ops); } static int configure_kgdboc(void) @@ -200,20 +206,79 @@ static int configure_kgdboc(void) kgdb_unregister_io_module(&kgdboc_io_ops); noconfig: kgdboc_unregister_kbd(); - config[0] = 0; configured = 0; - cleanup_kgdboc(); return err; } +static int kgdboc_probe(struct platform_device *pdev) +{ + int ret = 0; + + mutex_lock(&config_mutex); + if (configured != 1) { + ret = configure_kgdboc(); + + /* Convert "no device" to "defer" so we'll keep trying */ + if (ret == -ENODEV) + ret = -EPROBE_DEFER; + } + mutex_unlock(&config_mutex); + + return ret; +} + +static struct platform_driver kgdboc_platform_driver = { + .probe = kgdboc_probe, + .driver = { + .name = "kgdboc", + .suppress_bind_attrs = true, + }, +}; + static int __init init_kgdboc(void) { - /* Already configured? */ - if (configured == 1) + int ret; + + /* + * kgdboc is a little bit of an odd "platform_driver". It can be + * up and running long before the platform_driver object is + * created and thus doesn't actually store anything in it. There's + * only one instance of kgdb so anything is stored as global state. + * The platform_driver is only created so that we can leverage the + * kernel's mechanisms (like -EPROBE_DEFER) to call us when our + * underlying tty is ready. Here we init our platform driver and + * then create the single kgdboc instance. + */ + ret = platform_driver_register(&kgdboc_platform_driver); + if (ret) + return ret; + + kgdboc_pdev = platform_device_alloc("kgdboc", PLATFORM_DEVID_NONE); + if (!kgdboc_pdev) { + ret = -ENOMEM; + goto err_did_register; + } + + ret = platform_device_add(kgdboc_pdev); + if (!ret) return 0; - return configure_kgdboc(); + platform_device_put(kgdboc_pdev); + +err_did_register: + platform_driver_unregister(&kgdboc_platform_driver); + return ret; +} + +static void exit_kgdboc(void) +{ + mutex_lock(&config_mutex); + cleanup_kgdboc(); + mutex_unlock(&config_mutex); + + platform_device_unregister(kgdboc_pdev); + platform_driver_unregister(&kgdboc_platform_driver); } static int kgdboc_get_char(void) @@ -236,24 +301,20 @@ static int param_set_kgdboc_var(const char *kmessage, const struct kernel_param *kp) { size_t len = strlen(kmessage); + int ret = 0; if (len >= MAX_CONFIG_LEN) { pr_err("config string too long\n"); return -ENOSPC; } - /* Only copy in the string if the init function has not run yet */ - if (configured < 0) { - strcpy(config, kmessage); - return 0; - } - if (kgdb_connected) { pr_err("Cannot reconfigure while KGDB is connected.\n"); - return -EBUSY; } + mutex_lock(&config_mutex); + strcpy(config, kmessage); /* Chop out \n char as a result of echo */ if (len && config[len - 1] == '\n') @@ -262,8 +323,30 @@ static int param_set_kgdboc_var(const char *kmessage, if (configured == 1) cleanup_kgdboc(); - /* Go and configure with the new params. */ - return configure_kgdboc(); + /* + * Configure with the new params as long as init already ran. + * Note that we can get called before init if someone loads us + * with "modprobe kgdboc kgdboc=..." or if they happen to use the + * the odd syntax of "kgdboc.kgdboc=..." on the kernel command. + */ + if (configured >= 0) + ret = configure_kgdboc(); + + /* + * If we couldn't configure then clear out the config. Note that + * specifying an invalid config on the kernel command line vs. + * through sysfs have slightly different behaviors. If we fail + * to configure what was specified on the kernel command line + * we'll leave it in the 'config' and return -EPROBE_DEFER from + * our probe. When specified through sysfs userspace is + * responsible for loading the tty driver before setting up. + */ + if (ret) + config[0] = '\0'; + + mutex_unlock(&config_mutex); + + return ret; } static int dbg_restore_graphics; @@ -326,15 +409,8 @@ __setup("kgdboc=", kgdboc_option_setup); /* This is only available if kgdboc is a built in for early debugging */ static int __init kgdboc_early_init(char *opt) { - /* save the first character of the config string because the - * init routine can destroy it. - */ - char save_ch; - kgdboc_option_setup(opt); - save_ch = config[0]; - init_kgdboc(); - config[0] = save_ch; + configure_kgdboc(); return 0; } @@ -342,7 +418,7 @@ early_param("ekgdboc", kgdboc_early_init); #endif /* CONFIG_KGDB_SERIAL_CONSOLE */ module_init(init_kgdboc); -module_exit(cleanup_kgdboc); +module_exit(exit_kgdboc); module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); MODULE_PARM_DESC(kgdboc, "[,baud]"); MODULE_DESCRIPTION("KGDB Console TTY Driver"); From patchwork Fri Apr 10 22:17:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 214108 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 23B2CC2BB85 for ; Fri, 10 Apr 2020 22:18:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E40EF20A8B for ; Fri, 10 Apr 2020 22:18:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="MHVBt2Ig" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726825AbgDJWS1 (ORCPT ); Fri, 10 Apr 2020 18:18:27 -0400 Received: from mail-pg1-f193.google.com ([209.85.215.193]:33395 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726793AbgDJWSY (ORCPT ); Fri, 10 Apr 2020 18:18:24 -0400 Received: by mail-pg1-f193.google.com with SMTP id d17so1542256pgo.0 for ; Fri, 10 Apr 2020 15:18:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CZZEM8zHHOknPexrydpRDd/A9CQLDTcTBB/h6CZWGog=; b=MHVBt2IgYBHTrCspWPShthhQT2kgu3DTNXdNJ1SxGgeVa03KjExi/dMeSMRHGaJdBF 1p3ePEadxFcV6QqbZ36oZK14lCUlZNgl2kPD3ebHFSZcvqkFhYH0VjcCJqr93VAPe8uT j7Da9ZUPKDBWAEhTiKChsUDHTMtz43rVDMmcc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CZZEM8zHHOknPexrydpRDd/A9CQLDTcTBB/h6CZWGog=; b=lKF3V7HcMmY+toRtu1cQIAPCgN2ZeNC3k1k6LuDnlvC+V30VCxxRj8/MdyHNZcJON7 WQAamN1V0JTxkVVPIRkRNuSygZrcwgYB8wQy8hR0vU2v/c38z7bun+1kPCfORY5PFnk+ 2P9dqPMEJ/xwVeqQo2S0/wjR0TMah6L7hiwul7V5olLbI+P7StDLNKtIfOnaJeAEYYUY ipQpmJLtVu7QnIH22hvaC7gEyE6ixYxxLlUp2HZJDRD0eJyKf00QSNxlihMPjGKhlR1g jwdq0Ax6jdQB28KdXTMoxLk8K6E928A6DgKpMhG2MhAdLscueo75DUDwK9xo6eNQCkjD Fq5Q== X-Gm-Message-State: AGi0PuY1JNdoxAY85J06UG4mwK5bx/AMv+ALcq2v4b8dVwk5On4xH+hp bqTyFio0n1NLxnOR7evc9QFIfQ== X-Google-Smtp-Source: APiQypLhHe1XgDyD7hEM5rJRm4fgDerRzQjGoAI4i0QzlEiG6qpgXUajRyIDJPscAh69ZecWUlVENQ== X-Received: by 2002:aa7:9148:: with SMTP id 8mr6898973pfi.70.1586557103438; Fri, 10 Apr 2020 15:18:23 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id x2sm2646600pfq.92.2020.04.10.15.18.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Apr 2020 15:18:22 -0700 (PDT) From: Douglas Anderson To: jason.wessel@windriver.com, daniel.thompson@linaro.org, gregkh@linuxfoundation.org Cc: hpa@zytor.com, kgdb-bugreport@lists.sourceforge.net, corbet@lwn.net, frowand.list@gmail.com, tglx@linutronix.de, jslaby@suse.com, linux-serial@vger.kernel.org, mingo@redhat.com, will@kernel.org, bjorn.andersson@linaro.org, agross@kernel.org, bp@alien8.de, catalin.marinas@arm.com, Douglas Anderson , Alexios Zavras , Allison Randal , Dave Martin , Enrico Weigelt , "Eric W. Biederman" , James Morse , Mark Rutland , Masami Hiramatsu , jinho lim , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/7] arm64: Add call_break_hook() to early_brk64() for early kgdb Date: Fri, 10 Apr 2020 15:17:22 -0700 Message-Id: <20200410151632.3.I22067ad43e77ddfd4b64c2d49030628480f9e8d9@changeid> X-Mailer: git-send-email 2.26.0.110.g2183baf09c-goog In-Reply-To: <20200410221726.36442-1-dianders@chromium.org> References: <20200410221726.36442-1-dianders@chromium.org> MIME-Version: 1.0 Sender: linux-serial-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org In order to make early kgdb work properly we need early_brk64() to be able to call into it. This is as easy as adding a call into call_break_hook() just like we do later in the normal brk_handler(). Once we do this we can let kgdb know that it can break into the debugger a little earlier (specifically when parsing early_param's). NOTE: without this patch it turns out that arm64 can't do breakpoints even at dbg_late_init(), so if we decide something about this patch is wrong we might need to move dbg_late_init() a little later. Signed-off-by: Douglas Anderson Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 2 ++ arch/arm64/kernel/debug-monitors.c | 2 +- arch/arm64/kernel/kgdb.c | 5 +++++ arch/arm64/kernel/traps.c | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index 7619f473155f..2d82a0314d29 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -97,6 +97,8 @@ void unregister_user_break_hook(struct break_hook *hook); void register_kernel_break_hook(struct break_hook *hook); void unregister_kernel_break_hook(struct break_hook *hook); +int call_break_hook(struct pt_regs *regs, unsigned int esr); + u8 debug_monitors_arch(void); enum dbg_active_el { diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index 48222a4760c2..59c353dfc8e9 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -297,7 +297,7 @@ void unregister_kernel_break_hook(struct break_hook *hook) unregister_debug_hook(&hook->node); } -static int call_break_hook(struct pt_regs *regs, unsigned int esr) +int call_break_hook(struct pt_regs *regs, unsigned int esr) { struct break_hook *hook; struct list_head *list; diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c index 43119922341f..96a47af870bc 100644 --- a/arch/arm64/kernel/kgdb.c +++ b/arch/arm64/kernel/kgdb.c @@ -301,6 +301,11 @@ static struct notifier_block kgdb_notifier = { .priority = -INT_MAX, }; +extern bool kgdb_arch_can_debug_early(void) +{ + return true; +} + /* * kgdb_arch_init - Perform any architecture specific initialization. * This function will handle the initialization of any architecture diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index cf402be5c573..a8173f0c1774 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -1044,6 +1044,9 @@ int __init early_brk64(unsigned long addr, unsigned int esr, if ((comment & ~KASAN_BRK_MASK) == KASAN_BRK_IMM) return kasan_handler(regs, esr) != DBG_HOOK_HANDLED; #endif + if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED) + return 0; + return bug_handler(regs, esr) != DBG_HOOK_HANDLED; } From patchwork Fri Apr 10 22:17:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 214106 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DA162C2D0EC for ; Fri, 10 Apr 2020 22:18:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A81C62087E for ; Fri, 10 Apr 2020 22:18:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="kTNmL3Zc" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726806AbgDJWSf (ORCPT ); Fri, 10 Apr 2020 18:18:35 -0400 Received: from mail-pg1-f194.google.com ([209.85.215.194]:36101 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726814AbgDJWS1 (ORCPT ); Fri, 10 Apr 2020 18:18:27 -0400 Received: by mail-pg1-f194.google.com with SMTP id c23so1533167pgj.3 for ; Fri, 10 Apr 2020 15:18:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=PDySh9LWSYaxL8uCUBY+B51ZCoRzLjU7ny3rtZ5WpyI=; b=kTNmL3Zc4rUnR8jhyMD6kS7nLOm+87Zz3ZdvIDzkYabQO9jCPXPbIS+o1xSHqHQD8F +RC7x+Jc9cze9VfxpkTubOw55NRdZd7cTmINA07JgTBLznRaCtvmPL58QcezHPv6+w4S zEP4Kj9rcQkNDBw688MoG0arZZndzwE+edZDE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=PDySh9LWSYaxL8uCUBY+B51ZCoRzLjU7ny3rtZ5WpyI=; b=hMRiIItjCYUjubTayTC4bK1tX2WKf5fKgWLumSpfEPDeAEO0up6kCHKZN2vzUxcD7A RqDSQFFmkpOK19h0/RUi/oJXnU5BuaGA6Ek4Dk9wwhoVdNA8BIq75FTB2woiVZtXcRlQ NO0lSTu5D6bcQBIzY3gDjHJfX39Aen2WLOsRl5fPYeUzNE1Xl4OP1+1m17PT4QJGP+EB Fi+RQ5UnhlYjEyEc3EzDqt4X6QzInsjZjOvLXj2cist5l/0DKT/a1hQO0OG8aKX87bFB LE5/cWOB3ulq1niIwwOahxaaiEQpisgmYmWfHkGhXImVMhXOPCvMMn7O22FFwKS7S7oi ku3A== X-Gm-Message-State: AGi0PuZPc2tP4zEYpHHcminT3zi4rFjY0iEYpzX0tlZGu1NNgglGON0Y LaWqjyW6szhHZRMm4QSmPMr1dQ== X-Google-Smtp-Source: APiQypJqnQrXOSYLc8xfrGjUwbaZUZKZQmllgHDzAQmyi+/TOLfvgvfoXcarJOR6YbaX9+ReCgsjkw== X-Received: by 2002:a63:e909:: with SMTP id i9mr6411527pgh.370.1586557104598; Fri, 10 Apr 2020 15:18:24 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id x2sm2646600pfq.92.2020.04.10.15.18.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Apr 2020 15:18:24 -0700 (PDT) From: Douglas Anderson To: jason.wessel@windriver.com, daniel.thompson@linaro.org, gregkh@linuxfoundation.org Cc: hpa@zytor.com, kgdb-bugreport@lists.sourceforge.net, corbet@lwn.net, frowand.list@gmail.com, tglx@linutronix.de, jslaby@suse.com, linux-serial@vger.kernel.org, mingo@redhat.com, will@kernel.org, bjorn.andersson@linaro.org, agross@kernel.org, bp@alien8.de, catalin.marinas@arm.com, Douglas Anderson , linux-kernel@vger.kernel.org Subject: [PATCH 4/7] kgdboc: Add earlycon_kgdboc to support early kgdb using boot consoles Date: Fri, 10 Apr 2020 15:17:23 -0700 Message-Id: <20200410151632.4.I8fba5961bf452ab92350654aa61957f23ecf0100@changeid> X-Mailer: git-send-email 2.26.0.110.g2183baf09c-goog In-Reply-To: <20200410221726.36442-1-dianders@chromium.org> References: <20200410221726.36442-1-dianders@chromium.org> MIME-Version: 1.0 Sender: linux-serial-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org We want to enable kgdb to debug the early parts of the kernel. Unfortunately kgdb normally is a client of the tty API in the kernel and serial drivers don't register to the tty layer until fairly late in the boot process. Serial drivers do, however, commonly register a boot console. Let's enable the kgdboc driver to work with boot consoles to provide early debugging. This change co-opts the existing read() function pointer that's part of "struct console". It's assumed that if a boot console (with the flag CON_BOOT) has implemented read() that both the read() and write() function are polling functions. That means they work without interrupts and read() will return immediately (with 0 bytes read) if there's nothing to read. This should be a safe assumption since it appears that no current boot consoles implement read() right now and there seems no reason to do so unless they wanted to support "earlycon_kgdboc". The console API isn't really intended to have clients work with it like we're doing. Specifically there doesn't appear to be any way for clients to be notified about a boot console being unregistered. We'll work around this by checking that our console is still valid before using it. We'll also try to transition off of the boot console and onto the "tty" API as quickly as possible. The normal/expected way to make all this work is to use "earlycon_kgdboc" and "kgdboc" together. You should point them both to the same physical serial connection. At boot time, as the system transitions from the boot console to the normal console, kgdb will switch over. If you don't use things in the normal/expected way it's a bit of a buyer-beware situation. Things thought about: - If you specify only "earlycon_kgdboc" but not "kgdboc" you still might end up dropping into kgdb upon a crash/sysrq but you may not be able to type. - If you use "keep_bootcon" (which is already a bit of a buyer-beware option) and specify "earlycon_kgdboc" but not "kgdboc" we'll keep trying to use your boot console for kgdb. - If your "earlycon_kgdboc" and "kgdboc" devices are not the same device things should work OK, but it'll be your job to switch over which device you're monitoring (including figuring out how to switch over gdb in-flight if you're using it). When trying to enable "earlycon_kgdboc" it should be noted that the names that are registered through the boot console layer and the tty layer are not the same for the same port. For example when debugging on one board I'd need to pass "earlycon_kgdboc=qcom_geni kgdboc=ttyMSM0" to enable things properly. Since digging up the boot console name is a pain and there will rarely be more than one boot console enabled, you can provide the "earlycon_kgdboc" parameter without specifying the name of the boot console. In this case we'll just pick the first boot that implements read() that we find. This new "earlycon_kgdboc" parameter should be contrasted to the existing "ekgdboc" parameter. While both provide a way to debug very early, the usage and mechanisms are quite different. Specifically "earlycon_kgdboc" is meant to be used in tandem with "kgdboc" and there is a transition from one to the other. The "ekgdboc" parameter, on the other hand, replaces the "kgdboc" parameter. It runs the same logic as the "kgdboc" parameter but just relies on your TTY driver being present super early. The only known usage of the old "ekgdboc" parameter is documented as "ekgdboc=kbd earlyprintk=vga". It should be noted that "kbd" has special treatment allowing it to init early as a tty device. Signed-off-by: Douglas Anderson --- drivers/tty/serial/kgdboc.c | 140 +++++++++++++++++++++++++++++++++++- include/linux/kgdb.h | 3 +- kernel/debug/debug_core.c | 15 +++- 3 files changed, 154 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 9ace39fc4f95..47cd0c28a0f6 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MAX_CONFIG_LEN 40 @@ -42,6 +43,14 @@ static int kgdb_tty_line; static struct platform_device *kgdboc_pdev; +#ifdef CONFIG_KGDB_SERIAL_CONSOLE +static struct kgdb_io earlycon_kgdboc_io_ops; +struct console *earlycon; +bool earlycon_neutered; +#else /* ! CONFIG_KGDB_SERIAL_CONSOLE */ +#define earlycon NULL +#endif /* ! CONFIG_KGDB_SERIAL_CONSOLE */ + #ifdef CONFIG_KDB_KEYBOARD static int kgdboc_reset_connect(struct input_handler *handler, struct input_dev *dev, @@ -135,8 +144,46 @@ static void kgdboc_unregister_kbd(void) #define kgdboc_restore_input() #endif /* ! CONFIG_KDB_KEYBOARD */ +#ifdef CONFIG_KGDB_SERIAL_CONSOLE + +static void cleanup_earlycon(bool unregister) +{ + if (earlycon && unregister) + kgdb_unregister_io_module(&earlycon_kgdboc_io_ops); + earlycon = NULL; +} + +static bool is_earlycon_still_valid(void) +{ + struct console *con; + + for_each_console(con) + if (con == earlycon) + return true; + return false; +} + +static void cleanup_earlycon_if_invalid(void) +{ + console_lock(); + if (earlycon && (earlycon_neutered || !is_earlycon_still_valid())) { + pr_warn("earlycon vanished; unregistering\n"); + cleanup_earlycon(true); + } + console_unlock(); +} + +#else /* ! CONFIG_KGDB_SERIAL_CONSOLE */ + +static inline void cleanup_earlycon(bool unregister) { ; } +static inline void cleanup_earlycon_if_invalid(void) { ; } + +#endif /* ! CONFIG_KGDB_SERIAL_CONSOLE */ + static void cleanup_kgdboc(void) { + cleanup_earlycon(true); + if (configured != 1) return; @@ -190,9 +237,10 @@ static int configure_kgdboc(void) kgdb_tty_line = tty_line; do_register: - err = kgdb_register_io_module(&kgdboc_io_ops); + err = kgdb_register_io_module(&kgdboc_io_ops, earlycon != NULL); if (err) goto noconfig; + cleanup_earlycon(false); err = kgdb_register_nmi_console(); if (err) @@ -208,6 +256,14 @@ static int configure_kgdboc(void) kgdboc_unregister_kbd(); configured = 0; + /* + * Each time we run configure_kgdboc() but don't find a console, use + * that as a chance to validate that our earlycon didn't vanish on + * us. If it vanished we should unregister which will disable kgdb + * if we're the last I/O module. + */ + cleanup_earlycon_if_invalid(); + return err; } @@ -415,6 +471,88 @@ static int __init kgdboc_early_init(char *opt) } early_param("ekgdboc", kgdboc_early_init); + +static int earlycon_kgdboc_get_char(void) +{ + char c; + + if (earlycon_neutered || !earlycon->read(earlycon, &c, 1)) + return NO_POLL_CHAR; + + return c; +} + +static void earlycon_kgdboc_put_char(u8 chr) +{ + if (!earlycon_neutered) + earlycon->write(earlycon, &chr, 1); +} + +static void earlycon_kgdboc_pre_exp_handler(void) +{ + atomic_inc(&ignore_console_lock_warning); + + /* + * We don't get notified when the boot console is unregistered. + * Double-check when we enter the debugger. Unfortunately we + * can't really unregister ourselves now, but at least don't crash. + */ + if (earlycon && !earlycon_neutered && !is_earlycon_still_valid()) { + pr_warn("Neutering kgdb since boot console vanished\n"); + earlycon_neutered = true; + } +} + +static void earlycon_kgdboc_post_exp_handler(void) +{ + atomic_dec(&ignore_console_lock_warning); +} + +static struct kgdb_io earlycon_kgdboc_io_ops = { + .name = "earlycon_kgdboc", + .read_char = earlycon_kgdboc_get_char, + .write_char = earlycon_kgdboc_put_char, + .pre_exception = earlycon_kgdboc_pre_exp_handler, + .post_exception = earlycon_kgdboc_post_exp_handler, + .is_console = true, +}; + +static int __init earlycon_kgdboc_init(char *opt) +{ + struct console *con; + + kdb_init(KDB_INIT_EARLY); + + /* + * Look for a matching console, or if the name was left blank just + * pick the first one we find. + */ + console_lock(); + for_each_console(con) { + if (con->write && con->read && + (con->flags & (CON_BOOT | CON_ENABLED)) && + (!opt || !opt[0] || strcmp(con->name, opt) == 0)) + break; + } + console_unlock(); + + if (!con) { + pr_info("Couldn't find kgdb earlycon\n"); + return 0; + } + + earlycon = con; + pr_info("Going to register kgdb with earlycon '%s'\n", con->name); + if (kgdb_register_io_module(&earlycon_kgdboc_io_ops, false) != 0) { + earlycon = NULL; + pr_info("Failed to register kgdb with earlycon\n"); + return 0; + } + + return 0; +} + +early_param("earlycon_kgdboc", earlycon_kgdboc_init); #endif /* CONFIG_KGDB_SERIAL_CONSOLE */ module_init(init_kgdboc); diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 7371517aeacc..2e86307f2683 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -323,7 +323,8 @@ static inline int kgdb_unregister_nmi_console(void) { return 0; } static inline bool kgdb_nmi_poll_knock(void) { return 1; } #endif -extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); +extern int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops, + bool replace); extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); extern struct kgdb_io *dbg_io_ops; diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 9a4551a0fb4b..82a9af56a0b5 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -1070,16 +1070,21 @@ EXPORT_SYMBOL_GPL(kgdb_schedule_breakpoint); /** * kgdb_register_io_module - register KGDB IO module * @new_dbg_io_ops: the io ops vector + * @replace: If true it's OK if there were old ops. This is used + * to transition from early kgdb to normal kgdb. It's + * assumed these are the same device so kgdb can continue. * * Register it with the KGDB core. */ -int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops) +int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops, bool replace) { + struct kgdb_io *old_dbg_io_ops; int err; spin_lock(&kgdb_registration_lock); - if (dbg_io_ops) { + old_dbg_io_ops = dbg_io_ops; + if (dbg_io_ops && !replace) { spin_unlock(&kgdb_registration_lock); pr_err("Another I/O driver is already registered with KGDB\n"); @@ -1098,6 +1103,12 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops) spin_unlock(&kgdb_registration_lock); + if (replace) { + pr_info("Replaced I/O driver %s with %s\n", + old_dbg_io_ops->name, new_dbg_io_ops->name); + return 0; + } + pr_info("Registered I/O driver %s\n", new_dbg_io_ops->name); /* Arm KGDB now. */ From patchwork Fri Apr 10 22:17:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 214107 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E912DC2BB85 for ; Fri, 10 Apr 2020 22:18:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BF144214DB for ; Fri, 10 Apr 2020 22:18:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="A8zixFy3" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726834AbgDJWSb (ORCPT ); Fri, 10 Apr 2020 18:18:31 -0400 Received: from mail-pj1-f67.google.com ([209.85.216.67]:51102 "EHLO mail-pj1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726829AbgDJWS2 (ORCPT ); Fri, 10 Apr 2020 18:18:28 -0400 Received: by mail-pj1-f67.google.com with SMTP id b7so1267344pju.0 for ; Fri, 10 Apr 2020 15:18:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7A6FUrEihYonXIpPhnCErlWl+4ZFT4mvYVljlFWGAP4=; b=A8zixFy38mun90CDAXlagVbAIIVwh9/25A/e43Q9RCFDEn+rOp9ZVO0j0mSlXrQ8vT YYiCKZpKJT2bIMJS9e7wnmEAtxwvF+vg9K8vHguKd7KWs8bmd0/ZXCQbNchlmGQ6f5id QXT8w0UcQ7ThQOglUn/LWks0X9xwLGASWJRQM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7A6FUrEihYonXIpPhnCErlWl+4ZFT4mvYVljlFWGAP4=; b=p/IUz+tK1hM2LzFx8zfPhkQUG3mfDzxHaOe8rRLnKCbN/1cR9Gd0zTKcO9WOD268IS ZCPu+2Gng8Yq3WQCus8kP/Ui5bbuqZJRswMAR2aGv7B6Pqt1UBQP7bNh2zMS1vpNHc25 GXgXxnaO2tVKeWE+MkJ2FpCI+CRcpB2XlqyMExCEzPrUplaR3nbe5PaXlBCifKe1nemu mlgxtwoN1C6b05BJHfm7Wqbeatsrm4XBDShSQjSOAzuJoDRIMTvQXU7vaKvIEo2GP7WU F2K8zP0yfBPeoslpuSkKlyHI6oQ4grreXCIZDMglhLw0pntm7/aS0DVKxbHHmzwj3/2t E7Bw== X-Gm-Message-State: AGi0PuYZflzBwFdv02zM2rOXTEIptkfbc2iJB2xqmjfaR85FIguo1noj iNJoK9tzPVkXN+iKR0kQlBCZKw== X-Google-Smtp-Source: APiQypJBkfxcG7ETfLq/uX0qKEMzrTaauzB9axhptLbpfS46Oj3ffr4yc5nX4ePFLIoum7gB6Llgbg== X-Received: by 2002:a17:90b:4902:: with SMTP id kr2mr5571773pjb.152.1586557108150; Fri, 10 Apr 2020 15:18:28 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id x2sm2646600pfq.92.2020.04.10.15.18.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Apr 2020 15:18:27 -0700 (PDT) From: Douglas Anderson To: jason.wessel@windriver.com, daniel.thompson@linaro.org, gregkh@linuxfoundation.org Cc: hpa@zytor.com, kgdb-bugreport@lists.sourceforge.net, corbet@lwn.net, frowand.list@gmail.com, tglx@linutronix.de, jslaby@suse.com, linux-serial@vger.kernel.org, mingo@redhat.com, will@kernel.org, bjorn.andersson@linaro.org, agross@kernel.org, bp@alien8.de, catalin.marinas@arm.com, Douglas Anderson , linux-kernel@vger.kernel.org Subject: [PATCH 7/7] serial: 8250_early: Support earlycon_kgdboc Date: Fri, 10 Apr 2020 15:17:26 -0700 Message-Id: <20200410151632.7.I8f668556c244776523320a95b09373a86eda11b7@changeid> X-Mailer: git-send-email 2.26.0.110.g2183baf09c-goog In-Reply-To: <20200410221726.36442-1-dianders@chromium.org> References: <20200410221726.36442-1-dianders@chromium.org> MIME-Version: 1.0 Sender: linux-serial-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org Implement the read() function in the early console driver. With recent kgdb patches this allows you to use kgdb to debug fairly early into the system boot. We only bother implementing this if polling is enabled since kgdb can't be enabled without that. Signed-off-by: Douglas Anderson --- drivers/tty/serial/8250/8250_early.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 5cd8c36c8fcc..70d7826788f5 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -109,6 +109,28 @@ static void early_serial8250_write(struct console *console, uart_console_write(port, s, count, serial_putc); } +#ifdef CONFIG_CONSOLE_POLL +static int early_serial8250_read(struct console *console, + char *s, unsigned int count) +{ + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; + unsigned int status; + int num_read = 0; + + while (num_read < count) { + status = serial8250_early_in(port, UART_LSR); + if (!(status & UART_LSR_DR)) + break; + s[num_read++] = serial8250_early_in(port, UART_RX); + } + + return num_read; +} +#else +#define early_serial8250_read NULL +#endif + static void __init init_port(struct earlycon_device *device) { struct uart_port *port = &device->port; @@ -149,6 +171,7 @@ int __init early_serial8250_setup(struct earlycon_device *device, init_port(device); device->con->write = early_serial8250_write; + device->con->read = early_serial8250_read; return 0; } EARLYCON_DECLARE(uart8250, early_serial8250_setup);