Skip to content

Commit

Permalink
Simplify the SYS_THREAD_CREATE syscall interface
Browse files Browse the repository at this point in the history
Removed the beefy uarg structure. Instead, the syscall gets two
parameters: %pc (program counter) and %sp (stack pointer). It starts
a thread with those values in corresponding registers, with no other
fuss whatsoever.

libc initializes threads by storing any other needed arguments on
the stack and retrieving them in __thread_entry. Importantly, this
includes the address of the __thread_main function which is now
called indirectly to fix dynamic linking issues on some archs.

There's a bit of weirdness on SPARC and IA-64, because of their
stacked register handling. The current solution is that we require
some space *above* the stack pointer to be available for those
architectures. I think for SPARC, it can be made more normal.

For the remaining ones, we can (probably) just set the initial
%sp to the top edge of the stack. There's some lingering offsets
on some archs just because I didn't want to accidentally break
anything. The initial thread bringup should be functionally
unchanged from the previous state, and no binaries are currently
multithreaded except thread1 test, so there should be minimal
risk of breakage. Naturally, I tested all available emulator
builds, save for msim.
  • Loading branch information
le-jzr committed Sep 20, 2024
1 parent 2cf8f99 commit 3fcea34
Show file tree
Hide file tree
Showing 50 changed files with 366 additions and 330 deletions.
58 changes: 0 additions & 58 deletions abi/include/abi/proc/uarg.h

This file was deleted.

8 changes: 6 additions & 2 deletions kernel/arch/abs32le/src/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@
#include <userspace.h>
#include <stdbool.h>
#include <arch.h>
#include <abi/proc/uarg.h>
#include <mm/as.h>

void userspace(uspace_arg_t *kernel_uarg)
uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
return stack_base + stack_size;
}

