1 /**
2   ******************************************************************************
3   * @file    rv_Sv39.c
4   * @version V1.0
5   * @date
6   * @brief   This file is the RISC-V arch c file
7   ******************************************************************************
8   * @attention
9   *
10   * <h2><center>&copy; COPYRIGHT(c) 2021 Bouffalo Lab</center></h2>
11   *
12   * Redistribution and use in source and binary forms, with or without modification,
13   * are permitted provided that the following conditions are met:
14   *   1. Redistributions of source code must retain the above copyright notice,
15   *      this list of conditions and the following disclaimer.
16   *   2. Redistributions in binary form must reproduce the above copyright notice,
17   *      this list of conditions and the following disclaimer in the documentation
18   *      and/or other materials provided with the distribution.
19   *   3. Neither the name of Bouffalo Lab nor the names of its contributors
20   *      may be used to endorse or promote products derived from this software
21   *      without specific prior written permission.
22   *
23   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   *
34   ******************************************************************************
35   */
36 
37 #include <stdint.h>
38 #include "rv_Sv39.h"
39 
40 /** @addtogroup  RISCV_ARCH_Driver
41  *  @{
42  */
43 
44 /** @addtogroup  SV39
45  *  @{
46  */
47 
48 /* allocate 4KB page table buffer */
49 __attribute__((weak))
50 uint64_t *
RV_Sv39_alloc_PageTable_buf(void)51 RV_Sv39_alloc_PageTable_buf(void)
52 {
53     return NULL;
54 }
55 
56 /** @defgroup  SV39_Public_Functions
57  *  @{
58  */
59 
60 /******************************************************************************
61  * @brief  OSD blend layer configuration
62  *
63  * @param  cfg: point to the Page Table Entry.
64  * @param  tlb_index: return the TLB index in use if MAP is created directly in TLB.
65  * @param  ttb0: the root translation table in memory.
66  *
67  * @return Result of the operation.
68  *
69 *******************************************************************************/
70 
RV_Sv39_Create_PageMapping(Sv39_PTE_cfg_t * cfg,uintptr_t * tlb_index,volatile uintptr_t * ttb0)71 int RV_Sv39_Create_PageMapping(Sv39_PTE_cfg_t *cfg, uintptr_t *tlb_index, volatile uintptr_t *ttb0)
72 {
73     uintptr_t smeh, smel, smcir;
74     uintptr_t t0;
75     volatile uint64_t *ttb1 = NULL;
76     volatile uint64_t *ttb2 = NULL;
77 
78     if (Sv39_PTE_LOC_JTLB == cfg->where) {
79         t0 = cfg->va;
80         smeh = ((t0 >> 12) << SMEH_VPN_OFFSET) | cfg->size | cfg->asid;
81         __asm volatile("csrw smeh, %0"
82                        :
83                        : "r"(smeh)
84                        : "memory");
85 
86         t0 = cfg->pa;
87         smel = cfg->flags | ((t0 >> 12) << PTE_PPN_OFFSET);
88         __asm volatile("csrw smel, %0"
89                        :
90                        : "r"(smel)
91                        : "memory");
92 
93         if (cfg->tlb_entry >= SV39_JTLB_ENTRY_CNT) {
94             /* random write */
95             smcir = SMCIR_TLBWR;
96         } else {
97             RV_Sv39_Set_SMIR(cfg->tlb_entry);
98             smcir = SMCIR_TLBWI;
99         }
100 
101         smcir |= cfg->asid;
102         RV_Sv39_Set_SMCIR(smcir);
103 
104         RV_Sv39_Set_SMCIR(SMCIR_TLBP);
105         t0 = RV_Sv39_Get_SMIR();
106 
107         *tlb_index = t0;
108 
109         return (t0 & (SMCIR_PF | SMCIR_TF)) ? -1 : 0;
110     } else {
111         /* top level: 1GB */
112         t0 = SV39_VPN2(cfg->va);
113 
114         if (!ttb0[t0]) {
115             /* no translation for this 1GB range */
116             if (Sv39_PAGESIZE_1GB == cfg->size) {
117                 /* finish map for top level */
118                 ttb0[t0] = (SV39_PA2PPN(cfg->pa) << PTE_PPN_OFFSET) |
119                            (cfg->flags);
120                 return 0;
121             } else {
122                 ttb1 = RV_Sv39_alloc_PageTable_buf();
123 
124                 if (NULL == ttb1) {
125                     return -1;
126                 }
127 
128                 __COMPILE_BARRIER();
129                 ttb0[t0] = (SV39_PA2PPN((uint64_t)ttb1) << PTE_PPN_OFFSET) |
130                            PTE_D | PTE_A |
131                            PTE_XWR_NEXT | PTE_V;
132             }
133         } else {
134             /* already mapped, get the next level table pointer */
135             ttb1 = (volatile uint64_t *)SV39_PTE2PA(ttb0[t0]);
136         }
137 
138         /* second level: 2MB */
139         t0 = SV39_VPN1(cfg->va);
140 
141         if (!ttb1[t0]) {
142             /* no translation for this 2MB range */
143             if (Sv39_PAGESIZE_2MB == cfg->size) {
144                 ttb1[t0] = (SV39_PA2PPN(cfg->pa) << PTE_PPN_OFFSET) |
145                            (cfg->flags);
146                 return 0;
147             } else {
148                 ttb2 = RV_Sv39_alloc_PageTable_buf();
149 
150                 if (NULL == ttb2) {
151                     return -1;
152                 }
153 
154                 ttb1[t0] = (SV39_PA2PPN((uint64_t)ttb2) << PTE_PPN_OFFSET) |
155                            PTE_D | PTE_A |
156                            PTE_XWR_NEXT | PTE_V;
157             }
158         } else {
159             ttb2 = (volatile uint64_t *)SV39_PTE2PA(ttb1[t0]);
160         }
161 
162         /* third level: 4KB */
163         t0 = SV39_VPN0(cfg->va);
164         __COMPILE_BARRIER();
165         ttb2[t0] = (SV39_PA2PPN(cfg->pa) << PTE_PPN_OFFSET) |
166                    (cfg->flags);
167     }
168 
169     /* flush the D cache */
170 
171     return 0;
172 }
173 
174 /*@} end of group SV39_Public_Functions */
175 
176 /*@} end of group SV39 */
177 
178 /*@} end of group RISCV_ARCH_Driver */
179