diff options
| author | laytan <laytanlaats@hotmail.com> | 2024-09-02 13:44:22 +0000 |
|---|---|---|
| committer | laytan <laytanlaats@hotmail.com> | 2024-09-02 14:06:19 +0000 |
| commit | 35731e66cf406144c83c7d9b6db576539b0e13fb (patch) | |
| tree | f6f67e893f8cee5fcd3c5c5887c047e07c314077 /core/sys/info | |
| parent | 28c643d23f989937c8d530b49a2369e8cd9d39e2 (diff) | |
sys/info: more CPU feature detection for RISC-V
Diffstat (limited to 'core/sys/info')
| -rw-r--r-- | core/sys/info/cpu_linux_riscv64.odin | 121 | ||||
| -rw-r--r-- | core/sys/info/cpu_riscv64.odin | 98 |
2 files changed, 185 insertions, 34 deletions
diff --git a/core/sys/info/cpu_linux_riscv64.odin b/core/sys/info/cpu_linux_riscv64.odin index 0f109e7ba..0b64c3725 100644 --- a/core/sys/info/cpu_linux_riscv64.odin +++ b/core/sys/info/cpu_linux_riscv64.odin @@ -8,35 +8,102 @@ import "core:sys/linux" @(init, private) init_cpu_features :: proc() { - fd, err := linux.open("/proc/self/auxv", {}) - if err != .NONE { return } - defer linux.close(fd) - - // This is probably enough right? - buf: [4096]byte - n, rerr := linux.read(fd, buf[:]) - if rerr != .NONE || n == 0 { return } - - ulong :: u64 - AT_HWCAP :: 16 - - // TODO: using these we could get more information than just the basics. - // AT_HWCAP2 :: 26 - // AT_HWCAP3 :: 29 - // AT_HWCAP4 :: 30 - - auxv := buf[:n] - for len(auxv) >= size_of(ulong)*2 { - key := intrinsics.unaligned_load((^ulong)(&auxv[0])) - val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)])) - auxv = auxv[2*size_of(ulong):] - - if key != AT_HWCAP { - continue + _features: CPU_Features + defer cpu_features = _features + + HWCAP_Bits :: enum u64 { + I = 'I' - 'A', + M = 'M' - 'A', + A = 'A' - 'A', + F = 'F' - 'A', + D = 'D' - 'A', + C = 'C' - 'A', + V = 'V' - 'A', + } + HWCAP :: bit_set[HWCAP_Bits; u64] + + // Read HWCAP for base extensions, we can get this info through hwprobe too but that is Linux 6.4+ only. + { + fd, err := linux.open("/proc/self/auxv", {}) + if err != .NONE { return } + defer linux.close(fd) + + // This is probably enough right? + buf: [4096]byte + n, rerr := linux.read(fd, buf[:]) + if rerr != .NONE || n == 0 { return } + + ulong :: u64 + AT_HWCAP :: 16 + + auxv := buf[:n] + for len(auxv) >= size_of(ulong)*2 { + key := intrinsics.unaligned_load((^ulong)(&auxv[0])) + val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)])) + auxv = auxv[2*size_of(ulong):] + + if key != AT_HWCAP { + continue + } + + cap := transmute(HWCAP)(val) + if .I in cap { + _features += { .I } + } + if .M in cap { + _features += { .M } + } + if .A in cap { + _features += { .A } + } + if .F in cap { + _features += { .F } + } + if .D in cap { + _features += { .D } + } + if .C in cap { + _features += { .C } + } + if .V in cap { + _features += { .V } + } + break } + } - cpu_features = transmute(CPU_Features)(val) - break + // hwprobe for other features. + { + pairs := []linux.RISCV_HWProbe{ + { key = .IMA_EXT_0 }, + { key = .CPUPERF_0 }, + { key = .MISALIGNED_SCALAR_PERF }, + } + err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {}) + if err != nil { + assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()") + return + } + + assert(pairs[0].key == .IMA_EXT_0) + exts := pairs[0].value.ima_ext_0 + exts -= { .FD, .C, .V } + _features += transmute(CPU_Features)exts + + if pairs[2].key == .MISALIGNED_SCALAR_PERF { + if pairs[2].value.misaligned_scalar_perf == .FAST { + _features += { .Misaligned_Supported, .Misaligned_Fast } + } else if pairs[2].value.misaligned_scalar_perf != .UNSUPPORTED { + _features += { .Misaligned_Supported } + } + } else { + assert(pairs[1].key == .CPUPERF_0) + if .FAST in pairs[1].value.cpu_perf_0 { + _features += { .Misaligned_Supported, .Misaligned_Fast } + } else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 { + _features += { .Misaligned_Supported } + } + } } } diff --git a/core/sys/info/cpu_riscv64.odin b/core/sys/info/cpu_riscv64.odin index 754110911..c3319c48c 100644 --- a/core/sys/info/cpu_riscv64.odin +++ b/core/sys/info/cpu_riscv64.odin @@ -1,13 +1,97 @@ package sysinfo CPU_Feature :: enum u64 { - I = 'I' - 'A', // Base features, don't think this is ever not here. - M = 'M' - 'A', // Integer multiplication and division, currently required by Odin. - A = 'A' - 'A', // Atomics. - F = 'F' - 'A', // Single precision floating point, currently required by Odin. - D = 'D' - 'A', // Double precision floating point, currently required by Odin. - C = 'C' - 'A', // Compressed instructions. - V = 'V' - 'A', // Vector operations. + // Bit-Manipulation ISA Extensions v1. + Zba = 3, + Zbb, + Zbs, + + // CMOs (ratified). + Zicboz, + + // Bit-Manipulation ISA Extensions v1. + Zbc, + + // Scalar Crypto ISA extensions v1. + Zbkb, + Zbkc, + Zbkx, + Zknd, + Zkne, + Zknh, + Zksed, + Zksh, + Zkt, + + // Cryptography Extensions Volume II v1. + Zvbb, + Zvbc, + Zvkb, + Zvkg, + Zvkned, + Zvknha, + Zvknhb, + Zvksed, + Zvksh, + Zvkt, + + // ISA Manual v1. + Zfh, + Zfhmin, + Zihintntl, + + // ISA manual (ratified). + Zvfh, + Zvfhmin, + Zfa, + Ztso, + + // Atomic Compare-and-Swap Instructions Manual (ratified). + Zacas, + Zicond, + + // ISA manual (ratified). + Zihintpause, + + // Vector Extensions Manual v1. + Zve32x, + Zve32f, + Zve64x, + Zve64f, + Zve64d, + + // ISA manual (ratified). + Zimop, + + // Code Size Reduction (ratified). + Zca, + Zcb, + Zcd, + Zcf, + + // ISA manual (ratified). + Zcmop, + Zawrs, + + // Base features, don't think this is ever not here. + I, + // Integer multiplication and division, currently required by Odin. + M, + // Atomics. + A, + // Single precision floating point, currently required by Odin. + F, + // Double precision floating point, currently required by Odin. + D, + // Compressed instructions. + C, + // Vector operations. + V, + + // Indicates Misaligned Scalar Loads will not trap the program. + Misaligned_Supported, + // Indicates Hardware Support for Misaligned Scalar Loads. + Misaligned_Fast, } CPU_Features :: distinct bit_set[CPU_Feature; u64] |