-
Notifications
You must be signed in to change notification settings - Fork 23
Description
Add the following function to hello.c
:
static inline uint32_t read_csr_mstatus(void){
uint32_t x;
__asm__ volatile ("csrr %0, mstatus" : "=r"(x));
return x;
}
Then, modify the printf
statements in task0
, task1
, and task2
as follows:
printf("[task %d %ld], mstatus: %x\n", mo_task_id(), cnt++, read_csr_mstatus());
The result:
Linmo kernel is starting...
Heap initialized, 130012200 bytes available
task 1: entry=800001c0 stack=80002c48 size=4096 prio_level=4 time_slice=5
task 2: entry=80000204 stack=80003cfc size=4096 prio_level=4 time_slice=5
task 3: entry=8000017c stack=80004d7c size=4096 prio_level=4 time_slice=5
task0 has id 1
task1 has id 2
task2 has id 3
Scheduler mode: Preemptive
[task 1 100000], mstatus: 1808
[task 2 200000], mstatus: 1808
[task 3 300000], mstatus: 1808
[task 1 100001], mstatus: 88
[task 2 200001], mstatus: 88
[task 3 300001], mstatus: 88
[task 1 100002], mstatus: 88
...
According to The RISC-V Instruction Set Manual, Volume II: Privileged Architecture, section 3.1.6 Machine Status Registers (mstatus
and mstatush
), the MPP field has a value of 11
, which corresponds to M-mode.
It can be observed that during the first execution, any task has machine mode privilege, and only afterwards does it return to user mode.
This means that any task at startup can directly affect the execution of other tasks — for example, by modifying mstatus
to disable interrupt enabling — which raises security concerns.
/* This causes task0 to never be preempted. */
void task0(void)
{
int32_t cnt = 100000;
while (1) {
__asm__ __volatile__(
"li t0, 0x1800\n"
"csrw mstatus, t0\n"
);
printf("[task %d %ld], mstatus: %x\n", mo_task_id(), cnt++, read_csr_mstatus());
}
}
In hal_context_init
, CONTEXT_MSTATUS
is explicitly set to MSTATUS_MPP_MACH
, so this situation might have been intentional.
However, doesn’t doing so defeat the purpose of distinguishing between machine mode and user mode?