On Sat, Nov 23, 2024 at 2:40 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> I poked into this with NetBSD and found that cpuctl's "identify"
> option works just fine without root. So that motivated me to dig
> into its source code, and I end up with the attached. Sadly it only
> works in 64-bit; there is presumably a way to detect this in 32-bit
> as well, but cpuctl doesn't know it. That doesn't bother me a whole
> lot though, at least not nearly as much as the 64-bit case. Anybody
> running PG on 32-bit ARM shouldn't be expecting great performance.
(Nerd sniped) No NetBSD here but think a 32 bit kernel should expose
sysctl machdep.id_isar, which should be an array of 6 ints, and bits
16-19 of id_isar[5] should give you the answer:
https://github.com/NetBSD/src/blob/312631d82871c81540b81abea3baa09313478bd3/sys/arch/arm/arm32/arm32_machdep.c#L142
https://github.com/NetBSD/src/blob/312631d82871c81540b81abea3baa09313478bd3/sys/arch/arm/arm32/cpu.c#L869
https://developer.arm.com/documentation/ddi0601/2024-09/AArch32-Registers/ID-ISAR5--Instruction-Set-Attribute-Register-5?lang=en
A real 32 bit armv7 or similar like RPI2 must say no. An armv8+ like
RPI3+ running a 32 bit kernel (ie a 64 bit chip running in aarch32
mode) should say yes.
With a 64 bit kernel running a 32 bit process, I think your code
should work, except that it wouldn't be used because it's gated on
__aarch64__.
So there are combinations to consider. However, beyond satisfying
curiosity about how it works, I agree that it's all a complete waste
of time and what you have is perfectly fine. (I wonder why there
isn't a sysctl that gives you the id_aa64isar0_el1 register more
directly, instead of having to slurp it out of struct
aarch64_sysctl_cpu_id. I mean, why expose similar "isar" registers
differently for aarch32 and aarch64 kernels... but OK.)
+#define ISAR0_CRC32_BITPOS 16
+#define ISAR0_CRC32_BITWIDTH 4
+#define WIDTHMASK(w) ((((uint64) 1) << (w)) - 1)
+
+ reg = id->ac_aa64isar0;
+ fld = (reg >> ISAR0_CRC32_BITPOS) & WIDTHMASK(ISAR0_CRC32_BITWIDTH);
+
+ /*
+ * Available documentation defines only the field values 0 (No CRC32) and
+ * 1 (CRC32B/CRC32H/CRC32W/CRC32X/CRC32CB/CRC32CH/CRC32CW/CRC32CX). Assume
+ * that any future nonzero value will be a superset of 1.
+ */
+ return (fld != 0);
Since you included <aarch64/armreg.h>, and only care about non-zero,
couldn't you use the mask from the header, instead of all that
bitswizzling?
return (id->ac_aa64isar0 & ID_AA64ISAR0_EL1_CRC32) != 0;
> I've checked this on NetBSD 9.2 and 10.0. I don't have hardware
> that should return false (and there may not be any such 64-bit
> hardware anyway...), so there's not much more I can test.
I wish qemu supported a cpu that didn't have that...