1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-07-12     RT-Thread    first version.
9  */
10 #define DBG_TAG "hw.asid"
11 #define DBG_LVL DBG_INFO
12 #include <rtdbg.h>
13 
14 #include <rtthread.h>
15 #include <board.h>
16 #include <cache.h>
17 #include <mm_aspace.h>
18 #include <mm_page.h>
19 #include <mmu.h>
20 #include <riscv_mmu.h>
21 #include <tlb.h>
22 
23 static rt_uint8_t ASID_BITS = 0;
24 static rt_uint32_t next_asid;
25 static rt_uint64_t global_asid_generation;
26 #define ASID_MASK ((1 << ASID_BITS) - 1)
27 #define ASID_FIRST_GENERATION (1 << ASID_BITS)
28 #define MAX_ASID ASID_FIRST_GENERATION
29 
rt_hw_asid_init(void)30 void rt_hw_asid_init(void)
31 {
32     rt_uint64_t satp_reg = read_csr(satp);
33     satp_reg |= (((rt_uint64_t)0xffff) << PPN_BITS);
34     write_csr(satp, satp_reg);
35     __asm__ volatile("sfence.vma x0, x0");
36     unsigned short valid_asid_bit = ((read_csr(satp) >> PPN_BITS) & 0xffff);
37 
38     // The maximal value of ASIDLEN, is 9 for Sv32 or 16 for Sv39, Sv48, and Sv57
39     for (unsigned i = 0; i < 16; i++)
40     {
41         if (!(valid_asid_bit & 0x1))
42         {
43             break;
44         }
45 
46         valid_asid_bit >>= 1;
47         ASID_BITS++;
48     }
49 
50     global_asid_generation = ASID_FIRST_GENERATION;
51     next_asid = 1;
52 }
53 
_asid_acquire(rt_aspace_t aspace)54 static rt_uint64_t _asid_acquire(rt_aspace_t aspace)
55 {
56     if ((aspace->asid ^ global_asid_generation) >> ASID_BITS) // not same generation
57     {
58         if (next_asid != MAX_ASID)
59         {
60             aspace->asid = global_asid_generation | next_asid;
61             next_asid++;
62         }
63         else
64         {
65             // scroll to next generation
66             global_asid_generation += ASID_FIRST_GENERATION;
67             next_asid = 1;
68             rt_hw_tlb_invalidate_all_local();
69 
70             aspace->asid = global_asid_generation | next_asid;
71             next_asid++;
72         }
73     }
74 
75     return aspace->asid & ASID_MASK;
76 }
77 
rt_hw_asid_switch_pgtbl(struct rt_aspace * aspace,rt_ubase_t pgtbl)78 void rt_hw_asid_switch_pgtbl(struct rt_aspace *aspace, rt_ubase_t pgtbl)
79 {
80     rt_uint64_t asid = _asid_acquire(aspace);
81     write_csr(satp, (((size_t)SATP_MODE) << SATP_MODE_OFFSET) |
82                         (asid << PPN_BITS) |
83                         ((rt_ubase_t)pgtbl >> PAGE_OFFSET_BIT));
84     asm volatile("sfence.vma x0,%0"::"r"(asid):"memory");
85 }
86 
87