VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllGst-armv8.cpp.h

Last change on this file was 108142, checked in by vboxsync, 8 weeks ago

VMM/PGM: Renamed the PGMAll*.h files to indicate target/host. jiraref:VBP-1531

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.8 KB
Line 
1/* $Id: PGMAllGst-armv8.cpp.h 108142 2025-02-10 14:38:31Z vboxsync $ */
2/** @file
3 * PGM - Page Manager, ARMv8 Guest Paging Template - All context code.
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29
30DECLINLINE(int) pgmGstWalkReturnNotPresent(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel)
31{
32 NOREF(pVCpu);
33 pWalk->fNotPresent = true;
34 pWalk->uLevel = uLevel;
35 pWalk->fFailed = PGM_WALKFAIL_NOT_PRESENT
36 | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
37 return VERR_PAGE_TABLE_NOT_PRESENT;
38}
39
40DECLINLINE(int) pgmGstWalkReturnBadPhysAddr(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel, int rc)
41{
42 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc); NOREF(pVCpu);
43 pWalk->fBadPhysAddr = true;
44 pWalk->uLevel = uLevel;
45 pWalk->fFailed = PGM_WALKFAIL_BAD_PHYSICAL_ADDRESS
46 | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
47 return VERR_PAGE_TABLE_NOT_PRESENT;
48}
49
50
51DECLINLINE(int) pgmGstWalkReturnRsvdError(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel)
52{
53 NOREF(pVCpu);
54 pWalk->fRsvdError = true;
55 pWalk->uLevel = uLevel;
56 pWalk->fFailed = PGM_WALKFAIL_RESERVED_BITS
57 | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
58 return VERR_PAGE_TABLE_NOT_PRESENT;
59}
60
61
62DECLINLINE(int) pgmGstGetPageArmv8Hack(PVMCPUCC pVCpu, RTGCPTR GCPtr, PPGMPTWALK pWalk)
63{
64 VMCPU_ASSERT_EMT(pVCpu);
65 Assert(pWalk);
66
67 pWalk->fSucceeded = false;
68
69 RTGCPHYS GCPhysPt = CPUMGetEffectiveTtbr(pVCpu, GCPtr);
70 if (GCPhysPt == RTGCPHYS_MAX) /* MMU disabled? */
71 {
72 pWalk->GCPtr = GCPtr;
73 pWalk->fSucceeded = true;
74 pWalk->GCPhys = GCPtr;
75 return VINF_SUCCESS;
76 }
77
78 /* Do the translation. */
79 /** @todo This is just a sketch to get something working for debugging, assumes 4KiB granules and 48-bit output address.
80 * Needs to be moved to PGMAllGst like on x86 and implemented for 16KiB and 64KiB granule sizes. */
81 uint64_t u64TcrEl1 = CPUMGetTcrEl1(pVCpu);
82 uint8_t u8TxSz = (GCPtr & RT_BIT_64(55))
83 ? ARMV8_TCR_EL1_AARCH64_T1SZ_GET(u64TcrEl1)
84 : ARMV8_TCR_EL1_AARCH64_T0SZ_GET(u64TcrEl1);
85 uint8_t uLookupLvl;
86 RTGCPHYS fLookupMask;
87
88 /*
89 * From: https://github.com/codingbelief/arm-architecture-reference-manual-for-armv8-a/blob/master/en/chapter_d4/d42_2_controlling_address_translation_stages.md
90 * For all translation stages
91 * The maximum TxSZ value is 39. If TxSZ is programmed to a value larger than 39 then it is IMPLEMENTATION DEFINED whether:
92 * - The implementation behaves as if the field is programmed to 39 for all purposes other than reading back the value of the field.
93 * - Any use of the TxSZ value generates a Level 0 Translation fault for the stage of translation at which TxSZ is used.
94 *
95 * For a stage 1 translation
96 * The minimum TxSZ value is 16. If TxSZ is programmed to a value smaller than 16 then it is IMPLEMENTATION DEFINED whether:
97 * - The implementation behaves as if the field were programmed to 16 for all purposes other than reading back the value of the field.
98 * - Any use of the TxSZ value generates a stage 1 Level 0 Translation fault.
99 *
100 * We currently choose the former for both.
101 */
102 if (/*u8TxSz >= 16 &&*/ u8TxSz <= 24)
103 {
104 uLookupLvl = 0;
105 fLookupMask = RT_BIT_64(24 - u8TxSz + 1) - 1;
106 }
107 else if (u8TxSz >= 25 && u8TxSz <= 33)
108 {
109 uLookupLvl = 1;
110 fLookupMask = RT_BIT_64(33 - u8TxSz + 1) - 1;
111 }
112 else /*if (u8TxSz >= 34 && u8TxSz <= 39)*/
113 {
114 uLookupLvl = 2;
115 fLookupMask = RT_BIT_64(39 - u8TxSz + 1) - 1;
116 }
117 /*else
118 return pgmGstWalkReturnBadPhysAddr(pVCpu, pWalk, 0, VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS);*/ /** @todo Better status (Invalid TCR config). */
119
120 uint64_t *pu64Pt = NULL;
121 uint64_t uPt;
122 int rc;
123 if (uLookupLvl == 0)
124 {
125 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GCPhysPt, &pu64Pt);
126 if (RT_SUCCESS(rc)) { /* probable */ }
127 else return pgmGstWalkReturnBadPhysAddr(pVCpu, pWalk, 0, rc);
128
129 uPt = pu64Pt[(GCPtr >> 39) & fLookupMask];
130 if (uPt & RT_BIT_64(0)) { /* probable */ }
131 else return pgmGstWalkReturnNotPresent(pVCpu, pWalk, 0);
132
133 if (uPt & RT_BIT_64(1)) { /* probable */ }
134 else return pgmGstWalkReturnRsvdError(pVCpu, pWalk, 0); /** @todo Only supported if TCR_EL1.DS is set. */
135
136 /* All nine bits from now on. */
137 fLookupMask = RT_BIT_64(9) - 1;
138 GCPhysPt = (RTGCPHYS)(uPt & UINT64_C(0xfffffffff000));
139 }
140
141 if (uLookupLvl <= 1)
142 {
143 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GCPhysPt, &pu64Pt);
144 if (RT_SUCCESS(rc)) { /* probable */ }
145 else return pgmGstWalkReturnBadPhysAddr(pVCpu, pWalk, 1, rc);
146
147 uPt = pu64Pt[(GCPtr >> 30) & fLookupMask];
148 if (uPt & RT_BIT_64(0)) { /* probable */ }
149 else return pgmGstWalkReturnNotPresent(pVCpu, pWalk, 1);
150
151 if (uPt & RT_BIT_64(1)) { /* probable */ }
152 else
153 {
154 /* Block descriptor (1G page). */
155 pWalk->GCPtr = GCPtr;
156 pWalk->fSucceeded = true;
157 pWalk->GCPhys = (RTGCPHYS)(uPt & UINT64_C(0xffffc0000000)) | (GCPtr & (RTGCPTR)(_1G - 1));
158 pWalk->fGigantPage = true;
159 return VINF_SUCCESS;
160 }
161
162 /* All nine bits from now on. */
163 fLookupMask = RT_BIT_64(9) - 1;
164 GCPhysPt = (RTGCPHYS)(uPt & UINT64_C(0xfffffffff000));
165 }
166
167 if (uLookupLvl <= 2)
168 {
169 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GCPhysPt, &pu64Pt);
170 if (RT_SUCCESS(rc)) { /* probable */ }
171 else return pgmGstWalkReturnBadPhysAddr(pVCpu, pWalk, 2, rc);
172
173 uPt = pu64Pt[(GCPtr >> 21) & fLookupMask];
174 if (uPt & RT_BIT_64(0)) { /* probable */ }
175 else return pgmGstWalkReturnNotPresent(pVCpu, pWalk, 2);
176
177 if (uPt & RT_BIT_64(1)) { /* probable */ }
178 else
179 {
180 /* Block descriptor (2M page). */
181 pWalk->GCPtr = GCPtr;
182 pWalk->fSucceeded = true;
183 pWalk->GCPhys = (RTGCPHYS)(uPt & UINT64_C(0xffffffe00000)) | (GCPtr & (RTGCPTR)(_2M - 1));
184 pWalk->fBigPage = true;
185 return VINF_SUCCESS;
186 }
187
188 /* All nine bits from now on. */
189 fLookupMask = RT_BIT_64(9) - 1;
190 GCPhysPt = (RTGCPHYS)(uPt & UINT64_C(0xfffffffff000));
191 }
192
193 Assert(uLookupLvl <= 3);
194
195 /* Next level. */
196 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GCPhysPt, &pu64Pt);
197 if (RT_SUCCESS(rc)) { /* probable */ }
198 else return pgmGstWalkReturnBadPhysAddr(pVCpu, pWalk, 3, rc);
199
200 uPt = pu64Pt[(GCPtr & UINT64_C(0x1ff000)) >> 12];
201 if (uPt & RT_BIT_64(0)) { /* probable */ }
202 else return pgmGstWalkReturnNotPresent(pVCpu, pWalk, 3);
203
204 if (uPt & RT_BIT_64(1)) { /* probable */ }
205 else return pgmGstWalkReturnRsvdError(pVCpu, pWalk, 3); /** No block descriptors. */
206
207 pWalk->GCPtr = GCPtr;
208 pWalk->fSucceeded = true;
209 pWalk->GCPhys = (RTGCPHYS)(uPt & UINT64_C(0xfffffffff000)) | (GCPtr & (RTGCPTR)(_4K - 1));
210 return VINF_SUCCESS;
211}
212
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette