Received: by 2002:a05:7412:d8a:b0:e2:908c:2ebd with SMTP id b10csp3421628rdg; Tue, 17 Oct 2023 14:26:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEErdB5o1mtjBNs/t2P03V0A21EEw+vrQE99sN7jBN046ZKqKRPvrD9vccXmOowRWUqGxsU X-Received: by 2002:a05:6a21:4984:b0:16b:e89b:fb11 with SMTP id ax4-20020a056a21498400b0016be89bfb11mr2975173pzc.56.1697577985027; Tue, 17 Oct 2023 14:26:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1697577985; cv=none; d=google.com; s=arc-20160816; b=f5s2x/IiYBCtK/xOC5DFklmG6+1GO+iJ0Tlul28x7aeTHmgojovhxepPHh1oZSUgZw euN/2bSAI2AkcD4G/v78yq5T5unIZkOaUvpvmK87Ixt3P341SUT5FKjD/4+wJxGo1ZTG 4zqwT6rRyOmvPly2stuspE0SG/TOKnhnGtT7tm3a3hsbflclvVZGLNBfLVjR5FFaQskO UoO/UowfxNL+bxGgCY5XhU4fuOgPrIjKzt4ASmrYKnxxf54ZrQG7V8SbTcphoexVqA1g 0Xo/nedF3fUbe9BvjSQKYNEFevl+bKJ+J54k/b6nrByNukeSy7PXs2nxQKk52Ba8Lu4e IENg== 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=FxegNWCnpFWvIlhkHULtqrm7vjN3o62RaGltaGWsUSA=; fh=8iy+GLBXZdpcs/hIddJ7mbUapYjefwP9Gb111pAzFms=; b=Fvoz5lXqCYI+t7xk+oU5437v+qC60fE9sqQonfURwFvtBC1eYWaBPnhjldDGsRoox2 qX2fDCcHX2F0FHkfToac5BAGW8UysHypyir+pBzIlwPpQdkDOujlc3MXoVrCwkz4ZR3h IU0ZdlKXMjogPrCPYsHaaBTKDLEoM3twAFByU+UiPxDhpaZwRjGyRPRSmyOQiv0LZ0vT anqS8au2ChfLWeLgHA5NOieqYiAu19Y56VrriRiRj3LlbwE2glGPzeELl99NeHPCLcis QZglRYwHvisEUx6uQJnuXzrNhEC4AokCAfgUwl6dHzl3DaSTTWAzNsoeHMeUTlyAHC8f 99rA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=cCU0zRWM; 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:5 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 groat.vger.email (groat.vger.email. [2620:137:e000::3:5]) by mx.google.com with ESMTPS id v13-20020a17090ac90d00b0027ced8e1837si2378091pjt.180.2023.10.17.14.26.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Oct 2023 14:26:25 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:5 as permitted sender) client-ip=2620:137:e000::3:5; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=cCU0zRWM; 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:5 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 groat.vger.email (Postfix) with ESMTP id 1295C804EE45; Tue, 17 Oct 2023 14:26:13 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at groat.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234650AbjJQVZi (ORCPT + 99 others); Tue, 17 Oct 2023 17:25:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234891AbjJQVZK (ORCPT ); Tue, 17 Oct 2023 17:25:10 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9ADF419A0 for ; Tue, 17 Oct 2023 14:24:03 -0700 (PDT) Message-ID: <20231017211723.465514319@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1697577841; 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=FxegNWCnpFWvIlhkHULtqrm7vjN3o62RaGltaGWsUSA=; b=cCU0zRWMDmLxyfgulio75QjVQgD2isJt3zbWv9/TXTo/IrcvJBoE+QG5ZsJF/Lo6vpUmGf Bhx4BqsMD49XqgYM3e8NZ1+WU06WHIzG6/u//QHbtBvoNFKcFUCfCYA2fyXW7iCsoF72JQ Y43veQ7eXD72VExHJwauMRzdWkcox5FCN02ZtdNFfF4I7xTsN29WL6vvNUyFgEvTnwoLr6 Z0gI8tUWsJP99md1hXyEF6nktGJI3UbmGZwqQahGodmsggZ0cqwEuyN0lm8DERt/O0/ZT8 yHZE0TcyvKMyyoF4dis/MlPgoRwhpmFskvhlRsjG4t3hYWr9fpUMRGxS9Fsxng== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1697577841; 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=FxegNWCnpFWvIlhkHULtqrm7vjN3o62RaGltaGWsUSA=; b=sXK0ukSPvkGQZchsR2qnYUzZuO7d1N9TyrZU2Cxpv8FDRwszGBAJ8xgTfsnidN/HS8FiuQ BBB3RUF6+lmbuhDg== From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Borislav Petkov Subject: [patch V5 27/39] x86/microcode: Handle "nosmt" correctly References: <20231017200758.877560658@linutronix.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Date: Tue, 17 Oct 2023 23:24:00 +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 groat.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 (groat.vger.email [0.0.0.0]); Tue, 17 Oct 2023 14:26:13 -0700 (PDT) From: Thomas Gleixner On CPUs where microcode loading is not NMI-safe the SMT siblings which are parked in one of the play_dead() variants still react to NMIs. So if an NMI hits while the primary thread updates the microcode the resulting behaviour is undefined. The default play_dead() implementation on modern CPUs is using MWAIT which is not guaranteed to be safe against a microcode update which affects MWAIT. Take the cpus_booted_once_mask into account to detect this case and refuse to load late if the vendor specific driver does not advertise that late loading is NMI safe. AMD stated that this is safe, so mark the AMD driver accordingly. This requirement will be partially lifted in later changes. Signed-off-by: Thomas Gleixner --- arch/x86/Kconfig | 2 - arch/x86/kernel/cpu/microcode/amd.c | 9 +++-- arch/x86/kernel/cpu/microcode/core.c | 51 +++++++++++++++++++------------ arch/x86/kernel/cpu/microcode/internal.h | 13 +++---- 4 files changed, 44 insertions(+), 31 deletions(-) --- --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1320,7 +1320,7 @@ config MICROCODE_INITRD32 config MICROCODE_LATE_LOADING bool "Late microcode loading (DANGEROUS)" default n - depends on MICROCODE + depends on MICROCODE && SMP help Loading microcode late, when the system is up and executing instructions is a tricky business and should be avoided if possible. Just the sequence --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -917,10 +917,11 @@ static void microcode_fini_cpu_amd(int c } static struct microcode_ops microcode_amd_ops = { - .request_microcode_fw = request_microcode_amd, - .collect_cpu_info = collect_cpu_info_amd, - .apply_microcode = apply_microcode_amd, - .microcode_fini_cpu = microcode_fini_cpu_amd, + .request_microcode_fw = request_microcode_amd, + .collect_cpu_info = collect_cpu_info_amd, + .apply_microcode = apply_microcode_amd, + .microcode_fini_cpu = microcode_fini_cpu_amd, + .nmi_safe = true, }; struct microcode_ops * __init init_amd_microcode(void) --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -254,23 +254,6 @@ static struct platform_device *microcode */ #define SPINUNIT 100 /* 100 nsec */ -static int check_online_cpus(void) -{ - unsigned int cpu; - - /* - * Make sure all CPUs are online. It's fine for SMT to be disabled if - * all the primary threads are still online. - */ - for_each_present_cpu(cpu) { - if (topology_is_primary_thread(cpu) && !cpu_online(cpu)) { - pr_err("Not all CPUs online, aborting microcode update.\n"); - return -EINVAL; - } - } - - return 0; -} static atomic_t late_cpus_in; static atomic_t late_cpus_out; @@ -387,6 +370,35 @@ static int microcode_reload_late(void) return ret; } +/* + * Ensure that all required CPUs which are present and have been booted + * once are online. + * + * To pass this check, all primary threads must be online. + * + * If the microcode load is not safe against NMI then all SMT threads + * must be online as well because they still react to NMIs when they are + * soft-offlined and parked in one of the play_dead() variants. So if a + * NMI hits while the primary thread updates the microcode the resulting + * behaviour is undefined. The default play_dead() implementation on + * modern CPUs uses MWAIT, which is also not guaranteed to be safe + * against a microcode update which affects MWAIT. + */ +static bool ensure_cpus_are_online(void) +{ + unsigned int cpu; + + for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) { + if (!cpu_online(cpu)) { + if (topology_is_primary_thread(cpu) || !microcode_ops->nmi_safe) { + pr_err("CPU %u not online\n", cpu); + return false; + } + } + } + return true; +} + static ssize_t reload_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) @@ -402,9 +414,10 @@ static ssize_t reload_store(struct devic cpus_read_lock(); - ret = check_online_cpus(); - if (ret) + if (!ensure_cpus_are_online()) { + ret = -EBUSY; goto put; + } tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev); if (tmp_ret != UCODE_NEW) --- a/arch/x86/kernel/cpu/microcode/internal.h +++ b/arch/x86/kernel/cpu/microcode/internal.h @@ -20,18 +20,17 @@ enum ucode_state { struct microcode_ops { enum ucode_state (*request_microcode_fw)(int cpu, struct device *dev); - void (*microcode_fini_cpu)(int cpu); /* - * The generic 'microcode_core' part guarantees that - * the callbacks below run on a target cpu when they - * are being called. + * The generic 'microcode_core' part guarantees that the callbacks + * below run on a target CPU when they are being called. * See also the "Synchronization" section in microcode_core.c. */ - enum ucode_state (*apply_microcode)(int cpu); - int (*collect_cpu_info)(int cpu, struct cpu_signature *csig); - void (*finalize_late_load)(int result); + enum ucode_state (*apply_microcode)(int cpu); + int (*collect_cpu_info)(int cpu, struct cpu_signature *csig); + void (*finalize_late_load)(int result); + unsigned int nmi_safe : 1; }; extern struct ucode_cpu_info ucode_cpu_info[];