authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-07 10:24:43+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-07 11:45:04+02:00
logde64c05f0baab5e9c0ec7c72d8ba13271dbc2a30
tree7d4a98ba52dcf354cb0bd6e86083f94e78c1278d
parenta098e693f0498cf87e9eac488ae715915de2fb3d
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

std.zig.system.linux: refactor

Also fix a couple minor edge case bugs.

1 files changed, 606 insertions(+), 520 deletions(-)

lib/std/zig/system/linux.zig+606-520
......@@ -9,456 +9,373 @@ const testing = std.testing;
99const Target = std.Target;
1010const assert = std.debug.assert;
1111
12const SparcCpuinfoImpl = struct {
13 model: ?*const Target.Cpu.Model = null,
14
15 const cpu_names = .{
16 .{ "BlackBird", &Target.sparc.cpu.ultrasparc },
17 .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 },
18 .{ "Hummingbird", &Target.sparc.cpu.ultrasparc },
19 .{ "HyperSparc", &Target.sparc.cpu.hypersparc },
20 .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 },
21 .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 },
22 .{ "LEON", &Target.sparc.cpu.leon3 },
23 .{ "MB86904", &Target.sparc.cpu.v8 },
24 .{ "MB86907", &Target.sparc.cpu.v8 },
25 .{ "MicroSparc II", &Target.sparc.cpu.v8 },
26 .{ "MicroSparc", &Target.sparc.cpu.v8 },
27 .{ "Panther", &Target.sparc.cpu.ultrasparc3 },
28 .{ "Sabre", &Target.sparc.cpu.ultrasparc },
29 .{ "Serrano", &Target.sparc.cpu.ultrasparc3 },
30 .{ "SPARC-M6", &Target.sparc.cpu.niagara4 },
31 .{ "SPARC-M7", &Target.sparc.cpu.niagara4 },
32 .{ "SPARC-M8", &Target.sparc.cpu.niagara4 },
33 .{ "SPARC-SN", &Target.sparc.cpu.niagara4 },
34 .{ "SPARC64-X", &Target.sparc.cpu.ultrasparc3 },
35 .{ "SpitFire", &Target.sparc.cpu.ultrasparc },
36 .{ "SuperSparc", &Target.sparc.cpu.supersparc },
37 .{ "UltraSparc T1", &Target.sparc.cpu.niagara },
38 .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 },
39 .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 },
40 .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 },
41 .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 },
42 };
43
44 fn line_hook(self: *SparcCpuinfoImpl, key: []const u8, value: []const u8) !bool {
45 if (mem.eql(u8, key, "cpu")) {
46 inline for (cpu_names) |pair| {
47 if (mem.findPos(u8, value, 0, pair[0]) != null) {
48 self.model = pair[1];
49 break;
50 }
12// The generic implementation of a /proc/cpuinfo parser.
13// For every line it invokes the lineHook method with the key and value strings
14// as first and second parameters. Returning false from the hook function stops
15// the iteration without raising an error.
16// When all the lines have been analyzed the finalize method is called.
17fn CpuinfoParser(comptime impl: anytype) type {
18 return struct {
19 fn parse(arch: Target.Cpu.Arch, reader: *Io.Reader) !?Target.Cpu {
20 var obj: impl = .{};
21 while (try reader.takeDelimiter('\n')) |line| {
22 const colon_pos = mem.findScalar(u8, line, ':') orelse continue;
23 const key = mem.trimEnd(u8, line[0..colon_pos], " \t");
24 const value = mem.trimStart(u8, line[colon_pos + 1 ..], " \t");
25 if (!try obj.lineHook(key, value)) break;
5126 }
27 return obj.finalize(arch);
5228 }
53
54 return true;
55 }
56
57 fn finalize(self: *const SparcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
58 const model = self.model orelse return null;
59 return Target.Cpu{
60 .arch = arch,
61 .model = model,
62 .features = model.features,
63 };
64 }
65};
66
67const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);
68
69test "cpuinfo: SPARC" {
70 try testParser(SparcCpuinfoParser, .sparc64, &Target.sparc.cpu.niagara2,
71 \\cpu : UltraSparc T2 (Niagara2)
72 \\fpu : UltraSparc T2 integrated FPU
73 \\pmu : niagara2
74 \\type : sun4v
75 );
76}
77
78const RiscvCpuinfoImpl = struct {
79 model: ?*const Target.Cpu.Model = null,
80
81 const cpu_names = .{
82 .{ "andestech,ax45mp", &Target.riscv.cpu.andes_ax45 },
83 .{ "sifive,bullet0", &Target.riscv.cpu.sifive_u74 },
84 .{ "sifive,p550", &Target.riscv.cpu.sifive_p550 },
85 .{ "sifive,u54", &Target.riscv.cpu.sifive_u54 },
86 .{ "sifive,u54-mc", &Target.riscv.cpu.sifive_u54 },
87 .{ "sifive,u7", &Target.riscv.cpu.sifive_u74 },
88 .{ "sifive,u74", &Target.riscv.cpu.sifive_u74 },
89 .{ "sifive,u74-mc", &Target.riscv.cpu.sifive_u74 },
90 .{ "sifive,x280", &Target.riscv.cpu.sifive_x280 },
91 .{ "spacemit,x60", &Target.riscv.cpu.spacemit_x60 },
92 .{ "spacemit,x100", &Target.riscv.cpu.spacemit_x100 },
9329 };
30}
9431
95 fn line_hook(self: *RiscvCpuinfoImpl, key: []const u8, value: []const u8) !bool {
96 if (mem.eql(u8, key, "uarch")) {
97 inline for (cpu_names) |pair| {
98 if (mem.eql(u8, value, pair[0])) {
99 self.model = pair[1];
100 break;
101 }
102 }
103 return false;
104 }
32fn testParser(
33 parser: anytype,
34 arch: Target.Cpu.Arch,
35 expected_model: *const Target.Cpu.Model,
36 input: []const u8,
37) !void {
38 var r: Io.Reader = .fixed(input);
39 const result = try parser.parse(arch, &r);
40 try testing.expectEqual(expected_model, result.?.model);
41 try testing.expect(expected_model.features.eql(result.?.features));
42}
10543
106 return true;
44const aarch64 = struct {
45 inline fn mrs(comptime feat_reg: []const u8) u64 {
46 return asm ("mrs %[ret], " ++ feat_reg
47 : [ret] "=r" (-> u64),
48 );
10749 }
10850
109 fn finalize(self: *const RiscvCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
110 const model = self.model orelse return null;
111 return Target.Cpu{
112 .arch = arch,
113 .model = model,
114 .features = model.features,
51 pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch) ?Target.Cpu {
52 const registers = [12]u64{
53 mrs("MIDR_EL1"),
54 mrs("ID_AA64PFR0_EL1"),
55 mrs("ID_AA64PFR1_EL1"),
56 mrs("ID_AA64DFR0_EL1"),
57 mrs("ID_AA64DFR1_EL1"),
58 mrs("ID_AA64AFR0_EL1"),
59 mrs("ID_AA64AFR1_EL1"),
60 mrs("ID_AA64ISAR0_EL1"),
61 mrs("ID_AA64ISAR1_EL1"),
62 mrs("ID_AA64MMFR0_EL1"),
63 mrs("ID_AA64MMFR1_EL1"),
64 mrs("ID_AA64MMFR2_EL1"),
11565 };
66
67 return @import("arm.zig").aarch64.detectNativeCpuAndFeatures(arch, registers);
11668 }
11769};
11870
119const RiscvCpuinfoParser = CpuinfoParser(RiscvCpuinfoImpl);
120
121test "cpuinfo: RISC-V" {
122 try testParser(RiscvCpuinfoParser, .riscv64, &Target.riscv.cpu.sifive_u74,
123 \\processor : 0
124 \\hart : 1
125 \\isa : rv64imafdc
126 \\mmu : sv39
127 \\isa-ext :
128 \\uarch : sifive,u74-mc
129 );
130}
131
132const PowerpcCpuinfoImpl = struct {
133 model: ?*const Target.Cpu.Model = null,
134
135 const cpu_names = .{
136 .{ "604e", &Target.powerpc.cpu.@"604e" },
137 .{ "604", &Target.powerpc.cpu.@"604" },
138 .{ "7400", &Target.powerpc.cpu.@"7400" },
139 .{ "7410", &Target.powerpc.cpu.@"7400" },
140 .{ "7447/7457", &Target.powerpc.cpu.@"7450" },
141 .{ "7447A", &Target.powerpc.cpu.@"7450" },
142 .{ "7455", &Target.powerpc.cpu.@"7450" },
143 .{ "POWER5", &Target.powerpc.cpu.g5 },
144 .{ "POWER6", &Target.powerpc.cpu.pwr6 },
145 .{ "POWER7", &Target.powerpc.cpu.pwr7 },
146 .{ "POWER8E", &Target.powerpc.cpu.pwr8 },
147 .{ "POWER8NVL", &Target.powerpc.cpu.pwr8 },
148 .{ "POWER8", &Target.powerpc.cpu.pwr8 },
149 .{ "POWER9", &Target.powerpc.cpu.pwr9 },
150 .{ "POWER10", &Target.powerpc.cpu.pwr10 },
151 .{ "Power11", &Target.powerpc.cpu.pwr11 },
152 .{ "PPC970FX", &Target.powerpc.cpu.@"970" },
153 .{ "PPC970MP", &Target.powerpc.cpu.@"970" },
154 };
71const arm = struct {
72 const cpuinfo = struct {
73 const Impl = struct {
74 const num_cores = 4;
75
76 cores: [num_cores]CoreInfo = undefined,
77 core_no: usize = 0,
78 have_fields: usize = 0,
79
80 const CoreInfo = struct {
81 architecture: u8 = 0,
82 implementer: u8 = 0,
83 variant: u8 = 0,
84 part: u16 = 0,
85 is_really_v6: bool = false,
86 };
15587
156 fn line_hook(self: *PowerpcCpuinfoImpl, key: []const u8, value: []const u8) !bool {
157 if (mem.eql(u8, key, "cpu")) {
158 // The model name is often followed by a comma or space and extra
159 // info.
160 inline for (cpu_names) |pair| {
161 const end_index = mem.findAny(u8, value, ", ") orelse value.len;
162 if (mem.eql(u8, value[0..end_index], pair[0])) {
163 self.model = pair[1];
164 break;
88 const cpu_models = @import("arm.zig").cpu_models;
89
90 fn addOne(self: *Impl) void {
91 if (self.have_fields == 4 and self.core_no < num_cores) {
92 if (self.core_no > 0) {
93 // Deduplicate the core info.
94 for (self.cores[0..self.core_no]) |it| {
95 if (std.meta.eql(it, self.cores[self.core_no]))
96 return;
97 }
98 }
99 self.core_no += 1;
165100 }
166101 }
167102
168 // Stop the detection once we've seen the first core.
169 return false;
170 }
171
172 return true;
173 }
103 fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool {
104 const info = &self.cores[self.core_no];
105
106 if (mem.eql(u8, key, "processor")) {
107 // Handle both old-style and new-style cpuinfo formats.
108 // The former prints a sequence of "processor: N" lines for each
109 // core and then the info for the core that's executing this code(!)
110 // while the latter prints the infos for each core right after the
111 // "processor" key.
112 self.have_fields = 0;
113 self.cores[self.core_no] = .{};
114 } else if (mem.eql(u8, key, "CPU implementer")) {
115 info.implementer = try fmt.parseInt(u8, value, 0);
116 self.have_fields += 1;
117 } else if (mem.eql(u8, key, "CPU architecture")) {
118 // "AArch64" on older kernels.
119 info.architecture = if (mem.startsWith(u8, value, "AArch64"))
120 8
121 else
122 try fmt.parseInt(u8, value, 0);
123 self.have_fields += 1;
124 } else if (mem.eql(u8, key, "CPU variant")) {
125 info.variant = try fmt.parseInt(u8, value, 0);
126 self.have_fields += 1;
127 } else if (mem.eql(u8, key, "CPU part")) {
128 info.part = try fmt.parseInt(u16, value, 0);
129 self.have_fields += 1;
130 } else if (mem.eql(u8, key, "model name")) {
131 // ARMv6 cores report "CPU architecture" equal to 7.
132 if (mem.find(u8, value, "(v6l)")) |_| {
133 info.is_really_v6 = true;
134 }
135 } else if (mem.eql(u8, key, "CPU revision")) {
136 // This field is always the last one for each CPU section.
137 _ = self.addOne();
138 }
174139
175 fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
176 const model = self.model orelse return null;
177 return Target.Cpu{
178 .arch = arch,
179 .model = model,
180 .features = model.features,
181 };
182 }
183};
140 return true;
141 }
184142
185const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl);
186
187test "cpuinfo: PowerPC" {
188 try testParser(PowerpcCpuinfoParser, .powerpc, &Target.powerpc.cpu.@"970",
189 \\processor : 0
190 \\cpu : PPC970MP, altivec supported
191 \\clock : 1250.000000MHz
192 \\revision : 1.1 (pvr 0044 0101)
193 );
194 try testParser(PowerpcCpuinfoParser, .powerpc64le, &Target.powerpc.cpu.pwr8,
195 \\processor : 0
196 \\cpu : POWER8 (raw), altivec supported
197 \\clock : 2926.000000MHz
198 \\revision : 2.0 (pvr 004d 0200)
199 );
200}
143 fn finalize(self: *Impl, arch: Target.Cpu.Arch) ?Target.Cpu {
144 if (self.core_no == 0) return null;
201145
202const S390xCpuinfoImpl = struct {
203 model: ?*const Target.Cpu.Model = null,
204
205 const cpu_names = .{
206 // z900: 2064, 2066
207 // z990: 2084, 2086
208 // z9: 2094, 2096
209
210 .{ "2097", &Target.s390x.cpu.z10 },
211 .{ "2098", &Target.s390x.cpu.z10 },
212 .{ "2817", &Target.s390x.cpu.z196 },
213 .{ "2818", &Target.s390x.cpu.z196 },
214 .{ "2827", &Target.s390x.cpu.zEC12 },
215 .{ "2828", &Target.s390x.cpu.zEC12 },
216 .{ "2964", &Target.s390x.cpu.z13 },
217 .{ "2965", &Target.s390x.cpu.z13 },
218 .{ "3906", &Target.s390x.cpu.z14 },
219 .{ "3907", &Target.s390x.cpu.z14 },
220 .{ "8561", &Target.s390x.cpu.z15 },
221 .{ "8562", &Target.s390x.cpu.z15 },
222 .{ "3931", &Target.s390x.cpu.z16 },
223 .{ "3932", &Target.s390x.cpu.z16 },
224 .{ "9175", &Target.s390x.cpu.z17 },
225 .{ "9176", &Target.s390x.cpu.z17 },
226 };
146 const is_64bit = switch (arch) {
147 .aarch64, .aarch64_be => true,
148 else => false,
149 };
227150
228 fn line_hook(self: *S390xCpuinfoImpl, key: []const u8, value: []const u8) !bool {
229 if (mem.eql(u8, key, "machine")) {
230 inline for (cpu_names) |pair| {
231 if (mem.eql(u8, value, pair[0])) {
232 self.model = pair[1];
233 break;
151 var known_models: [num_cores]?*const Target.Cpu.Model = undefined;
152 for (self.cores[0..self.core_no], 0..) |core, i| {
153 known_models[i] = cpu_models.isKnown(.{
154 .architecture = core.architecture,
155 .implementer = core.implementer,
156 .variant = core.variant,
157 .part = core.part,
158 }, is_64bit);
234159 }
160
161 // XXX We pick the first core on big.LITTLE systems, hopefully the
162 // LITTLE one.
163 const model = known_models[0] orelse return null;
164 return Target.Cpu{
165 .arch = arch,
166 .model = model,
167 .features = model.features,
168 };
235169 }
170 };
236171
237 return false;
238 }
172 const Parser = CpuinfoParser(Impl);
173 };
239174
240 return true;
175 test cpuinfo {
176 try testParser(cpuinfo.Parser, .arm, &Target.arm.cpu.arm1176jz_s,
177 \\processor : 0
178 \\model name : ARMv6-compatible processor rev 7 (v6l)
179 \\BogoMIPS : 997.08
180 \\Features : half thumb fastmult vfp edsp java tls
181 \\CPU implementer : 0x41
182 \\CPU architecture: 7
183 \\CPU variant : 0x0
184 \\CPU part : 0xb76
185 \\CPU revision : 7
186 );
187 try testParser(cpuinfo.Parser, .arm, &Target.arm.cpu.cortex_a7,
188 \\processor : 0
189 \\model name : ARMv7 Processor rev 3 (v7l)
190 \\BogoMIPS : 18.00
191 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
192 \\CPU implementer : 0x41
193 \\CPU architecture: 7
194 \\CPU variant : 0x0
195 \\CPU part : 0xc07
196 \\CPU revision : 3
197 \\
198 \\processor : 4
199 \\model name : ARMv7 Processor rev 3 (v7l)
200 \\BogoMIPS : 90.00
201 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
202 \\CPU implementer : 0x41
203 \\CPU architecture: 7
204 \\CPU variant : 0x2
205 \\CPU part : 0xc0f
206 \\CPU revision : 3
207 );
208 try testParser(cpuinfo.Parser, .aarch64, &Target.aarch64.cpu.cortex_a72,
209 \\processor : 0
210 \\BogoMIPS : 108.00
211 \\Features : fp asimd evtstrm crc32 cpuid
212 \\CPU implementer : 0x41
213 \\CPU architecture: 8
214 \\CPU variant : 0x0
215 \\CPU part : 0xd08
216 \\CPU revision : 3
217 );
241218 }
242219
243 fn finalize(self: *const S390xCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
244 const model = self.model orelse return null;
245 return Target.Cpu{
246 .arch = arch,
247 .model = model,
248 .features = model.features,
249 };
250 }
251};
220 pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu {
221 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null;
222 defer file.close(io);
252223
253const S390xCpuinfoParser = CpuinfoParser(S390xCpuinfoImpl);
254
255test "cpuinfo: S390x" {
256 try testParser(S390xCpuinfoParser, .s390x, &Target.s390x.cpu.z15,
257 \\physical id : 5
258 \\core id : 5
259 \\book id : 5
260 \\drawer id : 5
261 \\dedicated : 0
262 \\address : 5
263 \\siblings : 1
264 \\cpu cores : 1
265 \\version : FF
266 \\identification : 09DD98
267 \\machine : 8561
268 \\cpu MHz dynamic : 5200
269 \\cpu MHz static : 5200
270 );
271}
224 var buffer: [4096]u8 = undefined;
225 var file_reader = file.reader(io, &buffer);
272226
273const ArmCpuinfoImpl = struct {
274 const num_cores = 4;
227 var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null;
275228
276 cores: [num_cores]CoreInfo = undefined,
277 core_no: usize = 0,
278 have_fields: usize = 0,
229 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
279230
280 const CoreInfo = struct {
281 architecture: u8 = 0,
282 implementer: u8 = 0,
283 variant: u8 = 0,
284 part: u16 = 0,
285 is_really_v6: bool = false,
286 };
231 return cpu;
232 }
233};
287234
288 const cpu_models = @import("arm.zig").cpu_models;
235const powerpc = struct {
236 const cpuinfo = struct {
237 const Impl = struct {
238 model: ?*const Target.Cpu.Model = null,
239
240 const cpu_names = .{
241 .{ "604e", &Target.powerpc.cpu.@"604e" },
242 .{ "604", &Target.powerpc.cpu.@"604" },
243 .{ "7400", &Target.powerpc.cpu.@"7400" },
244 .{ "7410", &Target.powerpc.cpu.@"7400" },
245 .{ "7447/7457", &Target.powerpc.cpu.@"7450" },
246 .{ "7447A", &Target.powerpc.cpu.@"7450" },
247 .{ "7455", &Target.powerpc.cpu.@"7450" },
248 .{ "POWER5", &Target.powerpc.cpu.g5 },
249 .{ "POWER6", &Target.powerpc.cpu.pwr6 },
250 .{ "POWER7", &Target.powerpc.cpu.pwr7 },
251 .{ "POWER8E", &Target.powerpc.cpu.pwr8 },
252 .{ "POWER8NVL", &Target.powerpc.cpu.pwr8 },
253 .{ "POWER8", &Target.powerpc.cpu.pwr8 },
254 .{ "POWER9", &Target.powerpc.cpu.pwr9 },
255 .{ "POWER10", &Target.powerpc.cpu.pwr10 },
256 .{ "Power11", &Target.powerpc.cpu.pwr11 },
257 .{ "PPC970FX", &Target.powerpc.cpu.@"970" },
258 .{ "PPC970MP", &Target.powerpc.cpu.@"970" },
259 };
289260
290 fn addOne(self: *ArmCpuinfoImpl) void {
291 if (self.have_fields == 4 and self.core_no < num_cores) {
292 if (self.core_no > 0) {
293 // Deduplicate the core info.
294 for (self.cores[0..self.core_no]) |it| {
295 if (std.meta.eql(it, self.cores[self.core_no]))
296 return;
261 fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool {
262 if (mem.eql(u8, key, "cpu")) {
263 // The model name is often followed by a comma or space and extra
264 // info.
265 inline for (cpu_names) |pair| {
266 const end_index = mem.findAny(u8, value, ", ") orelse value.len;
267 if (mem.eql(u8, value[0..end_index], pair[0])) {
268 self.model = pair[1];
269 break;
270 }
271 }
272
273 // Stop the detection once we've seen the first core.
274 return false;
297275 }
276
277 return true;
298278 }
299 self.core_no += 1;
300 }
301 }
302279
303 fn line_hook(self: *ArmCpuinfoImpl, key: []const u8, value: []const u8) !bool {
304 const info = &self.cores[self.core_no];
305
306 if (mem.eql(u8, key, "processor")) {
307 // Handle both old-style and new-style cpuinfo formats.
308 // The former prints a sequence of "processor: N" lines for each
309 // core and then the info for the core that's executing this code(!)
310 // while the latter prints the infos for each core right after the
311 // "processor" key.
312 self.have_fields = 0;
313 self.cores[self.core_no] = .{};
314 } else if (mem.eql(u8, key, "CPU implementer")) {
315 info.implementer = try fmt.parseInt(u8, value, 0);
316 self.have_fields += 1;
317 } else if (mem.eql(u8, key, "CPU architecture")) {
318 // "AArch64" on older kernels.
319 info.architecture = if (mem.startsWith(u8, value, "AArch64"))
320 8
321 else
322 try fmt.parseInt(u8, value, 0);
323 self.have_fields += 1;
324 } else if (mem.eql(u8, key, "CPU variant")) {
325 info.variant = try fmt.parseInt(u8, value, 0);
326 self.have_fields += 1;
327 } else if (mem.eql(u8, key, "CPU part")) {
328 info.part = try fmt.parseInt(u16, value, 0);
329 self.have_fields += 1;
330 } else if (mem.eql(u8, key, "model name")) {
331 // ARMv6 cores report "CPU architecture" equal to 7.
332 if (mem.find(u8, value, "(v6l)")) |_| {
333 info.is_really_v6 = true;
280 fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu {
281 const model = self.model orelse return null;
282 return Target.Cpu{
283 .arch = arch,
284 .model = model,
285 .features = model.features,
286 };
334287 }
335 } else if (mem.eql(u8, key, "CPU revision")) {
336 // This field is always the last one for each CPU section.
337 _ = self.addOne();
338 }
288 };
339289
340 return true;
290 const Parser = CpuinfoParser(Impl);
291 };
292
293 test cpuinfo {
294 try testParser(cpuinfo.Parser, .powerpc, &Target.powerpc.cpu.@"970",
295 \\processor : 0
296 \\cpu : PPC970MP, altivec supported
297 \\clock : 1250.000000MHz
298 \\revision : 1.1 (pvr 0044 0101)
299 );
300 try testParser(cpuinfo.Parser, .powerpc64le, &Target.powerpc.cpu.pwr8,
301 \\processor : 0
302 \\cpu : POWER8 (raw), altivec supported
303 \\clock : 2926.000000MHz
304 \\revision : 2.0 (pvr 004d 0200)
305 );
341306 }
342307
343 fn finalize(self: *ArmCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
344 if (self.core_no == 0) return null;
308 pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu {
309 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null;
310 defer file.close(io);
345311
346 const is_64bit = switch (arch) {
347 .aarch64, .aarch64_be => true,
348 else => false,
349 };
312 var buffer: [4096]u8 = undefined;
313 var file_reader = file.reader(io, &buffer);
350314
351 var known_models: [num_cores]?*const Target.Cpu.Model = undefined;
352 for (self.cores[0..self.core_no], 0..) |core, i| {
353 known_models[i] = cpu_models.isKnown(.{
354 .architecture = core.architecture,
355 .implementer = core.implementer,
356 .variant = core.variant,
357 .part = core.part,
358 }, is_64bit);
359 }
315 var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null;
360316
361 // XXX We pick the first core on big.LITTLE systems, hopefully the
362 // LITTLE one.
363 const model = known_models[0] orelse return null;
364 return Target.Cpu{
365 .arch = arch,
366 .model = model,
367 .features = model.features,
368 };
317 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
318
319 return cpu;
369320 }
370321};
371322
372const ArmCpuinfoParser = CpuinfoParser(ArmCpuinfoImpl);
373
374test "cpuinfo: ARM" {
375 try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.arm1176jz_s,
376 \\processor : 0
377 \\model name : ARMv6-compatible processor rev 7 (v6l)
378 \\BogoMIPS : 997.08
379 \\Features : half thumb fastmult vfp edsp java tls
380 \\CPU implementer : 0x41
381 \\CPU architecture: 7
382 \\CPU variant : 0x0
383 \\CPU part : 0xb76
384 \\CPU revision : 7
385 );
386 try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.cortex_a7,
387 \\processor : 0
388 \\model name : ARMv7 Processor rev 3 (v7l)
389 \\BogoMIPS : 18.00
390 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
391 \\CPU implementer : 0x41
392 \\CPU architecture: 7
393 \\CPU variant : 0x0
394 \\CPU part : 0xc07
395 \\CPU revision : 3
396 \\
397 \\processor : 4
398 \\model name : ARMv7 Processor rev 3 (v7l)
399 \\BogoMIPS : 90.00
400 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
401 \\CPU implementer : 0x41
402 \\CPU architecture: 7
403 \\CPU variant : 0x2
404 \\CPU part : 0xc0f
405 \\CPU revision : 3
406 );
407 try testParser(ArmCpuinfoParser, .aarch64, &Target.aarch64.cpu.cortex_a72,
408 \\processor : 0
409 \\BogoMIPS : 108.00
410 \\Features : fp asimd evtstrm crc32 cpuid
411 \\CPU implementer : 0x41
412 \\CPU architecture: 8
413 \\CPU variant : 0x0
414 \\CPU part : 0xd08
415 \\CPU revision : 3
416 );
417}
323const riscv = struct {
324 const cpuinfo = struct {
325 const Impl = struct {
326 model: ?*const Target.Cpu.Model = null,
327
328 const cpu_names = .{
329 .{ "andestech,ax45mp", &Target.riscv.cpu.andes_ax45 },
330 .{ "sifive,bullet0", &Target.riscv.cpu.sifive_u74 },
331 .{ "sifive,p550", &Target.riscv.cpu.sifive_p550 },
332 .{ "sifive,u54", &Target.riscv.cpu.sifive_u54 },
333 .{ "sifive,u54-mc", &Target.riscv.cpu.sifive_u54 },
334 .{ "sifive,u7", &Target.riscv.cpu.sifive_u74 },
335 .{ "sifive,u74", &Target.riscv.cpu.sifive_u74 },
336 .{ "sifive,u74-mc", &Target.riscv.cpu.sifive_u74 },
337 .{ "sifive,x280", &Target.riscv.cpu.sifive_x280 },
338 .{ "spacemit,x60", &Target.riscv.cpu.spacemit_x60 },
339 .{ "spacemit,x100", &Target.riscv.cpu.spacemit_x100 },
340 };
418341
419fn testParser(
420 parser: anytype,
421 arch: Target.Cpu.Arch,
422 expected_model: *const Target.Cpu.Model,
423 input: []const u8,
424) !void {
425 var r: Io.Reader = .fixed(input);
426 const result = try parser.parse(arch, &r);
427 try testing.expectEqual(expected_model, result.?.model);
428 try testing.expect(expected_model.features.eql(result.?.features));
429}
342 fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool {
343 if (mem.eql(u8, key, "uarch")) {
344 inline for (cpu_names) |pair| {
345 if (mem.eql(u8, value, pair[0])) {
346 self.model = pair[1];
347 break;
348 }
349 }
350 return false;
351 }
430352
431// The generic implementation of a /proc/cpuinfo parser.
432// For every line it invokes the line_hook method with the key and value strings
433// as first and second parameters. Returning false from the hook function stops
434// the iteration without raising an error.
435// When all the lines have been analyzed the finalize method is called.
436fn CpuinfoParser(comptime impl: anytype) type {
437 return struct {
438 fn parse(arch: Target.Cpu.Arch, reader: *Io.Reader) !?Target.Cpu {
439 var obj: impl = .{};
440 while (try reader.takeDelimiter('\n')) |line| {
441 const colon_pos = mem.findScalar(u8, line, ':') orelse continue;
442 const key = mem.trimEnd(u8, line[0..colon_pos], " \t");
443 const value = mem.trimStart(u8, line[colon_pos + 1 ..], " \t");
444 if (!try obj.line_hook(key, value)) break;
353 return true;
445354 }
446 return obj.finalize(arch);
447 }
355
356 fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu {
357 const model = self.model orelse return null;
358 return Target.Cpu{
359 .arch = arch,
360 .model = model,
361 .features = model.features,
362 };
363 }
364 };
365
366 const Parser = CpuinfoParser(Impl);
448367 };
449}
450368
451const aarch64 = struct {
452 inline fn mrs(comptime feat_reg: []const u8) u64 {
453 return asm ("mrs %[ret], " ++ feat_reg
454 : [ret] "=r" (-> u64),
369 test cpuinfo {
370 try testParser(cpuinfo.Parser, .riscv64, &Target.riscv.cpu.sifive_u74,
371 \\processor : 0
372 \\hart : 1
373 \\isa : rv64imafdc
374 \\mmu : sv39
375 \\isa-ext :
376 \\uarch : sifive,u74-mc
455377 );
456378 }
457};
458
459const riscv = struct {
460 const linux = std.os.linux;
461 const RISCV_HWPROBE = linux.RISCV_HWPROBE;
462379
463380 fn setFeature(cpu: *Target.Cpu, feature: Target.riscv.Feature, enabled: bool) void {
464381 const idx = @as(Target.Cpu.Feature.Set.Index, @backingInt(feature));
......@@ -470,8 +387,18 @@ const riscv = struct {
470387 return (value & mask) == mask;
471388 }
472389
473 pub fn detectCpuFeatures(cpu: *Target.Cpu) void {
474 var probes = [_]linux.riscv_hwprobe{
390 pub fn detectNativeCpuAndFeatures(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu {
391 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null;
392 defer file.close(io);
393
394 var buffer: [4096]u8 = undefined;
395 var file_reader = file.reader(io, &buffer);
396
397 const maybe_cpu = cpuinfo.Parser.parse(arch, &file_reader.interface) catch null;
398
399 const RISCV_HWPROBE = std.os.linux.RISCV_HWPROBE;
400
401 var probes = [_]std.os.linux.riscv_hwprobe{
475402 .{ .key = RISCV_HWPROBE.KEY.BASE_BEHAVIOR, .value = 0 },
476403 .{ .key = RISCV_HWPROBE.KEY.IMA_EXT_0, .value = 0 },
477404 .{ .key = RISCV_HWPROBE.KEY.MISALIGNED_SCALAR_PERF, .value = 0 },
......@@ -481,9 +408,25 @@ const riscv = struct {
481408 .{ .key = RISCV_HWPROBE.KEY.IMA_EXT_1, .value = 0 },
482409 };
483410
484 const rc = linux.sys_riscv_hwprobe(&probes, probes.len, 0, null, 0);
485 if (linux.errno(rc) == .NOSYS)
486 return;
411 const rc = std.os.linux.sys_riscv_hwprobe(&probes, probes.len, 0, null, 0);
412 if (std.os.linux.errno(rc) == .NOSYS) {
413 // Even if SYS_riscv_hwprobe is unavailable, we should still return
414 // the model if we managed to detect it.
415 var cpu = maybe_cpu orelse return null;
416
417 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
418
419 return cpu;
420 }
421
422 var cpu: Target.Cpu = maybe_cpu orelse cpu: {
423 const model = Target.Cpu.Model.generic(arch);
424 break :cpu .{
425 .arch = arch,
426 .model = model,
427 .features = model.features,
428 };
429 };
487430
488431 var ima_support = false;
489432 for (probes) |probe| {
......@@ -493,153 +436,296 @@ const riscv = struct {
493436 -1 => continue, // The running kernel doesn't know this key.
494437 RISCV_HWPROBE.KEY.BASE_BEHAVIOR => {
495438 ima_support = set(value, RISCV_HWPROBE.BASE_BEHAVIOR_IMA);
496 setFeature(cpu, Target.riscv.Feature.i, ima_support);
497 setFeature(cpu, Target.riscv.Feature.m, ima_support);
498 setFeature(cpu, Target.riscv.Feature.a, ima_support);
439 setFeature(&cpu, Target.riscv.Feature.i, ima_support);
440 setFeature(&cpu, Target.riscv.Feature.m, ima_support);
441 setFeature(&cpu, Target.riscv.Feature.a, ima_support);
499442 },
500443 RISCV_HWPROBE.KEY.IMA_EXT_0 => {
501444 // https://bugzilla.kernel.org/show_bug.cgi?id=221874
502445 const fd_support = set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_FD);
503 setFeature(cpu, .f, ima_support and fd_support);
504 setFeature(cpu, .d, ima_support and fd_support);
505 setFeature(cpu, .c, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_C));
506 setFeature(cpu, .v, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_V));
507 setFeature(cpu, .zba, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBA));
508 setFeature(cpu, .zbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBB));
509 setFeature(cpu, .zbs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBS));
510 setFeature(cpu, .zicboz, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOZ));
511 setFeature(cpu, .zbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBC));
512 setFeature(cpu, .zbkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKB));
513 setFeature(cpu, .zbkc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKC));
514 setFeature(cpu, .zbkx, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKX));
515 setFeature(cpu, .zknd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKND));
516 setFeature(cpu, .zkne, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNE));
517 setFeature(cpu, .zknh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNH));
518 setFeature(cpu, .zksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSED));
519 setFeature(cpu, .zksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSH));
520 setFeature(cpu, .zkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKT));
521 setFeature(cpu, .zvbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBB));
522 setFeature(cpu, .zvbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBC));
523 setFeature(cpu, .zvkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKB));
524 setFeature(cpu, .zvkg, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKG));
525 setFeature(cpu, .zvkned, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNED));
526 setFeature(cpu, .zvknha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHA));
527 setFeature(cpu, .zvknhb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHB));
528 setFeature(cpu, .zvksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSED));
529 setFeature(cpu, .zvksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSH));
530 setFeature(cpu, .zvkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKT));
531 setFeature(cpu, .zfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFH));
532 setFeature(cpu, .zfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFHMIN));
533 setFeature(cpu, .zihintntl, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTNTL));
534 setFeature(cpu, .zvfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFH));
535 setFeature(cpu, .zvfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFHMIN));
536 setFeature(cpu, .zfa, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFA));
537 setFeature(cpu, .ztso, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZTSO));
538 setFeature(cpu, .zacas, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZACAS));
539 setFeature(cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR));
540 setFeature(cpu, .zicond, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICOND));
541 setFeature(cpu, .zihintpause, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTPAUSE));
542 setFeature(cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM));
543 setFeature(cpu, .zve32x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32X));
544 setFeature(cpu, .zve32f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32F));
545 setFeature(cpu, .zve64x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64X));
546 setFeature(cpu, .zve64f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64F));
547 setFeature(cpu, .zve64d, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64D));
548 setFeature(cpu, .zimop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIMOP));
549 setFeature(cpu, .zca, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCA));
550 setFeature(cpu, .zcb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCB));
551 setFeature(cpu, .zcd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCD));
552 setFeature(cpu, .zcf, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCF));
553 setFeature(cpu, .zcmop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCMOP));
554 setFeature(cpu, .zawrs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAWRS));
555 setFeature(cpu, .supm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_SUPM));
556 setFeature(cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR));
557 setFeature(cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM));
558 setFeature(cpu, .zfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFBFMIN));
559 setFeature(cpu, .zvfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFMIN));
560 setFeature(cpu, .zvfbfwma, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFWMA));
561 setFeature(cpu, .zicbom, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOM));
562 setFeature(cpu, .zaamo, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAAMO));
563 setFeature(cpu, .zalrsc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALRSC));
564 setFeature(cpu, .zabha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZABHA));
565 setFeature(cpu, .zalasr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALASR));
566 setFeature(cpu, .zicbop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOP));
567 setFeature(cpu, .zilsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZILSD));
568 setFeature(cpu, .zclsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCLSD));
569 setFeature(cpu, .experimental_zicfilp, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICFILP));
446 setFeature(&cpu, .f, ima_support and fd_support);
447 setFeature(&cpu, .d, ima_support and fd_support);
448 setFeature(&cpu, .c, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_C));
449 setFeature(&cpu, .v, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_V));
450 setFeature(&cpu, .zba, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBA));
451 setFeature(&cpu, .zbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBB));
452 setFeature(&cpu, .zbs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBS));
453 setFeature(&cpu, .zicboz, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOZ));
454 setFeature(&cpu, .zbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBC));
455 setFeature(&cpu, .zbkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKB));
456 setFeature(&cpu, .zbkc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKC));
457 setFeature(&cpu, .zbkx, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKX));
458 setFeature(&cpu, .zknd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKND));
459 setFeature(&cpu, .zkne, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNE));
460 setFeature(&cpu, .zknh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNH));
461 setFeature(&cpu, .zksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSED));
462 setFeature(&cpu, .zksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSH));
463 setFeature(&cpu, .zkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKT));
464 setFeature(&cpu, .zvbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBB));
465 setFeature(&cpu, .zvbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBC));
466 setFeature(&cpu, .zvkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKB));
467 setFeature(&cpu, .zvkg, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKG));
468 setFeature(&cpu, .zvkned, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNED));
469 setFeature(&cpu, .zvknha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHA));
470 setFeature(&cpu, .zvknhb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHB));
471 setFeature(&cpu, .zvksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSED));
472 setFeature(&cpu, .zvksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSH));
473 setFeature(&cpu, .zvkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKT));
474 setFeature(&cpu, .zfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFH));
475 setFeature(&cpu, .zfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFHMIN));
476 setFeature(&cpu, .zihintntl, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTNTL));
477 setFeature(&cpu, .zvfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFH));
478 setFeature(&cpu, .zvfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFHMIN));
479 setFeature(&cpu, .zfa, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFA));
480 setFeature(&cpu, .ztso, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZTSO));
481 setFeature(&cpu, .zacas, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZACAS));
482 setFeature(&cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR));
483 setFeature(&cpu, .zicond, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICOND));
484 setFeature(&cpu, .zihintpause, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTPAUSE));
485 setFeature(&cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM));
486 setFeature(&cpu, .zve32x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32X));
487 setFeature(&cpu, .zve32f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32F));
488 setFeature(&cpu, .zve64x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64X));
489 setFeature(&cpu, .zve64f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64F));
490 setFeature(&cpu, .zve64d, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64D));
491 setFeature(&cpu, .zimop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIMOP));
492 setFeature(&cpu, .zca, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCA));
493 setFeature(&cpu, .zcb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCB));
494 setFeature(&cpu, .zcd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCD));
495 setFeature(&cpu, .zcf, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCF));
496 setFeature(&cpu, .zcmop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCMOP));
497 setFeature(&cpu, .zawrs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAWRS));
498 setFeature(&cpu, .supm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_SUPM));
499 setFeature(&cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR));
500 setFeature(&cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM));
501 setFeature(&cpu, .zfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFBFMIN));
502 setFeature(&cpu, .zvfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFMIN));
503 setFeature(&cpu, .zvfbfwma, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFWMA));
504 setFeature(&cpu, .zicbom, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOM));
505 setFeature(&cpu, .zaamo, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAAMO));
506 setFeature(&cpu, .zalrsc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALRSC));
507 setFeature(&cpu, .zabha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZABHA));
508 setFeature(&cpu, .zalasr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALASR));
509 setFeature(&cpu, .zicbop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOP));
510 setFeature(&cpu, .zilsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZILSD));
511 setFeature(&cpu, .zclsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCLSD));
512 setFeature(&cpu, .experimental_zicfilp, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICFILP));
570513 },
571514 RISCV_HWPROBE.KEY.MISALIGNED_SCALAR_PERF => {
572 setFeature(cpu, .unaligned_scalar_mem, value == RISCV_HWPROBE.MISALIGNED_SCALAR.FAST);
515 setFeature(&cpu, .unaligned_scalar_mem, value == RISCV_HWPROBE.MISALIGNED_SCALAR.FAST);
573516 },
574517 RISCV_HWPROBE.KEY.MISALIGNED_VECTOR_PERF => {
575 setFeature(cpu, .unaligned_vector_mem, value == RISCV_HWPROBE.MISALIGNED_VECTOR.FAST);
518 setFeature(&cpu, .unaligned_vector_mem, value == RISCV_HWPROBE.MISALIGNED_VECTOR.FAST);
576519 },
577520 RISCV_HWPROBE.KEY.VENDOR_EXT_MIPS_0 => {
578 setFeature(cpu, .xmipsexectl, ima_support and set(value, RISCV_HWPROBE.MIPS_VENDOR_EXT_XMIPSEXECTL));
521 setFeature(&cpu, .xmipsexectl, ima_support and set(value, RISCV_HWPROBE.MIPS_VENDOR_EXT_XMIPSEXECTL));
579522 },
580523 RISCV_HWPROBE.KEY.VENDOR_EXT_SIFIVE_0 => {
581 setFeature(cpu, .xsfvqmaccdod, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCDOD));
582 setFeature(cpu, .xsfvqmaccqoq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCQOQ));
583 setFeature(cpu, .xsfvfnrclipxfqf, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFNRCLIPXFQF));
584 setFeature(cpu, .xsfvfwmaccqqq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFWMACCQQQ));
524 setFeature(&cpu, .xsfvqmaccdod, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCDOD));
525 setFeature(&cpu, .xsfvqmaccqoq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCQOQ));
526 setFeature(&cpu, .xsfvfnrclipxfqf, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFNRCLIPXFQF));
527 setFeature(&cpu, .xsfvfwmaccqqq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFWMACCQQQ));
585528 },
586529 RISCV_HWPROBE.KEY.IMA_EXT_1 => {
587 setFeature(cpu, .experimental_zicfiss, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_1_EXT_ZICFISS));
530 setFeature(&cpu, .experimental_zicfiss, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_1_EXT_ZICFISS));
588531 },
589532 else => unreachable,
590533 }
591534 }
535
536 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
537
538 return cpu;
592539 }
593540};
594541
595pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
596 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch |err| switch (err) {
597 else => return null,
542const s390x = struct {
543 const cpuinfo = struct {
544 const Impl = struct {
545 model: ?*const Target.Cpu.Model = null,
546
547 const cpu_names = .{
548 .{ "2097", &Target.s390x.cpu.z10 },
549 .{ "2098", &Target.s390x.cpu.z10 },
550 .{ "2817", &Target.s390x.cpu.z196 },
551 .{ "2818", &Target.s390x.cpu.z196 },
552 .{ "2827", &Target.s390x.cpu.zEC12 },
553 .{ "2828", &Target.s390x.cpu.zEC12 },
554 .{ "2964", &Target.s390x.cpu.z13 },
555 .{ "2965", &Target.s390x.cpu.z13 },
556 .{ "3906", &Target.s390x.cpu.z14 },
557 .{ "3907", &Target.s390x.cpu.z14 },
558 .{ "8561", &Target.s390x.cpu.z15 },
559 .{ "8562", &Target.s390x.cpu.z15 },
560 .{ "3931", &Target.s390x.cpu.z16 },
561 .{ "3932", &Target.s390x.cpu.z16 },
562 .{ "9175", &Target.s390x.cpu.z17 },
563 .{ "9176", &Target.s390x.cpu.z17 },
564 };
565
566 fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool {
567 if (mem.eql(u8, key, "machine")) {
568 inline for (cpu_names) |pair| {
569 if (mem.eql(u8, value, pair[0])) {
570 self.model = pair[1];
571 break;
572 }
573 }
574
575 return false;
576 }
577
578 return true;
579 }
580
581 fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu {
582 const model = self.model orelse return null;
583 return Target.Cpu{
584 .arch = arch,
585 .model = model,
586 .features = model.features,
587 };
588 }
589 };
590
591 const Parser = CpuinfoParser(Impl);
598592 };
599 defer file.close(io);
600593
601 var buffer: [4096]u8 = undefined; // "flags" lines can get pretty long.
602 var file_reader = file.reader(io, &buffer);
594 test cpuinfo {
595 try testParser(cpuinfo.Parser, .s390x, &Target.s390x.cpu.z15,
596 \\physical id : 5
597 \\core id : 5
598 \\book id : 5
599 \\drawer id : 5
600 \\dedicated : 0
601 \\address : 5
602 \\siblings : 1
603 \\cpu cores : 1
604 \\version : FF
605 \\identification : 09DD98
606 \\machine : 8561
607 \\cpu MHz dynamic : 5200
608 \\cpu MHz static : 5200
609 );
610 }
603611
604 const current_arch = builtin.cpu.arch;
605 return switch (current_arch) {
606 .aarch64, .aarch64_be => b: {
607 const registers = [12]u64{
608 aarch64.mrs("MIDR_EL1"),
609 aarch64.mrs("ID_AA64PFR0_EL1"),
610 aarch64.mrs("ID_AA64PFR1_EL1"),
611 aarch64.mrs("ID_AA64DFR0_EL1"),
612 aarch64.mrs("ID_AA64DFR1_EL1"),
613 aarch64.mrs("ID_AA64AFR0_EL1"),
614 aarch64.mrs("ID_AA64AFR1_EL1"),
615 aarch64.mrs("ID_AA64ISAR0_EL1"),
616 aarch64.mrs("ID_AA64ISAR1_EL1"),
617 aarch64.mrs("ID_AA64MMFR0_EL1"),
618 aarch64.mrs("ID_AA64MMFR1_EL1"),
619 aarch64.mrs("ID_AA64MMFR2_EL1"),
612 pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu {
613 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null;
614 defer file.close(io);
615
616 var buffer: [4096]u8 = undefined;
617 var file_reader = file.reader(io, &buffer);
618
619 var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null;
620
621 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
622
623 return cpu;
624 }
625};
626
627const sparc = struct {
628 const cpuinfo = struct {
629 const Impl = struct {
630 model: ?*const Target.Cpu.Model = null,
631
632 const cpu_names = .{
633 .{ "BlackBird", &Target.sparc.cpu.ultrasparc },
634 .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 },
635 .{ "Hummingbird", &Target.sparc.cpu.ultrasparc },
636 .{ "HyperSparc", &Target.sparc.cpu.hypersparc },
637 .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 },
638 .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 },
639 .{ "LEON", &Target.sparc.cpu.leon3 },
640 .{ "MB86904", &Target.sparc.cpu.v8 },
641 .{ "MB86907", &Target.sparc.cpu.v8 },
642 .{ "MicroSparc II", &Target.sparc.cpu.v8 },
643 .{ "MicroSparc", &Target.sparc.cpu.v8 },
644 .{ "Panther", &Target.sparc.cpu.ultrasparc3 },
645 .{ "Sabre", &Target.sparc.cpu.ultrasparc },
646 .{ "Serrano", &Target.sparc.cpu.ultrasparc3 },
647 .{ "SPARC-M6", &Target.sparc.cpu.niagara4 },
648 .{ "SPARC-M7", &Target.sparc.cpu.niagara4 },
649 .{ "SPARC-M8", &Target.sparc.cpu.niagara4 },
650 .{ "SPARC-SN", &Target.sparc.cpu.niagara4 },
651 .{ "SPARC64-X", &Target.sparc.cpu.ultrasparc3 },
652 .{ "SpitFire", &Target.sparc.cpu.ultrasparc },
653 .{ "SuperSparc", &Target.sparc.cpu.supersparc },
654 .{ "UltraSparc T1", &Target.sparc.cpu.niagara },
655 .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 },
656 .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 },
657 .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 },
658 .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 },
620659 };
621660
622 break :b @import("arm.zig").aarch64.detectNativeCpuAndFeatures(current_arch, registers);
623 },
624 .arm, .armeb, .thumb, .thumbeb => ArmCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
625 .powerpc, .powerpcle, .powerpc64, .powerpc64le => PowerpcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
626 .riscv64, .riscv32 => b: {
627 var cpu = (RiscvCpuinfoParser.parse(current_arch, &file_reader.interface) catch null) orelse cpu: {
628 const model = Target.Cpu.Model.generic(current_arch);
629 break :cpu Target.Cpu{
630 .arch = current_arch,
661 fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool {
662 if (mem.eql(u8, key, "cpu")) {
663 inline for (cpu_names) |pair| {
664 if (mem.findPos(u8, value, 0, pair[0]) != null) {
665 self.model = pair[1];
666 break;
667 }
668 }
669 }
670
671 return true;
672 }
673
674 fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu {
675 const model = self.model orelse return null;
676 return Target.Cpu{
677 .arch = arch,
631678 .model = model,
632679 .features = model.features,
633680 };
634 };
681 }
682 };
635683
636 riscv.detectCpuFeatures(&cpu);
637 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
684 const Parser = CpuinfoParser(Impl);
685 };
686
687 test cpuinfo {
688 try testParser(cpuinfo.Parser, .sparc64, &Target.sparc.cpu.niagara2,
689 \\cpu : UltraSparc T2 (Niagara2)
690 \\fpu : UltraSparc T2 integrated FPU
691 \\pmu : niagara2
692 \\type : sun4v
693 );
694 }
638695
639 break :b cpu;
640 },
641 .s390x => S390xCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
642 .sparc, .sparc64 => SparcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
696 pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu {
697 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null;
698 defer file.close(io);
699
700 var buffer: [4096]u8 = undefined;
701 var file_reader = file.reader(io, &buffer);
702
703 var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null;
704
705 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
706
707 return cpu;
708 }
709};
710
711pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
712 const current_arch = builtin.cpu.arch;
713 return switch (current_arch) {
714 .aarch64, .aarch64_be => aarch64.detectNativeCpuAndFeatures(current_arch),
715 .arm, .armeb, .thumb, .thumbeb => arm.detectNativeCpu(io, current_arch),
716 .powerpc, .powerpcle, .powerpc64, .powerpc64le => powerpc.detectNativeCpu(io, current_arch),
717 .riscv64, .riscv32 => riscv.detectNativeCpuAndFeatures(io, current_arch),
718 .s390x => s390x.detectNativeCpu(io, current_arch),
719 .sparc, .sparc64 => sparc.detectNativeCpu(io, current_arch),
643720 else => null,
644721 };
645722}
723
724test {
725 _ = aarch64;
726 _ = arm;
727 _ = powerpc;
728 _ = riscv;
729 _ = s390x;
730 _ = sparc;
731}