Received: by 2002:a05:7412:d8a:b0:e2:908c:2ebd with SMTP id b10csp3421797rdg; Tue, 17 Oct 2023 14:26:55 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF6hgg/Hb+uUHfaQQWvewbn2M3yU4QeQdM55aMnqm7Ik8sftCTlLj9w7vZcsDDD9HMINGjp X-Received: by 2002:a17:90a:4b:b0:27d:3ed2:86a5 with SMTP id 11-20020a17090a004b00b0027d3ed286a5mr3311061pjb.33.1697578015661; Tue, 17 Oct 2023 14:26:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1697578015; cv=none; d=google.com; s=arc-20160816; b=LcZGC44SN70UaiLn66he7bx6zBSzhwfCDJMFN/CP1LhLmk5hVCZaZi8TF1c6zGRGFw ych/JVsfb/5V48HLWm+tPPU3bPTMDRTWgjFmj9AYGBGyLItS8VNWJ3VnJh6GuEhEVAP7 S/s1OfpRJKIDL2CvxEvadnp4jgck3p6ExRvztpAFgnRH3GGEUVzBABvuUmL1fWrTqxSa 2gfzaJjUQkIc6EXPjbxyI+SUxQwZw5HcNLOJkknheFGh23B7yEJ+lbg6VJKSkgf+yCW+ jHyNjDbIJkRK8vtTpqqIWwpfWlXLE9s19iZ/SV1lIQICFjHqLtuMI4ZN0RFmE0aG2ffP uBdQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:date:mime-version:references:subject:cc:to:from :dkim-signature:dkim-signature:message-id; bh=pcUNzlGOZjGTyhpL0LalziQeFNTF1DVz8FsuLXtLvIU=; fh=8iy+GLBXZdpcs/hIddJ7mbUapYjefwP9Gb111pAzFms=; b=R9fZcDFmDrr+sCzT9WONiTctOMmjC3jtKGA+/+rCVNFsqF2hYwpp3NC8g61Dm8ocGF MABPBLkqz1mJRiIyJ/fFktZnfr1ihUT7CjrZFpgunY8Kq1GRTdb+Snfzko+49CDnjgcF ntTXWRyHKhU+35yE1GSQ0Fon7oGThdhvgMWdPhavBnuMTEyF+v8gQRNYrE1gYiMZ76uy HvqkdM7Wilrs5GmklPF5dUn3rMzVfAxHvfZuf7Eu4wuDgWajVQO8UvyOfj0Vovty8awe aPbpDq+leRlrGmVv/I4EZOBR0sWoDDQqWfPqmyO9meFz1rTNckDaBqLDrGXpLXMRu7Kk HQhg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=YE5eGKKR; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:6 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Return-Path: Received: from pete.vger.email (pete.vger.email. [2620:137:e000::3:6]) by mx.google.com with ESMTPS id e24-20020a633718000000b00578d6cb1a16si679497pga.178.2023.10.17.14.26.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Oct 2023 14:26:55 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:6 as permitted sender) client-ip=2620:137:e000::3:6; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=YE5eGKKR; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:6 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by pete.vger.email (Postfix) with ESMTP id E9FBF80C9A5C; Tue, 17 Oct 2023 14:26:45 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at pete.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344302AbjJQV0O (ORCPT + 99 others); Tue, 17 Oct 2023 17:26:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44782 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234836AbjJQVZb (ORCPT ); Tue, 17 Oct 2023 17:25:31 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DF612F0 for ; Tue, 17 Oct 2023 14:24:13 -0700 (PDT) Message-ID: <20231017211723.912645011@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1697577852; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=pcUNzlGOZjGTyhpL0LalziQeFNTF1DVz8FsuLXtLvIU=; b=YE5eGKKReBJ9rydVVCuMK3J5Js1dxYh4e58jp6NqqUbTk+NeetoMZu47IgssueMNFe06yY XfwAtADCfmQxR4iZJ9yHEWAdJHR9u1hHWwW5i9400O2oE8b1wPFyIqKLISeFtEHVp7ZKpJ OdtAuSa0f6xYEHF9531d1+CRU0stBSaL2g1JLC0ZOuOwWWKIt7A9+JLR//NijQY5r2alq5 HOK1cB3qaAld60eVVonRo6b89WkjcQywLgkJow0K8aqCzeEVdmEoGelry+Db3WygIFjqZ2 /6UwL2mVdRkovQbidAM8APt7k+CkCerL0vgB119ELLWE3jCgkJVI/28BpjH9gQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1697577852; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=pcUNzlGOZjGTyhpL0LalziQeFNTF1DVz8FsuLXtLvIU=; b=uVV5etO5KswKTSb/CmrNIiXEubKr8RWJF3xJ8ubO75DIkI9IwTBcnRDkRrU0Zk0Utp1FBN aEPTbVIPZwZboNDQ== From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Borislav Petkov Subject: [patch V5 35/39] x86/microcode: Protect against instrumentation References: <20231017200758.877560658@linutronix.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Date: Tue, 17 Oct 2023 23:24:12 +0200 (CEST) X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on pete.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (pete.vger.email [0.0.0.0]); Tue, 17 Oct 2023 14:26:46 -0700 (PDT) From: Thomas Gleixner The wait for control loop in which the siblings are waiting for the microcode update on the primary thread must be protected against instrumentation as instrumentation can end up in #INT3, #DB or #PF, which then returns with IRET. That IRET reenables NMI which is the opposite of what the NMI rendezvous is trying to achieve. Signed-off-by: Thomas Gleixner --- arch/x86/kernel/cpu/microcode/core.c | 111 ++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 28 deletions(-) --- --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -272,54 +272,65 @@ struct microcode_ctrl { DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable); static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl); +static unsigned int loops_per_usec; static atomic_t late_cpus_in; -static bool wait_for_cpus(atomic_t *cnt) +static noinstr bool wait_for_cpus(atomic_t *cnt) { - unsigned int timeout; + unsigned int timeout, loops; - WARN_ON_ONCE(atomic_dec_return(cnt) < 0); + WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0); for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { - if (!atomic_read(cnt)) + if (!raw_atomic_read(cnt)) return true; - udelay(1); + for (loops = 0; loops < loops_per_usec; loops++) + cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ - if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) + if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { + instrumentation_begin(); touch_nmi_watchdog(); + instrumentation_end(); + } } /* Prevent the late comers from making progress and let them time out */ - atomic_inc(cnt); + raw_atomic_inc(cnt); return false; } -static bool wait_for_ctrl(void) +static noinstr bool wait_for_ctrl(void) { - unsigned int timeout; + unsigned int timeout, loops; for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { - if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) + if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) return true; - udelay(1); + + for (loops = 0; loops < loops_per_usec; loops++) + cpu_relax(); + /* If invoked directly, tickle the NMI watchdog */ - if (!microcode_ops->use_nmi && !(timeout % 1000)) + if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { + instrumentation_begin(); touch_nmi_watchdog(); + instrumentation_end(); + } } return false; } -static void load_secondary(unsigned int cpu) +/* + * Protected against instrumentation up to the point where the primary + * thread completed the update. See microcode_nmi_handler() for details. + */ +static noinstr bool load_secondary_wait(unsigned int ctrl_cpu) { - unsigned int ctrl_cpu = this_cpu_read(ucode_ctrl.ctrl_cpu); - enum ucode_state ret; - /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { - pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); - this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); - return; + raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); + return false; } /* @@ -329,9 +340,33 @@ static void load_secondary(unsigned int * scheduler, watchdogs etc. There is no way to safely evacuate the * machine. */ - if (!wait_for_ctrl()) - panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); + if (wait_for_ctrl()) + return true; + + instrumentation_begin(); + panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); + instrumentation_end(); +} +/* + * Protected against instrumentation up to the point where the primary + * thread completed the update. See microcode_nmi_handler() for details. + */ +static noinstr void load_secondary(unsigned int cpu) +{ + unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu); + enum ucode_state ret; + + if (!load_secondary_wait(ctrl_cpu)) { + instrumentation_begin(); + pr_err_once("load: %d CPUs timed out\n", + atomic_read(&late_cpus_in) - 1); + instrumentation_end(); + return; + } + + /* Primary thread completed. Allow to invoke instrumentable code */ + instrumentation_begin(); /* * If the primary succeeded then invoke the apply() callback, * otherwise copy the state from the primary thread. @@ -343,6 +378,7 @@ static void load_secondary(unsigned int this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); + instrumentation_end(); } static void load_primary(unsigned int cpu) @@ -380,25 +416,43 @@ static void load_primary(unsigned int cp } } -static bool microcode_update_handler(void) +static noinstr bool microcode_update_handler(void) { - unsigned int cpu = smp_processor_id(); + unsigned int cpu = raw_smp_processor_id(); - if (this_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) + if (raw_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) { + instrumentation_begin(); load_primary(cpu); - else + instrumentation_end(); + } else { load_secondary(cpu); + } + instrumentation_begin(); touch_nmi_watchdog(); + instrumentation_end(); + return true; } -bool microcode_nmi_handler(void) +/* + * Protection against instrumentation is required for CPUs which are not + * safe against an NMI which is delivered to the secondary SMT sibling + * while the primary thread updates the microcode. Instrumentation can end + * up in #INT3, #DB and #PF. The IRET from those exceptions reenables NMI + * which is the opposite of what the NMI rendezvous is trying to achieve. + * + * The primary thread is safe versus instrumentation as the actual + * microcode update handles this correctly. It's only the sibling code + * path which must be NMI safe until the primary thread completed the + * update. + */ +bool noinstr microcode_nmi_handler(void) { - if (!this_cpu_read(ucode_ctrl.nmi_enabled)) + if (!raw_cpu_read(ucode_ctrl.nmi_enabled)) return false; - this_cpu_write(ucode_ctrl.nmi_enabled, false); + raw_cpu_write(ucode_ctrl.nmi_enabled, false); return microcode_update_handler(); } @@ -425,6 +479,7 @@ static int load_late_stop_cpus(void) pr_err("You should switch to early loading, if possible.\n"); atomic_set(&late_cpus_in, num_online_cpus()); + loops_per_usec = loops_per_jiffy / (TICK_NSEC / 1000); /* * Take a snapshot before the microcode update in order to compare and