void userspace(uintptr_t pc, uintptr_t sp)
{
/*
* On real hardware this switches the CPU to user
Expand Down
16 changes: 8 additions & 8 deletions kernel/arch/amd64/src/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@
#include <stdbool.h>
#include <stdint.h>
#include <arch.h>
#include <abi/proc/uarg.h>
#include <mm/as.h>

uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
return stack_base + stack_size;
}

/** Enter userspace
*
* Change CPU protection level to 3, enter userspace.
*
*/
void userspace(uspace_arg_t *kernel_uarg)
void userspace(uintptr_t pc, uintptr_t sp)
{
uint64_t rflags = read_rflags();

Expand All @@ -59,19 +63,15 @@ void userspace(uspace_arg_t *kernel_uarg)
"pushq %[rflags]\n"
"pushq %[utext_des]\n"
"pushq %[entry]\n"
"movq %[uarg], %%rax\n"

/* %rdi is defined to hold pcb_ptr - set it to 0 */
"xorq %%rdi, %%rdi\n"
"iretq\n"
:: [udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
[stack_top] "r" (kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size),
[stack_top] "r" (sp),
[rflags] "r" (rflags),
[utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
[entry] "r" (kernel_uarg->uspace_entry),
[uarg] "r" (kernel_uarg->uspace_uarg)
: "rax"
[entry] "r" (pc)
);

unreachable();
Expand Down
36 changes: 9 additions & 27 deletions kernel/arch/arm32/src/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,43 +60,25 @@ typedef struct {
uint32_t pc;
} ustate_t;

uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
return stack_base + stack_size;
}

/** Change processor mode
*
* @param kernel_uarg Userspace settings (entry point, stack, ...).
*
*/
void userspace(uspace_arg_t *kernel_uarg)
void userspace(uintptr_t pc, uintptr_t sp)
{
volatile ustate_t ustate;

/* set first parameter */
ustate.r0 = kernel_uarg->uspace_uarg;

/* %r1 is defined to hold pcb_ptr - set it to 0 */
ustate.r1 = 0;
volatile ustate_t ustate = { };

/* pass the RAS page address in %r2 */
ustate.r2 = (uintptr_t) ras_page;

/* clear other registers */
ustate.r3 = 0;
ustate.r4 = 0;
ustate.r5 = 0;
ustate.r6 = 0;
ustate.r7 = 0;
ustate.r8 = 0;
ustate.r9 = 0;
ustate.r10 = 0;
ustate.r11 = 0;
ustate.r12 = 0;
ustate.lr = 0;

/* set user stack */
ustate.sp = kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size;

/* set where uspace execution starts */
ustate.pc = kernel_uarg->uspace_entry;
ustate.sp = sp;
ustate.pc = pc;

/* status register in user mode */
ipl_t user_mode = current_status_reg_read() &
Expand Down
21 changes: 11 additions & 10 deletions kernel/arch/arm64/src/arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,22 +145,26 @@ void asm_delay_loop(uint32_t usec)
;
}

uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
return stack_base + stack_size;
}

/** Change processor mode.
*
* @param kernel_uarg Userspace settings (entry point, stack, ...).
*/
void userspace(uspace_arg_t *kernel_uarg)
void userspace(uintptr_t pc, uintptr_t sp)
{
/* Prepare return to EL0. */
SPSR_EL1_write((SPSR_EL1_read() & ~SPSR_MODE_MASK) |
SPSR_MODE_ARM64_EL0T);

/* Set program entry. */
ELR_EL1_write(kernel_uarg->uspace_entry);
ELR_EL1_write(pc);

/* Set user stack. */
SP_EL0_write(kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size);
SP_EL0_write(sp);

/* Clear Thread ID register. */
TPIDR_EL0_write(0);
Expand All @@ -169,12 +173,10 @@ void userspace(uspace_arg_t *kernel_uarg)
/*
* Reset the kernel stack to its base value.
*
* Clear all general-purpose registers,
* except x0 that holds an argument for
* the user space.
* Clear all general-purpose registers.
*/
"mov sp, %[kstack]\n"
"mov x0, %[uspace_uarg]\n"
"mov x0, #0\n"
"mov x1, #0\n"
"mov x2, #0\n"
"mov x3, #0\n"
Expand Down Expand Up @@ -206,8 +208,7 @@ void userspace(uspace_arg_t *kernel_uarg)
"mov x29, #0\n"
"mov x30, #0\n"
"eret\n"
:: [uspace_uarg] "r" (kernel_uarg->uspace_uarg),
[kstack] "r" (((uint64_t) (THREAD->kstack)) +
:: [kstack] "r" (((uint64_t) (THREAD->kstack)) +
MEM_STACK_SIZE - SP_DELTA)
);

Expand Down
15 changes: 8 additions & 7 deletions kernel/arch/ia32/src/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,21 @@
#include <stdbool.h>
#include <stdint.h>
#include <arch.h>
#include <abi/proc/uarg.h>
#include <mm/as.h>
#include <arch/cpu.h>
#include <arch/asm.h>

uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
return stack_base + stack_size;
}

/** Enter userspace
*
* Change CPU protection level to 3, enter userspace.
*
*/
void userspace(uspace_arg_t *kernel_uarg)
void userspace(uintptr_t pc, uintptr_t sp)
{
uint32_t eflags = read_eflags();

Expand All @@ -60,7 +64,6 @@ void userspace(uspace_arg_t *kernel_uarg)
"pushl %[eflags]\n"
"pushl %[utext_des]\n"
"pushl %[entry]\n"
"movl %[uarg], %%eax\n"

/* %edi is defined to hold pcb_ptr - set it to 0 */
"xorl %%edi, %%edi\n"
Expand All @@ -69,12 +72,10 @@ void userspace(uspace_arg_t *kernel_uarg)
:
: [eflags_mask] "i" (~EFLAGS_NT),
[udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
[stack_top] "r" (kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size),
[stack_top] "r" (sp),
[eflags] "r" ((eflags & ~(EFLAGS_NT)) | EFLAGS_IF),
[utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
[entry] "r" (kernel_uarg->uspace_entry),
[uarg] "r" (kernel_uarg->uspace_uarg),
[entry] "r" (pc),
[vreg_des] "r" (GDT_SELECTOR(VREG_DES))
: "eax");

Expand Down
21 changes: 11 additions & 10 deletions kernel/arch/ia64/src/ia64.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,13 @@ void ia64_post_smp_init(void)
sysinfo_set_item_val("ia64_iospace.address.virtual", NULL, LEGACYIO_USER_BASE);
}

uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
return ALIGN_DOWN(stack_base + stack_size / 2, STACK_ALIGNMENT);
}

/** Enter userspace and never return. */
void userspace(uspace_arg_t *kernel_uarg)
void userspace(uintptr_t pc, uintptr_t sp)
{
psr_t psr;
rsc_t rsc;
Expand All @@ -240,16 +245,12 @@ void userspace(uspace_arg_t *kernel_uarg)
* Switch to userspace.
*
* When calculating stack addresses, mind the stack split between the
* memory stack and the RSE stack. Each occuppies
* uspace_stack_size / 2 bytes.
* memory stack and the RSE stack.
* Memory stack occupies area under sp, while RSE stack occupies area above.
*/
switch_to_userspace(kernel_uarg->uspace_entry,
kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size / 2 -
ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT),
kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size / 2,
kernel_uarg->uspace_uarg, psr.value, rsc.value);
switch_to_userspace(pc,
sp, sp + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT),
0, psr.value, rsc.value);

