/*
 * Copyright (c) 2026, Chloe M.
 * Provided under the BSD-3 clause.
 *
 * Description: MD thread management
 * Author:      Chloe M.
 */

#include <hal/thread.h>
#include <hal/page.h>
#include <ps/thread.h>
#include <machine/gdt.h>
#include <machine/lapic.h>
#include <mm/vm.h>
#include <string.h>

/*
 * Allocate a kernel stack for a thread
 */
static VOID *
ThreadAllocKStack(VOID)
{
    MM_RANGE StackRange;
    PT_STATUS Status;

    Status = MmAllocatePages(1, &StackRange);
    if (PT_ERROR(Status)) {
        return NULL;
    }

    return RANGE_PTR(&StackRange);
}

/*
 * Initialize a thread control block
 *
 * @Thread:  Thread to initialize TCB of
 * @Tcb:     Thread control block to initialize
 * @Ip:      Instruction pointer value to start off with
 *
 * TODO: Support user threads
 */
static PT_STATUS
ThreadInitTcb(THREAD *Thread, TCB *Tcb, UPTR Ip)
{
    TRAP_FRAME *Frame;

    if (Thread == NULL || Tcb == NULL) {
        return STATUS_INVALID_PARAM;
    }

    Thread->StackBase = (UPTR)ThreadAllocKStack();
    if (Thread->StackBase == 0) {
        return STATUS_NO_MEMORY;
    }

    /* Zero the whole frame */
    Frame = &Tcb->FrameSnapshot;
    RtlMemSet(Frame, 0, sizeof(*Frame));

    /* Initialize only whats needed */
    Frame->Rflags = 0x202;
    Frame->Rsp = Thread->StackBase + PAGESIZE;
    Frame->Rip = Ip;
    Frame->CodeSeg = GDT_KCODE;
    Frame->StackSeg = GDT_KDATA;
    return STATUS_SUCCESS;
}

PT_STATUS
HalThreadInit(THREAD *Thread, ULONG Flags, UPTR Ip)
{
    TCB *Tcb;

    if (Thread == NULL) {
        return STATUS_INVALID_PARAM;
    }

    Tcb = &Thread->Tcb;
    ThreadInitTcb(Thread, Tcb, Ip);
    return STATUS_SUCCESS;
}

VOID
HalPrimeThreadTimer(ULONG Usec)
{
    MdLapicTimerOneshotUs(Usec);
}
