mmu.c 6.6 KB
Newer Older
1
/*
B
bigmagic 已提交
2
 * Copyright (c) 2006-2019, RT-Thread Development Team
3
 *
B
bigmagic 已提交
4
 * SPDX-License-Identifier: Apache-2.0
5 6
 *
 * Change Logs:
B
bigmagic 已提交
7 8
 * Date           Author             Notes
 * 2020-02-20     bigmagic           first version
9 10
 */

B
bigmagic 已提交
11 12
#include <mmu.h>
#include <stddef.h>
13

B
bigmagic 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#define TTBR_CNP    1

typedef unsigned long int	uint64_t;

static unsigned long main_tbl[512 * 20] __attribute__((aligned (4096)));

#define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)

//映射方式
#define PMD_TYPE_SECT		(1 << 0)

#define PMD_TYPE_TABLE		(3 << 0)

#define PTE_TYPE_PAGE		(3 << 0)

#define BITS_PER_VA                39

/* Granule size of 4KB is being used */
#define GRANULE_SIZE_SHIFT         12
#define GRANULE_SIZE               (1 << GRANULE_SIZE_SHIFT)
#define XLAT_ADDR_MASK             ((1UL << BITS_PER_VA) - GRANULE_SIZE)
35

B
bigmagic 已提交
36 37 38 39 40 41 42
#define PMD_TYPE_MASK		(3 << 0)

int free_idx = 1;

void mmu_memset(char *dst, char v,  size_t len)
{
    while (len--)
43
    {
B
bigmagic 已提交
44 45 46
        *dst++ = v;
    }
}
47

B
bigmagic 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static unsigned long __page_off = 0;
static unsigned long get_free_page(void) {
    __page_off += 512;
    return (unsigned long)(main_tbl + __page_off);
}

void mmu_init(void)
{
    unsigned long val64;
    unsigned long val32; //val32不是uint32_t,val32只是表示相关的那个寄存器是32位的

    val64 = 0x007f6eUL;
    __asm__ volatile("msr MAIR_EL1, %0\n dsb sy\n"::"r"(val64));
    __asm__ volatile("mrs %0, MAIR_EL1\n dsb sy\n":"=r"(val64));

    //TCR_EL1
    val32 = (16UL << 0)//48 位
        | (0x0UL << 6)//没有用到
        | (0x0UL << 7)//使能enable lower half
        | (0x3UL << 8)//写回模式,没有cahce访问
        | (0x3UL << 10)//Inner Shareable
        | (0x2UL << 12)
        | (0x0UL << 14)//4K
        | (0x0UL << 16)
        | (0x0UL << 22)
        | (0x1UL << 23)
        | (0x2UL << 30)
        | (0x1UL << 32)
        | (0x0UL << 35)
        | (0x0UL << 36)
        | (0x0UL << 37)
        | (0x0UL << 38);
    __asm__ volatile("msr TCR_EL1, %0\n"::"r"(val32));
    __asm__ volatile("mrs %0, TCR_EL1\n":"=r"(val32));

    __asm__ volatile("msr TTBR0_EL1, %0\n dsb sy\n"::"r"(main_tbl));
    __asm__ volatile("mrs %0, TTBR0_EL1\n dsb sy\n":"=r"(val64));

    mmu_memset((char *)main_tbl, 0, 4096);
}

void mmu_enable(void)
{
    unsigned long val64;
    unsigned long val32;

    //关闭指令cache
    __asm__ volatile("mrs %0, SCTLR_EL1\n":"=r"(val64));
    val64 &= ~0x1000; //disable I
    __asm__ volatile("dmb sy\n msr SCTLR_EL1, %0\n isb sy\n"::"r"(val64));

    //清除指令cache
    __asm__ volatile("IC IALLUIS\n dsb sy\n isb sy\n");
    //清除tlb
    __asm__ volatile("tlbi vmalle1\n dsb sy\n isb sy\n");

    //SCTLR_EL1, turn on mmu
    __asm__ volatile("mrs %0, SCTLR_EL1\n":"=r"(val32));
    val32 |= 0x1005; //enable mmu, I C M
    __asm__ volatile("dmb sy\n msr SCTLR_EL1, %0\nisb sy\n"::"r"(val32));
}

static int map_single_page_2M(unsigned long* lv0_tbl, unsigned long va, unsigned long pa, unsigned long attr) {
    int level;
    unsigned long* cur_lv_tbl = lv0_tbl;
    unsigned long page;
    unsigned long off;
    int level_shift = 39;

    if (va & (0x200000UL - 1)) {
        return MMU_MAP_ERROR_VANOTALIGN;
    }
    if (pa & (0x200000UL - 1)) {
        return MMU_MAP_ERROR_PANOTALIGN;
    }
    for (level = 0; level < 2; level++) {
        off = (va >> level_shift);
        off &= MMU_LEVEL_MASK;
        if ((cur_lv_tbl[off] & 1) == 0) {
            page = get_free_page();
            if (!page) {
                return MMU_MAP_ERROR_NOPAGE;
            }
            mmu_memset((char *)page, 0, 4096);
            cur_lv_tbl[off] = page | 0x3UL;
133
        }
B
bigmagic 已提交
134 135 136 137
        page = cur_lv_tbl[off];
        if (!(page & 0x2)) {
            //is block! error!
            return MMU_MAP_ERROR_CONFLICT;
138
        }
B
bigmagic 已提交
139 140
        cur_lv_tbl = (unsigned long*)(page & 0x0000fffffffff000UL);
        level_shift -= 9;
141
    }
B
bigmagic 已提交
142 143 144 145 146 147
    attr &= 0xfff0000000000ffcUL;
    pa |= (attr | 0x1UL); //block
    off = (va >> 21);
    off &= MMU_LEVEL_MASK;
    cur_lv_tbl[off] = pa;
    return 0;
148 149
}

