Added privilidges
This commit is contained in:
80
commands.c
80
commands.c
@@ -39,6 +39,7 @@ static void cmd_ps(BootInfo *Boot, CHAR16 *Args);
|
|||||||
static void cmd_spawn(BootInfo *Boot, CHAR16 *Args);
|
static void cmd_spawn(BootInfo *Boot, CHAR16 *Args);
|
||||||
static void cmd_memtest(BootInfo *Boot, CHAR16 *Args);
|
static void cmd_memtest(BootInfo *Boot, CHAR16 *Args);
|
||||||
static void cmd_tasktest(BootInfo *Boot, CHAR16 *Args);
|
static void cmd_tasktest(BootInfo *Boot, CHAR16 *Args);
|
||||||
|
static void cmd_kusr(BootInfo *Boot, CHAR16 *Args);
|
||||||
|
|
||||||
/* Small helper struct used to pass arguments into per-command tasks. */
|
/* Small helper struct used to pass arguments into per-command tasks. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -75,48 +76,56 @@ static Command commands[] = {
|
|||||||
L"shutdown",
|
L"shutdown",
|
||||||
L"Shutdown the system",
|
L"Shutdown the system",
|
||||||
L"Usage: shutdown\n\r Initiates a system shutdown using UEFI runtime services.",
|
L"Usage: shutdown\n\r Initiates a system shutdown using UEFI runtime services.",
|
||||||
|
TASK_PRIV_KERNEL,
|
||||||
cmd_shutdown
|
cmd_shutdown
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"help",
|
L"help",
|
||||||
L"Display available commands",
|
L"Display available commands",
|
||||||
L"Usage: help\n\r Lists all available commands with brief descriptions.",
|
L"Usage: help\n\r Lists all available commands with brief descriptions.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_help
|
cmd_help
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"man",
|
L"man",
|
||||||
L"Display manual page for a command",
|
L"Display manual page for a command",
|
||||||
L"Usage: man <command>\n\r Shows detailed help for the specified command.",
|
L"Usage: man <command>\n\r Shows detailed help for the specified command.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_man
|
cmd_man
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"clear",
|
L"clear",
|
||||||
L"Clear the screen",
|
L"Clear the screen",
|
||||||
L"Usage: clear\n\r Clears the console screen.",
|
L"Usage: clear\n\r Clears the console screen.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_clear
|
cmd_clear
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"about",
|
L"about",
|
||||||
L"Display system information",
|
L"Display system information",
|
||||||
L"Usage: about\n\r Shows information about this operating system.",
|
L"Usage: about\n\r Shows information about this operating system.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_about
|
cmd_about
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"mem",
|
L"mem",
|
||||||
L"Display memory statistics",
|
L"Display memory statistics",
|
||||||
L"Usage: mem\n\r Shows physical memory, heap, and paging information.",
|
L"Usage: mem\n\r Shows physical memory, heap, and paging information.",
|
||||||
|
TASK_PRIV_KERNEL,
|
||||||
cmd_mem
|
cmd_mem
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"ps",
|
L"ps",
|
||||||
L"List running tasks",
|
L"List running tasks",
|
||||||
L"Usage: ps\n\r Displays all active tasks with PID, state, and name.",
|
L"Usage: ps\n\r Displays all active tasks with PID, state, and name.",
|
||||||
|
TASK_PRIV_DRIVER,
|
||||||
cmd_ps
|
cmd_ps
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"spawn",
|
L"spawn",
|
||||||
L"Spawn a demo background task",
|
L"Spawn a demo background task",
|
||||||
L"Usage: spawn [name]\n\r Creates a cooperative demo task.\n\r Optional argument sets the task name.",
|
L"Usage: spawn [name]\n\r Creates a cooperative demo task.\n\r Optional argument sets the task name.",
|
||||||
|
TASK_PRIV_DRIVER,
|
||||||
cmd_spawn
|
cmd_spawn
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -128,6 +137,7 @@ static Command commands[] = {
|
|||||||
L" 2) Heap free and coalescing verification via kfree()\n\r"
|
L" 2) Heap free and coalescing verification via kfree()\n\r"
|
||||||
L" 3) Single-page PMM allocate/free via pmm_alloc_page()/pmm_free_page()\n\r"
|
L" 3) Single-page PMM allocate/free via pmm_alloc_page()/pmm_free_page()\n\r"
|
||||||
L" 4) Multi-page (4-page) PMM allocate/free via pmm_alloc_pages()/pmm_free_pages()\n\r",
|
L" 4) Multi-page (4-page) PMM allocate/free via pmm_alloc_pages()/pmm_free_pages()\n\r",
|
||||||
|
TASK_PRIV_KERNEL,
|
||||||
cmd_memtest
|
cmd_memtest
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -138,9 +148,19 @@ static Command commands[] = {
|
|||||||
L" each printing three progress steps and yielding between them.\n\r"
|
L" each printing three progress steps and yielding between them.\n\r"
|
||||||
L" After the workers finish, prints the final task list to\n\r"
|
L" After the workers finish, prints the final task list to\n\r"
|
||||||
L" demonstrate the cooperative round-robin scheduler.",
|
L" demonstrate the cooperative round-robin scheduler.",
|
||||||
|
TASK_PRIV_DRIVER,
|
||||||
cmd_tasktest
|
cmd_tasktest
|
||||||
},
|
},
|
||||||
{NULL, NULL, NULL, NULL} /* sentinel */
|
{
|
||||||
|
L"kusr",
|
||||||
|
L"Run a command with kernel privilege",
|
||||||
|
L"Usage: kusr <command> [args...]\n\r"
|
||||||
|
L" Temporarily elevates the current task to kernel privilege,\n\r"
|
||||||
|
L" executes the given command, then restores the original level.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
|
cmd_kusr
|
||||||
|
},
|
||||||
|
{NULL, NULL, NULL, 0, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
@@ -149,10 +169,19 @@ static Command commands[] = {
|
|||||||
|
|
||||||
static void request_shutdown(BootInfo *Boot)
|
static void request_shutdown(BootInfo *Boot)
|
||||||
{
|
{
|
||||||
|
Task *caller;
|
||||||
|
|
||||||
if (Boot == NULL) {
|
if (Boot == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: shutdown requires KERNEL. */
|
||||||
|
caller = task_current();
|
||||||
|
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_KERNEL) {
|
||||||
|
SAFE_PRINT(Boot, L"Permission denied: shutdown requires kernel privilege.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Boot->shutdown != NULL) {
|
if (Boot->shutdown != NULL) {
|
||||||
Boot->shutdown();
|
Boot->shutdown();
|
||||||
return;
|
return;
|
||||||
@@ -310,8 +339,16 @@ static void cmd_memtest(BootInfo *Boot, CHAR16 *Args)
|
|||||||
UINTN i;
|
UINTN i;
|
||||||
UINT64 page;
|
UINT64 page;
|
||||||
UINTN h_total, h_used, h_free, h_blocks;
|
UINTN h_total, h_used, h_free, h_blocks;
|
||||||
|
Task *caller;
|
||||||
(void)Args;
|
(void)Args;
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: memtest requires KERNEL. */
|
||||||
|
caller = task_current();
|
||||||
|
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_KERNEL) {
|
||||||
|
SAFE_PRINT(Boot, L"Permission denied: memtest requires kernel privilege.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L"\n\r");
|
SAFE_PRINT(Boot, L"\n\r");
|
||||||
SAFE_PRINT(Boot, L"Memory Test\n\r");
|
SAFE_PRINT(Boot, L"Memory Test\n\r");
|
||||||
SAFE_PRINT(Boot, L"================================================\n\r");
|
SAFE_PRINT(Boot, L"================================================\n\r");
|
||||||
@@ -434,6 +471,40 @@ static void cmd_tasktest(BootInfo *Boot, CHAR16 *Args)
|
|||||||
SAFE_PRINT(Boot, L"Task scheduler test completed.\n\r\n\r");
|
SAFE_PRINT(Boot, L"Task scheduler test completed.\n\r\n\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* kusr – run a command with escalated privilege
|
||||||
|
* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void cmd_kusr(BootInfo *Boot, CHAR16 *Args)
|
||||||
|
{
|
||||||
|
Task *self;
|
||||||
|
TaskPrivilege saved_priv;
|
||||||
|
|
||||||
|
if (Args == NULL || Args[0] == L'\0') {
|
||||||
|
SAFE_PRINT(Boot, L"Usage: kusr <command> [args...]\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self = task_current();
|
||||||
|
if (self == NULL) {
|
||||||
|
SAFE_PRINT(Boot, L"kusr: no task context available.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Elevate, dispatch, restore. */
|
||||||
|
saved_priv = task_get_privilege(self);
|
||||||
|
task_set_privilege(self, TASK_PRIV_KERNEL);
|
||||||
|
|
||||||
|
{
|
||||||
|
Task *cmd_task = execute_command(Boot, Args, TASK_PRIV_KERNEL);
|
||||||
|
if (cmd_task != NULL) {
|
||||||
|
task_wait(cmd_task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task_set_privilege(self, saved_priv);
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
* Public API
|
* Public API
|
||||||
* ================================================================ */
|
* ================================================================ */
|
||||||
@@ -490,7 +561,7 @@ void show_help(BootInfo *Boot)
|
|||||||
* - Pointer to the spawned Task for the command, or NULL if the
|
* - Pointer to the spawned Task for the command, or NULL if the
|
||||||
* command was not found or had to run synchronously.
|
* command was not found or had to run synchronously.
|
||||||
*/
|
*/
|
||||||
Task *execute_command(BootInfo *Boot, CHAR16 *Input)
|
Task *execute_command(BootInfo *Boot, CHAR16 *Input, TaskPrivilege caller_priv)
|
||||||
{
|
{
|
||||||
CHAR16 *cmd_start = NULL;
|
CHAR16 *cmd_start = NULL;
|
||||||
CHAR16 *args_start = NULL;
|
CHAR16 *args_start = NULL;
|
||||||
@@ -543,7 +614,10 @@ Task *execute_command(BootInfo *Boot, CHAR16 *Input)
|
|||||||
ctx->handler = commands[i].handler;
|
ctx->handler = commands[i].handler;
|
||||||
wstrcpy16_local(ctx->args, args_start, sizeof(ctx->args) / sizeof(ctx->args[0]));
|
wstrcpy16_local(ctx->args, args_start, sizeof(ctx->args) / sizeof(ctx->args[0]));
|
||||||
|
|
||||||
t = task_create(commands[i].name, command_task_entry, ctx);
|
t = task_create_with_priv(commands[i].name,
|
||||||
|
command_task_entry,
|
||||||
|
ctx,
|
||||||
|
caller_priv);
|
||||||
if (t == NULL) {
|
if (t == NULL) {
|
||||||
SAFE_PRINT(Boot, L"Failed to create task for command '%s'; running in core thread.\n\r",
|
SAFE_PRINT(Boot, L"Failed to create task for command '%s'; running in core thread.\n\r",
|
||||||
commands[i].name);
|
commands[i].name);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ typedef struct {
|
|||||||
const CHAR16 *name; /* command keyword (e.g. L"help") */
|
const CHAR16 *name; /* command keyword (e.g. L"help") */
|
||||||
const CHAR16 *description; /* one-line summary for `help` */
|
const CHAR16 *description; /* one-line summary for `help` */
|
||||||
const CHAR16 *usage; /* detailed text shown by `man` */
|
const CHAR16 *usage; /* detailed text shown by `man` */
|
||||||
|
TaskPrivilege min_priv; /* minimum privilege required */
|
||||||
CommandHandlerFn handler; /* function that executes the cmd */
|
CommandHandlerFn handler; /* function that executes the cmd */
|
||||||
} Command;
|
} Command;
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ typedef struct {
|
|||||||
* - Pointer to a Task representing the spawned command process,
|
* - Pointer to a Task representing the spawned command process,
|
||||||
* or NULL if the command was not found or ran synchronously.
|
* or NULL if the command was not found or ran synchronously.
|
||||||
*/
|
*/
|
||||||
Task *execute_command(BootInfo *Boot, CHAR16 *Input);
|
Task *execute_command(BootInfo *Boot, CHAR16 *Input, TaskPrivilege caller_priv);
|
||||||
|
|
||||||
/* Print a formatted list of all registered commands. */
|
/* Print a formatted list of all registered commands. */
|
||||||
void show_help(BootInfo *Boot);
|
void show_help(BootInfo *Boot);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
User interaction with the kernel is mediated by the **Starling Terminal** and a command registry implemented in `kernel.c` and `commands.c`.
|
User interaction with the kernel is mediated by the **Starling Terminal** and a command registry implemented in `kernel.c` and `commands.c`.
|
||||||
|
|
||||||
- The **Starling Terminal** is a task that runs a read–eval–print loop, reading keystrokes via `BootInfo` services and dispatching commands.
|
- The **Starling Terminal** is a task that runs a read–eval–print loop, reading keystrokes via `BootInfo` services and dispatching commands.
|
||||||
- The **command subsystem** maintains a table of commands, each with a name, description, usage string, and handler function.
|
- The **command subsystem** maintains a table of commands, each with a name, description, usage string, minimum privilege level, and handler function.
|
||||||
- Each command typically runs in its own task so that long-running work does not block the terminal.
|
- Each command typically runs in its own task so that long-running work does not block the terminal.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -23,6 +23,7 @@ static void starling_terminal_task(void *arg)
|
|||||||
CHAR16 line[128];
|
CHAR16 line[128];
|
||||||
UINTN len = 0;
|
UINTN len = 0;
|
||||||
UINTN depth = 0;
|
UINTN depth = 0;
|
||||||
|
TaskPrivilege shell_priv;
|
||||||
|
|
||||||
if (ctx == NULL || ctx->Boot == NULL) {
|
if (ctx == NULL || ctx->Boot == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -30,8 +31,10 @@ static void starling_terminal_task(void *arg)
|
|||||||
|
|
||||||
Boot = ctx->Boot;
|
Boot = ctx->Boot;
|
||||||
depth = ctx->depth;
|
depth = ctx->depth;
|
||||||
|
shell_priv = ctx->shell_priv;
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d] ready.\n\r\n\r", depth);
|
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d, priv %d] ready.\n\r\n\r",
|
||||||
|
depth, (INT32)shell_priv);
|
||||||
SAFE_PRINT(Boot, L"starling> ");
|
SAFE_PRINT(Boot, L"starling> ");
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
@@ -66,7 +69,7 @@ static void starling_terminal_task(void *arg)
|
|||||||
trim_spaces_inplace(line);
|
trim_spaces_inplace(line);
|
||||||
...
|
...
|
||||||
} else {
|
} else {
|
||||||
Task *cmd_task = execute_command(Boot, line);
|
Task *cmd_task = execute_command(Boot, line, shell_priv);
|
||||||
|
|
||||||
/* If a command task was spawned, wait for it to finish. */
|
/* If a command task was spawned, wait for it to finish. */
|
||||||
if (cmd_task != NULL) {
|
if (cmd_task != NULL) {
|
||||||
@@ -119,14 +122,19 @@ if (ctx == NULL) {
|
|||||||
StarlingContext inline_ctx;
|
StarlingContext inline_ctx;
|
||||||
inline_ctx.Boot = Boot;
|
inline_ctx.Boot = Boot;
|
||||||
inline_ctx.depth = 0;
|
inline_ctx.depth = 0;
|
||||||
|
inline_ctx.shell_priv = TASK_PRIV_USER;
|
||||||
starling_terminal_task(&inline_ctx);
|
starling_terminal_task(&inline_ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->Boot = Boot;
|
ctx->Boot = Boot;
|
||||||
ctx->depth = 0;
|
ctx->depth = 0;
|
||||||
|
ctx->shell_priv = TASK_PRIV_USER;
|
||||||
|
|
||||||
terminal_task = task_create(L"starling-term", starling_terminal_task, ctx);
|
terminal_task = task_create_with_priv(L"starling-term",
|
||||||
|
starling_terminal_task,
|
||||||
|
ctx,
|
||||||
|
TASK_PRIV_USER);
|
||||||
if (terminal_task == NULL) {
|
if (terminal_task == NULL) {
|
||||||
SAFE_PRINT(Boot, L"Failed to start Starling Terminal task; falling back to kernel loop.\n\r");
|
SAFE_PRINT(Boot, L"Failed to start Starling Terminal task; falling back to kernel loop.\n\r");
|
||||||
...
|
...
|
||||||
@@ -153,69 +161,88 @@ This ensures that:
|
|||||||
|
|
||||||
The command registry is defined in `commands.c` as a static array:
|
The command registry is defined in `commands.c` as a static array:
|
||||||
|
|
||||||
```73:144:/home/lochlan/Documents/Coding/c/os/commands.c
|
```73:164:/home/lochlan/Documents/Coding/c/os/commands.c
|
||||||
static Command commands[] = {
|
static Command commands[] = {
|
||||||
{
|
{
|
||||||
L"shutdown",
|
L"shutdown",
|
||||||
L"Shutdown the system",
|
L"Shutdown the system",
|
||||||
L"Usage: shutdown\n\r Initiates a system shutdown using UEFI runtime services.",
|
L"Usage: shutdown\n\r Initiates a system shutdown using UEFI runtime services.",
|
||||||
|
TASK_PRIV_KERNEL,
|
||||||
cmd_shutdown
|
cmd_shutdown
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"help",
|
L"help",
|
||||||
L"Display available commands",
|
L"Display available commands",
|
||||||
L"Usage: help\n\r Lists all available commands with brief descriptions.",
|
L"Usage: help\n\r Lists all available commands with brief descriptions.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_help
|
cmd_help
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"man",
|
L"man",
|
||||||
L"Display manual page for a command",
|
L"Display manual page for a command",
|
||||||
L"Usage: man <command>\n\r Shows detailed help for the specified command.",
|
L"Usage: man <command>\n\r Shows detailed help for the specified command.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_man
|
cmd_man
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"clear",
|
L"clear",
|
||||||
L"Clear the screen",
|
L"Clear the screen",
|
||||||
L"Usage: clear\n\r Clears the console screen.",
|
L"Usage: clear\n\r Clears the console screen.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_clear
|
cmd_clear
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"about",
|
L"about",
|
||||||
L"Display system information",
|
L"Display system information",
|
||||||
L"Usage: about\n\r Shows information about this operating system.",
|
L"Usage: about\n\r Shows information about this operating system.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
cmd_about
|
cmd_about
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"mem",
|
L"mem",
|
||||||
L"Display memory statistics",
|
L"Display memory statistics",
|
||||||
L"Usage: mem\n\r Shows physical memory, heap, and paging information.",
|
L"Usage: mem\n\r Shows physical memory, heap, and paging information.",
|
||||||
|
TASK_PRIV_KERNEL,
|
||||||
cmd_mem
|
cmd_mem
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"ps",
|
L"ps",
|
||||||
L"List running tasks",
|
L"List running tasks",
|
||||||
L"Usage: ps\n\r Displays all active tasks with PID, state, and name.",
|
L"Usage: ps\n\r Displays all active tasks with PID, state, and name.",
|
||||||
|
TASK_PRIV_DRIVER,
|
||||||
cmd_ps
|
cmd_ps
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"spawn",
|
L"spawn",
|
||||||
L"Spawn a demo background task",
|
L"Spawn a demo background task",
|
||||||
L"Usage: spawn [name]\n\r Creates a cooperative demo task.\n\r Optional argument sets the task name.",
|
L"Usage: spawn [name]\n\r Creates a cooperative demo task.\n\r Optional argument sets the task name.",
|
||||||
|
TASK_PRIV_DRIVER,
|
||||||
cmd_spawn
|
cmd_spawn
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"memtest",
|
L"memtest",
|
||||||
L"Test memory allocation and deallocation",
|
L"Test memory allocation and deallocation",
|
||||||
...
|
...
|
||||||
|
TASK_PRIV_KERNEL,
|
||||||
cmd_memtest
|
cmd_memtest
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
L"tasktest",
|
L"tasktest",
|
||||||
L"Test task scheduler with multiple tasks",
|
L"Test task scheduler with multiple tasks",
|
||||||
...
|
...
|
||||||
|
TASK_PRIV_DRIVER,
|
||||||
cmd_tasktest
|
cmd_tasktest
|
||||||
},
|
},
|
||||||
{NULL, NULL, NULL, NULL} /* sentinel */
|
{
|
||||||
|
L"kusr",
|
||||||
|
L"Run a command with kernel privilege",
|
||||||
|
L"Usage: kusr <command> [args...]\n\r"
|
||||||
|
L" Temporarily elevates the current task to kernel privilege,\n\r"
|
||||||
|
L" executes the given command, then restores the original level.",
|
||||||
|
TASK_PRIV_USER,
|
||||||
|
cmd_kusr
|
||||||
|
},
|
||||||
|
{NULL, NULL, NULL, 0, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -224,6 +251,7 @@ Each `Command` entry includes:
|
|||||||
- `name` – the token typed at the prompt.
|
- `name` – the token typed at the prompt.
|
||||||
- `description` – a short summary used by `help`.
|
- `description` – a short summary used by `help`.
|
||||||
- `usage` – a longer description and usage details for `man`.
|
- `usage` – a longer description and usage details for `man`.
|
||||||
|
- `min_priv` – the minimum `TaskPrivilege` required to run the command (see `task.h`).
|
||||||
- `handler` – a function of type:
|
- `handler` – a function of type:
|
||||||
|
|
||||||
```14:19:/home/lochlan/Documents/Coding/c/os/commands.h
|
```14:19:/home/lochlan/Documents/Coding/c/os/commands.h
|
||||||
@@ -246,7 +274,7 @@ To add a new command, follow the guide in the file header:
|
|||||||
The central function that processes a line of user input is `execute_command`:
|
The central function that processes a line of user input is `execute_command`:
|
||||||
|
|
||||||
```493:557:/home/lochlan/Documents/Coding/c/os/commands.c
|
```493:557:/home/lochlan/Documents/Coding/c/os/commands.c
|
||||||
Task *execute_command(BootInfo *Boot, CHAR16 *Input)
|
Task *execute_command(BootInfo *Boot, CHAR16 *Input, TaskPrivilege caller_priv)
|
||||||
{
|
{
|
||||||
CHAR16 *cmd_start = NULL;
|
CHAR16 *cmd_start = NULL;
|
||||||
CHAR16 *args_start = NULL;
|
CHAR16 *args_start = NULL;
|
||||||
@@ -299,7 +327,10 @@ Task *execute_command(BootInfo *Boot, CHAR16 *Input)
|
|||||||
ctx->handler = commands[i].handler;
|
ctx->handler = commands[i].handler;
|
||||||
wstrcpy16_local(ctx->args, args_start, sizeof(ctx->args) / sizeof(ctx->args[0]));
|
wstrcpy16_local(ctx->args, args_start, sizeof(ctx->args) / sizeof(ctx->args[0]));
|
||||||
|
|
||||||
t = task_create(commands[i].name, command_task_entry, ctx);
|
t = task_create_with_priv(commands[i].name,
|
||||||
|
command_task_entry,
|
||||||
|
ctx,
|
||||||
|
caller_priv);
|
||||||
if (t == NULL) {
|
if (t == NULL) {
|
||||||
SAFE_PRINT(Boot, L"Failed to create task for command '%s'; running in core thread.\n\r",
|
SAFE_PRINT(Boot, L"Failed to create task for command '%s'; running in core thread.\n\r",
|
||||||
commands[i].name);
|
commands[i].name);
|
||||||
@@ -336,10 +367,11 @@ Pipeline stages:
|
|||||||
- `Boot` pointer.
|
- `Boot` pointer.
|
||||||
- Handler function.
|
- Handler function.
|
||||||
- A bounded copy of the argument string.
|
- A bounded copy of the argument string.
|
||||||
- A new task is created via `task_create` with:
|
- A new task is created via `task_create_with_priv` with:
|
||||||
- Task name = command name.
|
- Task name = command name.
|
||||||
- Entry = `command_task_entry`.
|
- Entry = `command_task_entry`.
|
||||||
- Argument = pointer to the context.
|
- Argument = pointer to the context.
|
||||||
|
- Privilege = `caller_priv` (inherited from the calling shell).
|
||||||
- If task creation fails, the command handler is run synchronously in the current thread as a fallback.
|
- If task creation fails, the command handler is run synchronously in the current thread as a fallback.
|
||||||
|
|
||||||
The terminal then optionally `task_wait`s on the returned `Task *`, serialising command execution from the user's perspective while still letting the scheduler run other tasks (e.g., background demos).
|
The terminal then optionally `task_wait`s on the returned `Task *`, serialising command execution from the user's perspective while still letting the scheduler run other tasks (e.g., background demos).
|
||||||
@@ -396,19 +428,21 @@ This design gives each command:
|
|||||||
Some notable built-in handlers:
|
Some notable built-in handlers:
|
||||||
|
|
||||||
- **System control**:
|
- **System control**:
|
||||||
- `shutdown` → `cmd_shutdown` calls `Boot->shutdown` via `request_shutdown` to power off the machine.
|
- `shutdown` (KERNEL) → `cmd_shutdown` calls `Boot->shutdown` via `request_shutdown` to power off the machine. `request_shutdown` enforces kernel privilege.
|
||||||
- `clear` → `cmd_clear` uses `Boot->clear_screen` to wipe the console.
|
- `clear` (USER) → `cmd_clear` uses `Boot->clear_screen` to wipe the console.
|
||||||
- **Information and help**:
|
- **Information and help**:
|
||||||
- `help` → `cmd_help` calls `show_help` to print a formatted table of available commands.
|
- `help` (USER) → `cmd_help` calls `show_help` to print a formatted table of available commands.
|
||||||
- `man` → `cmd_man` prints the `usage` field for a specific command.
|
- `man` (USER) → `cmd_man` prints the `usage` field for a specific command.
|
||||||
- `about` → `cmd_about` prints OS information and feature list.
|
- `about` (USER) → `cmd_about` prints OS information and feature list.
|
||||||
- **Diagnostics**:
|
- **Diagnostics**:
|
||||||
- `mem` → `cmd_mem` calls `memory_print_stats` to show PMM and heap state.
|
- `mem` (KERNEL) → `cmd_mem` calls `memory_print_stats` to show PMM and heap state. The callee enforces kernel privilege.
|
||||||
- `ps` → `cmd_ps` calls `task_print_list` to show current tasks.
|
- `ps` (DRIVER) → `cmd_ps` calls `task_print_list` to show current tasks. The callee enforces driver privilege.
|
||||||
- `memtest` → `cmd_memtest` exercises heap and PMM allocations.
|
- `memtest` (KERNEL) → `cmd_memtest` exercises heap and PMM allocations. The handler enforces kernel privilege.
|
||||||
- `tasktest` → `cmd_tasktest` spawns multiple worker tasks to demonstrate cooperative scheduling.
|
- `tasktest` (DRIVER) → `cmd_tasktest` spawns multiple worker tasks to demonstrate cooperative scheduling.
|
||||||
- **Tasking demo**:
|
- **Tasking demo**:
|
||||||
- `spawn` → `cmd_spawn` creates a demonstration task using `demo_task_fn`, which yields in a loop and reports progress.
|
- `spawn` (DRIVER) → `cmd_spawn` creates a demonstration task using `demo_task_fn`, which yields in a loop and reports progress.
|
||||||
|
- **Privilege escalation**:
|
||||||
|
- `kusr` (USER) → `cmd_kusr` temporarily elevates the calling task to `TASK_PRIV_KERNEL`, dispatches the given sub-command, then restores the original privilege level.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
@@ -441,11 +475,12 @@ To add a new command `foo`:
|
|||||||
|
|
||||||
1. **Declare the handler** near the top of `commands.c`:
|
1. **Declare the handler** near the top of `commands.c`:
|
||||||
|
|
||||||
```32:41:/home/lochlan/Documents/Coding/c/os/commands.c
|
```32:42:/home/lochlan/Documents/Coding/c/os/commands.c
|
||||||
static void cmd_shutdown(BootInfo *Boot, CHAR16 *Args);
|
static void cmd_shutdown(BootInfo *Boot, CHAR16 *Args);
|
||||||
static void cmd_help(BootInfo *Boot, CHAR16 *Args);
|
static void cmd_help(BootInfo *Boot, CHAR16 *Args);
|
||||||
...
|
...
|
||||||
static void cmd_tasktest(BootInfo *Boot, CHAR16 *Args);
|
static void cmd_tasktest(BootInfo *Boot, CHAR16 *Args);
|
||||||
|
static void cmd_kusr(BootInfo *Boot, CHAR16 *Args);
|
||||||
/* Add: */
|
/* Add: */
|
||||||
static void cmd_foo(BootInfo *Boot, CHAR16 *Args);
|
static void cmd_foo(BootInfo *Boot, CHAR16 *Args);
|
||||||
```
|
```
|
||||||
@@ -465,13 +500,14 @@ Use this as a template for `cmd_foo`, replacing the body with your logic and usi
|
|||||||
|
|
||||||
3. **Register the command** in `commands[]` before the sentinel:
|
3. **Register the command** in `commands[]` before the sentinel:
|
||||||
|
|
||||||
```140:143:/home/lochlan/Documents/Coding/c/os/commands.c
|
```140:164:/home/lochlan/Documents/Coding/c/os/commands.c
|
||||||
{
|
{
|
||||||
L"tasktest",
|
L"kusr",
|
||||||
...
|
...
|
||||||
cmd_tasktest
|
TASK_PRIV_USER,
|
||||||
|
cmd_kusr
|
||||||
},
|
},
|
||||||
{NULL, NULL, NULL, NULL} /* sentinel */
|
{NULL, NULL, NULL, 0, NULL} /* sentinel */
|
||||||
```
|
```
|
||||||
|
|
||||||
Insert a new block above the sentinel:
|
Insert a new block above the sentinel:
|
||||||
@@ -481,6 +517,7 @@ Insert a new block above the sentinel:
|
|||||||
L"foo",
|
L"foo",
|
||||||
L"One-line description",
|
L"One-line description",
|
||||||
L"Usage: foo [args]\n\r Detailed explanation...",
|
L"Usage: foo [args]\n\r Detailed explanation...",
|
||||||
|
TASK_PRIV_USER, /* minimum privilege required */
|
||||||
cmd_foo
|
cmd_foo
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ This approach preserves any firmware-installed handlers for higher interrupt vec
|
|||||||
The IDT/ISR subsystem interacts with other parts of the kernel in the following ways:
|
The IDT/ISR subsystem interacts with other parts of the kernel in the following ways:
|
||||||
|
|
||||||
- **BootInfo access**:
|
- **BootInfo access**:
|
||||||
- `id_tinit` stores `Boot` in `gBoot` so that `isr_handler` can safely use `Boot->print` for diagnostics.
|
- `idt_init` stores `Boot` in `gBoot` so that `isr_handler` can safely use `Boot->print` for diagnostics.
|
||||||
- **Memory subsystem**:
|
- **Memory subsystem**:
|
||||||
- `isr_handler` reads CR2 for page faults; combined with `paging_get_phys` from `memory.c`, this can be used to inspect paging state.
|
- `isr_handler` reads CR2 for page faults; combined with `paging_get_phys` from `memory.c`, this can be used to inspect paging state.
|
||||||
- **Tasks and scheduler**:
|
- **Tasks and scheduler**:
|
||||||
|
|||||||
@@ -565,13 +565,21 @@ These statistics are surfaced to the user via the `mem` and `memtest` commands.
|
|||||||
|
|
||||||
## Runtime memory diagnostics (`mem` and `memtest`)
|
## Runtime memory diagnostics (`mem` and `memtest`)
|
||||||
|
|
||||||
The `mem` command (in `commands.c`) prints a snapshot of PMM and heap state by calling `memory_print_stats`:
|
The `mem` command (in `commands.c`) prints a snapshot of PMM and heap state by calling `memory_print_stats`. Access requires `TASK_PRIV_KERNEL`:
|
||||||
|
|
||||||
```525:562:/home/lochlan/Documents/Coding/c/os/memory.c
|
```525:572:/home/lochlan/Documents/Coding/c/os/memory.c
|
||||||
void memory_print_stats(BootInfo *Boot)
|
void memory_print_stats(BootInfo *Boot)
|
||||||
{
|
{
|
||||||
UINTN h_total, h_used, h_free, h_blocks;
|
UINTN h_total, h_used, h_free, h_blocks;
|
||||||
UINTN p_total, p_free, p_used;
|
UINTN p_total, p_free, p_used;
|
||||||
|
Task *caller;
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: memory stats require KERNEL. */
|
||||||
|
caller = task_current();
|
||||||
|
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_KERNEL) {
|
||||||
|
SAFE_PRINT(Boot, L"Permission denied: memory stats require kernel privilege.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
p_total = pmm_get_total_pages();
|
p_total = pmm_get_total_pages();
|
||||||
p_free = pmm_get_free_pages();
|
p_free = pmm_get_free_pages();
|
||||||
@@ -590,7 +598,7 @@ void memory_print_stats(BootInfo *Boot)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `memtest` command runs a scripted set of tests that exercise heap allocation, heap free/coalescing, and PMM single- and multi-page allocation:
|
The `memtest` command runs a scripted set of tests that exercise heap allocation, heap free/coalescing, and PMM single- and multi-page allocation. It also enforces `TASK_PRIV_KERNEL`:
|
||||||
|
|
||||||
```306:379:/home/lochlan/Documents/Coding/c/os/commands.c
|
```306:379:/home/lochlan/Documents/Coding/c/os/commands.c
|
||||||
static void cmd_memtest(BootInfo *Boot, CHAR16 *Args)
|
static void cmd_memtest(BootInfo *Boot, CHAR16 *Args)
|
||||||
@@ -600,8 +608,16 @@ static void cmd_memtest(BootInfo *Boot, CHAR16 *Args)
|
|||||||
UINTN i;
|
UINTN i;
|
||||||
UINT64 page;
|
UINT64 page;
|
||||||
UINTN h_total, h_used, h_free, h_blocks;
|
UINTN h_total, h_used, h_free, h_blocks;
|
||||||
|
Task *caller;
|
||||||
(void)Args;
|
(void)Args;
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: memtest requires KERNEL. */
|
||||||
|
caller = task_current();
|
||||||
|
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_KERNEL) {
|
||||||
|
SAFE_PRINT(Boot, L"Permission denied: memtest requires kernel privilege.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L"\n\r");
|
SAFE_PRINT(Boot, L"\n\r");
|
||||||
SAFE_PRINT(Boot, L"Memory Test\n\r");
|
SAFE_PRINT(Boot, L"Memory Test\n\r");
|
||||||
SAFE_PRINT(Boot, L"================================================\n\r");
|
SAFE_PRINT(Boot, L"================================================\n\r");
|
||||||
|
|||||||
@@ -157,7 +157,14 @@ void kmain(BootInfo *Boot)
|
|||||||
/* ---- Spawn Starling Terminal as its own task ---- */
|
/* ---- Spawn Starling Terminal as its own task ---- */
|
||||||
ctx = (StarlingContext *)kmalloc(sizeof(StarlingContext));
|
ctx = (StarlingContext *)kmalloc(sizeof(StarlingContext));
|
||||||
...
|
...
|
||||||
terminal_task = task_create(L"starling-term", starling_terminal_task, ctx);
|
ctx->Boot = Boot;
|
||||||
|
ctx->depth = 0;
|
||||||
|
ctx->shell_priv = TASK_PRIV_USER;
|
||||||
|
|
||||||
|
terminal_task = task_create_with_priv(L"starling-term",
|
||||||
|
starling_terminal_task,
|
||||||
|
ctx,
|
||||||
|
TASK_PRIV_USER);
|
||||||
if (terminal_task == NULL) {
|
if (terminal_task == NULL) {
|
||||||
...
|
...
|
||||||
starling_terminal_task(Boot);
|
starling_terminal_task(Boot);
|
||||||
@@ -180,7 +187,7 @@ void kmain(BootInfo *Boot)
|
|||||||
- `idt_init(Boot)` to install the kernel's Interrupt Descriptor Table and exception handlers.
|
- `idt_init(Boot)` to install the kernel's Interrupt Descriptor Table and exception handlers.
|
||||||
- `memory_init(Boot)` to bring up the physical allocator, paging helpers, and heap.
|
- `memory_init(Boot)` to bring up the physical allocator, paging helpers, and heap.
|
||||||
- `task_init(Boot)` to bootstrap the cooperative scheduler and register the current thread as task 0.
|
- `task_init(Boot)` to bootstrap the cooperative scheduler and register the current thread as task 0.
|
||||||
3. **User interface** – prints a banner and spawns the Starling Terminal as a separate task via `task_create`, then turns the core thread into an idle loop that continuously `task_yield`s to allow other tasks to run.
|
3. **User interface** – prints a banner and spawns the Starling Terminal as a separate task via `task_create_with_priv` with `TASK_PRIV_USER` privilege, then turns the core thread into an idle loop that continuously `task_yield`s to allow other tasks to run.
|
||||||
|
|
||||||
At this point, the system has:
|
At this point, the system has:
|
||||||
|
|
||||||
@@ -208,8 +215,10 @@ static void starling_terminal_task(void *arg)
|
|||||||
|
|
||||||
Boot = ctx->Boot;
|
Boot = ctx->Boot;
|
||||||
depth = ctx->depth;
|
depth = ctx->depth;
|
||||||
|
shell_priv = ctx->shell_priv;
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d] ready.\n\r\n\r", depth);
|
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d, priv %d] ready.\n\r\n\r",
|
||||||
|
depth, (INT32)shell_priv);
|
||||||
SAFE_PRINT(Boot, L"starling> ");
|
SAFE_PRINT(Boot, L"starling> ");
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
@@ -234,7 +243,7 @@ static void starling_terminal_task(void *arg)
|
|||||||
trim_spaces_inplace(line);
|
trim_spaces_inplace(line);
|
||||||
...
|
...
|
||||||
} else {
|
} else {
|
||||||
Task *cmd_task = execute_command(Boot, line);
|
Task *cmd_task = execute_command(Boot, line, shell_priv);
|
||||||
|
|
||||||
/* If a command task was spawned, wait for it to finish. */
|
/* If a command task was spawned, wait for it to finish. */
|
||||||
if (cmd_task != NULL) {
|
if (cmd_task != NULL) {
|
||||||
@@ -258,7 +267,7 @@ Key points:
|
|||||||
|
|
||||||
- **Non-blocking idle**: when `try_read_key` returns no key, the terminal calls `task_yield()` so other tasks can run while the user is idle.
|
- **Non-blocking idle**: when `try_read_key` returns no key, the terminal calls `task_yield()` so other tasks can run while the user is idle.
|
||||||
- **Line editing**: handles printable ASCII and backspace to maintain a simple line buffer (`line[128]`).
|
- **Line editing**: handles printable ASCII and backspace to maintain a simple line buffer (`line[128]`).
|
||||||
- **Command execution**: on Enter, the line is trimmed and passed to `execute_command(Boot, line)` in `commands.c`. If that function spawns a dedicated command task, the terminal waits for it via `task_wait`.
|
- **Command execution**: on Enter, the line is trimmed and passed to `execute_command(Boot, line, shell_priv)` in `commands.c`, propagating the shell's privilege level. If that function spawns a dedicated command task, the terminal waits for it via `task_wait`.
|
||||||
- **Nested terminals**: entering `starling` recursively spawns another Starling Terminal task with increased `depth`, demonstrating multi-level shells.
|
- **Nested terminals**: entering `starling` recursively spawns another Starling Terminal task with increased `depth`, demonstrating multi-level shells.
|
||||||
|
|
||||||
The command registry and dispatch path are documented in detail in `commands-and-terminal.md`.
|
The command registry and dispatch path are documented in detail in `commands-and-terminal.md`.
|
||||||
@@ -278,15 +287,17 @@ The kernel is organised into focused subsystems, each in its own translation uni
|
|||||||
- **Tasks and scheduler** (`task.c` + `task.h`):
|
- **Tasks and scheduler** (`task.c` + `task.h`):
|
||||||
- Static process control block (PCB) pool.
|
- Static process control block (PCB) pool.
|
||||||
- Cooperative round-robin scheduler.
|
- Cooperative round-robin scheduler.
|
||||||
|
- Software privilege levels (`TASK_PRIV_USER`, `TASK_PRIV_DRIVER`, `TASK_PRIV_KERNEL`) for access control.
|
||||||
- Stack management and context switch support (via an external `context_switch` assembly routine).
|
- Stack management and context switch support (via an external `context_switch` assembly routine).
|
||||||
- **Interrupts and exceptions** (`idt.c` + `idt.h`):
|
- **Interrupts and exceptions** (`idt.c` + `idt.h`):
|
||||||
- IDT mirroring of firmware entries.
|
- IDT mirroring of firmware entries.
|
||||||
- Replacement of CPU exception vectors 0–31 with kernel stubs.
|
- Replacement of CPU exception vectors 0–31 with kernel stubs.
|
||||||
- Central `isr_handler` that prints diagnostics and halts on unrecoverable faults.
|
- Central `isr_handler` that prints diagnostics and halts on unrecoverable faults.
|
||||||
- **Commands and shell** (`commands.c` + `commands.h`):
|
- **Commands and shell** (`commands.c` + `commands.h`):
|
||||||
- Command registry and help/man system.
|
- Command registry with per-command minimum privilege levels and help/man system.
|
||||||
- System control commands (`shutdown`, `about`, `mem`, `ps`).
|
- System control commands (`shutdown`, `about`, `mem`, `ps`).
|
||||||
- Test commands (`memtest`, `tasktest`, `spawn`) that exercise memory and scheduler subsystems in isolation.
|
- Test commands (`memtest`, `tasktest`, `spawn`) that exercise memory and scheduler subsystems in isolation.
|
||||||
|
- Privilege escalation command (`kusr`) for running commands with elevated privilege.
|
||||||
|
|
||||||
Each of these subsystems is covered in a dedicated document:
|
Each of these subsystems is covered in a dedicated document:
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ void task_init(BootInfo *Boot)
|
|||||||
for (i = 0; i < TASK_MAX; i++) {
|
for (i = 0; i < TASK_MAX; i++) {
|
||||||
tasks[i].state = TASK_STATE_FREE;
|
tasks[i].state = TASK_STATE_FREE;
|
||||||
tasks[i].pid = 0;
|
tasks[i].pid = 0;
|
||||||
|
tasks[i].privilege = TASK_PRIV_USER;
|
||||||
tasks[i].saved_rsp = 0;
|
tasks[i].saved_rsp = 0;
|
||||||
tasks[i].stack_base = 0;
|
tasks[i].stack_base = 0;
|
||||||
tasks[i].stack_pages = 0;
|
tasks[i].stack_pages = 0;
|
||||||
@@ -53,6 +54,7 @@ void task_init(BootInfo *Boot)
|
|||||||
*/
|
*/
|
||||||
tasks[0].pid = next_pid++;
|
tasks[0].pid = next_pid++;
|
||||||
tasks[0].state = TASK_STATE_RUNNING;
|
tasks[0].state = TASK_STATE_RUNNING;
|
||||||
|
tasks[0].privilege = TASK_PRIV_KERNEL;
|
||||||
tasks[0].switches = 1;
|
tasks[0].switches = 1;
|
||||||
wstrcpy16(tasks[0].name, L"core", TASK_NAME_LEN);
|
wstrcpy16(tasks[0].name, L"core", TASK_NAME_LEN);
|
||||||
|
|
||||||
@@ -66,22 +68,26 @@ void task_init(BootInfo *Boot)
|
|||||||
|
|
||||||
Important points:
|
Important points:
|
||||||
|
|
||||||
- Task 0 represents the **kernel core thread**, which uses the boot-time stack provided by the loader.
|
- Task 0 represents the **kernel core thread**, which uses the boot-time stack provided by the loader. It receives `TASK_PRIV_KERNEL` privilege.
|
||||||
- No stack is allocated for task 0; its `saved_rsp` is populated the first time a context switch occurs.
|
- No stack is allocated for task 0; its `saved_rsp` is populated the first time a context switch occurs.
|
||||||
- All other PCBs begin in `TASK_STATE_FREE`.
|
- All other PCBs begin in `TASK_STATE_FREE` with `TASK_PRIV_USER`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Task creation and stack layout
|
## Task creation and stack layout
|
||||||
|
|
||||||
New tasks are created via `task_create`, which:
|
New tasks are created via `task_create_with_priv` (or its wrapper `task_create`), which:
|
||||||
|
|
||||||
1. Finds a free PCB slot.
|
1. Checks that the caller is not escalating privilege beyond its own level.
|
||||||
2. Allocates a stack from the PMM.
|
2. Finds a free PCB slot.
|
||||||
3. Sets up an initial stack frame so that `context_switch` can "return" into a C trampoline function.
|
3. Allocates a stack from the PMM.
|
||||||
|
4. Sets up an initial stack frame so that `context_switch` can "return" into a C trampoline function.
|
||||||
|
|
||||||
```121:197:/home/lochlan/Documents/Coding/c/os/task.c
|
```121:211:/home/lochlan/Documents/Coding/c/os/task.c
|
||||||
Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
Task *task_create_with_priv(const CHAR16 *name,
|
||||||
|
TaskEntryFn entry,
|
||||||
|
void *arg,
|
||||||
|
TaskPrivilege privilege)
|
||||||
{
|
{
|
||||||
Task *t = NULL;
|
Task *t = NULL;
|
||||||
UINTN i;
|
UINTN i;
|
||||||
@@ -89,6 +95,14 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
|||||||
UINT64 *sp;
|
UINT64 *sp;
|
||||||
...
|
...
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: prevent privilege escalation. */
|
||||||
|
{
|
||||||
|
Task *caller = task_current();
|
||||||
|
if (caller != NULL && privilege > task_get_privilege(caller)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Find a free PCB slot */
|
/* Find a free PCB slot */
|
||||||
for (i = 0; i < TASK_MAX; i++) {
|
for (i = 0; i < TASK_MAX; i++) {
|
||||||
if (tasks[i].state == TASK_STATE_FREE) {
|
if (tasks[i].state == TASK_STATE_FREE) {
|
||||||
@@ -107,6 +121,7 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
|||||||
/* Fill in the PCB */
|
/* Fill in the PCB */
|
||||||
t->pid = next_pid++;
|
t->pid = next_pid++;
|
||||||
t->state = TASK_STATE_READY;
|
t->state = TASK_STATE_READY;
|
||||||
|
t->privilege = privilege;
|
||||||
t->entry = entry;
|
t->entry = entry;
|
||||||
t->arg = arg;
|
t->arg = arg;
|
||||||
t->switches = 0;
|
t->switches = 0;
|
||||||
@@ -154,6 +169,19 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The convenience wrapper `task_create` inherits the calling task's privilege level:
|
||||||
|
|
||||||
|
```213:220:/home/lochlan/Documents/Coding/c/os/task.c
|
||||||
|
Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
||||||
|
{
|
||||||
|
/* Inherit privilege from the calling task (kernel if no task context). */
|
||||||
|
Task *caller = task_current();
|
||||||
|
TaskPrivilege priv = (caller != NULL) ? task_get_privilege(caller)
|
||||||
|
: TASK_PRIV_KERNEL;
|
||||||
|
return task_create_with_priv(name, entry, arg, priv);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The effective stack layout (low to high addresses) after `task_create` is:
|
The effective stack layout (low to high addresses) after `task_create` is:
|
||||||
|
|
||||||
- Saved `flags`, `r15`, `r14`, `r13`, `r12`, `rbx`, `rbp` (pushed by `context_switch` semantics).
|
- Saved `flags`, `r15`, `r14`, `r13`, `r12`, `rbx`, `rbp` (pushed by `context_switch` semantics).
|
||||||
@@ -367,7 +395,7 @@ Because the scheduler is cooperative, this **busy-wait** loop is benign: it yiel
|
|||||||
Example usage from the Starling Terminal:
|
Example usage from the Starling Terminal:
|
||||||
|
|
||||||
```135:140:/home/lochlan/Documents/Coding/c/os/kernel.c
|
```135:140:/home/lochlan/Documents/Coding/c/os/kernel.c
|
||||||
Task *cmd_task = execute_command(Boot, line);
|
Task *cmd_task = execute_command(Boot, line, shell_priv);
|
||||||
|
|
||||||
/* If a command task was spawned, wait for it to finish. */
|
/* If a command task was spawned, wait for it to finish. */
|
||||||
if (cmd_task != NULL) {
|
if (cmd_task != NULL) {
|
||||||
@@ -379,25 +407,34 @@ if (cmd_task != NULL) {
|
|||||||
|
|
||||||
## Task inspection (`ps` and `tasktest`)
|
## Task inspection (`ps` and `tasktest`)
|
||||||
|
|
||||||
The `ps` command uses `task_print_list` to show current tasks:
|
The `ps` command uses `task_print_list` to show current tasks. Access requires at least `TASK_PRIV_DRIVER`:
|
||||||
|
|
||||||
```366:389:/home/lochlan/Documents/Coding/c/os/task.c
|
```407:439:/home/lochlan/Documents/Coding/c/os/task.c
|
||||||
void task_print_list(BootInfo *Boot)
|
void task_print_list(BootInfo *Boot)
|
||||||
{
|
{
|
||||||
UINTN i;
|
UINTN i;
|
||||||
|
Task *caller;
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: task list requires DRIVER. */
|
||||||
|
caller = task_current();
|
||||||
|
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_DRIVER) {
|
||||||
|
SAFE_PRINT(Boot, L"Permission denied: task list requires driver privilege.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L"\n\r");
|
SAFE_PRINT(Boot, L"\n\r");
|
||||||
SAFE_PRINT(Boot, L" PID STATE SWITCHES NAME\n\r");
|
SAFE_PRINT(Boot, L" PID STATE PRIV SWITCHES NAME\n\r");
|
||||||
SAFE_PRINT(Boot, L" --- ---------- -------- ----\n\r");
|
SAFE_PRINT(Boot, L" --- ---------- ---- -------- ----\n\r");
|
||||||
|
|
||||||
for (i = 0; i < TASK_MAX; i++) {
|
for (i = 0; i < TASK_MAX; i++) {
|
||||||
if (tasks[i].state == TASK_STATE_FREE) {
|
if (tasks[i].state == TASK_STATE_FREE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L" %3d %-10s %8d %s\n\r",
|
SAFE_PRINT(Boot, L" %3d %-10s %4d %8d %s\n\r",
|
||||||
tasks[i].pid,
|
tasks[i].pid,
|
||||||
state_str(tasks[i].state),
|
state_str(tasks[i].state),
|
||||||
|
(INT32)tasks[i].privilege,
|
||||||
tasks[i].switches,
|
tasks[i].switches,
|
||||||
tasks[i].name);
|
tasks[i].name);
|
||||||
}
|
}
|
||||||
@@ -444,3 +481,28 @@ Each worker task:
|
|||||||
|
|
||||||
This demonstrates how cooperative tasks interleave output and how `task_yield` drives scheduling.
|
This demonstrates how cooperative tasks interleave output and how `task_yield` drives scheduling.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Privilege system
|
||||||
|
|
||||||
|
Each task carries a `TaskPrivilege` level defined in `task.h`:
|
||||||
|
|
||||||
|
```47:52:/home/lochlan/Documents/Coding/c/os/task.h
|
||||||
|
typedef enum {
|
||||||
|
TASK_PRIV_USER = 0,
|
||||||
|
TASK_PRIV_DRIVER = 1,
|
||||||
|
TASK_PRIV_KERNEL = 2,
|
||||||
|
} TaskPrivilege;
|
||||||
|
```
|
||||||
|
|
||||||
|
All tasks still execute in CPU ring 0; this is a **software-only** hierarchy used for access control decisions:
|
||||||
|
|
||||||
|
- `task_create_with_priv` prevents a caller from creating a task with a higher privilege than its own.
|
||||||
|
- Subsystem functions like `memory_print_stats`, `task_print_list`, and `request_shutdown` check the calling task's privilege before proceeding.
|
||||||
|
- The `kusr` command (`commands.c`) temporarily elevates a task to `TASK_PRIV_KERNEL` to run a privileged sub-command, then restores the original level.
|
||||||
|
|
||||||
|
Accessors:
|
||||||
|
|
||||||
|
- `task_get_privilege(Task *t)` – returns the task's current privilege level.
|
||||||
|
- `task_set_privilege(Task *t, TaskPrivilege p)` – changes it (no enforcement; callers are responsible).
|
||||||
|
|
||||||
|
|||||||
21
kernel.c
21
kernel.c
@@ -38,6 +38,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
BootInfo *Boot;
|
BootInfo *Boot;
|
||||||
UINTN depth; /* 0 = top-level, 1+ = nested shells */
|
UINTN depth; /* 0 = top-level, 1+ = nested shells */
|
||||||
|
TaskPrivilege shell_priv; /* logical privilege for this shell */
|
||||||
} StarlingContext;
|
} StarlingContext;
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
@@ -54,6 +55,7 @@ static void starling_terminal_task(void *arg)
|
|||||||
CHAR16 line[128];
|
CHAR16 line[128];
|
||||||
UINTN len = 0;
|
UINTN len = 0;
|
||||||
UINTN depth = 0;
|
UINTN depth = 0;
|
||||||
|
TaskPrivilege shell_priv;
|
||||||
|
|
||||||
if (ctx == NULL || ctx->Boot == NULL) {
|
if (ctx == NULL || ctx->Boot == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -61,8 +63,10 @@ static void starling_terminal_task(void *arg)
|
|||||||
|
|
||||||
Boot = ctx->Boot;
|
Boot = ctx->Boot;
|
||||||
depth = ctx->depth;
|
depth = ctx->depth;
|
||||||
|
shell_priv = ctx->shell_priv;
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d] ready.\n\r\n\r", depth);
|
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d, priv %d] ready.\n\r\n\r",
|
||||||
|
depth, (INT32)shell_priv);
|
||||||
SAFE_PRINT(Boot, L"starling> ");
|
SAFE_PRINT(Boot, L"starling> ");
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
@@ -116,8 +120,12 @@ static void starling_terminal_task(void *arg)
|
|||||||
} else {
|
} else {
|
||||||
child_ctx->Boot = Boot;
|
child_ctx->Boot = Boot;
|
||||||
child_ctx->depth = depth + 1;
|
child_ctx->depth = depth + 1;
|
||||||
|
child_ctx->shell_priv = shell_priv;
|
||||||
|
|
||||||
child_task = task_create(L"starling-term", starling_terminal_task, child_ctx);
|
child_task = task_create_with_priv(L"starling-term",
|
||||||
|
starling_terminal_task,
|
||||||
|
child_ctx,
|
||||||
|
shell_priv);
|
||||||
if (child_task == NULL) {
|
if (child_task == NULL) {
|
||||||
SAFE_PRINT(Boot, L"Starling: failed to spawn nested terminal.\n\r");
|
SAFE_PRINT(Boot, L"Starling: failed to spawn nested terminal.\n\r");
|
||||||
kfree(child_ctx);
|
kfree(child_ctx);
|
||||||
@@ -132,7 +140,7 @@ static void starling_terminal_task(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Task *cmd_task = execute_command(Boot, line);
|
Task *cmd_task = execute_command(Boot, line, shell_priv);
|
||||||
|
|
||||||
/* If a command task was spawned, wait for it to finish. */
|
/* If a command task was spawned, wait for it to finish. */
|
||||||
if (cmd_task != NULL) {
|
if (cmd_task != NULL) {
|
||||||
@@ -225,14 +233,19 @@ void kmain(BootInfo *Boot)
|
|||||||
StarlingContext inline_ctx;
|
StarlingContext inline_ctx;
|
||||||
inline_ctx.Boot = Boot;
|
inline_ctx.Boot = Boot;
|
||||||
inline_ctx.depth = 0;
|
inline_ctx.depth = 0;
|
||||||
|
inline_ctx.shell_priv = TASK_PRIV_USER;
|
||||||
starling_terminal_task(&inline_ctx);
|
starling_terminal_task(&inline_ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->Boot = Boot;
|
ctx->Boot = Boot;
|
||||||
ctx->depth = 0;
|
ctx->depth = 0;
|
||||||
|
ctx->shell_priv = TASK_PRIV_USER;
|
||||||
|
|
||||||
terminal_task = task_create(L"starling-term", starling_terminal_task, ctx);
|
terminal_task = task_create_with_priv(L"starling-term",
|
||||||
|
starling_terminal_task,
|
||||||
|
ctx,
|
||||||
|
TASK_PRIV_USER);
|
||||||
if (terminal_task == NULL) {
|
if (terminal_task == NULL) {
|
||||||
SAFE_PRINT(Boot, L"Failed to start Starling Terminal task; falling back to kernel loop.\n\r");
|
SAFE_PRINT(Boot, L"Failed to start Starling Terminal task; falling back to kernel loop.\n\r");
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ typedef uint16_t UINT16;
|
|||||||
typedef uint32_t UINT32;
|
typedef uint32_t UINT32;
|
||||||
typedef uint64_t UINT64;
|
typedef uint64_t UINT64;
|
||||||
|
|
||||||
|
typedef int32_t INT32;
|
||||||
|
|
||||||
typedef size_t UINTN;
|
typedef size_t UINTN;
|
||||||
|
|
||||||
#ifndef BOOLEAN
|
#ifndef BOOLEAN
|
||||||
|
|||||||
9
memory.c
9
memory.c
@@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
/* Null-safe print helper used throughout the kernel. */
|
/* Null-safe print helper used throughout the kernel. */
|
||||||
#define SAFE_PRINT(Boot, ...) \
|
#define SAFE_PRINT(Boot, ...) \
|
||||||
@@ -526,6 +527,14 @@ void memory_print_stats(BootInfo *Boot)
|
|||||||
{
|
{
|
||||||
UINTN h_total, h_used, h_free, h_blocks;
|
UINTN h_total, h_used, h_free, h_blocks;
|
||||||
UINTN p_total, p_free, p_used;
|
UINTN p_total, p_free, p_used;
|
||||||
|
Task *caller;
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: memory stats require KERNEL. */
|
||||||
|
caller = task_current();
|
||||||
|
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_KERNEL) {
|
||||||
|
SAFE_PRINT(Boot, L"Permission denied: memory stats require kernel privilege.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
p_total = pmm_get_total_pages();
|
p_total = pmm_get_total_pages();
|
||||||
p_free = pmm_get_free_pages();
|
p_free = pmm_get_free_pages();
|
||||||
|
|||||||
56
task.c
56
task.c
@@ -69,6 +69,7 @@ void task_init(BootInfo *Boot)
|
|||||||
for (i = 0; i < TASK_MAX; i++) {
|
for (i = 0; i < TASK_MAX; i++) {
|
||||||
tasks[i].state = TASK_STATE_FREE;
|
tasks[i].state = TASK_STATE_FREE;
|
||||||
tasks[i].pid = 0;
|
tasks[i].pid = 0;
|
||||||
|
tasks[i].privilege = TASK_PRIV_USER;
|
||||||
tasks[i].saved_rsp = 0;
|
tasks[i].saved_rsp = 0;
|
||||||
tasks[i].stack_base = 0;
|
tasks[i].stack_base = 0;
|
||||||
tasks[i].stack_pages = 0;
|
tasks[i].stack_pages = 0;
|
||||||
@@ -86,6 +87,7 @@ void task_init(BootInfo *Boot)
|
|||||||
*/
|
*/
|
||||||
tasks[0].pid = next_pid++;
|
tasks[0].pid = next_pid++;
|
||||||
tasks[0].state = TASK_STATE_RUNNING;
|
tasks[0].state = TASK_STATE_RUNNING;
|
||||||
|
tasks[0].privilege = TASK_PRIV_KERNEL;
|
||||||
tasks[0].switches = 1;
|
tasks[0].switches = 1;
|
||||||
wstrcpy16(tasks[0].name, L"core", TASK_NAME_LEN);
|
wstrcpy16(tasks[0].name, L"core", TASK_NAME_LEN);
|
||||||
|
|
||||||
@@ -119,7 +121,10 @@ static void task_trampoline(void)
|
|||||||
* Create a new task
|
* Create a new task
|
||||||
* ---------------------------------------------------------------- */
|
* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
Task *task_create_with_priv(const CHAR16 *name,
|
||||||
|
TaskEntryFn entry,
|
||||||
|
void *arg,
|
||||||
|
TaskPrivilege privilege)
|
||||||
{
|
{
|
||||||
Task *t = NULL;
|
Task *t = NULL;
|
||||||
UINTN i;
|
UINTN i;
|
||||||
@@ -130,6 +135,14 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: prevent privilege escalation. */
|
||||||
|
{
|
||||||
|
Task *caller = task_current();
|
||||||
|
if (caller != NULL && privilege > task_get_privilege(caller)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Find a free PCB slot */
|
/* Find a free PCB slot */
|
||||||
for (i = 0; i < TASK_MAX; i++) {
|
for (i = 0; i < TASK_MAX; i++) {
|
||||||
if (tasks[i].state == TASK_STATE_FREE) {
|
if (tasks[i].state == TASK_STATE_FREE) {
|
||||||
@@ -150,6 +163,7 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
|||||||
/* Fill in the PCB */
|
/* Fill in the PCB */
|
||||||
t->pid = next_pid++;
|
t->pid = next_pid++;
|
||||||
t->state = TASK_STATE_READY;
|
t->state = TASK_STATE_READY;
|
||||||
|
t->privilege = privilege;
|
||||||
t->entry = entry;
|
t->entry = entry;
|
||||||
t->arg = arg;
|
t->arg = arg;
|
||||||
t->switches = 0;
|
t->switches = 0;
|
||||||
@@ -196,6 +210,15 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
||||||
|
{
|
||||||
|
/* Inherit privilege from the calling task (kernel if no task context). */
|
||||||
|
Task *caller = task_current();
|
||||||
|
TaskPrivilege priv = (caller != NULL) ? task_get_privilege(caller)
|
||||||
|
: TASK_PRIV_KERNEL;
|
||||||
|
return task_create_with_priv(name, entry, arg, priv);
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* Schedule – pick the next READY task (round-robin)
|
* Schedule – pick the next READY task (round-robin)
|
||||||
* ---------------------------------------------------------------- */
|
* ---------------------------------------------------------------- */
|
||||||
@@ -318,6 +341,22 @@ Task *task_current(void)
|
|||||||
return current_task;
|
return current_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TaskPrivilege task_get_privilege(Task *t)
|
||||||
|
{
|
||||||
|
if (t == NULL) {
|
||||||
|
return TASK_PRIV_KERNEL;
|
||||||
|
}
|
||||||
|
return t->privilege;
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_set_privilege(Task *t, TaskPrivilege privilege)
|
||||||
|
{
|
||||||
|
if (t == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t->privilege = privilege;
|
||||||
|
}
|
||||||
|
|
||||||
UINTN task_count(void)
|
UINTN task_count(void)
|
||||||
{
|
{
|
||||||
UINTN i, count = 0;
|
UINTN i, count = 0;
|
||||||
@@ -366,19 +405,28 @@ static const CHAR16 *state_str(TaskState s)
|
|||||||
void task_print_list(BootInfo *Boot)
|
void task_print_list(BootInfo *Boot)
|
||||||
{
|
{
|
||||||
UINTN i;
|
UINTN i;
|
||||||
|
Task *caller;
|
||||||
|
|
||||||
|
/* Subsystem-level privilege enforcement: task list requires DRIVER. */
|
||||||
|
caller = task_current();
|
||||||
|
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_DRIVER) {
|
||||||
|
SAFE_PRINT(Boot, L"Permission denied: task list requires driver privilege.\n\r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L"\n\r");
|
SAFE_PRINT(Boot, L"\n\r");
|
||||||
SAFE_PRINT(Boot, L" PID STATE SWITCHES NAME\n\r");
|
SAFE_PRINT(Boot, L" PID STATE PRIV SWITCHES NAME\n\r");
|
||||||
SAFE_PRINT(Boot, L" --- ---------- -------- ----\n\r");
|
SAFE_PRINT(Boot, L" --- ---------- ---- -------- ----\n\r");
|
||||||
|
|
||||||
for (i = 0; i < TASK_MAX; i++) {
|
for (i = 0; i < TASK_MAX; i++) {
|
||||||
if (tasks[i].state == TASK_STATE_FREE) {
|
if (tasks[i].state == TASK_STATE_FREE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_PRINT(Boot, L" %3d %-10s %8d %s\n\r",
|
SAFE_PRINT(Boot, L" %3d %-10s %4d %8d %s\n\r",
|
||||||
tasks[i].pid,
|
tasks[i].pid,
|
||||||
state_str(tasks[i].state),
|
state_str(tasks[i].state),
|
||||||
|
(INT32)tasks[i].privilege,
|
||||||
tasks[i].switches,
|
tasks[i].switches,
|
||||||
tasks[i].name);
|
tasks[i].name);
|
||||||
}
|
}
|
||||||
|
|||||||
30
task.h
30
task.h
@@ -32,6 +32,23 @@ typedef enum {
|
|||||||
TASK_STATE_TERMINATED /* finished; slot will be recycled */
|
TASK_STATE_TERMINATED /* finished; slot will be recycled */
|
||||||
} TaskState;
|
} TaskState;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Logical privilege level for a task.
|
||||||
|
*
|
||||||
|
* Higher numeric values are more privileged:
|
||||||
|
* USER (0) – least privileged
|
||||||
|
* DRIVER (1) – mid-level, can talk to hardware-facing subsystems
|
||||||
|
* KERNEL (2) – most privileged, core kernel and management threads
|
||||||
|
*
|
||||||
|
* All tasks still execute in ring 0 today; this is a software
|
||||||
|
* hierarchy used for access control decisions and future paging work.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
TASK_PRIV_USER = 0,
|
||||||
|
TASK_PRIV_DRIVER = 1,
|
||||||
|
TASK_PRIV_KERNEL = 2,
|
||||||
|
} TaskPrivilege;
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
* Task entry function
|
* Task entry function
|
||||||
* ================================================================ */
|
* ================================================================ */
|
||||||
@@ -46,6 +63,7 @@ typedef void (*TaskEntryFn)(void *arg);
|
|||||||
typedef struct Task {
|
typedef struct Task {
|
||||||
UINT32 pid; /* unique process ID */
|
UINT32 pid; /* unique process ID */
|
||||||
TaskState state; /* current lifecycle state */
|
TaskState state; /* current lifecycle state */
|
||||||
|
TaskPrivilege privilege; /* logical privilege level */
|
||||||
CHAR16 name[TASK_NAME_LEN]; /* human-readable label */
|
CHAR16 name[TASK_NAME_LEN]; /* human-readable label */
|
||||||
|
|
||||||
/* Context switch state */
|
/* Context switch state */
|
||||||
@@ -66,11 +84,21 @@ typedef struct Task {
|
|||||||
* ================================================================ */
|
* ================================================================ */
|
||||||
|
|
||||||
void task_init(BootInfo *Boot); /* initialise scheduler */
|
void task_init(BootInfo *Boot); /* initialise scheduler */
|
||||||
Task *task_create(const CHAR16 *name, /* spawn a new task */
|
|
||||||
|
/* Spawn a new task with a specific privilege level. */
|
||||||
|
Task *task_create_with_priv(const CHAR16 *name,
|
||||||
|
TaskEntryFn entry,
|
||||||
|
void *arg,
|
||||||
|
TaskPrivilege privilege);
|
||||||
|
|
||||||
|
/* Backwards-compatible helper: creates a kernel-privileged task. */
|
||||||
|
Task *task_create(const CHAR16 *name,
|
||||||
TaskEntryFn entry, void *arg);
|
TaskEntryFn entry, void *arg);
|
||||||
void task_yield(void); /* voluntarily give up the CPU */
|
void task_yield(void); /* voluntarily give up the CPU */
|
||||||
void task_exit(void); /* terminate the current task */
|
void task_exit(void); /* terminate the current task */
|
||||||
Task *task_current(void); /* return the running task's PCB */
|
Task *task_current(void); /* return the running task's PCB */
|
||||||
|
TaskPrivilege task_get_privilege(Task *t);
|
||||||
|
void task_set_privilege(Task *t, TaskPrivilege privilege);
|
||||||
UINTN task_count(void); /* number of non-FREE tasks */
|
UINTN task_count(void); /* number of non-FREE tasks */
|
||||||
void task_print_list(BootInfo *Boot); /* print task table (for `ps`) */
|
void task_print_list(BootInfo *Boot); /* print task table (for `ps`) */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user