1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#pragma once
8
9#include <config.h>
10#include <arch/object/vcpu.h>
11
12#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
13
14/** Sets the VMID for the current stage 2 address space.
15 *
16 * This will update the current VMID in VTTBR while preserving the
17 * stage 2 translation table base paddr.
18 */
19static inline void writeContextIDPL2(word_t id)
20{
21    word_t pd_val, vmid;
22    asm volatile("mrrc p15, 6, %0, %1, c2" : "=r"(pd_val), "=r"(vmid));
23    asm volatile("mcrr p15, 6, %0, %1, c2" : : "r"(pd_val), "r"(id << (48-32)));
24    isb();
25}
26
27/** Sets the stage 2 translation table base address and VMID.
28 *
29 * The only difference between this and setCurrentPDPL2() is that
30 * the latter preserves the VMID.
31 */
32static inline void writeContextIDAndPD(word_t id, word_t pd_val)
33{
34    asm volatile("mcrr p15, 6, %0, %1, c2"  : : "r"(pd_val), "r"(id << (48-32)));
35    isb();
36}
37
38/** Sets the stage 2 translation table base address.
39 *
40 * "P15, 6, <r0>, <r1>, c2" refers to the VTTBR register.
41 *
42 * VTTBR can only be accessed in hyp mode (or monitor mode with SCR.NS==1).
43 * It sets the physical address of the page tables that the CPU will walk
44 * for stage 2 translation. It also sets the VMID of the current stage 2
45 * address space.
46 */
47static inline void setCurrentPDPL2(paddr_t addr)
48{
49    word_t pd_val, vmid;
50    asm volatile("mrrc p15, 6, %0, %1, c2" : "=r"(pd_val), "=r"(vmid));
51    dsb();
52    asm volatile("mcrr p15, 6, %0, %1, c2" : : "r"(addr), "r"(vmid));
53    isb();
54}
55
56static inline void setCurrentHypPD(paddr_t addr)
57{
58    word_t zero = 0;
59    dsb();
60    asm volatile("mcrr p15, 4, %0, %1, c2" : : "r"(addr), "r"(zero));
61    isb();
62}
63
64static inline void setVTCR(word_t r)
65{
66    dsb();
67    asm volatile("mcr p15, 4, %0, c2, c1, 2" : : "r"(r));
68    isb();
69}
70
71static inline void setHCR(word_t r)
72{
73    dsb();
74    asm volatile("mcr p15, 4, %0, c1, c1, 0" : : "r"(r));
75    isb();
76}
77
78static inline word_t getHCR(void)
79{
80    word_t HCR;
81    asm volatile("mrc p15, 4, %0, c1, c1, 0" : "=r"(HCR));
82    return HCR;
83}
84
85static inline void setHCPTR(word_t r)
86{
87    dsb();
88    asm volatile("mcr p15, 4, %0, c1, c1, 2" : : "r"(r));
89    isb();
90}
91
92static inline word_t PURE getHCPTR(void)
93{
94    word_t HCPTR;
95    asm volatile("mrc p15, 4, %0, c1, c1, 2" : "=r"(HCPTR));
96    return HCPTR;
97}
98
99static inline void setHMAIR(word_t hmair0, word_t hmair1)
100{
101    asm volatile("mcr p15, 4, %0, c10, c2, 0" : : "r"(hmair0));
102    asm volatile("mcr p15, 4, %0, c10, c2, 1" : : "r"(hmair1));
103    isb();
104}
105
106static inline void setMAIR(word_t hmair0, word_t hmair1)
107{
108    asm volatile("mcr p15, 0, %0, c10, c2, 0" : : "r"(hmair0));
109    asm volatile("mcr p15, 0, %0, c10, c2, 1" : : "r"(hmair1));
110    isb();
111}
112
113static inline void invalidateHypTLB(void)
114{
115    dsb();
116    asm volatile("mcr p15, 4, %0, c8, c7, 0" : : "r"(0));
117    dsb();
118    isb();
119}
120
121static inline paddr_t PURE addressTranslateS1CPR(vptr_t vaddr)
122{
123    uint32_t ipa0, ipa1;
124    asm volatile("mcr  p15, 0, %0, c7, c8, 0" :: "r"(vaddr));
125    isb();
126    asm volatile("mrrc p15, 0, %0, %1, c7"   : "=r"(ipa0), "=r"(ipa1));
127
128    return ipa0;
129}
130
131static inline word_t PURE getHSR(void)
132{
133    word_t HSR;
134    asm volatile("mrc p15, 4, %0, c5, c2, 0" : "=r"(HSR));
135    return HSR;
136}
137
138static inline word_t PURE getHDFAR(void)
139{
140    word_t HDFAR;
141    asm volatile("mrc p15, 4, %0, c6, c0, 0" : "=r"(HDFAR));
142    return HDFAR;
143}
144
145static inline word_t PURE getHIFAR(void)
146{
147    word_t HIFAR;
148    asm volatile("mrc p15, 4, %0, c6, c0, 2" : "=r"(HIFAR));
149    return HIFAR;
150}
151
152static inline word_t PURE getHPFAR(void)
153{
154    word_t HPFAR;
155    asm volatile("mrc p15, 4, %0, c6, c0, 4" : "=r"(HPFAR));
156    return HPFAR;
157}
158
159static inline word_t getSCTLR(void)
160{
161    word_t SCTLR;
162    asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(SCTLR));
163    return SCTLR;
164}
165
166static inline void setSCTLR(word_t sctlr)
167{
168    asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr));
169}
170
171static inline void writeHTPIDR(word_t reg)
172{
173    asm volatile("mcr p15, 4, %0, c13, c0, 2" :: "r"(reg));
174}
175
176static inline word_t readHTPIDR(void)
177{
178    word_t reg;
179    asm volatile("mrc p15, 4, %0, c13, c0, 2" : "=r"(reg));
180    return reg;
181}
182
183#else
184
185/* used in other files without guards */
186static inline void setCurrentPDPL2(paddr_t pa) {}
187static inline void invalidateHypTLB(void) {}
188static inline void writeContextIDPL2(word_t pd_val) {}
189static inline void writeContextIDAndPD(word_t id, word_t pd_val) {}
190static inline void writeHTPIDR(word_t htpidr) {}
191static inline word_t readHTPIDR(void)
192{
193    return 0;
194}
195static inline paddr_t addressTranslateS1CPR(vptr_t vaddr)
196{
197    return vaddr;
198}
199
200#endif /* !CONFIG_ARM_HYPERVISOR_SUPPORT */
201