B
bigmagic 已提交
150
int armv8_map_2M(unsigned long va, unsigned long pa, int count, unsigned long attr)
151 152
{
    int i;
B
bigmagic 已提交
153
    int ret;
154

B
bigmagic 已提交
155
    if (va & (0x200000 - 1))
156
    {
B
bigmagic 已提交
157 158 159 160 161 162 163 164 165 166 167 168
        return -1;
    }
    if (pa & (0x200000 - 1))
    {
        return -1;
    }
    for (i = 0; i < count; i++)
    {
        ret = map_single_page_2M((unsigned long *)main_tbl, va, pa, attr);
        va += 0x200000;
        pa += 0x200000;
        if (ret != 0)
169
        {
B
bigmagic 已提交
170
            return ret;
171 172
        }
    }
B
bigmagic 已提交
173 174 175 176 177 178 179 180 181 182 183
    return 0;
}

//将表的地址映射到其他的地方去
static void set_table(uint64_t *pt, uint64_t *table_addr)
{
	uint64_t val;
    //0x607

	val = (0x3UL | (uint64_t)table_addr);//(0x3UL | (uint64_t)table_addr);
	*pt = val;
184 185
}

B
bigmagic 已提交
186
void mmu_memset2(unsigned char *dst, char v,  int len)
187
{
B
bigmagic 已提交
188
    while (len--)
189
    {
B
bigmagic 已提交
190
        *dst++ = v;
191 192 193
    }
}

B
bigmagic 已提交
194
static uint64_t *create_table(void)
195
{
B
bigmagic 已提交
196 197 198 199 200
	uint64_t *new_table = (uint64_t *)((unsigned char *)&main_tbl[0] + free_idx * 4096); //+ free_idx * GRANULE_SIZE;
	/* Mark all entries as invalid */
	mmu_memset2((unsigned char *)new_table, 0, 4096);
	free_idx++;
	return new_table;
B
bigmagic 已提交
201 202
}

B
bigmagic 已提交
203
static int pte_type(uint64_t *pte)
B
bigmagic 已提交
204
{
B
bigmagic 已提交
205
	return *pte & PMD_TYPE_MASK;
B
bigmagic 已提交
206 207
}

B
bigmagic 已提交
208
static int level2shift(int level)
B
bigmagic 已提交
209
{
B
bigmagic 已提交
210 211 212
	/* Page is 12 bits wide, every level translates 9 bits */
    //
	return (12 + 9 * (3 - level));
213 214
}

B
bigmagic 已提交
215 216 217 218 219 220 221

uint64_t *test_table = 0;



//根据表映射
static uint64_t *get_level_table(uint64_t *pte)
222
{
B
bigmagic 已提交
223 224 225 226 227 228 229 230
	uint64_t *table = (uint64_t *)(*pte & XLAT_ADDR_MASK);
	
	if (pte_type(pte) != PMD_TYPE_TABLE) {
		table = create_table();
		set_table(pte, table);
	}
	return table;
}
231 232


B
bigmagic 已提交
233 234 235 236 237 238 239 240 241
static void map_region(uint64_t virt, uint64_t phys, uint64_t size, uint64_t attr)
{
	uint64_t block_size = 0;
	uint64_t block_shift = 0;
	uint64_t *pte;
	uint64_t idx = 0;
	uint64_t addr = 0;
	uint64_t *table = 0;
	int level = 0;
242

B
bigmagic 已提交
243 244 245 246 247 248 249 250 251
	addr = virt;
	while (size) {
		table = &main_tbl[0];//将一级页表的地址赋值
		for (level = 0; level < 4; level++) {
			block_shift = level2shift(level);
            idx = addr >> block_shift;
			idx = idx%512;
            block_size = (uint64_t)(1L << block_shift);
			pte = table + idx;
252

B
bigmagic 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
			if (size >= block_size && IS_ALIGNED(addr, block_size)) {
                attr &= 0xfff0000000000ffcUL;
                if(level != 3)
                {
                    *pte = phys | (attr | 0x1UL);
                }
                else
                {
                    *pte = phys | (attr | 0x3UL);
                }
				addr += block_size;
				phys += block_size;
				size -= block_size;
				break;
			}
			table = get_level_table(pte);
		}
	}
271
}
B
bigmagic 已提交
272 273 274 275 276 277

void armv8_map(unsigned long va, unsigned long pa, unsigned long size, unsigned long attr)
{
    map_region(va, pa, size, attr);
}