aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv64/kernel/power.c6
-rw-r--r--arch/riscv64/kernel/sbi.h6
-rw-r--r--include/kmi/power.h8
-rw-r--r--include/kmi/syscalls.h3
-rw-r--r--include/kmi/uapi.h5
-rw-r--r--src/uapi/conf.c10
-rw-r--r--src/uapi/dispatch.c1
7 files changed, 38 insertions, 1 deletions
diff --git a/arch/riscv64/kernel/power.c b/arch/riscv64/kernel/power.c
index 49fc9c5..21e4957 100644
--- a/arch/riscv64/kernel/power.c
+++ b/arch/riscv64/kernel/power.c
@@ -49,3 +49,9 @@ stat_t poweroff(enum poweroff_type type)
return ERR_INVAL;
}
+
+stat_t sleep()
+{
+ sbi_hart_stop();
+ return ERR_MISC;
+}
diff --git a/arch/riscv64/kernel/sbi.h b/arch/riscv64/kernel/sbi.h
index fe75c85..d536f58 100644
--- a/arch/riscv64/kernel/sbi.h
+++ b/arch/riscv64/kernel/sbi.h
@@ -149,6 +149,12 @@ static inline struct sbiret sbi_hart_start(unsigned long hartid,
0, 0, 0);
}
+#define FID_HSM_STOP 1
+static inline struct sbiret sbi_hart_stop()
+{
+ return sbi_ecall(EID_HSM, FID_HSM_STOP, 0, 0, 0, 0, 0, 0);
+}
+
/** Hart status function ID. */
#define FID_HSM_STATUS 2
diff --git a/include/kmi/power.h b/include/kmi/power.h
index d11b9d1..db00999 100644
--- a/include/kmi/power.h
+++ b/include/kmi/power.h
@@ -35,4 +35,12 @@ enum poweroff_type {
*/
stat_t poweroff(enum poweroff_type type);
+/**
+ * Set the current core to sleep.
+ *
+ * @return Nothing on success (we should be sleeping),
+ * \ref ERR_MISC if sleep was not successful
+ */
+stat_t sleep();
+
#endif
diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h
index 1de4fb2..e503709 100644
--- a/include/kmi/syscalls.h
+++ b/include/kmi/syscalls.h
@@ -142,6 +142,9 @@ enum {
/** Shutdown, reboot, etc. */
SYS_POWEROFF,
+ /** Set this core to sleep. */
+ SYS_SLEEP,
+
/** Request to handle IRQ. */
SYS_IRQ_REQ,
diff --git a/include/kmi/uapi.h b/include/kmi/uapi.h
index 40cfae4..d1d3a38 100644
--- a/include/kmi/uapi.h
+++ b/include/kmi/uapi.h
@@ -764,6 +764,11 @@ SYSCALL_DECLARE3(clear_cap, tid, off, cap);
SYSCALL_DECLARE1(poweroff, type);
/**
+ * Sets the current core to sleep. Might take parameters in the future if there
+ * arises a need for different levels of sleep, but for now zero params. */
+SYSCALL_DECLARE0(sleep);
+
+/**
* Request to handle IRQ.
*
* @param t Current tcb.
diff --git a/src/uapi/conf.c b/src/uapi/conf.c
index 894b98a..497aef0 100644
--- a/src/uapi/conf.c
+++ b/src/uapi/conf.c
@@ -108,8 +108,16 @@ SYSCALL_DEFINE1(poweroff)(struct tcb *t, sys_arg_t type)
case SHUTDOWN:
case COLD_REBOOT:
case WARM_REBOOT:
- return_args2(t, OK, poweroff(type));
+ return_args1(t, poweroff(type));
};
return_args1(t, ERR_INVAL);
}
+
+SYSCALL_DEFINE0(sleep)(struct tcb *t)
+{
+ if (!(has_cap(t->caps, CAP_POWER)))
+ return_args1(t, ERR_PERM);
+
+ return_args1(t, sleep());
+}
diff --git a/src/uapi/dispatch.c b/src/uapi/dispatch.c
index 5b523cc..f160091 100644
--- a/src/uapi/dispatch.c
+++ b/src/uapi/dispatch.c
@@ -76,6 +76,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b,
case SYS_GET_CAP: sys_get_cap(t, a, b, c, d, e); break;
case SYS_CLEAR_CAP: sys_clear_cap(t, a, b, c, d, e); break;
case SYS_POWEROFF: sys_poweroff(t, a, b, c, d, e); break;
+ case SYS_SLEEP: sys_sleep(t, a, b, c, d, e); break;
case SYS_IRQ_REQ: sys_irq_req(t, a, b, c, d, e); break;
default:
error("Syscall %zu outside allowed range [0 - %i]\n", syscall,