Skip to content

Commit 4570b22

Browse files
committed
Support runtime CRC feature probing on NetBSD/ARM using sysctl().
Commit aac831c 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
1 parent 32a2aa7 commit 4570b22

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

src/port/pg_crc32c_armv8_choose.c

+50
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131
#endif
3232
#endif
3333

34+
#if defined(__NetBSD__)
35+
#include <sys/sysctl.h>
36+
#if defined(__aarch64__)
37+
#include <aarch64/armreg.h>
38+
#endif
39+
#endif
40+
3441
#include "port/pg_crc32c.h"
3542

3643
static bool
@@ -52,6 +59,49 @@ pg_crc32c_armv8_available(void)
5259
#else
5360
return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0;
5461
#endif
62+
#elif defined(__NetBSD__)
63+
/*
64+
* On NetBSD we can read the Instruction Set Attribute Registers via
65+
* sysctl. For doubtless-historical reasons the sysctl interface is
66+
* completely different on 64-bit than 32-bit, but the underlying
67+
* registers contain the same fields.
68+
*/
69+
#define ISAR0_CRC32_BITPOS 16
70+
#define ISAR0_CRC32_BITWIDTH 4
71+
#define WIDTHMASK(w) ((1 << (w)) - 1)
72+
#define SYSCTL_CPU_ID_MAXSIZE 64
73+
74+
size_t len;
75+
uint64 sysctlbuf[SYSCTL_CPU_ID_MAXSIZE];
76+
#if defined(__aarch64__)
77+
/* We assume cpu0 is representative of all the machine's CPUs. */
78+
const char *path = "machdep.cpu0.cpu_id";
79+
size_t expected_len = sizeof(struct aarch64_sysctl_cpu_id);
80+
#define ISAR0 ((struct aarch64_sysctl_cpu_id *) sysctlbuf)->ac_aa64isar0
81+
#else
82+
const char *path = "machdep.id_isar";
83+
size_t expected_len = 6 * sizeof(int);
84+
#define ISAR0 ((int *) sysctlbuf)[5]
85+
#endif
86+
uint64 fld;
87+
88+
/* Fetch the appropriate set of register values. */
89+
len = sizeof(sysctlbuf);
90+
memset(sysctlbuf, 0, len);
91+
if (sysctlbyname(path, sysctlbuf, &len, NULL, 0) != 0)
92+
return false; /* perhaps kernel is 64-bit and we aren't? */
93+
if (len != expected_len)
94+
return false; /* kernel API change? */
95+
96+
/* Fetch the CRC32 field from ISAR0. */
97+
fld = (ISAR0 >> ISAR0_CRC32_BITPOS) & WIDTHMASK(ISAR0_CRC32_BITWIDTH);
98+
99+
/*
100+
* Current documentation defines only the field values 0 (No CRC32) and 1
101+
* (CRC32B/CRC32H/CRC32W/CRC32X/CRC32CB/CRC32CH/CRC32CW/CRC32CX). Assume
102+
* that any future nonzero value will be a superset of 1.
103+
*/
104+
return (fld != 0);
55105
#else
56106
return false;
57107
#endif

0 commit comments

Comments
 (0)