blob: 2bd80f2824439f7198f5688f4f41383c9749429d [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>
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01006
Andrew Scull8dce4982018-08-06 13:02:20 +01007#include "addr.h"
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01008
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01009/**
10 * Converts a physical address to a table PTE.
11 *
12 * The spec says that 'Table descriptors for stage 2 translations do not
13 * include any attribute field', so we don't take any attributes as arguments.
14 */
15static inline pte_t arch_mm_pa_to_table_pte(paddr_t pa)
16{
Andrew Scull265ada92018-07-30 15:19:01 +010017 return pa_addr(pa) | 0x3;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010018}
19
20/**
21 * Converts a physical address to a block PTE.
22 */
23static inline pte_t arch_mm_pa_to_block_pte(paddr_t pa, uint64_t attrs)
24{
Andrew Scull265ada92018-07-30 15:19:01 +010025 return pa_addr(pa) | attrs;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010026}
27
28/**
29 * Converts a physical address to a page PTE.
30 */
31static inline pte_t arch_mm_pa_to_page_pte(paddr_t pa, uint64_t attrs)
32{
Andrew Scull265ada92018-07-30 15:19:01 +010033 return pa_addr(pa) | attrs | ((attrs & 1) << 1);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010034}
35
36/**
37 * Converts a block PTE to a page PTE.
38 */
39static inline pte_t arch_mm_block_to_page_pte(pte_t pte)
40{
41 return pte | 2;
42}
43
44/**
45 * Specifies whether block mappings are acceptable at the given level.
46 */
47static inline bool arch_mm_is_block_allowed(int level)
48{
49 return level == 1 || level == 2;
50}
51
52/**
53 * Returns the encoding of a page table entry that isn't present.
54 */
55static inline pte_t arch_mm_absent_pte(void)
56{
57 return 0;
58}
59
60/**
61 * Determines if the given pte is present, i.e., if it points to another table,
62 * to a page, or a block of pages.
63 */
64static inline bool arch_mm_pte_is_present(pte_t pte)
65{
66 return (pte & 1) != 0;
67}
68
69/**
70 * Determines if the given pte references another table.
71 */
72static inline bool arch_mm_pte_is_table(pte_t pte)
73{
74 return (pte & 3) == 3;
75}
76
77/**
78 * Determines if the given pte references a block of pages.
79 */
80static inline bool arch_mm_pte_is_block(pte_t pte)
81{
82 return (pte & 3) == 1;
83}
84
Andrew Scull265ada92018-07-30 15:19:01 +010085#define CLEAR_PTE_ATTRS(v) \
86 ((v) & ~((1ull << PAGE_BITS) - 1) & ((1ull << 48) - 1))
87
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010088/**
89 * Clears the given virtual address, i.e., sets the ignored bits (from a page
90 * table perspective) to zero.
91 */
Andrew Scull265ada92018-07-30 15:19:01 +010092static inline vaddr_t arch_mm_clear_va(vaddr_t va)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010093{
Andrew Scull265ada92018-07-30 15:19:01 +010094 return va_init(CLEAR_PTE_ATTRS(va_addr(va)));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010095}
96
97/**
98 * Clears the given physical address, i.e., sets the ignored bits (from a page
99 * table perspective) to zero.
100 */
Andrew Scull265ada92018-07-30 15:19:01 +0100101static inline paddr_t arch_mm_clear_pa(paddr_t pa)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100102{
Andrew Scull265ada92018-07-30 15:19:01 +0100103 return pa_init(CLEAR_PTE_ATTRS(pa_addr(pa)));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100104}
105
106/**
107 * Extracts the physical address from a page table entry.
108 */
109static inline paddr_t arch_mm_pte_to_paddr(pte_t pte)
110{
Andrew Scull265ada92018-07-30 15:19:01 +0100111 return pa_init(CLEAR_PTE_ATTRS(pte));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100112}
113
114/**
115 * Extracts a page table pointer from the given page table entry.
116 */
117static inline pte_t *arch_mm_pte_to_table(pte_t pte)
118{
Andrew Scull265ada92018-07-30 15:19:01 +0100119 return (pte_t *)CLEAR_PTE_ATTRS(pte);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100120}
121
Andrew Scull265ada92018-07-30 15:19:01 +0100122#undef CLEAR_PTE_ATTRS
123
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100124/**
125 * Invalidates stage-1 TLB entries referring to the given virtual address range.
126 */
Andrew Scull265ada92018-07-30 15:19:01 +0100127static inline void arch_mm_invalidate_stage1_range(vaddr_t va_begin,
128 vaddr_t va_end)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100129{
Andrew Scull265ada92018-07-30 15:19:01 +0100130 uintvaddr_t begin = va_addr(va_begin);
131 uintvaddr_t end = va_addr(va_end);
132 uintvaddr_t it;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100133
134 begin >>= 12;
135 end >>= 12;
136
137 __asm__ volatile("dsb ishst");
138
Andrew Scull7364a8e2018-07-19 15:39:29 +0100139 for (it = begin; it < end; it += (1ull << (PAGE_BITS - 12))) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100140 __asm__("tlbi vae2is, %0" : : "r"(it));
Andrew Scull7364a8e2018-07-19 15:39:29 +0100141 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100142
143 __asm__ volatile("dsb ish");
144}
145
146/**
147 * Invalidates stage-2 TLB entries referring to the given virtual address range.
148 */
Andrew Scull265ada92018-07-30 15:19:01 +0100149static inline void arch_mm_invalidate_stage2_range(vaddr_t va_begin,
150 vaddr_t va_end)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100151{
Andrew Scull265ada92018-07-30 15:19:01 +0100152 uintvaddr_t begin = va_addr(va_begin);
153 uintvaddr_t end = va_addr(va_end);
154 uintvaddr_t it;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100155
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{
Andrew Scull265ada92018-07-30 15:19:01 +0100175 __asm__ volatile("msr vttbr_el2, %0"
176 :
177 : "r"(pa_addr(table) | (vmid << 48)));
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100178}
179
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100180uint64_t arch_mm_mode_to_attrs(int mode);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100181bool arch_mm_init(paddr_t table, bool first);
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100182int arch_mm_max_level(int mode);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100183
Andrew Scull4f170f52018-07-19 12:58:20 +0100184#endif /* _ARCH_MM_H */