diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2024-11-25 11:53:26 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2024-11-25 11:53:26 -0500 |
commit | 4570b22666dd4c45a4c355f7d156d949c0247e2d (patch) | |
tree | 4abff68f6a2042652f34dd23f5438e259d9db824 /src | |
parent | 32a2aa77ef7eec5ca46cfdbe6b175435cac1af61 (diff) | |
download | postgresql-4570b22666dd4c45a4c355f7d156d949c0247e2d.tar.gz postgresql-4570b22666dd4c45a4c355f7d156d949c0247e2d.zip |
Support runtime CRC feature probing on NetBSD/ARM using sysctl().
Commit aac831caf left this as a to-do; here's code to do it.
Like the previous patch, this is HEAD-only for now.
Discussion: https://postgr.es/m/4496616.iHFcN1HehY@portable-bastien
Diffstat (limited to 'src')
-rw-r--r-- | src/port/pg_crc32c_armv8_choose.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/port/pg_crc32c_armv8_choose.c b/src/port/pg_crc32c_armv8_choose.c index 306500154ee..45a52c77247 100644 --- a/src/port/pg_crc32c_armv8_choose.c +++ b/src/port/pg_crc32c_armv8_choose.c @@ -31,6 +31,13 @@ #endif #endif +#if defined(__NetBSD__) +#include <sys/sysctl.h> +#if defined(__aarch64__) +#include <aarch64/armreg.h> +#endif +#endif + #include "port/pg_crc32c.h" static bool @@ -52,6 +59,49 @@ pg_crc32c_armv8_available(void) #else return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0; #endif +#elif defined(__NetBSD__) + /* + * On NetBSD we can read the Instruction Set Attribute Registers via + * sysctl. For doubtless-historical reasons the sysctl interface is + * completely different on 64-bit than 32-bit, but the underlying + * registers contain the same fields. + */ +#define ISAR0_CRC32_BITPOS 16 +#define ISAR0_CRC32_BITWIDTH 4 +#define WIDTHMASK(w) ((1 << (w)) - 1) +#define SYSCTL_CPU_ID_MAXSIZE 64 + + size_t len; + uint64 sysctlbuf[SYSCTL_CPU_ID_MAXSIZE]; +#if defined(__aarch64__) + /* We assume cpu0 is representative of all the machine's CPUs. */ + const char *path = "machdep.cpu0.cpu_id"; + size_t expected_len = sizeof(struct aarch64_sysctl_cpu_id); +#define ISAR0 ((struct aarch64_sysctl_cpu_id *) sysctlbuf)->ac_aa64isar0 +#else + const char *path = "machdep.id_isar"; + size_t expected_len = 6 * sizeof(int); +#define ISAR0 ((int *) sysctlbuf)[5] +#endif + uint64 fld; + + /* Fetch the appropriate set of register values. */ + len = sizeof(sysctlbuf); + memset(sysctlbuf, 0, len); + if (sysctlbyname(path, sysctlbuf, &len, NULL, 0) != 0) + return false; /* perhaps kernel is 64-bit and we aren't? */ + if (len != expected_len) + return false; /* kernel API change? */ + + /* Fetch the CRC32 field from ISAR0. */ + fld = (ISAR0 >> ISAR0_CRC32_BITPOS) & WIDTHMASK(ISAR0_CRC32_BITWIDTH); + + /* + * Current 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 |