aboutsummaryrefslogtreecommitdiff
path: root/pk/syscall.c
diff options
context:
space:
mode:
authorWojciech Muła <wojciech_mula@poczta.onet.pl>2024-04-24 06:58:59 +0200
committerAndrew Waterman <andrew@sifive.com>2024-05-20 18:37:48 -0700
commitab24ff26666e14b3b6c4a8c8bb2c209d2587bb3e (patch)
tree98780651ffcc8ea390e77bce5869983f31be5ab4 /pk/syscall.c
parent86ed1b3b062bc81c2f42d6676a71cfba52880915 (diff)
downloadriscv-pk-ab24ff26666e14b3b6c4a8c8bb2c209d2587bb3e.zip
riscv-pk-ab24ff26666e14b3b6c4a8c8bb2c209d2587bb3e.tar.gz
riscv-pk-ab24ff26666e14b3b6c4a8c8bb2c209d2587bb3e.tar.bz2
Implementation of riscv_hwprobe syscall from Linux (#325)
See: https://www.kernel.org/doc/html/latest/arch/riscv/hwprobe.html
Diffstat (limited to 'pk/syscall.c')
-rw-r--r--pk/syscall.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/pk/syscall.c b/pk/syscall.c
index 3dd0bf7..dc0d35f 100644
--- a/pk/syscall.c
+++ b/pk/syscall.c
@@ -8,6 +8,7 @@
#include "mmap.h"
#include "boot.h"
#include "usermem.h"
+#include <stdint.h>
#include <string.h>
#include <errno.h>
@@ -662,6 +663,55 @@ int sys_getdents(int fd, void* dirbuf, int count)
return 0; //stub
}
+// Partial implementation on riscv_hwprobe from Linux
+// See: https://www.kernel.org/doc/html/latest/arch/riscv/hwprobe.html
+
+#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
+#define RISCV_HWPROBE_IMA_FD (1 << 0)
+#define RISCV_HWPROBE_IMA_C (1 << 1)
+#define RISCV_HWPROBE_IMA_V (1 << 2)
+#define RISCV_HWPROBE_EXT_ZBA (1 << 3)
+#define RISCV_HWPROBE_EXT_ZBB (1 << 4)
+#define RISCV_HWPROBE_EXT_ZBS (1 << 5)
+#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6)
+
+struct riscv_hwprobe {
+ int64_t key;
+ uint64_t value;
+};
+
+long sys_riscv_hwprobe(struct riscv_hwprobe* probes, size_t count, size_t reserved_cpusetsize, void* reserved_cpuset, unsigned int reserved_flags)
+{
+ if ((reserved_cpusetsize != 0) || (reserved_cpuset != NULL) || (reserved_flags != 0)) {
+ return -EBADF;
+ }
+
+ for (size_t i=0; i < count; i++) {
+ struct riscv_hwprobe kv;
+ memcpy_from_user(&kv, &probes[i], sizeof(kv));
+
+ if (kv.key == RISCV_HWPROBE_KEY_IMA_EXT_0) {
+ kv.value = 0;
+ #define supports_extension(letter) (misa_image & (1 << (letter - 'A')))
+
+ if (supports_extension('C'))
+ kv.value |= RISCV_HWPROBE_IMA_C;
+ if (supports_extension('V'))
+ kv.value |= RISCV_HWPROBE_IMA_V;
+
+ #undef supports_extension
+ } else {
+ // "If a key is unknown to the kernel, its key field will be cleared to -1, and its value set to 0"
+ kv.key = -1;
+ kv.value = 0;
+ }
+
+ memcpy_to_user(&probes[i], &kv, sizeof(kv));
+ }
+
+ return 0;
+}
+
static int sys_stub_success()
{
return 0;
@@ -719,6 +769,7 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, unsigned l
[SYS_chdir] = sys_chdir,
[SYS_readlinkat] = sys_readlinkat,
[SYS_readv] = sys_readv,
+ [SYS_riscv_hwprobe] = sys_riscv_hwprobe,
};
const static void* old_syscall_table[] = {