Viewing: arch_process.c
📄 arch_process.c (Read Only) ⬅ To go back
#include "arch_process.h"
#include "arch/x86/idt.h"

#if defined(__i386__)

/*
 * x86 kernel stack layout expected by context_switch (process.S):
 *
 *   context_switch saves:  pushf, push edi, esi, ebx, ebp
 *   context_switch restores: popf, pop edi, esi, ebx, ebp, ret
 *
 * So for a NEW process we build a fake frame that context_switch will
 * "restore":
 *
 *   sp -> [EFLAGS  0x202]   <- popf  (IF=1, reserved bit 1)
 *         [EDI     0]       <- pop edi
 *         [ESI     0]       <- pop esi
 *         [EBX     0]       <- pop ebx
 *         [EBP     0]       <- pop ebp
 *         [wrapper addr]    <- ret jumps here
 *         [0  (fake retaddr for wrapper)]
 *         [arg]             <- first argument to wrapper (cdecl)
 */
uintptr_t arch_kstack_init(void* stack_top,
                            void (*wrapper)(void (*)(void)),
                            void (*arg)(void))
{
    uint32_t* sp = (uint32_t*)stack_top;

    *--sp = (uint32_t)(uintptr_t)arg;       /* argument for wrapper */
    *--sp = 0;                               /* fake return address  */
    *--sp = (uint32_t)(uintptr_t)wrapper;    /* ret target           */
    *--sp = 0;                               /* EBP                  */
    *--sp = 0;                               /* EBX                  */
    *--sp = 0;                               /* ESI                  */
    *--sp = 0;                               /* EDI                  */
    *--sp = 0x002;                           /* EFLAGS: IF=0 (thread_wrapper enables interrupts) */

    return (uintptr_t)sp;
}

void arch_regs_set_retval(void* opaque, uint32_t val)
{
    struct registers* regs = (struct registers*)opaque;
    if (regs) regs->eax = val;
}

void arch_regs_set_ustack(void* opaque, uintptr_t sp)
{
    struct registers* regs = (struct registers*)opaque;
    if (regs) regs->useresp = (uint32_t)sp;
}

#endif /* __i386__ */