authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-05 14:51:48+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-05 14:51:48+02:00
log58a5cdde51972142d4255499233521a0de0494ca
treeec153500610d0ef850b817fbfafd2782cef00bb6
parent7b905d6a2b8f6fadc55e6c58a3d558a3d5899326
parent88ee09fd917b93397926aa077772c89aec92e864

Merge pull request '`std.zig.system`: add aarch64 CPU feature/model detection for NetBSD and OpenBSD' (#36758) from alexrp/zig:aarch64-detect into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36758

6 files changed, 189 insertions(+), 37 deletions(-)

lib/std/c.zig+21
......@@ -1366,6 +1366,27 @@ pub const CTL = switch (native_os) {
13661366 },
13671367 else => void,
13681368};
1369pub const CPU = switch (native_os) {
1370 .openbsd => switch (native_arch) {
1371 .aarch64, .aarch64_be => struct {
1372 pub const COMPATIBLE = 1;
1373 pub const ID_AA64ISAR0 = 2;
1374 pub const ID_AA64ISAR1 = 3;
1375 pub const ID_AA64ISAR2 = 4;
1376 pub const ID_AA64MMFR0 = 5;
1377 pub const ID_AA64MMFR1 = 6;
1378 pub const ID_AA64MMFR2 = 7;
1379 pub const AA64PFR0 = 8;
1380 pub const AA64PFR1 = 9;
1381 pub const AA64SMFR0 = 10;
1382 pub const AA64ZFR0 = 11;
1383 pub const LIDACTION = 12;
1384 pub const LED_BLINK = 13;
1385 },
1386 else => void,
1387 },
1388 else => void,
1389};
13691390pub const KERN = switch (native_os) {
13701391 .freebsd => struct {
13711392 /// struct: process entries
lib/std/zig/system.zig+6-3
......@@ -12,10 +12,12 @@ const Io = std.Io;
1212
1313pub const NativePaths = @import("system/NativePaths.zig");
1414
15pub const windows = @import("system/windows.zig");
1615pub const darwin = @import("system/darwin.zig");
17pub const linux = @import("system/linux.zig");
1816pub const freebsd = @import("system/freebsd.zig");
17pub const linux = @import("system/linux.zig");
18pub const netbsd = @import("system/netbsd.zig");
19pub const openbsd = @import("system/openbsd.zig");
20pub const windows = @import("system/windows.zig");
1921
2022pub const Executor = union(enum) {
2123 native,
......@@ -547,12 +549,13 @@ fn detectNativeCpuAndFeatures(io: Io, cpu_arch: Target.Cpu.Arch, os: Target.Os,
547549 .freebsd => return freebsd.detectNativeCpuAndFeatures(),
548550 .linux => return linux.detectNativeCpuAndFeatures(io),
549551 .macos => return darwin.macos.detectNativeCpuAndFeatures(),
552 .netbsd => return netbsd.detectNativeCpuAndFeatures(),
553 .openbsd => return openbsd.detectNativeCpuAndFeatures(),
550554 .windows => return windows.detectNativeCpuAndFeatures(),
551555 else => {},
552556 }
553557
554558 // This architecture does not have CPU model & feature detection yet.
555 // See https://github.com/ziglang/zig/issues/4591
556559 return null;
557560}
558561
lib/std/zig/system/freebsd.zig+19-17
......@@ -3,28 +3,30 @@ const std = @import("std");
33
44const native_arch = builtin.target.cpu.arch;
55
6inline fn getAArch64CpuFeature(comptime feat_reg: []const u8) u64 {
7 return asm ("mrs %[ret], " ++ feat_reg
8 : [ret] "=r" (-> u64),
9 );
10}
6const aarch64 = struct {
7 inline fn mrs(comptime feat_reg: []const u8) u64 {
8 return asm ("mrs %[ret], " ++ feat_reg
9 : [ret] "=r" (-> u64),
10 );
11 }
12};
1113
1214pub fn detectNativeCpuAndFeatures() ?std.Target.Cpu {
1315 return switch (native_arch) {
1416 .aarch64, .aarch64_be => b: {
1517 const registers = [12]u64{
16 getAArch64CpuFeature("MIDR_EL1"),
17 getAArch64CpuFeature("ID_AA64PFR0_EL1"),
18 getAArch64CpuFeature("ID_AA64PFR1_EL1"),
19 getAArch64CpuFeature("ID_AA64DFR0_EL1"),
20 getAArch64CpuFeature("ID_AA64DFR1_EL1"),
21 getAArch64CpuFeature("ID_AA64AFR0_EL1"),
22 getAArch64CpuFeature("ID_AA64AFR1_EL1"),
23 getAArch64CpuFeature("ID_AA64ISAR0_EL1"),
24 getAArch64CpuFeature("ID_AA64ISAR1_EL1"),
25 getAArch64CpuFeature("ID_AA64MMFR0_EL1"),
26 getAArch64CpuFeature("ID_AA64MMFR1_EL1"),
27 getAArch64CpuFeature("ID_AA64MMFR2_EL1"),
18 aarch64.mrs("MIDR_EL1"),
19 aarch64.mrs("ID_AA64PFR0_EL1"),
20 aarch64.mrs("ID_AA64PFR1_EL1"),
21 aarch64.mrs("ID_AA64DFR0_EL1"),
22 aarch64.mrs("ID_AA64DFR1_EL1"),
23 aarch64.mrs("ID_AA64AFR0_EL1"),
24 aarch64.mrs("ID_AA64AFR1_EL1"),
25 aarch64.mrs("ID_AA64ISAR0_EL1"),
26 aarch64.mrs("ID_AA64ISAR1_EL1"),
27 aarch64.mrs("ID_AA64MMFR0_EL1"),
28 aarch64.mrs("ID_AA64MMFR1_EL1"),
29 aarch64.mrs("ID_AA64MMFR2_EL1"),
2830 };
2931
3032 break :b @import("arm.zig").aarch64.detectNativeCpuAndFeatures(native_arch, registers);
lib/std/zig/system/linux.zig+19-17
......@@ -441,11 +441,13 @@ fn CpuinfoParser(comptime impl: anytype) type {
441441 };
442442}
443443
444inline fn getAArch64CpuFeature(comptime feat_reg: []const u8) u64 {
445 return asm ("mrs %[ret], " ++ feat_reg
446 : [ret] "=r" (-> u64),
447 );
448}
444const aarch64 = struct {
445 inline fn mrs(comptime feat_reg: []const u8) u64 {
446 return asm ("mrs %[ret], " ++ feat_reg
447 : [ret] "=r" (-> u64),
448 );
449 }
450};
449451
450452const riscv = struct {
451453 const linux = std.os.linux;
......@@ -596,18 +598,18 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
596598 return switch (current_arch) {
597599 .aarch64, .aarch64_be => b: {
598600 const registers = [12]u64{
599 getAArch64CpuFeature("MIDR_EL1"),
600 getAArch64CpuFeature("ID_AA64PFR0_EL1"),
601 getAArch64CpuFeature("ID_AA64PFR1_EL1"),
602 getAArch64CpuFeature("ID_AA64DFR0_EL1"),
603 getAArch64CpuFeature("ID_AA64DFR1_EL1"),
604 getAArch64CpuFeature("ID_AA64AFR0_EL1"),
605 getAArch64CpuFeature("ID_AA64AFR1_EL1"),
606 getAArch64CpuFeature("ID_AA64ISAR0_EL1"),
607 getAArch64CpuFeature("ID_AA64ISAR1_EL1"),
608 getAArch64CpuFeature("ID_AA64MMFR0_EL1"),
609 getAArch64CpuFeature("ID_AA64MMFR1_EL1"),
610 getAArch64CpuFeature("ID_AA64MMFR2_EL1"),
601 aarch64.mrs("MIDR_EL1"),
602 aarch64.mrs("ID_AA64PFR0_EL1"),
603 aarch64.mrs("ID_AA64PFR1_EL1"),
604 aarch64.mrs("ID_AA64DFR0_EL1"),
605 aarch64.mrs("ID_AA64DFR1_EL1"),
606 aarch64.mrs("ID_AA64AFR0_EL1"),
607 aarch64.mrs("ID_AA64AFR1_EL1"),
608 aarch64.mrs("ID_AA64ISAR0_EL1"),
609 aarch64.mrs("ID_AA64ISAR1_EL1"),
610 aarch64.mrs("ID_AA64MMFR0_EL1"),
611 aarch64.mrs("ID_AA64MMFR1_EL1"),
612 aarch64.mrs("ID_AA64MMFR2_EL1"),
611613 };
612614
613615 break :b @import("arm.zig").aarch64.detectNativeCpuAndFeatures(current_arch, registers);
lib/std/zig/system/netbsd.zig created+75
......@@ -0,0 +1,75 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const native_arch = builtin.target.cpu.arch;
5
6const aarch64 = struct {
7 const sysctl_cpu_id = extern struct {
8 midr: u64,
9 revidr: u64,
10 mpidr: u64,
11
12 aa64dfr0: u64,
13 aa64dfr1: u64,
14
15 aa64isar0: u64,
16 aa64isar1: u64,
17
18 aa64mmfr0: u64,
19 aa64mmfr1: u64,
20 aa64mmfr2: u64,
21
22 aa64pfr0: u64,
23 aa64pfr1: u64,
24
25 aa64zfr0: u64,
26
27 mvfr0: u32,
28 mvfr1: u32,
29 mvfr2: u32,
30 _pad: u32 = 0,
31
32 clidr: u64,
33 ctr: u64,
34 };
35};
36
37pub fn detectNativeCpuAndFeatures() ?std.Target.Cpu {
38 return switch (native_arch) {
39 .aarch64, .aarch64_be => b: {
40 var value: aarch64.sysctl_cpu_id = undefined;
41 var len: usize = @sizeOf(@TypeOf(value));
42 switch (std.posix.errno(std.c.sysctlbyname("machdep.cpu0.cpu_id", &value, &len, null, 0))) {
43 .SUCCESS => {},
44 .FAULT => unreachable,
45 .INVAL => unreachable,
46 .ISDIR => unreachable,
47 .NOENT => unreachable, // 👻
48 .NOMEM => {}, // `aarch64.sysctl_cpu_id` has grown upstream, harmless
49 .NOTDIR => unreachable,
50 .NOTEMPTY => unreachable,
51 .OPNOTSUPP => unreachable,
52 .PERM => unreachable,
53 else => return null,
54 }
55
56 const registers = [12]u64{
57 value.midr,
58 value.aa64pfr0,
59 value.aa64pfr1,
60 value.aa64dfr0,
61 value.aa64dfr1,
62 0, // ID_AA64AFR0_EL1
63 0, // ID_AA64AFR1_EL1
64 value.aa64isar0,
65 value.aa64isar1,
66 value.aa64mmfr0,
67 value.aa64mmfr1,
68 value.aa64mmfr2,
69 };
70
71 break :b @import("arm.zig").aarch64.detectNativeCpuAndFeatures(native_arch, registers);
72 },
73 else => null,
74 };
75}
lib/std/zig/system/openbsd.zig created+49
......@@ -0,0 +1,49 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const native_arch = builtin.target.cpu.arch;
5
6const aarch64 = struct {
7 fn sysctlReg(key: c_int) u64 {
8 const mib: [2]c_int = [_]c_int{
9 std.c.CTL.MACHDEP,
10 key,
11 };
12 var value: u64 = undefined;
13 var len: usize = @sizeOf(@TypeOf(value));
14
15 std.posix.sysctl(&mib, &value, &len, null, 0) catch |err| switch (err) {
16 error.NameTooLong => unreachable,
17 error.PermissionDenied => unreachable,
18 error.SystemResources => unreachable,
19 error.UnknownName => unreachable,
20 error.Unexpected => return 0,
21 };
22
23 return value;
24 }
25};
26
27pub fn detectNativeCpuAndFeatures() ?std.Target.Cpu {
28 return switch (native_arch) {
29 .aarch64, .aarch64_be => b: {
30 const registers = [12]u64{
31 0, // MIDR_EL1
32 aarch64.sysctlReg(std.c.CPU.AA64PFR0),
33 aarch64.sysctlReg(std.c.CPU.AA64PFR1),
34 0, // ID_AA64DFR0_EL1
35 0, // ID_AA64DFR1_EL1
36 0, // ID_AA64AFR0_EL1
37 0, // ID_AA64AFR1_EL1
38 aarch64.sysctlReg(std.c.CPU.ID_AA64ISAR0),
39 aarch64.sysctlReg(std.c.CPU.ID_AA64ISAR1),
40 aarch64.sysctlReg(std.c.CPU.ID_AA64MMFR0),
41 aarch64.sysctlReg(std.c.CPU.ID_AA64MMFR1),
42 aarch64.sysctlReg(std.c.CPU.ID_AA64MMFR2),
43 };
44
45 break :b @import("arm.zig").aarch64.detectNativeCpuAndFeatures(native_arch, registers);
46 },
47 else => null,
48 };
49}