Skip to content

Commit 430851f

Browse files
committed
Add U-mode safe output syscall
User mode tasks cannot directly use the standard output functions because the logger system requires privileged operations for synchronization. When user mode code attempts these operations, the processor triggers illegal instruction exceptions that prevent normal execution. To address this limitation, a new system call interface provides safe output capabilities for user mode tasks. The implementation splits the work between user and machine modes: formatting occurs in user space using only unprivileged operations, while the actual output is performed through a system call that executes in machine mode where privileged operations are permitted. The kernel handles all synchronization and hardware access transparently, allowing user mode tasks to produce output without violating privilege boundaries.
1 parent e9499a5 commit 430851f

File tree

4 files changed

+55
-1
lines changed

4 files changed

+55
-1
lines changed

include/lib/libc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,9 @@ char *getline(char *s);
153153
int32_t printf(const char *fmt, ...);
154154
int32_t snprintf(char *str, size_t size, const char *fmt, ...);
155155
int vsnprintf(char *str, size_t size, const char *fmt, va_list args);
156+
157+
/* User mode safe formatted output.
158+
* Similar to printf but safe for U-mode tasks - formats in user space
159+
* then uses syscall to output, avoiding privilege violations.
160+
*/
161+
int32_t umode_printf(const char *fmt, ...);

include/sys/syscall.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
_(twfi, 40, int, (void) ) \
4949
_(tcount, 41, int, (void) ) \
5050
_(ticks, 42, int, (void) ) \
51-
_(uptime, 43, int, (void) )
51+
_(uptime, 43, int, (void) ) \
52+
_(tputs, 44, int, (const char *str))
5253

5354
/* Generate enumeration of system call numbers */
5455
#define _(name, num, rettype, arglist) SYS_##name = num,

kernel/syscall.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,3 +382,21 @@ int sys_uptime(void)
382382
{
383383
return syscall(SYS_uptime, 0, 0, 0);
384384
}
385+
386+
/* User mode safe output syscall.
387+
* Outputs a string from user mode by executing puts() in kernel context.
388+
* This avoids privilege violations from printf's logger mutex operations.
389+
*/
390+
static int _tputs(const char *str)
391+
{
392+
if (unlikely(!str))
393+
return -EINVAL;
394+
395+
/* Use puts() which will handle logger enqueue or direct output */
396+
return puts(str);
397+
}
398+
399+
int sys_tputs(const char *str)
400+
{
401+
return syscall(SYS_tputs, (void *) str, 0, 0);
402+
}

lib/stdio.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,3 +446,32 @@ char *getline(char *s)
446446

447447
return s;
448448
}
449+
450+
/* User mode safe formatted output.
451+
* Formats string in user space using vsnprintf, then outputs via syscall.
452+
* This avoids privilege violations from printf's logger mutex operations.
453+
*
454+
* Safe for U-mode tasks because:
455+
* 1. vsnprintf runs in user space (no privileged operations)
456+
* 2. sys_tputs syscall transitions to M-mode for actual output
457+
* 3. Kernel handles logger mutex/direct output decision
458+
*/
459+
int32_t umode_printf(const char *fmt, ...)
460+
{
461+
char buf[256]; /* Stack buffer for formatted output */
462+
va_list args;
463+
464+
va_start(args, fmt);
465+
int32_t len = vsnprintf(buf, sizeof(buf), fmt, args);
466+
va_end(args);
467+
468+
/* Handle vsnprintf error */
469+
if (len < 0)
470+
return len;
471+
472+
/* Output via syscall - safe for U-mode */
473+
extern int sys_tputs(const char *str);
474+
sys_tputs(buf);
475+
476+
return len;
477+
}

0 commit comments

Comments
 (0)