riscv_unpriv.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2019 Western Digital Corporation or its affiliates.
  5. *
  6. * Authors:
  7. * Anup Patel <anup.patel@wdc.com>
  8. */
  9. #include <sbi/riscv_encoding.h>
  10. #include <sbi/riscv_unpriv.h>
  11. #include <sbi/sbi_bits.h>
  12. #include <sbi/sbi_hart.h>
  13. #include <sbi/sbi_scratch.h>
  14. #define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn, insnlen) \
  15. type load_##type(const type *addr, \
  16. struct sbi_scratch *scratch, \
  17. struct unpriv_trap *trap) \
  18. { \
  19. register ulong __mstatus asm("a2"); \
  20. type val = 0; \
  21. trap->ilen = insnlen; \
  22. trap->cause = 0; \
  23. trap->tval = 0; \
  24. sbi_hart_set_trap_info(scratch, trap); \
  25. asm volatile( \
  26. "csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
  27. #insn " %1, %2\n" \
  28. "csrw " STR(CSR_MSTATUS) ", %0" \
  29. : "+&r"(__mstatus), "=&r"(val) \
  30. : "m"(*addr), "r"(MSTATUS_MPRV)); \
  31. sbi_hart_set_trap_info(scratch, NULL); \
  32. return val; \
  33. }
  34. #define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn, insnlen) \
  35. void store_##type(type *addr, type val, \
  36. struct sbi_scratch *scratch, \
  37. struct unpriv_trap *trap) \
  38. { \
  39. register ulong __mstatus asm("a3"); \
  40. trap->ilen = insnlen; \
  41. trap->cause = 0; \
  42. trap->tval = 0; \
  43. sbi_hart_set_trap_info(scratch, trap); \
  44. asm volatile( \
  45. "csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
  46. #insn " %1, %2\n" \
  47. "csrw " STR(CSR_MSTATUS) ", %0" \
  48. : "+&r"(__mstatus) \
  49. : "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \
  50. sbi_hart_set_trap_info(scratch, NULL); \
  51. }
  52. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu, 4)
  53. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu, 4)
  54. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb, 4)
  55. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh, 4)
  56. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw, 2)
  57. DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb, 4)
  58. DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh, 4)
  59. DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw, 2)
  60. #if __riscv_xlen == 64
  61. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu, 4)
  62. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld, 2)
  63. DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd, 2)
  64. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld, 2)
  65. #else
  66. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw, 2)
  67. DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw, 2)
  68. u64 load_u64(const u64 *addr,
  69. struct sbi_scratch *scratch, struct unpriv_trap *trap)
  70. {
  71. u64 ret = load_u32((u32 *)addr, scratch, trap);
  72. if (trap->cause)
  73. return 0;
  74. ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32);
  75. if (trap->cause)
  76. return 0;
  77. return ret;
  78. }
  79. void store_u64(u64 *addr, u64 val,
  80. struct sbi_scratch *scratch, struct unpriv_trap *trap)
  81. {
  82. store_u32((u32 *)addr, val, scratch, trap);
  83. if (trap->cause)
  84. return;
  85. store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
  86. if (trap->cause)
  87. return;
  88. }
  89. #endif
  90. ulong get_insn(ulong mepc, ulong *mstatus)
  91. {
  92. register ulong __mepc asm("a2") = mepc;
  93. register ulong __mstatus asm("a3");
  94. ulong val;
  95. #ifndef __riscv_compressed
  96. asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
  97. #if __riscv_xlen == 64
  98. STR(LWU) " %[insn], (%[addr])\n"
  99. #else
  100. STR(LW) " %[insn], (%[addr])\n"
  101. #endif
  102. "csrw " STR(CSR_MSTATUS) ", %[mstatus]"
  103. : [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
  104. : [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc));
  105. #else
  106. ulong rvc_mask = 3, tmp;
  107. asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
  108. "and %[tmp], %[addr], 2\n"
  109. "bnez %[tmp], 1f\n"
  110. #if __riscv_xlen == 64
  111. STR(LWU) " %[insn], (%[addr])\n"
  112. #else
  113. STR(LW) " %[insn], (%[addr])\n"
  114. #endif
  115. "and %[tmp], %[insn], %[rvc_mask]\n"
  116. "beq %[tmp], %[rvc_mask], 2f\n"
  117. "sll %[insn], %[insn], %[xlen_minus_16]\n"
  118. "srl %[insn], %[insn], %[xlen_minus_16]\n"
  119. "j 2f\n"
  120. "1:\n"
  121. "lhu %[insn], (%[addr])\n"
  122. "and %[tmp], %[insn], %[rvc_mask]\n"
  123. "bne %[tmp], %[rvc_mask], 2f\n"
  124. "lhu %[tmp], 2(%[addr])\n"
  125. "sll %[tmp], %[tmp], 16\n"
  126. "add %[insn], %[insn], %[tmp]\n"
  127. "2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
  128. : [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp)
  129. : [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc),
  130. [rvc_mask] "r"(rvc_mask), [xlen_minus_16] "i"(__riscv_xlen - 16));
  131. #endif
  132. if (mstatus)
  133. *mstatus = __mstatus;
  134. return val;
  135. }