aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/sys/info/cpu_linux_riscv64.odin121
-rw-r--r--core/sys/info/cpu_riscv64.odin98
-rw-r--r--core/sys/linux/bits.odin84
-rw-r--r--core/sys/linux/sys.odin15
-rw-r--r--core/sys/linux/syscall_riscv64.odin1
-rw-r--r--core/sys/linux/types.odin17
6 files changed, 302 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]
diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin
index f78891bc8..8a4a6dd7a 100644
--- a/core/sys/linux/bits.odin
+++ b/core/sys/linux/bits.odin
@@ -1839,3 +1839,87 @@ Execveat_Flags_Bits :: enum {
AT_SYMLINK_NOFOLLOW = 8,
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,
+}
+
diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin
index 6e4194be7..5ee07a93d 100644
--- a/core/sys/linux/sys.odin
+++ b/core/sys/linux/sys.odin
@@ -2993,3 +2993,18 @@ epoll_pwait2 :: proc(epfd: Fd, events: [^]EPoll_Event, count: i32, timeout: ^Tim
// TODO(flysand): fchmodat2
// 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)
+ }
+}
diff --git a/core/sys/linux/syscall_riscv64.odin b/core/sys/linux/syscall_riscv64.odin
index ce374312e..d2fd0c2ff 100644
--- a/core/sys/linux/syscall_riscv64.odin
+++ b/core/sys/linux/syscall_riscv64.odin
@@ -248,6 +248,7 @@ SYS_rt_tgsigqueueinfo :: uintptr(240)
SYS_perf_event_open :: uintptr(241)
SYS_accept4 :: uintptr(242)
SYS_recvmmsg :: uintptr(243)
+SYS_riscv_hwprobe :: uintptr(258)
SYS_wait4 :: uintptr(260)
SYS_prlimit64 :: uintptr(261)
SYS_fanotify_init :: uintptr(262)
diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin
index 3f873f96c..0e5b8218b 100644
--- a/core/sys/linux/types.odin
+++ b/core/sys/linux/types.odin
@@ -1335,3 +1335,20 @@ EPoll_Event :: struct #packed {
Flags for execveat(2) syscall.
*/
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,
+ },
+}