Skip to content

Conversation

@HeatCrab
Copy link
Collaborator

@HeatCrab HeatCrab commented Jan 27, 2026

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.

Related to #53


Summary by cubic

Default the application entry to U-mode and unify task creation with a privilege mode parameter. This enforces syscall-only task creation from user space, keeps M-mode available via a build flag for kernel tests, and aligns with #53.

  • New Features

    • app_main now runs in U-mode by default; the kernel wraps it and enables preemptive scheduling. M-mode remains available via CONFIG_PRIVILEGED.
    • New API: mo_task_spawn(entry, stack_size, mode). sys_tadd always creates U-mode tasks to prevent escalation.
    • Build updates: Makefile auto-enables CONFIG_PRIVILEGED for specific test apps; RISC-V build exports the define.
    • Docs and sample apps updated for the new calling convention and API signature.
  • Migration

    • Add the mode argument to mo_task_spawn calls; replace mo_task_spawn_user with sys_tadd in user apps or mo_task_spawn(..., TASK_MODE_U) in kernel code.
    • If you rely on app_main’s return value to select scheduling mode, set CONFIG_PRIVILEGED=1; in U-mode it’s ignored and preemptive mode is always on.

Written for commit 1710f76. Summary will update on new commits.

@HeatCrab HeatCrab marked this pull request as draft January 27, 2026 08:33
@HeatCrab HeatCrab force-pushed the umode/configurable-privilege branch from 3baacae to 25da8b7 Compare January 27, 2026 08:39
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 26 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="Makefile">

<violation number="1" location="Makefile:19">
P1: Auto-enabling `CONFIG_PRIVILEGED` never invalidates existing kernel/lib objects, so switching between M-mode and U-mode apps reuses stale artifacts compiled in the wrong mode, causing the built binary to run with the wrong privilege level.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

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.
@HeatCrab HeatCrab force-pushed the umode/configurable-privilege branch from 25da8b7 to 1710f76 Compare January 27, 2026 08:46
@HeatCrab HeatCrab marked this pull request as ready for review January 27, 2026 08:51
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 26 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="kernel/main.c">

<violation number="1" location="kernel/main.c:67">
P2: Spawning the wrapper in U-mode makes `kcb->task_current` non-NULL before app_main creates any tasks, so the later ERR_NO_TASKS check can no longer detect when app_main failed to spawn tasks. This can leave the system running only the wrapper’s yield loop instead of panicking as intended. Consider tracking task_count before/after app_main (or requiring at least one additional task) in the U-mode path.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

#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);
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Spawning the wrapper in U-mode makes kcb->task_current non-NULL before app_main creates any tasks, so the later ERR_NO_TASKS check can no longer detect when app_main failed to spawn tasks. This can leave the system running only the wrapper’s yield loop instead of panicking as intended. Consider tracking task_count before/after app_main (or requiring at least one additional task) in the U-mode path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At kernel/main.c, line 67:

<comment>Spawning the wrapper in U-mode makes `kcb->task_current` non-NULL before app_main creates any tasks, so the later ERR_NO_TASKS check can no longer detect when app_main failed to spawn tasks. This can leave the system running only the wrapper’s yield loop instead of panicking as intended. Consider tracking task_count before/after app_main (or requiring at least one additional task) in the U-mode path.</comment>

<file context>
@@ -42,8 +58,15 @@ int32_t main(void)
+#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
+
</file context>
Fix with Cubic

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In U-mode, app_main() runs as a user task itself via wrapper. The wrapper is the application. If app_main() doesn't create additional tasks, the system has one valid task running.

This differs from M-mode semantics by design:

  • M-mode: app_main() is a bootstrapper that creates tasks and returns
  • U-mode: app_main() is the application entry point running in user space

The ERR_NO_TASKS check ensures there's at least one schedulable task, which is satisfied by the wrapper.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

@jserv jserv merged commit b611b64 into sysprog21:main Jan 27, 2026
7 checks passed
@jserv
Copy link
Contributor

jserv commented Jan 27, 2026

Thank @HeatCrab for contributing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants