From patchwork Fri Apr 7 23:10:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Evan Green X-Patchwork-Id: 13205456 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4C9EEC76196 for ; Fri, 7 Apr 2023 23:11:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=kPMnbhAsv8oEp4v5xQWEkH64bfotyTBeUXuZKhn3wVU=; b=2/U0ekzqdLFMdc RGGLLW4HHOg7CftbTvIopMKgMc5xvE6qqTSBEbFxUhKkkDbEhBfZRn8DOOp5eP30BuJFZumE709Uw wR/UGqfJu6VXfh60BLrV8KtxWlgbCdRqPkCA+RXLj86lYqZB99jTpfIEOWq4UW2OVyv2tkMzGvIlW l8BvICwMqIahFr0+oZi8Qo1J01jD4mPAISVNFbZSzRHhRLgDMpkhTlDjWksX04430WXnGwujXIikd xZ7IHiMZPFq+vgLJW+kMpM3CaxhQV4wbK/OZhwSh69uB+tEv4hSbAz9mzNu1TM3VRElI/A7HIEOUi ss8W7jYvcrhHmSUYL2OA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1pkvEr-00BJjY-32; Fri, 07 Apr 2023 23:11:25 +0000 Received: from mail-pj1-x102c.google.com ([2607:f8b0:4864:20::102c]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1pkvEn-00BJXq-2h for linux-riscv@lists.infradead.org; Fri, 07 Apr 2023 23:11:23 +0000 Received: by mail-pj1-x102c.google.com with SMTP id pc4-20020a17090b3b8400b0024676052044so100842pjb.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=GjbXqAXrRnVR8MtY4Ez0wZmEWcKCsR9h4g9d5uuInCCYw/AbltxQugxp3Wjazr8s/P GbwPrR8n6fnATitpHhmwMna4bYlnyEjxv+H2/3YVRrt6+XJCtkG7Qw6Bty5WXwLaFr2P uiv9o1t09cgPger8vND5geFRErhyvAPzvk68fVFUecYJ6hTtGYiqTzVEpdCzpA6DF1Le IOAlTgGOGMCmErA2qefaw4LJmNNW4Rsf0G7ELgjpaB35l+1dmk1jryUFBRd+jWcgSLph iRnDjeSexKRjKJ+Nm+4QTbTF0tpnOn+pBQ4wdw0RATF99GagyC0LW3N4M3rDsi52h1+8 /GXA== X-Gm-Message-State: AAQBX9fiegJFeyv5fCEFV5po7y5C4DOUaz0cfkN+Pk6mdDB77hTYXSgy kE9JqkRRLQhmpJpw7dlrh+VFLg== X-Google-Smtp-Source: AKy350YuBgrzwnElvZ05IlugrPNPgL1+zenFUfofOO/9vK/595eJbS0HTFyZXpy44QFpS4OKtlf1iw== 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 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230407_161121_874202_467D86B3 X-CRM114-Status: GOOD ( 35.02 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.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); +}