netbsd-arm-crc-detection.patch
text/x-diff
Filename: netbsd-arm-crc-detection.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/port/pg_crc32c_armv8_choose.c | 41 | 0 |
diff --git a/src/port/pg_crc32c_armv8_choose.c b/src/port/pg_crc32c_armv8_choose.c index 306500154e..f035ac9855 100644 --- a/src/port/pg_crc32c_armv8_choose.c +++ b/src/port/pg_crc32c_armv8_choose.c @@ -31,6 +31,11 @@ #endif #endif +#if defined(__NetBSD__) && defined(__aarch64__) +#include <sys/sysctl.h> +#include <aarch64/armreg.h> +#endif + #include "port/pg_crc32c.h" static bool @@ -52,6 +57,42 @@ pg_crc32c_armv8_available(void) #else return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0; #endif +#elif defined(__NetBSD__) && defined(__aarch64__) + /* + * On NetBSD we can read AArch64 Instruction Set Attribute Register 0 via + * sysctl. We could probably do something similar on arm32 as well, but + * it's undocumented. Note we assume cpu0 is representative of all the + * machine's CPUs. + */ + const char *path = "machdep.cpu0.cpu_id"; + size_t len; +#define SYSCTL_CPU_ID_MAXSIZE 64 + uint64 sysctlbuf[SYSCTL_CPU_ID_MAXSIZE]; + struct aarch64_sysctl_cpu_id *id = + (struct aarch64_sysctl_cpu_id *) sysctlbuf; + uint64 reg; + uint64 fld; + + len = sizeof(sysctlbuf); + memset(sysctlbuf, 0, len); + if (sysctlbyname(path, id, &len, NULL, 0) != 0) + return false; + if (len != sizeof(struct aarch64_sysctl_cpu_id)) + return false; /* kernel incompatibility? */ + +#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); #else return false; #endif