Skip to content

Commit 1710f76

Browse files
committed
Add configurable privilege mode for application entry
User mode applications should create tasks through system calls rather than direct kernel interfaces. The previous design required a separate privileged interface for spawning user tasks, which conflicted with the principle that user code should only interact with the kernel through the trap-based syscall mechanism. The application entry point now runs in user mode by default, allowing applications to use system calls naturally for task creation. Privileged mode remains available as a build-time option for kernel API tests that require direct kernel access. The build system automatically selects the appropriate mode based on the target application. The task creation interface has been unified to accept a privilege mode parameter directly, removing the need for separate interfaces. The syscall layer enforces user mode for all tasks created through traps, preventing privilege escalation from user space.
1 parent b1ad446 commit 1710f76

26 files changed

Lines changed: 116 additions & 89 deletions

Documentation/hal-calling-convention.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ This "red zone" is reserved at the top of every task stack to guarantee ISR safe
141141
Standard RISC-V calling convention applies:
142142
143143
```c
144-
/* Example: mo_task_spawn(entry, stack_size) */
145-
/* a0 = entry, a1 = stack_size, return value in a0 */
146-
int32_t result = mo_task_spawn(task_function, 2048);
144+
/* Example: mo_task_spawn(entry, stack_size, mode) */
145+
/* a0 = entry, a1 = stack_size, a2 = mode, return value in a0 */
146+
int32_t result = mo_task_spawn(task_function, 2048, TASK_MODE_M);
147147
```
148148

149149
### System Call Interface

Makefile

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ BUILD_APP_DIR := $(BUILD_DIR)/app
99
BUILD_KERNEL_DIR := $(BUILD_DIR)/kernel
1010
BUILD_LIB_DIR := $(BUILD_DIR)/lib
1111

12+
# Apps requiring M-mode (kernel API tests)
13+
# All other apps run in U-mode by default (secure)
14+
MMODE_APPS := cond coop cpubench echo hello mqueues mutex \
15+
pipes pipes_small pipes_struct prodcons progress \
16+
rtsched semaphore suspend test64 test_libc timer timer_kill
17+
18+
# Auto-detect: if building an M-mode app, enable CONFIG_PRIVILEGED
19+
ifneq ($(filter $(MAKECMDGOALS),$(MMODE_APPS)),)
20+
CONFIG_PRIVILEGED := 1
21+
endif
22+
1223
include mk/common.mk
1324
# architecture-specific settings
1425
include arch/$(ARCH)/build.mk
@@ -97,7 +108,8 @@ $(BUILD_DIR)/code.txt: $(IMAGE_BASE).bin
97108

98109
# Utility targets
99110
rebuild:
100-
$(Q)find '$(BUILD_APP_DIR)' -type f -name '*.o' -delete 2>/dev/null || true
111+
$(Q)find '$(BUILD_APP_DIR)' '$(BUILD_KERNEL_DIR)' -type f -name '*.o' -delete 2>/dev/null || true
112+
$(Q)rm -f '$(BUILD_DIR)/liblinmo.a' 2>/dev/null || true
101113
$(Q)mkdir -p $(BUILD_APP_DIR) $(BUILD_KERNEL_DIR) $(BUILD_LIB_DIR)
102114

103115
clean:

app/cond.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ int32_t app_main(void)
110110
mo_mutex_init(&m);
111111
mo_cond_init(&cv);
112112

113-
mo_task_spawn(producer, DEFAULT_STACK_SIZE);
114-
mo_task_spawn(consumer, DEFAULT_STACK_SIZE);
115-
mo_task_spawn(mutex_tester, DEFAULT_STACK_SIZE);
116-
mo_task_spawn(idle_task, DEFAULT_STACK_SIZE);
113+
mo_task_spawn(producer, DEFAULT_STACK_SIZE, TASK_MODE_M);
114+
mo_task_spawn(consumer, DEFAULT_STACK_SIZE, TASK_MODE_M);
115+
mo_task_spawn(mutex_tester, DEFAULT_STACK_SIZE, TASK_MODE_M);
116+
mo_task_spawn(idle_task, DEFAULT_STACK_SIZE, TASK_MODE_M);
117117

118118
/* preemptive mode */
119119
return 1;

app/coop.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ void task0(void)
3434

3535
int32_t app_main(void)
3636
{
37-
mo_task_spawn(task0, DEFAULT_STACK_SIZE);
38-
mo_task_spawn(task1, DEFAULT_STACK_SIZE);
39-
mo_task_spawn(task2, DEFAULT_STACK_SIZE);
37+
mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M);
38+
mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M);
39+
mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M);
4040

