From nobody Mon Jun 2 10:42:00 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4b9r4m2j5kz5xs7G; Mon, 02 Jun 2025 10:42:00 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4b9r4m1jpSz3gSH; Mon, 02 Jun 2025 10:42:00 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1748860920; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=vmTswQHAYJdR1jU8xNnErb1tVHP4zeNIf6CYOldpwM8=; b=a06devoQAYcpRlyqTPA93z6GzXGxdM+5L1ikGL05ZSk+jCOavWVgZGaBrhRKQjjnjorWIs 8KB9UtBtrWoyxSJq2snVjCCJv//MLeiz8pzVHxMdBy8QEPKndm9tJiURHCgQcCSDbIAZL7 AWQk677Nw82NdTINe7wZpTgfT+qlG8w5/i+CHbkRwFTQRlPSGCRmbrQGzzIPjZZ/0p4bfZ pYJ+8td7cgLuFYzoIlGRd7g7QTpuwfrIN7ElJD8VCJhFM6NWBwI/rUaOxsbET4clHgIT4t yZc/75OYohfU5ls2IG/CykCJEgg2TNigz5gK1MTMPxjTmBMqApGI2SOabQHudQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1748860920; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=vmTswQHAYJdR1jU8xNnErb1tVHP4zeNIf6CYOldpwM8=; b=MocwYzDaoGRQY+yY5nNFh+723vTOHocBm/Yr3gGRPEuTdVr+ZLETRih9Tkc4B5pWUEzoZN dK7/I7QWsEYWt6+cfoounCInQZt2lFIqxAamVT2wrgI/Zt1PzQLUTi/BIZzBIoE4alte1V X0ZCT92KveewQ2obovtROhyk1S4NfHiMvezDQtVlhCqgISzhQ49Ia0AGi9kDQ6rnLQc/KP fW97sIa/kgCSUEPOQtjvRGYgwJoXJcxZuKkifzMeH2PrnHSwbka7TYlVyfsoD9mQO4LS/n El7G+cVmGAC6pUATsGOVK/Fx3vHJWus+AruSm/fmojE7g0bNUdr/TDf2ZfhMaA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1748860920; a=rsa-sha256; cv=none; b=LcNTeXvCp7RIQJ+14U6QLcTL1YiWhl1bFUunReGaYgli6StTfnMCnpgvCFhSlwWAw3oP+N Yi0BXjZi0ureI/ZhAc7WsTs1hqXI/Q65jFT2xMsaJ0wvZfYFyNFdkXBeMmMu2izbM+7WmW CL0KuLEXy7T559ScwxPlM28nyFMBjVLw8EYAmTtRq54mmofdBzeu55V1zzH1i4hGY3Fbfp tKt62g7WXq7ochGAj6zzyETI/8l02JaDmqJ56wjwVimjuqNnjCaRjta2jh8refKLTA1pDl fwUUZitY7eZn3uTphXDcvEFaVLKvRYG4wWCODlYGZdBpBhoufgQ3fxnE4tdqIg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4b9r4m197pz14WG; Mon, 02 Jun 2025 10:42:00 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 552Ag0qT012378; Mon, 2 Jun 2025 10:42:00 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 552Ag0TJ012375; Mon, 2 Jun 2025 10:42:00 GMT (envelope-from git) Date: Mon, 2 Jun 2025 10:42:00 GMT Message-Id: <202506021042.552Ag0TJ012375@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Andrew Turner Subject: git: 2aeac25bcb72 - main - arm64: Add a function to restrict the ID registers List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: andrew X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 2aeac25bcb72723d436721ab97bb2fd6df3dfb9b Auto-Submitted: auto-generated The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=2aeac25bcb72723d436721ab97bb2fd6df3dfb9b commit 2aeac25bcb72723d436721ab97bb2fd6df3dfb9b Author: Andrew Turner AuthorDate: 2025-06-02 09:56:59 +0000 Commit: Andrew Turner CommitDate: 2025-06-02 09:56:59 +0000 arm64: Add a function to restrict the ID registers This will be used when we need to restrict the register values, e.g. when an erratum is present that means we need to disable a feature we will need to remove some fields from these registers. Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D50572 --- sys/arm64/arm64/identcpu.c | 131 ++++++++++++++++++++++++++++++++------------- sys/arm64/include/cpu.h | 1 + 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c index fe10e0eb551a..6dc9c447ee29 100644 --- a/sys/arm64/arm64/identcpu.c +++ b/sys/arm64/arm64/identcpu.c @@ -51,6 +51,9 @@ static MALLOC_DEFINE(M_IDENTCPU, "CPU ID", "arm64 CPU identification memory"); struct cpu_desc; +#ifdef INVARIANTS +static bool hwcaps_set = false; +#endif static void print_cpu_midr(struct sbuf *sb, u_int cpu); static void print_cpu_features(u_int cpu, struct cpu_desc *desc, @@ -2594,13 +2597,62 @@ update_special_reg_field(uint64_t user_reg, u_int type, uint64_t value, return (user_reg); } +static void +clear_set_special_reg_idx(int idx, uint64_t clear, uint64_t set) +{ + const struct mrs_field *fields; + uint64_t k_old, k_new; + uint64_t f_old, f_new; + uint64_t l_old, l_new; + + MPASS(idx < nitems(user_regs)); + + k_old = CPU_DESC_FIELD(kern_cpu_desc, idx); + k_new = (k_old & ~clear) | set; + + f_old = CPU_DESC_FIELD(user_cpu_desc, idx); + f_new = (f_old & ~clear) | set; + + l_old = CPU_DESC_FIELD(l_user_cpu_desc, idx); + l_new = (l_old & ~clear) | set; + + fields = user_regs[idx].fields; + for (int j = 0; fields[j].type != 0; j++) { + u_int type; + + /* Update the FreeBSD userspace ID register view */ + type = ((fields[j].type & MRS_FREEBSD) != 0) ? + fields[j].type : + (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK)); + f_new = update_special_reg_field(f_new, + type, f_old, fields[j].width, fields[j].shift, + fields[j].sign); + + /* Update the Linux userspace ID register view */ + type = ((fields[j].type & MRS_LINUX) != 0) ? + fields[j].type : + (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK)); + l_new = update_special_reg_field(l_new, + type, l_old, fields[j].width, fields[j].shift, + fields[j].sign); + + /* Update the kernel ID register view */ + k_new = update_special_reg_field(k_new, + fields[j].type, k_old, fields[j].width, + fields[j].shift, fields[j].sign); + } + + CPU_DESC_FIELD(kern_cpu_desc, idx) = k_new; + CPU_DESC_FIELD(user_cpu_desc, idx) = f_new; + CPU_DESC_FIELD(l_user_cpu_desc, idx) = l_new; +} + void update_special_regs(u_int cpu) { struct cpu_desc *desc; - const struct mrs_field *fields; - uint64_t l_user_reg, user_reg, kern_reg, value; - int i, j; + uint64_t value; + int i; if (cpu == 0) { /* Create a user visible cpu description with safe values */ @@ -2618,44 +2670,42 @@ update_special_regs(u_int cpu) for (i = 0; i < nitems(user_regs); i++) { value = CPU_DESC_FIELD(*desc, i); if (cpu == 0) { - kern_reg = value; - user_reg = value; - l_user_reg = value; - } else { - kern_reg = CPU_DESC_FIELD(kern_cpu_desc, i); - user_reg = CPU_DESC_FIELD(user_cpu_desc, i); - l_user_reg = CPU_DESC_FIELD(l_user_cpu_desc, i); + CPU_DESC_FIELD(kern_cpu_desc, i) = value; + CPU_DESC_FIELD(user_cpu_desc, i) = value; + CPU_DESC_FIELD(l_user_cpu_desc, i) = value; } - fields = user_regs[i].fields; - for (j = 0; fields[j].type != 0; j++) { - u_int type; - - /* Update the FreeBSD userspace ID register view */ - type = ((fields[j].type & MRS_FREEBSD) != 0) ? - fields[j].type : - (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK)); - user_reg = update_special_reg_field(user_reg, - type, value, fields[j].width, fields[j].shift, - fields[j].sign); - - /* Update the Linux userspace ID register view */ - type = ((fields[j].type & MRS_LINUX) != 0) ? - fields[j].type : - (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK)); - l_user_reg = update_special_reg_field(l_user_reg, - type, value, fields[j].width, fields[j].shift, - fields[j].sign); - - /* Update the kernel ID register view */ - kern_reg = update_special_reg_field(kern_reg, - fields[j].type, value, fields[j].width, - fields[j].shift, fields[j].sign); - } + clear_set_special_reg_idx(i, UINT64_MAX, value); + } +} + +/* + * Updates a special register in all views. This creates a copy of the + * register then clears it and sets new bits. It will then compare this + * with the old version as if it was the ID register for a new CPU. + * + * It is intended to let code that disables features, e.g. due to errata, + * to clear the user visible field. + * + * This needs to be called before the HWCAPs are set. If called from a CPU + * feature handler this safe to call from CPU_FEAT_EARLY_BOOT. It also needs + * to be before link_elf_late_ireloc is called. As this is called after the + * HWCAPs are set the check for these is enough. + */ +void +update_special_reg(u_int reg, uint64_t clear, uint64_t set) +{ + MPASS(hwcaps_set == false); + /* There is no locking here, so we only support changing this on CPU0 */ + /* TODO: Add said locking */ + MPASS(PCPU_GET(cpuid) == 0); + + for (int i = 0; i < nitems(user_regs); i++) { + if (user_regs[i].reg != reg) + continue; - CPU_DESC_FIELD(kern_cpu_desc, i) = kern_reg; - CPU_DESC_FIELD(user_cpu_desc, i) = user_reg; - CPU_DESC_FIELD(l_user_cpu_desc, i) = l_user_reg; + clear_set_special_reg_idx(i, clear, set); + return; } } @@ -2757,6 +2807,11 @@ identify_cpu_sysinit(void *dummy __unused) prev_desc = desc; } +#ifdef INVARIANTS + /* Check we dont update the special registers after this point */ + hwcaps_set = true; +#endif + /* Find the values to export to userspace as AT_HWCAP and AT_HWCAP2 */ parse_cpu_features(true, &user_cpu_desc, &elf_hwcap, &elf_hwcap2); parse_cpu_features(true, &l_user_cpu_desc, &linux_elf_hwcap, diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h index 91ed3634c6d8..df38c69fdb30 100644 --- a/sys/arm64/include/cpu.h +++ b/sys/arm64/include/cpu.h @@ -232,6 +232,7 @@ void ptrauth_mp_start(uint64_t); /* Functions to read the sanitised view of the special registers */ void update_special_regs(u_int); +void update_special_reg(u_int reg, uint64_t, uint64_t); bool extract_user_id_field(u_int, u_int, uint8_t *); bool get_kernel_reg(u_int, uint64_t *); bool get_kernel_reg_masked(u_int, uint64_t *, uint64_t);