/** @file
  RISC-V Processor supervisor mode trap handler

  Copyright (c) 2019, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <Base.h>
#include <RiscVImpl.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>

#include "CpuExceptionHandlerLib.h"

  .align 3
  .section .entry, "ax", %progbits
  .globl SupervisorModeTrap
SupervisorModeTrap:
  addi sp, sp, -SMODE_TRAP_REGS_SIZE

  /* Save all general regisers except SP */
  sd    t0, SMODE_TRAP_REGS_OFFSET(t0)(sp)

  csrr  t0, RISCV_CSR_SUPERVISOR_SSTATUS
  and   t0, t0, (1 << SSTATUS_SIE_BIT_POSITION) | (1 << SSTATUS_SPP_BIT_POSITION)
  sd    t0, SMODE_TRAP_REGS_OFFSET(sstatus)(sp)
  csrr  t0, RISCV_CSR_SUPERVISOR_SEPC
  sd    t0, SMODE_TRAP_REGS_OFFSET(sepc)(sp)
  csrr  t0, RISCV_CSR_SUPERVISOR_SIE
  sd    t0, SMODE_TRAP_REGS_OFFSET(sie)(sp)
  ld    t0, SMODE_TRAP_REGS_OFFSET(t0)(sp)

  sd    ra, SMODE_TRAP_REGS_OFFSET(ra)(sp)
  sd    gp, SMODE_TRAP_REGS_OFFSET(gp)(sp)
  sd    tp, SMODE_TRAP_REGS_OFFSET(tp)(sp)
  sd    t1, SMODE_TRAP_REGS_OFFSET(t1)(sp)
  sd    t2, SMODE_TRAP_REGS_OFFSET(t2)(sp)
  sd    s0, SMODE_TRAP_REGS_OFFSET(s0)(sp)
  sd    s1, SMODE_TRAP_REGS_OFFSET(s1)(sp)
  sd    a0, SMODE_TRAP_REGS_OFFSET(a0)(sp)
  sd    a1, SMODE_TRAP_REGS_OFFSET(a1)(sp)
  sd    a2, SMODE_TRAP_REGS_OFFSET(a2)(sp)
  sd    a3, SMODE_TRAP_REGS_OFFSET(a3)(sp)
  sd    a4, SMODE_TRAP_REGS_OFFSET(a4)(sp)
  sd    a5, SMODE_TRAP_REGS_OFFSET(a5)(sp)
  sd    a6, SMODE_TRAP_REGS_OFFSET(a6)(sp)
  sd    a7, SMODE_TRAP_REGS_OFFSET(a7)(sp)
  sd    s2, SMODE_TRAP_REGS_OFFSET(s2)(sp)
  sd    s3, SMODE_TRAP_REGS_OFFSET(s3)(sp)
  sd    s4, SMODE_TRAP_REGS_OFFSET(s4)(sp)
  sd    s5, SMODE_TRAP_REGS_OFFSET(s5)(sp)
  sd    s6, SMODE_TRAP_REGS_OFFSET(s6)(sp)
  sd    s7, SMODE_TRAP_REGS_OFFSET(s7)(sp)
  sd    s8, SMODE_TRAP_REGS_OFFSET(s8)(sp)
  sd    s9, SMODE_TRAP_REGS_OFFSET(s9)(sp)
  sd    s10, SMODE_TRAP_REGS_OFFSET(s10)(sp)
  sd    s11, SMODE_TRAP_REGS_OFFSET(s11)(sp)
  sd    t3, SMODE_TRAP_REGS_OFFSET(t3)(sp)
  sd    t4, SMODE_TRAP_REGS_OFFSET(t4)(sp)
  sd    t5, SMODE_TRAP_REGS_OFFSET(t5)(sp)
  sd    t6, SMODE_TRAP_REGS_OFFSET(t6)(sp)

  /* Call to Supervisor mode trap handler in CpuExceptionHandlerLib.c */
  call  RiscVSupervisorModeTrapHandler

  /* Restore all general regisers except SP */
  ld    ra, SMODE_TRAP_REGS_OFFSET(ra)(sp)
  ld    gp, SMODE_TRAP_REGS_OFFSET(gp)(sp)
  ld    tp, SMODE_TRAP_REGS_OFFSET(tp)(sp)
  ld    t2, SMODE_TRAP_REGS_OFFSET(t2)(sp)
  ld    s0, SMODE_TRAP_REGS_OFFSET(s0)(sp)
  ld    s1, SMODE_TRAP_REGS_OFFSET(s1)(sp)
  ld    a0, SMODE_TRAP_REGS_OFFSET(a0)(sp)
  ld    a1, SMODE_TRAP_REGS_OFFSET(a1)(sp)
  ld    a2, SMODE_TRAP_REGS_OFFSET(a2)(sp)
  ld    a3, SMODE_TRAP_REGS_OFFSET(a3)(sp)
  ld    a4, SMODE_TRAP_REGS_OFFSET(a4)(sp)
  ld    a5, SMODE_TRAP_REGS_OFFSET(a5)(sp)
  ld    a6, SMODE_TRAP_REGS_OFFSET(a6)(sp)
  ld    a7, SMODE_TRAP_REGS_OFFSET(a7)(sp)
  ld    s2, SMODE_TRAP_REGS_OFFSET(s2)(sp)
  ld    s3, SMODE_TRAP_REGS_OFFSET(s3)(sp)
  ld    s4, SMODE_TRAP_REGS_OFFSET(s4)(sp)
  ld    s5, SMODE_TRAP_REGS_OFFSET(s5)(sp)
  ld    s6, SMODE_TRAP_REGS_OFFSET(s6)(sp)
  ld    s7, SMODE_TRAP_REGS_OFFSET(s7)(sp)
  ld    s8, SMODE_TRAP_REGS_OFFSET(s8)(sp)
  ld    s9, SMODE_TRAP_REGS_OFFSET(s9)(sp)
  ld    s10, SMODE_TRAP_REGS_OFFSET(s10)(sp)
  ld    s11, SMODE_TRAP_REGS_OFFSET(s11)(sp)
  ld    t3, SMODE_TRAP_REGS_OFFSET(t3)(sp)
  ld    t4, SMODE_TRAP_REGS_OFFSET(t4)(sp)
  ld    t5, SMODE_TRAP_REGS_OFFSET(t5)(sp)
  ld    t6, SMODE_TRAP_REGS_OFFSET(t6)(sp)

  ld    t0, SMODE_TRAP_REGS_OFFSET(sepc)(sp)
  csrw  RISCV_CSR_SUPERVISOR_SEPC, t0
  ld    t0, SMODE_TRAP_REGS_OFFSET(sie)(sp)
  csrw  RISCV_CSR_SUPERVISOR_SIE, t0
  csrr  t0, RISCV_CSR_SUPERVISOR_SSTATUS
  ld    t1, SMODE_TRAP_REGS_OFFSET(sstatus)(sp)
  or    t0, t0, t1
  csrw  RISCV_CSR_SUPERVISOR_SSTATUS, t0
  ld    t1, SMODE_TRAP_REGS_OFFSET(t1)(sp)
  ld    t0, SMODE_TRAP_REGS_OFFSET(t0)(sp)
  addi  sp, sp, SMODE_TRAP_REGS_SIZE
  sret
