// vi:ft=asm:

.section .text

.macro SAVE_TASK_STATE
    addi sp, sp, -{context_size}

    sd ra,   0 * 8(sp)
    sd gp,   1 * 8(sp)
    sd s11,  2 * 8(sp)
    sd s10,  3 * 8(sp)
    sd s9,   4 * 8(sp)
    sd s8,   5 * 8(sp)
    sd s7,   6 * 8(sp)
    sd s6,   7 * 8(sp)
    sd s5,   8 * 8(sp)
    sd s4,   9 * 8(sp)
    sd s3,  10 * 8(sp)
    sd s2,  11 * 8(sp)
    sd s1,  12 * 8(sp)
    sd s0,  13 * 8(sp)
.endm

.macro LOAD_TASK_STATE
    ld ra,   0 * 8(sp)
    ld gp,   1 * 8(sp)
    ld s11,  2 * 8(sp)
    ld s10,  3 * 8(sp)
    ld s9,   4 * 8(sp)
    ld s8,   5 * 8(sp)
    ld s7,   6 * 8(sp)
    ld s6,   7 * 8(sp)
    ld s5,   8 * 8(sp)
    ld s4,   9 * 8(sp)
    ld s3,  10 * 8(sp)
    ld s2,  11 * 8(sp)
    ld s1,  12 * 8(sp)
    ld s0,  13 * 8(sp)

    addi sp, sp, {context_size}
.endm

.option push
.option norvc

.global __rv64_task_enter_kernel
.global __rv64_task_enter_user
.global __rv64_switch_task
.global __rv64_switch_task_and_drop
.global __rv64_enter_task

// Context switching
.type __rv64_enter_task, @function
__rv64_enter_task:
    // a0 - task ctx
    ld sp, (a0)
    LOAD_TASK_STATE
    ret
.size __rv64_enter_task, . - __rv64_enter_task

.type __rv64_switch_task, @function
__rv64_switch_task:
    // a0 - destination task ctx
    // a1 - source task ctx
    SAVE_TASK_STATE
    sd sp, (a1)
    ld sp, (a0)
    LOAD_TASK_STATE
    ret
.size __rv64_switch_task, . - __rv64_switch_task

.type __rv64_switch_task_and_drop, @function
__rv64_switch_task_and_drop:
    // a0 - destination task ctx
    // a1 - thread struct to drop
    ld sp, (a0)

    mv a0, a1
    call __arch_drop_thread

    LOAD_TASK_STATE
    ret
.size __rv64_switch_task_and_drop, . - __rv64_switch_task_and_drop

// Entry functions
.type __rv64_task_enter_kernel, @function
__rv64_task_enter_kernel:
    ld a0, (sp)     // argument
    ld ra, 8(sp)    // entry
    addi sp, sp, 16

    // Set SPIE to enable interrupts
    // Set SPP = 1 to indicate a return to S-mode
    csrr t0, sstatus
    ori t0, t0, (1 << 5)
    ori t0, t0, (1 << 8)

    csrw sstatus, t0
    csrw sepc, ra
    csrw sscratch, zero

    sret
.size __rv64_task_enter_kernel, . - __rv64_task_enter_kernel

.type __rv64_task_enter_user, @function
__rv64_task_enter_user:
    csrw sscratch, tp

    ld a0, 0 * 8(sp)    // argument
    ld ra, 1 * 8(sp)    // entry
    ld tp, 2 * 8(sp)    // thread pointer
    ld sp, 3 * 8(sp)    // user stack

    // Set SPIE to enable interrupts
    // Set SPP = 0 to indicate a return to U-mode
    li t1, (1 << 8)
    not t1, t1

    csrr t0, sstatus
    ori t0, t0, (1 << 5)
    and t0, t0, t1
    csrw sstatus, t0
    csrw sepc, ra

    sret
.size __rv64_task_enter_user, . - __rv64_task_enter_user

.option pop