while (true)
;
Expand Down
2 changes: 1 addition & 1 deletion kernel/arch/mips32/include/arch/asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ _NO_TRACE static inline uint32_t pio_read_32(ioport32_t *port)

extern void cpu_halt(void) __attribute__((noreturn));
extern void asm_delay_loop(uint32_t);
extern void userspace_asm(uintptr_t, uintptr_t, uintptr_t);
extern void userspace_asm(uintptr_t, uintptr_t);

extern ipl_t interrupts_disable(void);
extern ipl_t interrupts_enable(void);
Expand Down
14 changes: 8 additions & 6 deletions kernel/arch/mips32/src/mips32.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,18 @@ void calibrate_delay_loop(void)
{
}

void userspace(uspace_arg_t *kernel_uarg)
uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
return stack_base + stack_size;
}

void userspace(uintptr_t pc, uintptr_t sp)
{
/* EXL = 1, UM = 1, IE = 1 */
cp0_status_write(cp0_status_read() | (cp0_status_exl_exception_bit |
cp0_status_um_bit | cp0_status_ie_enabled_bit));
cp0_epc_write(kernel_uarg->uspace_entry);
userspace_asm(kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size,
kernel_uarg->uspace_uarg,
kernel_uarg->uspace_entry);
cp0_epc_write(pc);
userspace_asm(sp, pc);

while (true)
;
Expand Down
7 changes: 3 additions & 4 deletions kernel/arch/mips32/src/start.S
Original file line number Diff line number Diff line change
Expand Up @@ -338,9 +338,8 @@ cache_error_handler:

FUNCTION_BEGIN(userspace_asm)
move $sp, $a0
move $v0, $a1
move $t9, $a2 /* set up correct entry into PIC code */
xor $a0, $a0, $a0 /* $a0 is defined to hold pcb_ptr */
/* set it to 0 */
xor $a0, $a0, $a0 /* $a0 is defined to hold pcb_ptr, set it to 0 */
xor $fp, $fp, $fp // FIXME: wipe all userspace-accessible registers
xor $ra, $ra, $ra
eret
FUNCTION_END(userspace_asm)
12 changes: 6 additions & 6 deletions kernel/arch/ppc32/src/ppc32.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
#include <mm/page.h>
#include <mm/km.h>
#include <time/clock.h>
#include <abi/proc/uarg.h>
#include <console/console.h>
#include <sysinfo/sysinfo.h>
#include <ddi/irq.h>
Expand Down Expand Up @@ -289,13 +288,14 @@ void calibrate_delay_loop(void)
{
}

void userspace(uspace_arg_t *kernel_uarg)
uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
{
userspace_asm(kernel_uarg->uspace_uarg,
kernel_uarg->uspace_stack +
kernel_uarg->uspace_stack_size - SP_DELTA,
kernel_uarg->uspace_entry);
return stack_base + stack_size - SP_DELTA;
}

void userspace(uintptr_t pc, uintptr_t sp)
{
userspace_asm(0, sp, pc);
unreachable();
}

Expand Down
Loading

0 comments on commit 3fcea34

Please sign in to comment.