blob: 8662f78e9387991f3c40912e164a91da206fa69e [file] [log] [blame]
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01001#ifndef _ARCH_MM_H
2#define _ARCH_MM_H
3
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +01008/* A physical address. */
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01009typedef size_t paddr_t;
10
11/* A virtual address. */
12typedef size_t vaddr_t;
13
14/* A page table entry. */
15typedef size_t pte_t;
16
17#define PAGE_LEVEL_BITS 9
18#define PAGE_BITS 12
19
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010020/**
21 * Converts a physical address to a table PTE.
22 *
23 * The spec says that 'Table descriptors for stage 2 translations do not
24 * include any attribute field', so we don't take any attributes as arguments.
25 */
26static inline pte_t arch_mm_pa_to_table_pte(paddr_t pa)
27{
28 return pa | 0x3;
29}
30
31/**
32 * Converts a physical address to a block PTE.
33 */
34static inline pte_t arch_mm_pa_to_block_pte(paddr_t pa, uint64_t attrs)
35{
36 return pa | attrs;
37}
38
39/**
40 * Converts a physical address to a page PTE.
41 */
42static inline pte_t arch_mm_pa_to_page_pte(paddr_t pa, uint64_t attrs)
43{
44 return pa | attrs | ((attrs & 1) << 1);
45}
46
47/**
48 * Converts a block PTE to a page PTE.
49 */
50static inline pte_t arch_mm_block_to_page_pte(pte_t pte)
51{
52 return pte | 2;
53}
54
55/**
56 * Specifies whether block mappings are acceptable at the given level.
57 */
58static inline bool arch_mm_is_block_allowed(int level)
59{
60 return level == 1 || level == 2;
61}
62
63/**
64 * Returns the encoding of a page table entry that isn't present.
65 */
66static inline pte_t arch_mm_absent_pte(void)
67{
68 return 0;
69}
70
71/**
72 * Determines if the given pte is present, i.e., if it points to another table,
73 * to a page, or a block of pages.
74 */
75static inline bool arch_mm_pte_is_present(pte_t pte)
76{
77 return (pte & 1) != 0;
78}
79
80/**
81 * Determines if the given pte references another table.
82 */
83static inline bool arch_mm_pte_is_table(pte_t pte)
84{
85 return (pte & 3) == 3;
86}
87
88/**
89 * Determines if the given pte references a block of pages.
90 */
91static inline bool arch_mm_pte_is_block(pte_t pte)
92{
93 return (pte & 3) == 1;
94}
95
96/**
97 * Clears the given virtual address, i.e., sets the ignored bits (from a page
98 * table perspective) to zero.
99 */
100static inline vaddr_t arch_mm_clear_va(vaddr_t addr)
101{
102 return addr & ~((1ull << PAGE_BITS) - 1) & ((1ull << 48) - 1);
103}
104
105/**
106 * Clears the given physical address, i.e., sets the ignored bits (from a page
107 * table perspective) to zero.
108 */
109static inline paddr_t arch_mm_clear_pa(paddr_t addr)
110{
111 return addr & ~((1ull << PAGE_BITS) - 1) & ((1ull << 48) - 1);
112}
113
114/**
115 * Extracts the physical address from a page table entry.
116 */
117static inline paddr_t arch_mm_pte_to_paddr(pte_t pte)
118{
119 return arch_mm_clear_pa(pte);
120}
121
122/**
123 * Extracts a page table pointer from the given page table entry.
124 */
125static inline pte_t *arch_mm_pte_to_table(pte_t pte)
126{
127 return (pte_t *)arch_mm_pte_to_paddr(pte);
128}
129
130/**
131 * Invalidates stage-1 TLB entries referring to the given virtual address range.
132 */
133static inline void arch_mm_invalidate_stage1_range(vaddr_t begin, vaddr_t end)
134{
135 vaddr_t it;
136
137 begin >>= 12;
138 end >>= 12;
139
140 __asm__ volatile("dsb ishst");
141
Andrew Scull7364a8e2018-07-19 15:39:29 +0100142 for (it = begin; it < end; it += (1ull << (PAGE_BITS - 12))) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100143 __asm__("tlbi vae2is, %0" : : "r"(it));
Andrew Scull7364a8e2018-07-19 15:39:29 +0100144 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100145
146 __asm__ volatile("dsb ish");
147}
148
149/**
150 * Invalidates stage-2 TLB entries referring to the given virtual address range.
151 */
152static inline void arch_mm_invalidate_stage2_range(vaddr_t begin, vaddr_t end)
153{
154 vaddr_t it;
155
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100156 /* TODO: This only applies to the current VMID. */
157
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100158 begin >>= 12;
159 end >>= 12;
160
161 __asm__ volatile("dsb ishst");
162
Andrew Scull7364a8e2018-07-19 15:39:29 +0100163 for (it = begin; it < end; it += (1ull << (PAGE_BITS - 12))) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100164 __asm__("tlbi ipas2e1, %0" : : "r"(it));
Andrew Scull7364a8e2018-07-19 15:39:29 +0100165 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100166
Andrew Scull4f170f52018-07-19 12:58:20 +0100167 __asm__ volatile(
168 "dsb ish\n"
169 "tlbi vmalle1is\n"
170 "dsb ish\n");
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100171}
172
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100173static inline void arch_mm_set_vm(uint64_t vmid, paddr_t table)
174{
175 __asm__ volatile("msr vttbr_el2, %0" : : "r"(table | (vmid << 48)));
176}
177
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100178uint64_t arch_mm_mode_to_attrs(int mode);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100179bool arch_mm_init(paddr_t table, bool first);
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100180int arch_mm_max_level(int mode);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100181
Andrew Scull4f170f52018-07-19 12:58:20 +0100182#endif /* _ARCH_MM_H */