From 1710f76d0f13550b909fce3b2560e341296af784 Mon Sep 17 00:00:00 2001 From: HeatCrab Date: Tue, 27 Jan 2026 16:26:27 +0800 Subject: [PATCH] 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. --- Documentation/hal-calling-convention.md | 6 +++--- Makefile | 14 +++++++++++++- app/cond.c | 8 ++++---- app/coop.c | 6 +++--- app/cpubench.c | 2 +- app/echo.c | 4 ++-- app/hello.c | 6 +++--- app/mqueues.c | 10 +++++----- app/mutex.c | 8 ++++---- app/pipes.c | 8 ++++---- app/pipes_small.c | 6 +++--- app/pipes_struct.c | 4 ++-- app/prodcons.c | 6 +++--- app/progress.c | 4 ++-- app/rtsched.c | 13 +++++++------ app/suspend.c | 6 +++--- app/test64.c | 2 +- app/timer.c | 2 +- app/timer_kill.c | 8 ++++---- app/umode.c | 7 +++---- arch/riscv/build.mk | 5 +++++ include/sys/task.h | 22 +++++++++------------- kernel/logger.c | 2 +- kernel/main.c | 25 ++++++++++++++++++++++++- kernel/syscall.c | 3 ++- kernel/task.c | 18 ++++-------------- 26 files changed, 116 insertions(+), 89 deletions(-) diff --git a/Documentation/hal-calling-convention.md b/Documentation/hal-calling-convention.md index 6df5017f..00d68a52 100644 --- a/Documentation/hal-calling-convention.md +++ b/Documentation/hal-calling-convention.md @@ -141,9 +141,9 @@ This "red zone" is reserved at the top of every task stack to guarantee ISR safe Standard RISC-V calling convention applies: ```c -/* Example: mo_task_spawn(entry, stack_size) */ -/* a0 = entry, a1 = stack_size, return value in a0 */ -int32_t result = mo_task_spawn(task_function, 2048); +/* Example: mo_task_spawn(entry, stack_size, mode) */ +/* a0 = entry, a1 = stack_size, a2 = mode, return value in a0 */ +int32_t result = mo_task_spawn(task_function, 2048, TASK_MODE_M); ``` ### System Call Interface diff --git a/Makefile b/Makefile index 4bb9103c..a4bf6da1 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,17 @@ BUILD_APP_DIR := $(BUILD_DIR)/app BUILD_KERNEL_DIR := $(BUILD_DIR)/kernel BUILD_LIB_DIR := $(BUILD_DIR)/lib +# Apps requiring M-mode (kernel API tests) +# All other apps run in U-mode by default (secure) +MMODE_APPS := cond coop cpubench echo hello mqueues mutex \ + pipes pipes_small pipes_struct prodcons progress \ + rtsched semaphore suspend test64 test_libc timer timer_kill + +# Auto-detect: if building an M-mode app, enable CONFIG_PRIVILEGED +ifneq ($(filter $(MAKECMDGOALS),$(MMODE_APPS)),) +CONFIG_PRIVILEGED := 1 +endif + include mk/common.mk # architecture-specific settings include arch/$(ARCH)/build.mk @@ -97,7 +108,8 @@ $(BUILD_DIR)/code.txt: $(IMAGE_BASE).bin # Utility targets rebuild: - $(Q)find '$(BUILD_APP_DIR)' -type f -name '*.o' -delete 2>/dev/null || true + $(Q)find '$(BUILD_APP_DIR)' '$(BUILD_KERNEL_DIR)' -type f -name '*.o' -delete 2>/dev/null || true + $(Q)rm -f '$(BUILD_DIR)/liblinmo.a' 2>/dev/null || true $(Q)mkdir -p $(BUILD_APP_DIR) $(BUILD_KERNEL_DIR) $(BUILD_LIB_DIR) clean: diff --git a/app/cond.c b/app/cond.c index ace81ef0..7b63f997 100644 --- a/app/cond.c +++ b/app/cond.c @@ -110,10 +110,10 @@ int32_t app_main(void) mo_mutex_init(&m); mo_cond_init(&cv); - mo_task_spawn(producer, DEFAULT_STACK_SIZE); - mo_task_spawn(consumer, DEFAULT_STACK_SIZE); - mo_task_spawn(mutex_tester, DEFAULT_STACK_SIZE); - mo_task_spawn(idle_task, DEFAULT_STACK_SIZE); + mo_task_spawn(producer, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(consumer, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(mutex_tester, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(idle_task, DEFAULT_STACK_SIZE, TASK_MODE_M); /* preemptive mode */ return 1; diff --git a/app/coop.c b/app/coop.c index 7921d82c..c1f8b8ce 100644 --- a/app/coop.c +++ b/app/coop.c @@ -34,9 +34,9 @@ void task0(void) int32_t app_main(void) { - mo_task_spawn(task0, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); - mo_task_spawn(task2, DEFAULT_STACK_SIZE); + mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M); /* cooperative mode */ return 0; diff --git a/app/cpubench.c b/app/cpubench.c index 6330d7e5..83342261 100644 --- a/app/cpubench.c +++ b/app/cpubench.c @@ -62,6 +62,6 @@ int32_t app_main(void) printf("Result: a=%d, b=%d, c=%d\n", a, b, c); printf("Elapsed time: %lu.%03lus\n", elapsed / 1000, elapsed % 1000); - mo_task_spawn(idle, DEFAULT_STACK_SIZE); + mo_task_spawn(idle, DEFAULT_STACK_SIZE, TASK_MODE_M); return 1; } diff --git a/app/echo.c b/app/echo.c index e5e9db9a..9d1aa50e 100644 --- a/app/echo.c +++ b/app/echo.c @@ -55,8 +55,8 @@ int32_t app_main(void) { pipe = mo_pipe_create(PIPE_CAP); - mo_task_spawn(task0, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); + mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); /* preemptive mode */ return 1; diff --git a/app/hello.c b/app/hello.c index d6e785be..7739b9d3 100644 --- a/app/hello.c +++ b/app/hello.c @@ -37,9 +37,9 @@ void task0(void) int32_t app_main(void) { - mo_task_spawn(task0, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); - mo_task_spawn(task2, DEFAULT_STACK_SIZE); + mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M); mo_task_priority(2, TASK_PRIO_LOW); diff --git a/app/mqueues.c b/app/mqueues.c index 5816a1ce..5dea26e4 100644 --- a/app/mqueues.c +++ b/app/mqueues.c @@ -162,11 +162,11 @@ int32_t app_main(void) /* Spawn all the tasks. The idle task (task 0) is typically spawned first * to ensure it's available when other tasks yield or block. */ - mo_task_spawn(idle, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); - mo_task_spawn(task2, DEFAULT_STACK_SIZE); - mo_task_spawn(task3, DEFAULT_STACK_SIZE); - mo_task_spawn(task4, DEFAULT_STACK_SIZE); + mo_task_spawn(idle, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task3, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task4, DEFAULT_STACK_SIZE, TASK_MODE_M); /* Create the message queues with a capacity of 8 items each. */ mq1 = mo_mq_create(8); /* Queue for signaling task1. */ diff --git a/app/mutex.c b/app/mutex.c index c332687d..6550027e 100644 --- a/app/mutex.c +++ b/app/mutex.c @@ -191,10 +191,10 @@ int32_t app_main(void) printf("Binary semaphore created successfully\n"); /* Create tasks */ - int32_t task_a_id = mo_task_spawn(task_a, 1024); - int32_t task_b_id = mo_task_spawn(task_b, 1024); - int32_t monitor_id = mo_task_spawn(monitor_task, 1024); - int32_t idle_id = mo_task_spawn(idle_task, 512); + int32_t task_a_id = mo_task_spawn(task_a, 1024, TASK_MODE_M); + int32_t task_b_id = mo_task_spawn(task_b, 1024, TASK_MODE_M); + int32_t monitor_id = mo_task_spawn(monitor_task, 1024, TASK_MODE_M); + int32_t idle_id = mo_task_spawn(idle_task, 512, TASK_MODE_M); if (task_a_id < 0 || task_b_id < 0 || monitor_id < 0 || idle_id < 0) { printf("FATAL: Failed to create tasks\n"); diff --git a/app/pipes.c b/app/pipes.c index 242bda9b..3bd35eb7 100644 --- a/app/pipes.c +++ b/app/pipes.c @@ -57,10 +57,10 @@ void task0(void) int32_t app_main(void) { - mo_task_spawn(task0, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); - mo_task_spawn(task2, DEFAULT_STACK_SIZE); - mo_task_spawn(task3, DEFAULT_STACK_SIZE); + mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task3, DEFAULT_STACK_SIZE, TASK_MODE_M); pipe1 = mo_pipe_create( 128); /* pipe buffer, 128 bytes (allocated on the heap) */ diff --git a/app/pipes_small.c b/app/pipes_small.c index a8cdea70..512829e5 100644 --- a/app/pipes_small.c +++ b/app/pipes_small.c @@ -42,9 +42,9 @@ void task0(void) int32_t app_main(void) { - mo_task_spawn(task0, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); - mo_task_spawn(task2, DEFAULT_STACK_SIZE); + mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M); pipe1 = mo_pipe_create( 64); /* pipe buffer, 64 bytes (allocated from the heap) */ diff --git a/app/pipes_struct.c b/app/pipes_struct.c index 645ae91f..5d04ee15 100644 --- a/app/pipes_struct.c +++ b/app/pipes_struct.c @@ -44,8 +44,8 @@ void task0(void) int32_t app_main(void) { - mo_task_spawn(task0, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); + mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); pipe1 = mo_pipe_create(64); /* pipe buffer, 64 bytes */ diff --git a/app/prodcons.c b/app/prodcons.c index f590b95a..3a8bd946 100644 --- a/app/prodcons.c +++ b/app/prodcons.c @@ -38,9 +38,9 @@ static void consumer(void) int32_t app_main(void) { - mo_task_spawn(producer, DEFAULT_STACK_SIZE); - mo_task_spawn(consumer, DEFAULT_STACK_SIZE); - mo_task_spawn(consumer, DEFAULT_STACK_SIZE); + mo_task_spawn(producer, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(consumer, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(consumer, DEFAULT_STACK_SIZE, TASK_MODE_M); empty = mo_sem_create(3, N); full = mo_sem_create(3, 0); diff --git a/app/progress.c b/app/progress.c index 57ea1775..9565eeff 100644 --- a/app/progress.c +++ b/app/progress.c @@ -36,9 +36,9 @@ int32_t app_main(void) int32_t i; for (i = 0; i < N_TASKS; i++) - mo_task_spawn(task, DEFAULT_STACK_SIZE); + mo_task_spawn(task, DEFAULT_STACK_SIZE, TASK_MODE_M); // add logger task - mo_task_spawn(logger, DEFAULT_STACK_SIZE); + mo_task_spawn(logger, DEFAULT_STACK_SIZE, TASK_MODE_M); /* preemptive mode */ return 1; diff --git a/app/rtsched.c b/app/rtsched.c index 56402814..25c8c7f1 100644 --- a/app/rtsched.c +++ b/app/rtsched.c @@ -452,17 +452,18 @@ int32_t app_main(void) /* test_start_time will be initialized by first task that runs */ /* Spawn all 5 RT/background tasks first */ - int32_t tid0 = mo_task_spawn(task0, DEFAULT_STACK_SIZE); - int32_t tid1 = mo_task_spawn(task1, DEFAULT_STACK_SIZE); - int32_t tid2 = mo_task_spawn(task2, DEFAULT_STACK_SIZE); - (void) mo_task_spawn(task3, DEFAULT_STACK_SIZE); /* Non-RT task 3 */ + int32_t tid0 = mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + int32_t tid1 = mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); + int32_t tid2 = mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M); + (void) mo_task_spawn(task3, DEFAULT_STACK_SIZE, + TASK_MODE_M); /* Non-RT task 3 */ /* Non-RT task 4 - displays stats */ - (void) mo_task_spawn(task4, DEFAULT_STACK_SIZE); + (void) mo_task_spawn(task4, DEFAULT_STACK_SIZE, TASK_MODE_M); /* Spawn IDLE task LAST so it's at end of round-robin list. * This ensures other ready tasks get scheduled before IDLE. */ - (void) mo_task_spawn(idle_task, DEFAULT_STACK_SIZE); + (void) mo_task_spawn(idle_task, DEFAULT_STACK_SIZE, TASK_MODE_M); /* Configure EDF priorities for RT tasks 0-2 with deadlines relative to * current time */ diff --git a/app/suspend.c b/app/suspend.c index 653ef68f..6153bcd4 100644 --- a/app/suspend.c +++ b/app/suspend.c @@ -54,9 +54,9 @@ void task0(void) int32_t app_main(void) { - mo_task_spawn(task0, DEFAULT_STACK_SIZE); - mo_task_spawn(task1, DEFAULT_STACK_SIZE); - mo_task_spawn(task2, DEFAULT_STACK_SIZE); + mo_task_spawn(task0, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task1, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(task2, DEFAULT_STACK_SIZE, TASK_MODE_M); /* preemptive mode */ return 1; diff --git a/app/test64.c b/app/test64.c index 6ed98aa8..9c6d4b3b 100644 --- a/app/test64.c +++ b/app/test64.c @@ -86,7 +86,7 @@ void task(void) int32_t app_main() { - mo_task_spawn(task, DEFAULT_STACK_SIZE); + mo_task_spawn(task, DEFAULT_STACK_SIZE, TASK_MODE_M); return 1; } diff --git a/app/timer.c b/app/timer.c index 19f53466..9db0e520 100644 --- a/app/timer.c +++ b/app/timer.c @@ -63,7 +63,7 @@ int32_t app_main(void) mo_timer_start(0x6002, TIMER_AUTORELOAD); /* Spawn a single idle task to keep the kernel running. */ - mo_task_spawn(idle_task, DEFAULT_STACK_SIZE); + mo_task_spawn(idle_task, DEFAULT_STACK_SIZE, TASK_MODE_M); /* preemptive mode */ return 1; diff --git a/app/timer_kill.c b/app/timer_kill.c index 3ab3c837..c1f9c82e 100644 --- a/app/timer_kill.c +++ b/app/timer_kill.c @@ -38,10 +38,10 @@ void idle(void) int32_t app_main(void) { - mo_task_spawn(timer1, DEFAULT_STACK_SIZE); - mo_task_spawn(timer2, DEFAULT_STACK_SIZE); - mo_task_spawn(timer3, DEFAULT_STACK_SIZE); - mo_task_spawn(idle, DEFAULT_STACK_SIZE); + mo_task_spawn(timer1, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(timer2, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(timer3, DEFAULT_STACK_SIZE, TASK_MODE_M); + mo_task_spawn(idle, DEFAULT_STACK_SIZE, TASK_MODE_M); /* preemptive mode */ return 1; diff --git a/app/umode.c b/app/umode.c index 518e111d..7b7c54d4 100644 --- a/app/umode.c +++ b/app/umode.c @@ -64,11 +64,10 @@ int32_t app_main(void) { umode_printf("[Kernel] Spawning U-mode validation task...\n"); - /* app_main is called from kernel context during bootstrap. - * Use mo_task_spawn_user to create the validation task in user mode. - * This ensures privilege isolation is properly tested. + /* app_main now runs in U-mode by default. + * Use sys_tadd syscall to create additional U-mode tasks. */ - mo_task_spawn_user(umode_validation_task, DEFAULT_STACK_SIZE); + sys_tadd(umode_validation_task, DEFAULT_STACK_SIZE); /* Return 1 to enable preemptive scheduler */ return 1; diff --git a/arch/riscv/build.mk b/arch/riscv/build.mk index 243a6ea2..a2cd1e7b 100644 --- a/arch/riscv/build.mk +++ b/arch/riscv/build.mk @@ -17,6 +17,11 @@ DEFINES := -DF_CPU=$(F_CLK) \ -DF_TIMER=$(F_TICK) \ -include config.h +# Privileged mode: app_main() runs in M-mode instead of default U-mode +ifdef CONFIG_PRIVILEGED +DEFINES += -DCONFIG_PRIVILEGED=1 +endif + CROSS_COMPILE ?= riscv-none-elf- # Detect LLVM/Clang toolchain diff --git a/include/sys/task.h b/include/sys/task.h index ccf5f4fa..4e030e69 100644 --- a/include/sys/task.h +++ b/include/sys/task.h @@ -44,6 +44,12 @@ enum task_states { TASK_SUSPENDED /* Task paused/excluded from scheduling until resumed */ }; +/* Task Privilege Mode */ +typedef enum { + TASK_MODE_M, /* Machine mode - full hardware access */ + TASK_MODE_U /* User mode - restricted, uses syscalls */ +} task_mode_t; + /* Priority Level Constants for Priority-Aware Time Slicing */ #define TASK_PRIORITY_LEVELS 8 /* Number of priority levels (0-7) */ #define TASK_HIGHEST_PRIORITY 0 /* Highest priority level */ @@ -187,24 +193,14 @@ void _yield(void); /* Task Lifecycle Management */ -/* Creates and starts a new task in machine mode. - * @task_entry : Pointer to the task's entry function (void func(void)) - * @stack_size : The desired stack size in bytes (minimum is enforced) - * - * Returns the new task's ID on success. Panics on memory allocation failure. - */ -int32_t mo_task_spawn(void *task_entry, uint16_t stack_size); - -/* Creates and starts a new task in user mode. - * User mode tasks run with reduced privileges and must use syscalls to access - * kernel services. This provides memory protection and privilege separation. - * +/* Creates and starts a new task. * @task_entry : Pointer to the task's entry function (void func(void)) * @stack_size : The desired stack size in bytes (minimum is enforced) + * @mode : Privilege mode (TASK_MODE_M or TASK_MODE_U) * * Returns the new task's ID on success. Panics on memory allocation failure. */ -int32_t mo_task_spawn_user(void *task_entry, uint16_t stack_size); +int32_t mo_task_spawn(void *task_entry, uint16_t stack_size, task_mode_t mode); /* Cancels and removes a task from the system. A task cannot cancel itself. * @id : The ID of the task to cancel diff --git a/kernel/logger.c b/kernel/logger.c index f2fe2733..cdb7a79b 100644 --- a/kernel/logger.c +++ b/kernel/logger.c @@ -82,7 +82,7 @@ int32_t mo_logger_init(void) return ERR_FAIL; /* 1024B stack: space for log_entry_t (130B) + ISR frame (128B) + calls */ - logger.task_id = mo_task_spawn(logger_task, 1024); + logger.task_id = mo_task_spawn(logger_task, 1024, TASK_MODE_M); if (logger.task_id < 0) { mo_mutex_destroy(&logger.lock); return ERR_FAIL; diff --git a/kernel/main.c b/kernel/main.c index 0015dca7..2b983187 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,10 +1,26 @@ #include #include #include +#include #include #include "private/error.h" +#ifndef CONFIG_PRIVILEGED +/* Wrapper to run app_main() in U-mode. + * + * In U-mode, the return value cannot control preemptive mode (kcb is + * inaccessible), so it's ignored. The infinite loop keeps the task alive + * after app_main() returns. + */ +static void app_main_wrapper(void) +{ + app_main(); + for (;;) + sys_tyield(); +} +#endif + /* C-level entry point for the kernel. * * This function is called from the boot code ('_entry'). It is responsible for @@ -42,8 +58,15 @@ int32_t main(void) printf("Logger initialized\n"); } - /* Call the application's main entry point to create initial tasks. */ +#ifdef CONFIG_PRIVILEGED + /* M-mode: app_main() controls preemptive mode via return value */ kcb->preemptive = (bool) app_main(); +#else + /* U-mode: preemptive mode fixed, app_main() runs as user task */ + kcb->preemptive = true; + mo_task_spawn(app_main_wrapper, DEFAULT_STACK_SIZE, TASK_MODE_U); +#endif + printf("Scheduler mode: %s\n", kcb->preemptive ? "Preemptive" : "Cooperative"); diff --git a/kernel/syscall.c b/kernel/syscall.c index 7be66632..af41f4c2 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -247,7 +247,8 @@ static int _tadd(void *task, int stack_size) if (unlikely(!task || stack_size <= 0)) return -EINVAL; - return mo_task_spawn(task, stack_size); + /* Syscall always creates U-mode tasks for security */ + return mo_task_spawn(task, stack_size, TASK_MODE_U); } int sys_tadd(void *task, int stack_size) diff --git a/kernel/task.c b/kernel/task.c index c9973e19..7c4fc4e8 100644 --- a/kernel/task.c +++ b/kernel/task.c @@ -712,10 +712,9 @@ static bool init_task_stack(tcb_t *tcb, size_t stack_size) /* Task Management API */ -/* Internal task spawning implementation with privilege mode control */ -static int32_t task_spawn_impl(void *task_entry, - uint16_t stack_size_req, - int user_mode) +int32_t mo_task_spawn(void *task_entry, + uint16_t stack_size_req, + task_mode_t mode) { if (!task_entry) panic(ERR_TCB_ALLOC); @@ -779,6 +778,7 @@ static int32_t task_spawn_impl(void *task_entry, CRITICAL_LEAVE(); /* Initialize execution context outside critical section. */ + int user_mode = (mode == TASK_MODE_U); hal_context_init(&tcb->context, (size_t) tcb->stack, new_stack_size, (size_t) task_entry, user_mode); @@ -799,16 +799,6 @@ static int32_t task_spawn_impl(void *task_entry, return tcb->id; } -int32_t mo_task_spawn(void *task_entry, uint16_t stack_size_req) -{ - return task_spawn_impl(task_entry, stack_size_req, false); -} - -int32_t mo_task_spawn_user(void *task_entry, uint16_t stack_size_req) -{ - return task_spawn_impl(task_entry, stack_size_req, true); -} - int32_t mo_task_cancel(uint16_t id) { if (id == 0 || id == mo_task_id())