blob: eaf7c4cefce4fbb943df2aaaa6544cc6c1bd0cac [file] [log] [blame]
Andrew Scullfbc938a2018-08-20 14:09:28 +01001#pragma once
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01002
3#include <stdbool.h>
4#include <stddef.h>
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01005
Andrew Scull18c78fc2018-08-20 12:57:41 +01006#include "hf/addr.h"
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01007
Andrew Scull80871322018-08-06 12:04:09 +01008/* A page table entry. */
9typedef uint64_t pte_t;
10
11#define PAGE_LEVEL_BITS 9
12
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010013/**
14 * Converts a physical address to a table PTE.
15 *
16 * The spec says that 'Table descriptors for stage 2 translations do not
17 * include any attribute field', so we don't take any attributes as arguments.
18 */
19static inline pte_t arch_mm_pa_to_table_pte(paddr_t pa)
20{
Andrew Scull265ada92018-07-30 15:19:01 +010021 return pa_addr(pa) | 0x3;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010022}
23
24/**
25 * Converts a physical address to a block PTE.
26 */
27static inline pte_t arch_mm_pa_to_block_pte(paddr_t pa, uint64_t attrs)
28{
Andrew Scull265ada92018-07-30 15:19:01 +010029 return pa_addr(pa) | attrs;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010030}
31
32/**
33 * Converts a physical address to a page PTE.
34 */
35static inline pte_t arch_mm_pa_to_page_pte(paddr_t pa, uint64_t attrs)
36{
Andrew Scull265ada92018-07-30 15:19:01 +010037 return pa_addr(pa) | attrs | ((attrs & 1) << 1);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010038}
39
40/**
41 * Converts a block PTE to a page PTE.
42 */
43static inline pte_t arch_mm_block_to_page_pte(pte_t pte)
44{
45 return pte | 2;
46}
47
48/**
49 * Specifies whether block mappings are acceptable at the given level.
50 */
51static inline bool arch_mm_is_block_allowed(int level)
52{
53 return level == 1 || level == 2;
54}
55
56/**
57 * Returns the encoding of a page table entry that isn't present.
58 */
59static inline pte_t arch_mm_absent_pte(void)
60{
61 return 0;
62}
63
64/**
65 * Determines if the given pte is present, i.e., if it points to another table,
66 * to a page, or a block of pages.
67 */
68static inline bool arch_mm_pte_is_present(pte_t pte)
69{
70 return (pte & 1) != 0;
71}
72
73/**
74 * Determines if the given pte references another table.
75 */
76static inline bool arch_mm_pte_is_table(pte_t pte)
77{
78 return (pte & 3) == 3;
79}
80
81/**
82 * Determines if the given pte references a block of pages.
83 */
84static inline bool arch_mm_pte_is_block(pte_t pte)
85{
86 return (pte & 3) == 1;
87}
88
Andrew Scull265ada92018-07-30 15:19:01 +010089#define CLEAR_PTE_ATTRS(v) \
90 ((v) & ~((1ull << PAGE_BITS) - 1) & ((1ull << 48) - 1))
91
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010092/**
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010093 * Clears the given physical address, i.e., sets the ignored bits (from a page
94 * table perspective) to zero.
95 */
Andrew Scull265ada92018-07-30 15:19:01 +010096static inline paddr_t arch_mm_clear_pa(paddr_t pa)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010097{
Andrew Scull265ada92018-07-30 15:19:01 +010098 return pa_init(CLEAR_PTE_ATTRS(pa_addr(pa)));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010099}
100
101/**
102 * Extracts the physical address from a page table entry.
103 */
104static inline paddr_t arch_mm_pte_to_paddr(pte_t pte)
105{
Andrew Scull265ada92018-07-30 15:19:01 +0100106 return pa_init(CLEAR_PTE_ATTRS(pte));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100107}
108
109/**
Andrew Scull80871322018-08-06 12:04:09 +0100110 * Extracts the physical address of the page table referred to by the given page
111 * table entry.
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100112 */
Andrew Scull80871322018-08-06 12:04:09 +0100113static inline paddr_t arch_mm_pte_to_table(pte_t pte)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100114{
Andrew Scull80871322018-08-06 12:04:09 +0100115 return pa_init(CLEAR_PTE_ATTRS(pte));
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100116}
117
Andrew Scull265ada92018-07-30 15:19:01 +0100118#undef CLEAR_PTE_ATTRS
119
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100120/**
121 * Invalidates stage-1 TLB entries referring to the given virtual address range.
122 */
Andrew Scull265ada92018-07-30 15:19:01 +0100123static inline void arch_mm_invalidate_stage1_range(vaddr_t va_begin,
124 vaddr_t va_end)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100125{
Andrew Scull265ada92018-07-30 15:19:01 +0100126 uintvaddr_t begin = va_addr(va_begin);
127 uintvaddr_t end = va_addr(va_end);
128 uintvaddr_t it;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100129
130 begin >>= 12;
131 end >>= 12;
132
133 __asm__ volatile("dsb ishst");
134
Andrew Scull7364a8e2018-07-19 15:39:29 +0100135 for (it = begin; it < end; it += (1ull << (PAGE_BITS - 12))) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100136 __asm__("tlbi vae2is, %0" : : "r"(it));
Andrew Scull7364a8e2018-07-19 15:39:29 +0100137 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100138
139 __asm__ volatile("dsb ish");
140}
141
142/**
Andrew Scull80871322018-08-06 12:04:09 +0100143 * Invalidates stage-2 TLB entries referring to the given intermediate physical
144 * address range.
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100145 */
Andrew Scull80871322018-08-06 12:04:09 +0100146static inline void arch_mm_invalidate_stage2_range(ipaddr_t va_begin,
147 ipaddr_t va_end)
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100148{
Andrew Scull80871322018-08-06 12:04:09 +0100149 uintpaddr_t begin = ipa_addr(va_begin);
150 uintpaddr_t end = ipa_addr(va_end);
151 uintpaddr_t it;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100152
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100153 /* TODO: This only applies to the current VMID. */
154
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100155 begin >>= 12;
156 end >>= 12;
157
158 __asm__ volatile("dsb ishst");
159
Andrew Scull7364a8e2018-07-19 15:39:29 +0100160 for (it = begin; it < end; it += (1ull << (PAGE_BITS - 12))) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100161 __asm__("tlbi ipas2e1, %0" : : "r"(it));
Andrew Scull7364a8e2018-07-19 15:39:29 +0100162 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100163
Andrew Scull4f170f52018-07-19 12:58:20 +0100164 __asm__ volatile(
165 "dsb ish\n"
166 "tlbi vmalle1is\n"
167 "dsb ish\n");
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100168}
169
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100170static inline void arch_mm_set_vm(uint64_t vmid, paddr_t table)
171{
Andrew Scull265ada92018-07-30 15:19:01 +0100172 __asm__ volatile("msr vttbr_el2, %0"
173 :
174 : "r"(pa_addr(table) | (vmid << 48)));
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100175}
176
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100177uint64_t arch_mm_mode_to_attrs(int mode);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100178bool arch_mm_init(paddr_t table, bool first);
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100179int arch_mm_max_level(int mode);