4141
/* cooperative mode */
4242
return 0;

app/cpubench.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ int32_t app_main(void)
6262
printf("Result: a=%d, b=%d, c=%d\n", a, b, c);
6363
printf("Elapsed time: %lu.%03lus\n", elapsed / 1000, elapsed % 1000);
6464

65-
mo_task_spawn(idle, DEFAULT_STACK_SIZE);
65+
mo_task_spawn(idle, DEFAULT_STACK_SIZE, TASK_MODE_M);
6666
return 1;
6767
}

app/echo.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ int32_t app_main(void)
5555
{
5656
pipe = mo_pipe_create(PIPE_CAP);
5757

58-
mo_task_spawn(task0, DEFAULT_STACK_SIZE);
59-
mo_task_spawn(task1, DEFAULT_STACK_SIZE);
58+
mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M);
59+
mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M);
6060

6161
/* preemptive mode */
6262
return 1;

app/hello.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ void task0(void)
3737

3838
int32_t app_main(void)
3939
{
40-
mo_task_spawn(task0, DEFAULT_STACK_SIZE);
41-
mo_task_spawn(task1, DEFAULT_STACK_SIZE);
42-
mo_task_spawn(task2, DEFAULT_STACK_SIZE);
40+
mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M);
41+
mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M);
42+
mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M);
4343

4444
mo_task_priority(2, TASK_PRIO_LOW);
4545

app/mqueues.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ int32_t app_main(void)
162162
/* Spawn all the tasks. The idle task (task 0) is typically spawned first
163163
* to ensure it's available when other tasks yield or block.
164164
*/
165-
mo_task_spawn(idle, DEFAULT_STACK_SIZE);
166-
mo_task_spawn(task1, DEFAULT_STACK_SIZE);
167-
mo_task_spawn(task2, DEFAULT_STACK_SIZE);
168-
mo_task_spawn(task3, DEFAULT_STACK_SIZE);
169-
mo_task_spawn(task4, DEFAULT_STACK_SIZE);
165+
mo_task_spawn(idle, DEFAULT_STACK_SIZE, TASK_MODE_M);
166+
mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M);
167+
mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M);
168+
mo_task_spawn(task3, DEFAULT_STACK_SIZE, TASK_MODE_M);
169+
mo_task_spawn(task4, DEFAULT_STACK_SIZE, TASK_MODE_M);
170170

171171
/* Create the message queues with a capacity of 8 items each. */
172172
mq1 = mo_mq_create(8); /* Queue for signaling task1. */

app/mutex.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,10 @@ int32_t app_main(void)
191191
printf("Binary semaphore created successfully\n");
192192

193193
/* Create tasks */
194-
int32_t task_a_id = mo_task_spawn(task_a, 1024);
195-
int32_t task_b_id = mo_task_spawn(task_b, 1024);
196-
int32_t monitor_id = mo_task_spawn(monitor_task, 1024);
197-
int32_t idle_id = mo_task_spawn(idle_task, 512);
194+
int32_t task_a_id = mo_task_spawn(task_a, 1024, TASK_MODE_M);
195+
int32_t task_b_id = mo_task_spawn(task_b, 1024, TASK_MODE_M);
196+
int32_t monitor_id = mo_task_spawn(monitor_task, 1024, TASK_MODE_M);
197+
int32_t idle_id = mo_task_spawn(idle_task, 512, TASK_MODE_M);
198198

199199
if (task_a_id < 0 || task_b_id < 0 || monitor_id < 0 || idle_id < 0) {
200200
printf("FATAL: Failed to create tasks\n");

app/pipes.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ void task0(void)
5757

5858
int32_t app_main(void)
5959
{
60-
mo_task_spawn(task0, DEFAULT_STACK_SIZE);
61-
mo_task_spawn(task1, DEFAULT_STACK_SIZE);
62-
mo_task_spawn(task2, DEFAULT_STACK_SIZE);
63-
mo_task_spawn(task3, DEFAULT_STACK_SIZE);
60+
mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M);
61+
mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M);
62+
mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M);
63+
mo_task_spawn(task3, DEFAULT_STACK_SIZE, TASK_MODE_M);
6464

6565
pipe1 = mo_pipe_create(
6666
128); /* pipe buffer, 128 bytes (allocated on the heap) */

0 commit comments

Comments
 (0)