31
31
#endif
32
32
#endif
33
33
34
+ #if defined(__NetBSD__ )
35
+ #include <sys/sysctl.h>
36
+ #if defined(__aarch64__ )
37
+ #include <aarch64/armreg.h>
38
+ #endif
39
+ #endif
40
+
34
41
#include "port/pg_crc32c.h"
35
42
36
43
static bool
@@ -52,6 +59,49 @@ pg_crc32c_armv8_available(void)
52
59
#else
53
60
return (getauxval (AT_HWCAP2 ) & HWCAP2_CRC32 ) != 0 ;
54
61
#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 );
55
105
#else
56
106
return false;
57
107
#endif
0 commit comments