blob: e904dab3ebafed434898acc8b0417345cb1bba48 [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
Andrew Scull80871322018-08-06 12:04:09 +01009/* A page table entry. */
10typedef uint64_t pte_t;
11
12#define PAGE_LEVEL_BITS 9
13
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010014/**
15 * Converts a physical address to a table PTE.
16 *
17 * The spec says that 'Table descriptors for stage 2 translations do not
18 * include any attribute field', so we don't take any attributes as arguments.
19 */
20static inline pte_t arch_mm_pa_to_table_pte(paddr_t pa)
21{
Andrew Scull265ada92018-07-30 15:19:01 +010022 return pa_addr(pa) | 0x3;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010023}
24
25/**
26 * Converts a physical address to a block PTE.
27 */
28static inline pte_t arch_mm_pa_to_block_pte(paddr_t pa, uint64_t attrs)
29{
Andrew Scull265ada92018-07-30 15:19:01 +010030 return pa_addr(pa) | attrs;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010031}
32
33/**
34 * Converts a physical address to a page PTE.
35 */
36static inline pte_t arch_mm_pa_to_page_pte(paddr_t pa, uint64_t attrs)
37{
Andrew Scull265ada92018-07-30 15:19:01 +010038 return pa_addr(pa) | attrs | ((attrs & 1) << 1);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010039}
40
41/**
42 * Converts a block PTE to a page PTE.
43 */
44static inline pte_t arch_mm_block_to_page_pte(pte_t pte)
45{
46 return pte | 2;
47}
48
49/**
50 * Specifies whether block mappings are acceptable at the given level.
51 */
52static inline bool arch_mm_is_block_allowed(int level)
53{
54 return level == 1 || level == 2;
55}
56
57/**
58 * Returns the encoding of a page table entry that isn't present.
59 */
60static inline pte_t arch_mm_absent_pte(void)
61{
62 return 0;
63}
64
65/**
66 * Determines if the given pte is present, i.e., if it points to another table,
67 * to a page, or a block of pages.
68 */
69static inline bool arch_mm_pte_is_present(pte_t pte)
70{
71 return (pte & 1) != 0;
72}
73
74/**
75 * Determines if the given pte references another table.
76 */
77static inline bool arch_mm_pte_is_table(pte_t pte)
78{
79 return (pte & 3) == 3;
80}
81
82/**
83 * Determines if the given pte references a block of pages.
84 */
85static inline bool arch_mm_pte_is_block(pte_t pte)
86{
87 return (pte & 3) == 1;
88}
89
Andrew Scull265ada92018-07-30 15:19:01 +010090#define CLEAR_PTE_ATTRS(v) \
91 ((v) & ~((1ull << PAGE_BITS) - 1) & ((1ull << 48) - 1))
92
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010093/**
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010094 * Clears the given physical address, i.e., sets the ignored bits (from a page
95 * table perspective) to zero.
96 */
Andrew Scull265ada92018-07-30 15:19:01 +010097static inline paddr_t arch_mm_clear_pa(paddr_t pa)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010098{
Andrew Scull265ada92018-07-30 15:19:01 +010099 return pa_init(CLEAR_PTE_ATTRS(pa_addr(pa)));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100100}
101
102/**
103 * Extracts the physical address from a page table entry.
104 */
105static inline paddr_t arch_mm_pte_to_paddr(pte_t pte)
106{
Andrew Scull265ada92018-07-30 15:19:01 +0100107 return pa_init(CLEAR_PTE_ATTRS(pte));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100108}
109
110/**
Andrew Scull80871322018-08-06 12:04:09 +0100111 * Extracts the physical address of the page table referred to by the given page
112 * table entry.
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100113 */
Andrew Scull80871322018-08-06 12:04:09 +0100114static inline paddr_t arch_mm_pte_to_table(pte_t pte)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100115{
Andrew Scull80871322018-08-06 12:04:09 +0100116 return pa_init(CLEAR_PTE_ATTRS(pte));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100117}
118
Andrew Scull265ada92018-07-30 15:19:01 +0100119#undef CLEAR_PTE_ATTRS
120
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100121/**
122 * Invalidates stage-1 TLB entries referring to the given virtual address range.
123 */
Andrew Scull265ada92018-07-30 15:19:01 +0100124static inline void arch_mm_invalidate_stage1_range(vaddr_t va_begin,
125 vaddr_t va_end)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100126{
Andrew Scull265ada92018-07-30 15:19:01 +0100127 uintvaddr_t begin = va_addr(va_begin);
128 uintvaddr_t end = va_addr(va_end);
129 uintvaddr_t it;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100130
131 begin >>= 12;
132 end >>= 12;
133
134 __asm__ volatile("dsb ishst");
135
Andrew Scull7364a8e2018-07-19 15:39:29 +0100136 for (it = begin; it < end; it += (1ull << (PAGE_BITS - 12))) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100137 __asm__("tlbi vae2is, %0" : : "r"(it));
Andrew Scull7364a8e2018-07-19 15:39:29 +0100138 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100139
140 __asm__ volatile("dsb ish");
141}
142
143/**
Andrew Scull80871322018-08-06 12:04:09 +0100144 * Invalidates stage-2 TLB entries referring to the given intermediate physical
145 * address range.
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100146 */
Andrew Scull80871322018-08-06 12:04:09 +0100147static inline void arch_mm_invalidate_stage2_range(ipaddr_t va_begin,
148 ipaddr_t va_end)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100149{
Andrew Scull80871322018-08-06 12:04:09 +0100150 uintpaddr_t begin = ipa_addr(va_begin);
151 uintpaddr_t end = ipa_addr(va_end);
152 uintpaddr_t it;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100153
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100154 /* TODO: This only applies to the current VMID. */
155
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100156 begin >>= 12;
157 end >>= 12;
158
159 __asm__ volatile("dsb ishst");
160
Andrew Scull7364a8e2018-07-19 15:39:29 +0100161 for (it = begin; it < end; it += (1ull << (PAGE_BITS - 12))) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100162 __asm__("tlbi ipas2e1, %0" : : "r"(it));
Andrew Scull7364a8e2018-07-19 15:39:29 +0100163 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100164
Andrew Scull4f170f52018-07-19 12:58:20 +0100165 __asm__ volatile(
166 "dsb ish\n"
167 "tlbi vmalle1is\n"
168 "dsb ish\n");
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100169}
170
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100171static inline void arch_mm_set_vm(uint64_t vmid, paddr_t table)
172{
Andrew Scull265ada92018-07-30 15:19:01 +0100173 __asm__ volatile("msr vttbr_el2, %0"
174 :
175 : "r"(pa_addr(table) | (vmid << 48)));
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100176}
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 */