mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Merge pull request #4181 from laytan/more-riscv-sysinfo
sys/info: more CPU feature detection for RISC-V
This commit is contained in:
@@ -8,35 +8,102 @@ import "core:sys/linux"
|
|||||||
|
|
||||||
@(init, private)
|
@(init, private)
|
||||||
init_cpu_features :: proc() {
|
init_cpu_features :: proc() {
|
||||||
fd, err := linux.open("/proc/self/auxv", {})
|
_features: CPU_Features
|
||||||
if err != .NONE { return }
|
defer cpu_features = _features
|
||||||
defer linux.close(fd)
|
|
||||||
|
|
||||||
// This is probably enough right?
|
HWCAP_Bits :: enum u64 {
|
||||||
buf: [4096]byte
|
I = 'I' - 'A',
|
||||||
n, rerr := linux.read(fd, buf[:])
|
M = 'M' - 'A',
|
||||||
if rerr != .NONE || n == 0 { return }
|
A = 'A' - 'A',
|
||||||
|
F = 'F' - 'A',
|
||||||
|
D = 'D' - 'A',
|
||||||
|
C = 'C' - 'A',
|
||||||
|
V = 'V' - 'A',
|
||||||
|
}
|
||||||
|
HWCAP :: bit_set[HWCAP_Bits; u64]
|
||||||
|
|
||||||
ulong :: u64
|
// Read HWCAP for base extensions, we can get this info through hwprobe too but that is Linux 6.4+ only.
|
||||||
AT_HWCAP :: 16
|
{
|
||||||
|
fd, err := linux.open("/proc/self/auxv", {})
|
||||||
|
if err != .NONE { return }
|
||||||
|
defer linux.close(fd)
|
||||||
|
|
||||||
// TODO: using these we could get more information than just the basics.
|
// This is probably enough right?
|
||||||
// AT_HWCAP2 :: 26
|
buf: [4096]byte
|
||||||
// AT_HWCAP3 :: 29
|
n, rerr := linux.read(fd, buf[:])
|
||||||
// AT_HWCAP4 :: 30
|
if rerr != .NONE || n == 0 { return }
|
||||||
|
|
||||||
auxv := buf[:n]
|
ulong :: u64
|
||||||
for len(auxv) >= size_of(ulong)*2 {
|
AT_HWCAP :: 16
|
||||||
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 {
|
auxv := buf[:n]
|
||||||
continue
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_features = transmute(CPU_Features)(val)
|
assert(pairs[0].key == .IMA_EXT_0)
|
||||||
break
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,97 @@
|
|||||||
package sysinfo
|
package sysinfo
|
||||||
|
|
||||||
CPU_Feature :: enum u64 {
|
CPU_Feature :: enum u64 {
|
||||||
I = 'I' - 'A', // Base features, don't think this is ever not here.
|
// Bit-Manipulation ISA Extensions v1.
|
||||||
M = 'M' - 'A', // Integer multiplication and division, currently required by Odin.
|
Zba = 3,
|
||||||
A = 'A' - 'A', // Atomics.
|
Zbb,
|
||||||
F = 'F' - 'A', // Single precision floating point, currently required by Odin.
|
Zbs,
|
||||||
D = 'D' - 'A', // Double precision floating point, currently required by Odin.
|
|
||||||
C = 'C' - 'A', // Compressed instructions.
|
// CMOs (ratified).
|
||||||
V = 'V' - 'A', // Vector operations.
|
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]
|
CPU_Features :: distinct bit_set[CPU_Feature; u64]
|
||||||
|
|||||||
@@ -1839,3 +1839,87 @@ Execveat_Flags_Bits :: enum {
|
|||||||
AT_SYMLINK_NOFOLLOW = 8,
|
AT_SYMLINK_NOFOLLOW = 8,
|
||||||
AT_EMPTY_PATH = 12,
|
AT_EMPTY_PATH = 12,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RISCV_HWProbe_Key :: enum i64 {
|
||||||
|
UNSUPPORTED = -1,
|
||||||
|
MVENDORID = 0,
|
||||||
|
MARCHID = 1,
|
||||||
|
MIMPID = 2,
|
||||||
|
BASE_BEHAVIOR = 3,
|
||||||
|
IMA_EXT_0 = 4,
|
||||||
|
// Deprecated, try `.MISALIGNED_SCALAR_PERF` first, if that is `.UNSUPPORTED`, use this.
|
||||||
|
CPUPERF_0 = 5,
|
||||||
|
ZICBOZ_BLOCK_SIZE = 6,
|
||||||
|
HIGHEST_VIRT_ADDRESS = 7,
|
||||||
|
TIME_CSR_FREQ = 8,
|
||||||
|
MISALIGNED_SCALAR_PERF = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
RISCV_HWProbe_Flags_Bits :: enum {
|
||||||
|
WHICH_CPUS,
|
||||||
|
}
|
||||||
|
|
||||||
|
RISCV_HWProbe_Base_Behavior_Bits :: enum {
|
||||||
|
IMA,
|
||||||
|
}
|
||||||
|
|
||||||
|
RISCV_HWProbe_IMA_Ext_0_Bits :: enum {
|
||||||
|
FD,
|
||||||
|
C,
|
||||||
|
V,
|
||||||
|
EXT_ZBA,
|
||||||
|
EXT_ZBB,
|
||||||
|
EXT_ZBS,
|
||||||
|
EXT_ZICBOZ,
|
||||||
|
EXT_ZBC,
|
||||||
|
EXT_ZBKB,
|
||||||
|
EXT_ZBKC,
|
||||||
|
EXT_ZBKX,
|
||||||
|
EXT_ZKND,
|
||||||
|
EXT_ZKNE,
|
||||||
|
EXT_ZKNH,
|
||||||
|
EXT_ZKSED,
|
||||||
|
EXT_ZKSH,
|
||||||
|
EXT_ZKT,
|
||||||
|
EXT_ZVBB,
|
||||||
|
EXT_ZVBC,
|
||||||
|
EXT_ZVKB,
|
||||||
|
EXT_ZVKG,
|
||||||
|
EXT_ZVKNED,
|
||||||
|
EXT_ZVKNHA,
|
||||||
|
EXT_ZVKNHB,
|
||||||
|
EXT_ZVKSED,
|
||||||
|
EXT_ZVKSH,
|
||||||
|
EXT_ZVKT,
|
||||||
|
EXT_ZFH,
|
||||||
|
EXT_ZFHMIN,
|
||||||
|
EXT_ZIHINTNTL,
|
||||||
|
EXT_ZVFH,
|
||||||
|
EXT_ZVFHMIN,
|
||||||
|
EXT_ZFA,
|
||||||
|
EXT_ZTSO,
|
||||||
|
EXT_ZACAS,
|
||||||
|
EXT_ZICOND,
|
||||||
|
EXT_ZIHINTPAUSE,
|
||||||
|
EXT_ZVE32X,
|
||||||
|
EXT_ZVE32F,
|
||||||
|
EXT_ZVE64X,
|
||||||
|
EXT_ZVE64F,
|
||||||
|
EXT_ZVE64D,
|
||||||
|
EXT_ZIMOP,
|
||||||
|
EXT_ZCA,
|
||||||
|
EXT_ZCB,
|
||||||
|
EXT_ZCD,
|
||||||
|
EXT_ZCF,
|
||||||
|
EXT_ZCMOP,
|
||||||
|
EXT_ZAWRS,
|
||||||
|
}
|
||||||
|
|
||||||
|
RISCV_HWProbe_Misaligned_Scalar_Perf :: enum {
|
||||||
|
UNKNOWN,
|
||||||
|
EMULATED,
|
||||||
|
SLOW,
|
||||||
|
FAST,
|
||||||
|
UNSUPPORTED,
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2993,3 +2993,18 @@ epoll_pwait2 :: proc(epfd: Fd, events: [^]EPoll_Event, count: i32, timeout: ^Tim
|
|||||||
// TODO(flysand): fchmodat2
|
// TODO(flysand): fchmodat2
|
||||||
|
|
||||||
// TODO(flysand): map_shadow_stack
|
// TODO(flysand): map_shadow_stack
|
||||||
|
|
||||||
|
when ODIN_ARCH == .riscv64 {
|
||||||
|
/*
|
||||||
|
Probe for RISC-V Hardware Support.
|
||||||
|
Available since Linux 6.4.
|
||||||
|
|
||||||
|
TODO: cpu_set_t
|
||||||
|
|
||||||
|
See: https://docs.kernel.org/arch/riscv/hwprobe.html
|
||||||
|
*/
|
||||||
|
riscv_hwprobe :: proc "contextless" (pairs: [^]RISCV_HWProbe, pair_count: uint, cpu_count: uint, cpus: rawptr /* cpu_set_t */, flags: RISCV_HWProbe_Flags) -> Errno {
|
||||||
|
ret := syscall(SYS_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, transmute(u32)flags)
|
||||||
|
return Errno(-ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -248,6 +248,7 @@ SYS_rt_tgsigqueueinfo :: uintptr(240)
|
|||||||
SYS_perf_event_open :: uintptr(241)
|
SYS_perf_event_open :: uintptr(241)
|
||||||
SYS_accept4 :: uintptr(242)
|
SYS_accept4 :: uintptr(242)
|
||||||
SYS_recvmmsg :: uintptr(243)
|
SYS_recvmmsg :: uintptr(243)
|
||||||
|
SYS_riscv_hwprobe :: uintptr(258)
|
||||||
SYS_wait4 :: uintptr(260)
|
SYS_wait4 :: uintptr(260)
|
||||||
SYS_prlimit64 :: uintptr(261)
|
SYS_prlimit64 :: uintptr(261)
|
||||||
SYS_fanotify_init :: uintptr(262)
|
SYS_fanotify_init :: uintptr(262)
|
||||||
|
|||||||
@@ -1335,3 +1335,20 @@ EPoll_Event :: struct #packed {
|
|||||||
Flags for execveat(2) syscall.
|
Flags for execveat(2) syscall.
|
||||||
*/
|
*/
|
||||||
Execveat_Flags :: bit_set[Execveat_Flags_Bits; i32]
|
Execveat_Flags :: bit_set[Execveat_Flags_Bits; i32]
|
||||||
|
|
||||||
|
RISCV_HWProbe_Flags :: bit_set[RISCV_HWProbe_Flags_Bits; u32]
|
||||||
|
RISCV_HWProbe_CPU_Perf_0 :: bit_set[RISCV_HWProbe_Misaligned_Scalar_Perf; u64]
|
||||||
|
RISCV_HWProbe_Base_Behavior :: bit_set[RISCV_HWProbe_Base_Behavior_Bits; u64]
|
||||||
|
RISCV_HWProbe_IMA_Ext_0 :: bit_set[RISCV_HWProbe_IMA_Ext_0_Bits; u64]
|
||||||
|
|
||||||
|
RISCV_HWProbe :: struct {
|
||||||
|
// set to `.UNSUPPORTED` by the kernel if that is the case.
|
||||||
|
key: RISCV_HWProbe_Key,
|
||||||
|
value: struct #raw_union {
|
||||||
|
base_behavior: RISCV_HWProbe_Base_Behavior,
|
||||||
|
ima_ext_0: RISCV_HWProbe_IMA_Ext_0,
|
||||||
|
cpu_perf_0: RISCV_HWProbe_CPU_Perf_0,
|
||||||
|
misaligned_scalar_perf: RISCV_HWProbe_Misaligned_Scalar_Perf,
|
||||||
|
raw: u64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user