199040Sbenno/*
299040Sbenno * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
399040Sbenno *
4139825Simp * SPDX-License-Identifier: GPL-2.0-only
599040Sbenno */
699040Sbenno
799040Sbenno#pragma once
899040Sbenno
999040Sbenno#include <util.h>
1099040Sbenno#include <arch/machine/registerset.h>
1199040Sbenno#include <arch/machine/hardware.h>
1299040Sbenno#include <arch/smp/ipi_inline.h>
1399040Sbenno
1499040Sbennostatic inline void set_fs_off(void)
1599040Sbenno{
1699040Sbenno    asm volatile("csrc sstatus, %0" :: "rK"(SSTATUS_FS));
1799040Sbenno}
1899040Sbenno
1999040Sbenno#ifdef CONFIG_HAVE_FPU
2099040Sbenno#if defined(CONFIG_RISCV_EXT_D)
2199040Sbenno
2299040Sbenno#define FL "fld"
2399040Sbenno#define FS "fsd"
2499040Sbenno#define FP_REG_BYTES "8"
2599040Sbenno
2699040Sbenno#elif defined(CONFIG_RISCV_EXT_F)
2799040Sbenno
2899040Sbenno#define FL "flw"
2999040Sbenno#define FS "fsw"
3099040Sbenno#define FP_REG_TYPES "4"
3199040Sbenno
3299040Sbenno#endif
3399040Sbenno
3499040Sbennoextern bool_t isFPUEnabledCached[CONFIG_MAX_NUM_NODES];
3599040Sbenno
3699040Sbennostatic inline void set_fs_clean(void)
3799040Sbenno{
3899040Sbenno    asm volatile("csrs sstatus, %0" :: "rK"(SSTATUS_FS_CLEAN));
3999040Sbenno}
4099040Sbenno
4199040Sbennostatic inline void set_fs_initial(void)
4299040Sbenno{
4399040Sbenno    asm volatile("csrs sstatus, %0" :: "rK"(SSTATUS_FS_INITIAL));
4499040Sbenno}
4599040Sbenno
4699040Sbennostatic inline void set_fs_dirty(void)
4799040Sbenno{
4899040Sbenno    asm volatile("csrs sstatus, %0" :: "rK"(SSTATUS_FS_DIRTY));
4999040Sbenno}
5099040Sbenno
5199040Sbennostatic inline word_t read_sstatus_fs(void)
5299040Sbenno{
5399040Sbenno    return (read_sstatus() & SSTATUS_FS);
5499040Sbenno}
5599040Sbenno
5699040Sbenno/* We unconditionally enable FPU accesses in kernel
5799040Sbenno * mode for save and store functions. The field
5899040Sbenno * we be set again before returning to user-mode
5999040Sbenno * to actually enable/disable FPU accesses in
6099040Sbenno * user mode.
6199040Sbenno */
6299040Sbennostatic inline void saveFpuState(user_fpu_state_t *dest)
6399040Sbenno{
6499040Sbenno    set_fs_clean();
6599040Sbenno
6699040Sbenno    asm volatile(
6799040Sbenno        FS " f0,  0*"  FP_REG_BYTES "(%0)\n\t"
6899040Sbenno        FS " f1,  1*"  FP_REG_BYTES "(%0)\n\t"
6999040Sbenno        FS " f2,  2*"  FP_REG_BYTES "(%0)\n\t"
7099040Sbenno        FS " f3,  3*"  FP_REG_BYTES "(%0)\n\t"
7199040Sbenno        FS " f4,  4*"  FP_REG_BYTES "(%0)\n\t"
7299040Sbenno        FS " f5,  5*"  FP_REG_BYTES "(%0)\n\t"
7399040Sbenno        FS " f6,  6*"  FP_REG_BYTES "(%0)\n\t"
7499040Sbenno        FS " f7,  7*"  FP_REG_BYTES "(%0)\n\t"
7599040Sbenno        FS " f8,  8*"  FP_REG_BYTES "(%0)\n\t"
7699040Sbenno        FS " f9,  9*"  FP_REG_BYTES "(%0)\n\t"
7799040Sbenno        FS " f10, 10*" FP_REG_BYTES "(%0)\n\t"
7899040Sbenno        FS " f11, 11*" FP_REG_BYTES "(%0)\n\t"
7999040Sbenno        FS " f12, 12*" FP_REG_BYTES "(%0)\n\t"
8099040Sbenno        FS " f13, 13*" FP_REG_BYTES "(%0)\n\t"
8199040Sbenno        FS " f14, 14*" FP_REG_BYTES "(%0)\n\t"
8299040Sbenno        FS " f15, 15*" FP_REG_BYTES "(%0)\n\t"
8399040Sbenno        FS " f16, 16*" FP_REG_BYTES "(%0)\n\t"
8499040Sbenno        FS " f17, 17*" FP_REG_BYTES "(%0)\n\t"
8599040Sbenno        FS " f18, 18*" FP_REG_BYTES "(%0)\n\t"
8699040Sbenno        FS " f19, 19*" FP_REG_BYTES "(%0)\n\t"
8799040Sbenno        FS " f20, 20*" FP_REG_BYTES "(%0)\n\t"
8899040Sbenno        FS " f21, 21*" FP_REG_BYTES "(%0)\n\t"
8999040Sbenno        FS " f22, 22*" FP_REG_BYTES "(%0)\n\t"
9099040Sbenno        FS " f23, 23*" FP_REG_BYTES "(%0)\n\t"
9199040Sbenno        FS " f24, 24*" FP_REG_BYTES "(%0)\n\t"
9299040Sbenno        FS " f25, 25*" FP_REG_BYTES "(%0)\n\t"
9399040Sbenno        FS " f26, 26*" FP_REG_BYTES "(%0)\n\t"
9499040Sbenno        FS " f27, 27*" FP_REG_BYTES "(%0)\n\t"
9599040Sbenno        FS " f28, 28*" FP_REG_BYTES "(%0)\n\t"
9699040Sbenno        FS " f29, 29*" FP_REG_BYTES "(%0)\n\t"
9799040Sbenno        FS " f30, 30*" FP_REG_BYTES "(%0)\n\t"
9899040Sbenno        FS " f31, 31*" FP_REG_BYTES "(%0)\n\t"
9999040Sbenno        :
10099040Sbenno        : "r"(&dest->regs[0])
10199040Sbenno        : "memory"
10299040Sbenno    );
10399040Sbenno
10499040Sbenno    dest->fcsr = read_fcsr();
10599040Sbenno}
10699040Sbenno
10799040Sbennostatic inline void loadFpuState(user_fpu_state_t *src)
10899040Sbenno{
10999040Sbenno    set_fs_clean();
11099040Sbenno
11199040Sbenno    asm volatile(
11299040Sbenno        FL " f0,  0*"  FP_REG_BYTES "(%0)\n\t"
11399040Sbenno        FL " f1,  1*"  FP_REG_BYTES "(%0)\n\t"
11499040Sbenno        FL " f2,  2*"  FP_REG_BYTES "(%0)\n\t"
11599040Sbenno        FL " f3,  3*"  FP_REG_BYTES "(%0)\n\t"
11699040Sbenno        FL " f4,  4*"  FP_REG_BYTES "(%0)\n\t"
11799040Sbenno        FL " f5,  5*"  FP_REG_BYTES "(%0)\n\t"
11899040Sbenno        FL " f6,  6*"  FP_REG_BYTES "(%0)\n\t"
11999040Sbenno        FL " f7,  7*"  FP_REG_BYTES "(%0)\n\t"
12099040Sbenno        FL " f8,  8*"  FP_REG_BYTES "(%0)\n\t"
12199040Sbenno        FL " f9,  9*"  FP_REG_BYTES "(%0)\n\t"
12299040Sbenno        FL " f10, 10*" FP_REG_BYTES "(%0)\n\t"
12399040Sbenno        FL " f11, 11*" FP_REG_BYTES "(%0)\n\t"
12499040Sbenno        FL " f12, 12*" FP_REG_BYTES "(%0)\n\t"
12599040Sbenno        FL " f13, 13*" FP_REG_BYTES "(%0)\n\t"
12699040Sbenno        FL " f14, 14*" FP_REG_BYTES "(%0)\n\t"
12799040Sbenno        FL " f15, 15*" FP_REG_BYTES "(%0)\n\t"
12899040Sbenno        FL " f16, 16*" FP_REG_BYTES "(%0)\n\t"
12999040Sbenno        FL " f17, 17*" FP_REG_BYTES "(%0)\n\t"
13099040Sbenno        FL " f18, 18*" FP_REG_BYTES "(%0)\n\t"
13199040Sbenno        FL " f19, 19*" FP_REG_BYTES "(%0)\n\t"
13299040Sbenno        FL " f20, 20*" FP_REG_BYTES "(%0)\n\t"
13399040Sbenno        FL " f21, 21*" FP_REG_BYTES "(%0)\n\t"
13499040Sbenno        FL " f22, 22*" FP_REG_BYTES "(%0)\n\t"
13599040Sbenno        FL " f23, 23*" FP_REG_BYTES "(%0)\n\t"
13699040Sbenno        FL " f24, 24*" FP_REG_BYTES "(%0)\n\t"
13799040Sbenno        FL " f25, 25*" FP_REG_BYTES "(%0)\n\t"
13899040Sbenno        FL " f26, 26*" FP_REG_BYTES "(%0)\n\t"
13999040Sbenno        FL " f27, 27*" FP_REG_BYTES "(%0)\n\t"
14099040Sbenno        FL " f28, 28*" FP_REG_BYTES "(%0)\n\t"
14199040Sbenno        FL " f29, 29*" FP_REG_BYTES "(%0)\n\t"
14299040Sbenno        FL " f30, 30*" FP_REG_BYTES "(%0)\n\t"
14399040Sbenno        FL " f31, 31*" FP_REG_BYTES "(%0)\n\t"
14499040Sbenno        :
14599040Sbenno        : "r"(&src->regs[0])
14699040Sbenno    );
14799040Sbenno
14899040Sbenno    write_fcsr(src->fcsr);
14999040Sbenno}
15099040Sbenno
15199040Sbennostatic inline void enableFpu(void)
15299040Sbenno{
15399040Sbenno    isFPUEnabledCached[SMP_TERNARY(getCurrentCPUIndex(), 0)] = true;
15499040Sbenno}
15599040Sbenno
15699040Sbennostatic inline void disableFpu(void)
15799040Sbenno{
15899040Sbenno    isFPUEnabledCached[SMP_TERNARY(getCurrentCPUIndex(), 0)] = false;
15999040Sbenno}
16099040Sbenno
16199040Sbennostatic inline bool_t isFpuEnable(void)
16299040Sbenno{
16399040Sbenno    return isFPUEnabledCached[SMP_TERNARY(getCurrentCPUIndex(), 0)];
16499040Sbenno}
16599040Sbenno
16699040Sbennostatic inline void set_tcb_fs_state(tcb_t *tcb, bool_t enabled)
16799040Sbenno{
16899040Sbenno    word_t sstatus = getRegister(tcb, SSTATUS);
16999040Sbenno    sstatus &= ~SSTATUS_FS;
17099040Sbenno    if (enabled) {
17199040Sbenno        sstatus |= SSTATUS_FS_CLEAN;
17299040Sbenno    }
17399040Sbenno    setRegister(tcb, SSTATUS, sstatus);
17499040Sbenno}
17599040Sbenno
17699040Sbenno#endif /* end of CONFIG_HAVE_FPU */
17799040Sbenno