authorgravatar for rqm@uvxi.orgVitor Fernandes <rqm@uvxi.org> 2026-07-09 08:32:59+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-29 19:52:26+02:00
loga1e5c0d25a8b4009b225b57c8469866631b0eb01
treea1d1b2116ac51ddad2e1f6b74354f994c7a4b7a1
parent321faf4e167e9de2588ba61bbd1f4ef3632b6c62
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

std.zig.system.linux: implement CPU feature detection using SYS_riscv_hwprobe


1 files changed, 159 insertions(+), 22 deletions(-)

lib/std/zig/system/linux.zig+159-22
...@@ -447,6 +447,142 @@ inline fn getAArch64CpuFeature(comptime feat_reg: []const u8) u64 {...@@ -447,6 +447,142 @@ inline fn getAArch64CpuFeature(comptime feat_reg: []const u8) u64 {
447 );447 );
448}448}
449449
450const riscv = struct {
451 const linux = std.os.linux;
452 const RISCV_HWPROBE = linux.RISCV_HWPROBE;
453
454 fn setFeature(cpu: *Target.Cpu, feature: Target.riscv.Feature, enabled: bool) void {
455 const idx = @as(Target.Cpu.Feature.Set.Index, @backingInt(feature));
456
457 if (enabled) cpu.features.addFeature(idx) else cpu.features.removeFeature(idx);
458 }
459
460 inline fn set(value: u64, mask: u64) bool {
461 return (value & mask) == mask;
462 }
463
464 pub fn detectCpuFeatures(cpu: *Target.Cpu) void {
465 var probes = [_]linux.riscv_hwprobe{
466 .{ .key = RISCV_HWPROBE.KEY.BASE_BEHAVIOR, .value = 0 },
467 .{ .key = RISCV_HWPROBE.KEY.IMA_EXT_0, .value = 0 },
468 .{ .key = RISCV_HWPROBE.KEY.MISALIGNED_SCALAR_PERF, .value = 0 },
469 .{ .key = RISCV_HWPROBE.KEY.MISALIGNED_VECTOR_PERF, .value = 0 },
470 .{ .key = RISCV_HWPROBE.KEY.VENDOR_EXT_MIPS_0, .value = 0 },
471 .{ .key = RISCV_HWPROBE.KEY.VENDOR_EXT_SIFIVE_0, .value = 0 },
472 .{ .key = RISCV_HWPROBE.KEY.IMA_EXT_1, .value = 0 },
473 };
474
475 const rc = linux.sys_riscv_hwprobe(&probes, probes.len, 0, null, 0);
476 if (linux.errno(rc) == .NOSYS)
477 return;
478
479 var ima_support = false;
480 for (probes) |probe| {
481 const value = probe.value;
482
483 switch (probe.key) {
484 -1 => continue, // The running kernel doesn't know this key.
485 RISCV_HWPROBE.KEY.BASE_BEHAVIOR => {
486 ima_support = set(value, RISCV_HWPROBE.BASE_BEHAVIOR_IMA);
487 setFeature(cpu, Target.riscv.Feature.i, ima_support);
488 setFeature(cpu, Target.riscv.Feature.m, ima_support);
489 setFeature(cpu, Target.riscv.Feature.a, ima_support);
490 },
491 RISCV_HWPROBE.KEY.IMA_EXT_0 => {
492 // https://bugzilla.kernel.org/show_bug.cgi?id=221874
493 const fd_support = set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_FD);
494 setFeature(cpu, .f, ima_support and fd_support);
495 setFeature(cpu, .d, ima_support and fd_support);
496 setFeature(cpu, .c, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_C));
497 setFeature(cpu, .v, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_V));
498 setFeature(cpu, .zba, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBA));
499 setFeature(cpu, .zbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBB));
500 setFeature(cpu, .zbs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBS));
501 setFeature(cpu, .zicboz, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOZ));
502 setFeature(cpu, .zbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBC));
503 setFeature(cpu, .zbkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKB));
504 setFeature(cpu, .zbkc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKC));
505 setFeature(cpu, .zbkx, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKX));
506 setFeature(cpu, .zknd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKND));
507 setFeature(cpu, .zkne, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNE));
508 setFeature(cpu, .zknh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNH));
509 setFeature(cpu, .zksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSED));
510 setFeature(cpu, .zksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSH));
511 setFeature(cpu, .zkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKT));
512 setFeature(cpu, .zvbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBB));
513 setFeature(cpu, .zvbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBC));
514 setFeature(cpu, .zvkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKB));
515 setFeature(cpu, .zvkg, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKG));
516 setFeature(cpu, .zvkned, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNED));
517 setFeature(cpu, .zvknha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHA));
518 setFeature(cpu, .zvknhb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHB));
519 setFeature(cpu, .zvksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSED));
520 setFeature(cpu, .zvksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSH));
521 setFeature(cpu, .zvkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKT));
522 setFeature(cpu, .zfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFH));
523 setFeature(cpu, .zfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFHMIN));
524 setFeature(cpu, .zihintntl, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTNTL));
525 setFeature(cpu, .zvfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFH));
526 setFeature(cpu, .zvfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFHMIN));
527 setFeature(cpu, .zfa, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFA));
528 setFeature(cpu, .ztso, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZTSO));
529 setFeature(cpu, .zacas, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZACAS));
530 setFeature(cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR));
531 setFeature(cpu, .zicond, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICOND));
532 setFeature(cpu, .zihintpause, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTPAUSE));
533 setFeature(cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM));
534 setFeature(cpu, .zve32x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32X));
535 setFeature(cpu, .zve32f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32F));
536 setFeature(cpu, .zve64x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64X));
537 setFeature(cpu, .zve64f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64F));
538 setFeature(cpu, .zve64d, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64D));
539 setFeature(cpu, .zimop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIMOP));
540 setFeature(cpu, .zca, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCA));
541 setFeature(cpu, .zcb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCB));
542 setFeature(cpu, .zcd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCD));
543 setFeature(cpu, .zcf, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCF));
544 setFeature(cpu, .zcmop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCMOP));
545 setFeature(cpu, .zawrs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAWRS));
546 setFeature(cpu, .supm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_SUPM));
547 setFeature(cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR));
548 setFeature(cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM));
549 setFeature(cpu, .zfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFBFMIN));
550 setFeature(cpu, .zvfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFMIN));
551 setFeature(cpu, .zvfbfwma, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFWMA));
552 setFeature(cpu, .zicbom, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOM));
553 setFeature(cpu, .zaamo, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAAMO));
554 setFeature(cpu, .zalrsc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALRSC));
555 setFeature(cpu, .zabha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZABHA));
556 setFeature(cpu, .zalasr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALASR));
557 setFeature(cpu, .zicbop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOP));
558 setFeature(cpu, .zilsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZILSD));
559 setFeature(cpu, .zclsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCLSD));
560 setFeature(cpu, .experimental_zicfilp, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICFILP));
561 },
562 RISCV_HWPROBE.KEY.MISALIGNED_SCALAR_PERF => {
563 setFeature(cpu, .unaligned_scalar_mem, value == RISCV_HWPROBE.MISALIGNED_SCALAR.FAST);
564 },
565 RISCV_HWPROBE.KEY.MISALIGNED_VECTOR_PERF => {
566 setFeature(cpu, .unaligned_vector_mem, value == RISCV_HWPROBE.MISALIGNED_VECTOR.FAST);
567 },
568 RISCV_HWPROBE.KEY.VENDOR_EXT_MIPS_0 => {
569 setFeature(cpu, .xmipsexectl, ima_support and set(value, RISCV_HWPROBE.MIPS_VENDOR_EXT_XMIPSEXECTL));
570 },
571 RISCV_HWPROBE.KEY.VENDOR_EXT_SIFIVE_0 => {
572 setFeature(cpu, .xsfvqmaccdod, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCDOD));
573 setFeature(cpu, .xsfvqmaccqoq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCQOQ));
574 setFeature(cpu, .xsfvfnrclipxfqf, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFNRCLIPXFQF));
575 setFeature(cpu, .xsfvfwmaccqqq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFWMACCQQQ));
576 },
577 RISCV_HWPROBE.KEY.IMA_EXT_1 => {
578 setFeature(cpu, .experimental_zicfiss, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_1_EXT_ZICFISS));
579 },
580 else => unreachable,
581 }
582 }
583 }
584};
585
450pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {586pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
451 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch |err| switch (err) {587 var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch |err| switch (err) {
452 else => return null,588 else => return null,
...@@ -457,11 +593,8 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {...@@ -457,11 +593,8 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
457 var file_reader = file.reader(io, &buffer);593 var file_reader = file.reader(io, &buffer);
458594
459 const current_arch = builtin.cpu.arch;595 const current_arch = builtin.cpu.arch;
460 switch (current_arch) {596 return switch (current_arch) {
461 .arm, .armeb, .thumb, .thumbeb => {597 .aarch64, .aarch64_be => b: {
462 return ArmCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
463 },
464 .aarch64, .aarch64_be => {
465 const registers = [12]u64{598 const registers = [12]u64{
466 getAArch64CpuFeature("MIDR_EL1"),599 getAArch64CpuFeature("MIDR_EL1"),
467 getAArch64CpuFeature("ID_AA64PFR0_EL1"),600 getAArch64CpuFeature("ID_AA64PFR0_EL1"),
...@@ -477,23 +610,27 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {...@@ -477,23 +610,27 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu {
477 getAArch64CpuFeature("ID_AA64MMFR2_EL1"),610 getAArch64CpuFeature("ID_AA64MMFR2_EL1"),
478 };611 };
479612
480 const core = @import("arm.zig").aarch64.detectNativeCpuAndFeatures(current_arch, registers);613 break :b @import("arm.zig").aarch64.detectNativeCpuAndFeatures(current_arch, registers);
481 return core;
482 },
483 .sparc, .sparc64 => {
484 return SparcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
485 },
486 .powerpc, .powerpcle, .powerpc64, .powerpc64le => {
487 return PowerpcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
488 },
489 .riscv64, .riscv32 => {
490 return RiscvCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
491 },
492 .s390x => {
493 return S390xCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
494 },614 },
495 else => {},615 .arm, .armeb, .thumb, .thumbeb => ArmCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
496 }616 .powerpc, .powerpcle, .powerpc64, .powerpc64le => PowerpcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
617 .riscv64, .riscv32 => b: {
618 var cpu = (RiscvCpuinfoParser.parse(current_arch, &file_reader.interface) catch null) orelse cpu: {
619 const model = Target.Cpu.Model.generic(current_arch);
620 break :cpu Target.Cpu{
621 .arch = current_arch,
622 .model = model,
623 .features = model.features,
624 };
625 };
626
627 riscv.detectCpuFeatures(&cpu);
628 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
497629
498 return null;630 break :b cpu;
631 },
632 .s390x => S390xCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
633 .sparc, .sparc64 => SparcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null,
634 else => null,
635 };
499}636}