Skip to content

When an application (such as hello.c) runs for the first time, it is executed in machine mode. #19

@weiso131

Description

@weiso131

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions