Received: by 2002:a05:6358:11c7:b0:104:8066:f915 with SMTP id i7csp1425344rwl; Fri, 7 Apr 2023 16:13:49 -0700 (PDT) X-Google-Smtp-Source: AKy350YXgqQveW8kKH52dpLiHNThnro5ZOwjk/8tnzL1CfpMmy5eAr6CHWoIvkonCJsjOw/jzl6E X-Received: by 2002:a17:906:5fc5:b0:948:f810:2960 with SMTP id k5-20020a1709065fc500b00948f8102960mr722705ejv.22.1680909228873; Fri, 07 Apr 2023 16:13:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680909228; cv=none; d=google.com; s=arc-20160816; b=BUVF1OVdVarprKDsZ+/UHTDCUmg++WnV9S3XCYHjFdv4k/IAb2j9tEhii+mC0hbRl5 Adv9tuqYRmOp7Ym16IFmm6IYUxwUgc8DWzKmZAtqUTWe/TqZZgM7vhiZT5f8k3IMzz0a o9Tkdy5HBBfFoT9j3WdgOq148rs0lYsXNZ+6tivyhoI3uVecvTlinbdzqtykpvbPjstc qhtHuuECSJq61fIPZTO6OUTP87JuPnr/o8/PslmAFN2HItjJ1gYOw9Ap4gWNrKHLKT1h Signth0zmaOcBi4G8gNLsHlj+EWsNtcHKu9YGOMAZ5HQTk99WIstnosNIlOO2kQr5Fb2 w4kQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=4oMAby9re+LXucyO0vYjK3/2G2wrGabkDMvU4DulRbM=; b=SNCZQ/6HtJxYgE/5C7jtGfT5dIX7zmqeIKP1I9ofxNLLzs1cqVzNBnc5YTy4OrOAIh mEg6D6DC825hCuXPhHr5mHq8KZPSv5RBhLDPhhF/lkvc7oWYoKtAB4w4Q1isZTPCJrzL 6p0jeiO9SJAqwqpoUfDaydUiravZD12i7d7sV2Gr98LK/d7JFSuSUxKhFcfScUG5M2GY +1UbvsRtQYHJc7VNzj2YLnghbSjxxHkAN4ggtqi8WNZV56V61LzsOw/BQV261AkoAO4j cLdTzvGaQdaT07I6CKwrtWLW4aFB0Uy0I/sx98Iduj92gl6LOEui1XYyBf/J3FtuYbjT Nl2w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@rivosinc-com.20210112.gappssmtp.com header.s=20210112 header.b=DKnA36df; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t27-20020a17090616db00b008cc8a6fea26si4390609ejd.561.2023.04.07.16.13.23; Fri, 07 Apr 2023 16:13:48 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@rivosinc-com.20210112.gappssmtp.com header.s=20210112 header.b=DKnA36df; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229834AbjDGXL0 (ORCPT + 99 others); Fri, 7 Apr 2023 19:11:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39650 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229542AbjDGXLV (ORCPT ); Fri, 7 Apr 2023 19:11:21 -0400 Received: from mail-pl1-x633.google.com (mail-pl1-x633.google.com [IPv6:2607:f8b0:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D5C76CA22 for ; Fri, 7 Apr 2023 16:11:19 -0700 (PDT) Received: by mail-pl1-x633.google.com with SMTP id h24so270923plr.1 for ; Fri, 07 Apr 2023 16:11:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; t=1680909079; x=1683501079; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4oMAby9re+LXucyO0vYjK3/2G2wrGabkDMvU4DulRbM=; b=DKnA36dfCwVQWntQl7q0/bNg5PIVoi1wQ8STKecFfQ3LgJTHJ7hycdQ7OnRc4cBeps OFi8gbsTgm4pvjyMiba6BJx07GOyX8/9Nu9yEfKMgBoUm9nKlB1Fx2ZG5t34fQITMVS3 +9J0t3QSZsK0yqiJ7CcSzGns6n9DfnlTxYC45geXFss/AC2ST8vKpPBUMJCU6XGCgXT2 p9fq+YQmJH014IuowDJwTkFfUAUxjCfwYFT1R9I5DL0TNv8BW6DLbc4MaoKULkdtE4qj D9duClOfVurVL3lKOSMrA/eCGoKcBpy2XNh9482wVnw+m2KAtMnSeoCTGDUcOXUFKIqN 3y7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680909079; x=1683501079; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4oMAby9re+LXucyO0vYjK3/2G2wrGabkDMvU4DulRbM=; b=mo6kLsIhefGlbNphGrqoJNPAN0gJEv1+3Fj2YsQLcYeCQiAFcav3tEc6ttwpVBJDNi vQ4z/F6eZBjh3GKslnZJBEUrta+80hnePFN10t8EKOY5S6zERBgMXAzisSimc+cCH+KB PkhMCjUpUXybDp0uhKG2AG6YqX5FF88bvks3w7hfxvB8EWa0LCJYzAumvy9enBqoCzrP rvdx6+r330FVTtdEbFDGKUPhL6rKAprRc3B+J7o4W5nOwRL4tEyUj/canFtOhNlwfXnI 2ckBx5SLGc4Gikq416t9+OjMCqSKI2xJmIBMgvo+5kPcNYXvEhNgAGPVqgcTIWf9H4MY V0hA== X-Gm-Message-State: AAQBX9dl9sCr4WCmDSmGeV1aRj+/1x596DDe4naROwkM/9KnBugTeXUB IrFrPnYukWQDAfAswMlF75ERlw== X-Received: by 2002:a17:903:2111:b0:1a2:2d2a:fc1b with SMTP id o17-20020a170903211100b001a22d2afc1bmr3449163ple.33.1680909079157; Fri, 07 Apr 2023 16:11:19 -0700 (PDT) Received: from evan.ba.rivosinc.com ([66.220.2.162]) by smtp.gmail.com with ESMTPSA id r5-20020a170902be0500b001a076568da9sm3361526pls.216.2023.04.07.16.11.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Apr 2023 16:11:18 -0700 (PDT) From: Evan Green To: Palmer Dabbelt Cc: slewis@rivosinc.com, heiko@sntech.de, Conor Dooley , vineetg@rivosinc.com, Evan Green , Conor Dooley , Heiko Stuebner , Paul Walmsley , Albert Ou , Andrew Bresticker , Celeste Liu , Guo Ren , Jonathan Corbet , Palmer Dabbelt , Tobias Klauser , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org Subject: [PATCH v6 2/6] RISC-V: Add a syscall for HW probing Date: Fri, 7 Apr 2023 16:10:59 -0700 Message-Id: <20230407231103.2622178-3-evan@rivosinc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230407231103.2622178-1-evan@rivosinc.com> References: <20230407231103.2622178-1-evan@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE,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 lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org We don't have enough space for these all in ELF_HWCAP{,2} and there's no system call that quite does this, so let's just provide an arch-specific one to probe for hardware capabilities. This currently just provides m{arch,imp,vendor}id, but with the key-value pairs we can pass more in the future. Co-developed-by: Palmer Dabbelt Signed-off-by: Palmer Dabbelt Signed-off-by: Evan Green Reviewed-by: Conor Dooley Reviewed-by: Heiko Stuebner Tested-by: Heiko Stuebner Reviewed-by: Paul Walmsley --- Changes in v6: - Remove spurious blank line (Conorbot) - Update copyrights (Paul) Changes in v4: - Used real types in syscall prototypes (Arnd) - Fixed static line break in do_riscv_hwprobe() (Conor) - Added newlines between documentation lists (Conor) - Crispen up size types to size_t, and cpu indices to int (Joe) - Fix copy_from_user() return logic bug (found via kselftests!) - Add __user to SYSCALL_DEFINE() to fix warning Changes in v3: - Refactored functions so that kernel mode can query too, in preparation for the vDSO data population. - Changed the vendor/arch/imp IDs to return a value of -1 on mismatch rather than failing the whole call. - Const cpumask pointer in hwprobe_mid() - Embellished documentation WRT cpu_set and the returned values. - Renamed hwprobe_mid() to hwprobe_arch_id() (Conor) - Fixed machine ID doc warnings, changed elements to c:macro:. - Completed dangling unistd.h comment (Conor) - Fixed line breaks and minor logic optimization (Conor). - Use riscv_cached_mxxxid() (Conor) Changes in v2: - Changed the interface to look more like poll(). Rather than supplying key_offset and getting back an array of values with numerically contiguous keys, have the user pre-fill the key members of the array, and the kernel will fill in the corresponding values. For any key it doesn't recognize, it will set the key of that element to -1. This allows usermode to quickly ask for exactly the elements it cares about, and not get bogged down in a back and forth about newer keys that older kernels might not recognize. In other words, the kernel can communicate that it doesn't recognize some of the keys while still providing the data for the keys it does know. - Added a shortcut to the cpuset parameters that if a size of 0 and NULL is provided for the CPU set, the kernel will use a cpu mask of all online CPUs. This is convenient because I suspect most callers will only want to act on a feature if it's supported on all CPUs, and it's a headache to dynamically allocate an array of all 1s, not to mention a waste to have the kernel loop over all of the offline bits. --- Documentation/riscv/hwprobe.rst | 41 ++++++++ Documentation/riscv/index.rst | 1 + arch/riscv/include/asm/hwprobe.h | 13 +++ arch/riscv/include/asm/syscall.h | 4 + arch/riscv/include/uapi/asm/hwprobe.h | 25 +++++ arch/riscv/include/uapi/asm/unistd.h | 9 ++ arch/riscv/kernel/sys_riscv.c | 135 +++++++++++++++++++++++++- 7 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 Documentation/riscv/hwprobe.rst create mode 100644 arch/riscv/include/asm/hwprobe.h create mode 100644 arch/riscv/include/uapi/asm/hwprobe.h diff --git a/Documentation/riscv/hwprobe.rst b/Documentation/riscv/hwprobe.rst new file mode 100644 index 000000000000..211828f706e3 --- /dev/null +++ b/Documentation/riscv/hwprobe.rst @@ -0,0 +1,41 @@ +.. SPDX-License-Identifier: GPL-2.0 + +RISC-V Hardware Probing Interface +--------------------------------- + +The RISC-V hardware probing interface is based around a single syscall, which +is defined in :: + + struct riscv_hwprobe { + __s64 key; + __u64 value; + }; + + long sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, cpu_set_t *cpus, + unsigned int flags); + +The arguments are split into three groups: an array of key-value pairs, a CPU +set, and some flags. The key-value pairs are supplied with a count. Userspace +must prepopulate the key field for each element, and the kernel will fill in the +value if the key is recognized. If a key is unknown to the kernel, its key field +will be cleared to -1, and its value set to 0. The CPU set is defined by +CPU_SET(3). For value-like keys (eg. vendor/arch/impl), the returned value will +be only be valid if all CPUs in the given set have the same value. Otherwise -1 +will be returned. For boolean-like keys, the value returned will be a logical +AND of the values for the specified CPUs. Usermode can supply NULL for cpus and +0 for cpu_count as a shortcut for all online CPUs. There are currently no flags, +this value must be zero for future compatibility. + +On success 0 is returned, on failure a negative error code is returned. + +The following keys are defined: + +* :c:macro:`RISCV_HWPROBE_KEY_MVENDORID`: Contains the value of ``mvendorid``, + as defined by the RISC-V privileged architecture specification. + +* :c:macro:`RISCV_HWPROBE_KEY_MARCHID`: Contains the value of ``marchid``, as + defined by the RISC-V privileged architecture specification. + +* :c:macro:`RISCV_HWPROBE_KEY_MIMPLID`: Contains the value of ``mimplid``, as + defined by the RISC-V privileged architecture specification. diff --git a/Documentation/riscv/index.rst b/Documentation/riscv/index.rst index 2e5b18fbb145..175a91db0200 100644 --- a/Documentation/riscv/index.rst +++ b/Documentation/riscv/index.rst @@ -7,6 +7,7 @@ RISC-V architecture boot-image-header vm-layout + hwprobe patch-acceptance uabi diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h new file mode 100644 index 000000000000..6184bbc77256 --- /dev/null +++ b/arch/riscv/include/asm/hwprobe.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright 2023 Rivos, Inc + */ + +#ifndef _ASM_HWPROBE_H +#define _ASM_HWPROBE_H + +#include + +#define RISCV_HWPROBE_MAX_KEY 2 + +#endif diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h index 384a63b86420..3b5a667928bf 100644 --- a/arch/riscv/include/asm/syscall.h +++ b/arch/riscv/include/asm/syscall.h @@ -10,6 +10,7 @@ #ifndef _ASM_RISCV_SYSCALL_H #define _ASM_RISCV_SYSCALL_H +#include #include #include #include @@ -75,4 +76,7 @@ static inline int syscall_get_arch(struct task_struct *task) } asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t); + +asmlinkage long sys_riscv_hwprobe(struct riscv_hwprobe *, size_t, size_t, + unsigned long *, unsigned int); #endif /* _ASM_RISCV_SYSCALL_H */ diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h new file mode 100644 index 000000000000..b79be00920db --- /dev/null +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright 2023 Rivos, Inc + */ + +#ifndef _UAPI_ASM_HWPROBE_H +#define _UAPI_ASM_HWPROBE_H + +#include + +/* + * Interface for probing hardware capabilities from userspace, see + * Documentation/riscv/hwprobe.rst for more information. + */ +struct riscv_hwprobe { + __s64 key; + __u64 value; +}; + +#define RISCV_HWPROBE_KEY_MVENDORID 0 +#define RISCV_HWPROBE_KEY_MARCHID 1 +#define RISCV_HWPROBE_KEY_MIMPID 2 +/* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ + +#endif diff --git a/arch/riscv/include/uapi/asm/unistd.h b/arch/riscv/include/uapi/asm/unistd.h index 73d7cdd2ec49..950ab3fd4409 100644 --- a/arch/riscv/include/uapi/asm/unistd.h +++ b/arch/riscv/include/uapi/asm/unistd.h @@ -43,3 +43,12 @@ #define __NR_riscv_flush_icache (__NR_arch_specific_syscall + 15) #endif __SYSCALL(__NR_riscv_flush_icache, sys_riscv_flush_icache) + +/* + * Allows userspace to query the kernel for CPU architecture and + * microarchitecture details across a given set of CPUs. + */ +#ifndef __NR_riscv_hwprobe +#define __NR_riscv_hwprobe (__NR_arch_specific_syscall + 14) +#endif +__SYSCALL(__NR_riscv_hwprobe, sys_riscv_hwprobe) diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 5d3f2fbeb33c..fe8e833ecb2e 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -6,8 +6,11 @@ */ #include -#include #include +#include +#include +#include +#include #include static long riscv_sys_mmap(unsigned long addr, unsigned long len, @@ -69,3 +72,133 @@ SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end, return 0; } + +/* + * The hwprobe interface, for allowing userspace to probe to see which features + * are supported by the hardware. See Documentation/riscv/hwprobe.rst for more + * details. + */ +static void hwprobe_arch_id(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + u64 id = -1ULL; + bool first = true; + int cpu; + + for_each_cpu(cpu, cpus) { + u64 cpu_id; + + switch (pair->key) { + case RISCV_HWPROBE_KEY_MVENDORID: + cpu_id = riscv_cached_mvendorid(cpu); + break; + case RISCV_HWPROBE_KEY_MIMPID: + cpu_id = riscv_cached_mimpid(cpu); + break; + case RISCV_HWPROBE_KEY_MARCHID: + cpu_id = riscv_cached_marchid(cpu); + break; + } + + if (first) + id = cpu_id; + + /* + * If there's a mismatch for the given set, return -1 in the + * value. + */ + if (id != cpu_id) { + id = -1ULL; + break; + } + } + + pair->value = id; +} + +static void hwprobe_one_pair(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + switch (pair->key) { + case RISCV_HWPROBE_KEY_MVENDORID: + case RISCV_HWPROBE_KEY_MARCHID: + case RISCV_HWPROBE_KEY_MIMPID: + hwprobe_arch_id(pair, cpus); + break; + + /* + * For forward compatibility, unknown keys don't fail the whole + * call, but get their element key set to -1 and value set to 0 + * indicating they're unrecognized. + */ + default: + pair->key = -1; + pair->value = 0; + break; + } +} + +static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs, + size_t pair_count, size_t cpu_count, + unsigned long __user *cpus_user, + unsigned int flags) +{ + size_t out; + int ret; + cpumask_t cpus; + + /* Check the reserved flags. */ + if (flags != 0) + return -EINVAL; + + /* + * The interface supports taking in a CPU mask, and returns values that + * are consistent across that mask. Allow userspace to specify NULL and + * 0 as a shortcut to all online CPUs. + */ + cpumask_clear(&cpus); + if (!cpu_count && !cpus_user) { + cpumask_copy(&cpus, cpu_online_mask); + } else { + if (cpu_count > cpumask_size()) + cpu_count = cpumask_size(); + + ret = copy_from_user(&cpus, cpus_user, cpu_count); + if (ret) + return -EFAULT; + + /* + * Userspace must provide at least one online CPU, without that + * there's no way to define what is supported. + */ + cpumask_and(&cpus, &cpus, cpu_online_mask); + if (cpumask_empty(&cpus)) + return -EINVAL; + } + + for (out = 0; out < pair_count; out++, pairs++) { + struct riscv_hwprobe pair; + + if (get_user(pair.key, &pairs->key)) + return -EFAULT; + + pair.value = 0; + hwprobe_one_pair(&pair, &cpus); + ret = put_user(pair.key, &pairs->key); + if (ret == 0) + ret = put_user(pair.value, &pairs->value); + + if (ret) + return -EFAULT; + } + + return 0; +} + +SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs, + size_t, pair_count, size_t, cpu_count, unsigned long __user *, + cpus, unsigned int, flags) +{ + return do_riscv_hwprobe(pairs, pair_count, cpu_count, + cpus, flags); +} -- 2.25.1