VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/NEMR3NativeTemplate-linux.cpp.h

Last change on this file was 108670, checked in by vboxsync, 3 weeks ago

VMM/VMMR3/NEMR3NativeTemplate-linux.cpp.h: Make it compile with older versions of kvm.h, bugref:10391

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.4 KB
Line 
1/* $Id: NEMR3NativeTemplate-linux.cpp.h 108670 2025-03-20 17:27:56Z vboxsync $ */
2/** @file
3 * NEM - Native execution manager, native ring-3 Linux backend, common bits for x86 and arm64.
4 */
5
6/*
7 * Copyright (C) 2021-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 * Supply stuff missing from the kvm.h on the build box.
30 */
31#ifndef KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON /* since 5.4 */
32# define KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON 4
33#endif
34
35
36
37/**
38 * Worker for nemR3NativeInit that gets the hypervisor capabilities.
39 *
40 * @returns VBox status code.
41 * @param pVM The cross context VM structure.
42 * @param pErrInfo Where to always return error info.
43 */
44static int nemR3LnxInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo)
45{
46 AssertReturn(pVM->nem.s.fdKvm != -1, RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER, "Wrong initalization order"));
47
48 /*
49 * Capabilities.
50 */
51 static const struct
52 {
53 const char *pszName;
54 int iCap;
55 uint32_t offNem : 24;
56 uint32_t cbNem : 3;
57 uint32_t fReqNonZero : 1;
58 uint32_t uReserved : 4;
59 } s_aCaps[] =
60 {
61#define CAP_ENTRY__L(a_Define) { #a_Define, a_Define, UINT32_C(0x00ffffff), 0, 0, 0 }
62#define CAP_ENTRY__S(a_Define, a_Member) { #a_Define, a_Define, RT_UOFFSETOF(NEM, a_Member), RT_SIZEOFMEMB(NEM, a_Member), 0, 0 }
63#define CAP_ENTRY_MS(a_Define, a_Member) { #a_Define, a_Define, RT_UOFFSETOF(NEM, a_Member), RT_SIZEOFMEMB(NEM, a_Member), 1, 0 }
64#define CAP_ENTRY__U(a_Number) { "KVM_CAP_" #a_Number, a_Number, UINT32_C(0x00ffffff), 0, 0, 0 }
65#define CAP_ENTRY_ML(a_Number) { "KVM_CAP_" #a_Number, a_Number, UINT32_C(0x00ffffff), 0, 1, 0 }
66
67 CAP_ENTRY__L(KVM_CAP_IRQCHIP), /* 0 */
68#ifdef VBOX_VMM_TARGET_X86
69 CAP_ENTRY_ML(KVM_CAP_HLT),
70#else
71 CAP_ENTRY__L(KVM_CAP_HLT),
72#endif
73 CAP_ENTRY__L(KVM_CAP_MMU_SHADOW_CACHE_CONTROL),
74 CAP_ENTRY_ML(KVM_CAP_USER_MEMORY),
75 CAP_ENTRY__L(KVM_CAP_SET_TSS_ADDR),
76 CAP_ENTRY__U(5),
77 CAP_ENTRY__L(KVM_CAP_VAPIC),
78 CAP_ENTRY__L(KVM_CAP_EXT_CPUID),
79 CAP_ENTRY__L(KVM_CAP_CLOCKSOURCE),
80 CAP_ENTRY__L(KVM_CAP_NR_VCPUS),
81 CAP_ENTRY_MS(KVM_CAP_NR_MEMSLOTS, cMaxMemSlots), /* 10 */
82 CAP_ENTRY__L(KVM_CAP_PIT),
83 CAP_ENTRY__L(KVM_CAP_NOP_IO_DELAY),
84 CAP_ENTRY__L(KVM_CAP_PV_MMU),
85 CAP_ENTRY__L(KVM_CAP_MP_STATE),
86 CAP_ENTRY__L(KVM_CAP_COALESCED_MMIO),
87 CAP_ENTRY__L(KVM_CAP_SYNC_MMU),
88 CAP_ENTRY__U(17),
89 CAP_ENTRY__L(KVM_CAP_IOMMU),
90 CAP_ENTRY__U(19), /* Buggy KVM_CAP_JOIN_MEMORY_REGIONS? */
91 CAP_ENTRY__U(20), /* Mon-working KVM_CAP_DESTROY_MEMORY_REGION? */
92 CAP_ENTRY__L(KVM_CAP_DESTROY_MEMORY_REGION_WORKS), /* 21 */
93 CAP_ENTRY__L(KVM_CAP_USER_NMI),
94#ifdef __KVM_HAVE_GUEST_DEBUG
95 CAP_ENTRY__L(KVM_CAP_SET_GUEST_DEBUG),
96#endif
97#ifdef __KVM_HAVE_PIT
98 CAP_ENTRY__L(KVM_CAP_REINJECT_CONTROL),
99#endif
100 CAP_ENTRY__L(KVM_CAP_IRQ_ROUTING),
101 CAP_ENTRY__L(KVM_CAP_IRQ_INJECT_STATUS),
102 CAP_ENTRY__U(27),
103 CAP_ENTRY__U(28),
104 CAP_ENTRY__L(KVM_CAP_ASSIGN_DEV_IRQ),
105 CAP_ENTRY__L(KVM_CAP_JOIN_MEMORY_REGIONS_WORKS), /* 30 */
106#ifdef __KVM_HAVE_MCE
107 CAP_ENTRY__L(KVM_CAP_MCE),
108#endif
109 CAP_ENTRY__L(KVM_CAP_IRQFD),
110#ifdef __KVM_HAVE_PIT
111 CAP_ENTRY__L(KVM_CAP_PIT2),
112#endif
113 CAP_ENTRY__L(KVM_CAP_SET_BOOT_CPU_ID),
114#ifdef __KVM_HAVE_PIT_STATE2
115 CAP_ENTRY__L(KVM_CAP_PIT_STATE2),
116#endif
117 CAP_ENTRY__L(KVM_CAP_IOEVENTFD),
118 CAP_ENTRY__L(KVM_CAP_SET_IDENTITY_MAP_ADDR),
119#ifdef __KVM_HAVE_XEN_HVM
120 CAP_ENTRY__L(KVM_CAP_XEN_HVM),
121#endif
122#ifdef VBOX_VMM_TARGET_X86
123 CAP_ENTRY_ML(KVM_CAP_ADJUST_CLOCK),
124#else
125 CAP_ENTRY__L(KVM_CAP_ADJUST_CLOCK),
126#endif
127 CAP_ENTRY__L(KVM_CAP_INTERNAL_ERROR_DATA), /* 40 */
128#ifdef __KVM_HAVE_VCPU_EVENTS
129 CAP_ENTRY_ML(KVM_CAP_VCPU_EVENTS),
130#else
131 CAP_ENTRY__U(41),
132#endif
133 CAP_ENTRY__L(KVM_CAP_S390_PSW),
134 CAP_ENTRY__L(KVM_CAP_PPC_SEGSTATE),
135 CAP_ENTRY__L(KVM_CAP_HYPERV),
136 CAP_ENTRY__L(KVM_CAP_HYPERV_VAPIC),
137 CAP_ENTRY__L(KVM_CAP_HYPERV_SPIN),
138 CAP_ENTRY__L(KVM_CAP_PCI_SEGMENT),
139 CAP_ENTRY__L(KVM_CAP_PPC_PAIRED_SINGLES),
140 CAP_ENTRY__L(KVM_CAP_INTR_SHADOW),
141#ifdef __KVM_HAVE_DEBUGREGS
142 CAP_ENTRY__L(KVM_CAP_DEBUGREGS), /* 50 */
143#endif
144#ifdef VBOX_VMM_TARGET_X86
145 CAP_ENTRY__S(KVM_CAP_X86_ROBUST_SINGLESTEP, fRobustSingleStep),
146#else
147 CAP_ENTRY__L(KVM_CAP_X86_ROBUST_SINGLESTEP),
148#endif
149 CAP_ENTRY__L(KVM_CAP_PPC_OSI),
150 CAP_ENTRY__L(KVM_CAP_PPC_UNSET_IRQ),
151 CAP_ENTRY__L(KVM_CAP_ENABLE_CAP),
152#ifdef __KVM_HAVE_XSAVE
153 CAP_ENTRY_ML(KVM_CAP_XSAVE),
154#else
155 CAP_ENTRY__U(55),
156#endif
157#ifdef __KVM_HAVE_XCRS
158 CAP_ENTRY_ML(KVM_CAP_XCRS),
159#else
160 CAP_ENTRY__U(56),
161#endif
162 CAP_ENTRY__L(KVM_CAP_PPC_GET_PVINFO),
163 CAP_ENTRY__L(KVM_CAP_PPC_IRQ_LEVEL),
164 CAP_ENTRY__L(KVM_CAP_ASYNC_PF),
165 CAP_ENTRY__L(KVM_CAP_TSC_CONTROL), /* 60 */
166 CAP_ENTRY__L(KVM_CAP_GET_TSC_KHZ),
167 CAP_ENTRY__L(KVM_CAP_PPC_BOOKE_SREGS),
168 CAP_ENTRY__L(KVM_CAP_SPAPR_TCE),
169 CAP_ENTRY__L(KVM_CAP_PPC_SMT),
170 CAP_ENTRY__L(KVM_CAP_PPC_RMA),
171 CAP_ENTRY__L(KVM_CAP_MAX_VCPUS),
172 CAP_ENTRY__L(KVM_CAP_PPC_HIOR),
173 CAP_ENTRY__L(KVM_CAP_PPC_PAPR),
174 CAP_ENTRY__L(KVM_CAP_SW_TLB),
175 CAP_ENTRY__L(KVM_CAP_ONE_REG), /* 70 */
176 CAP_ENTRY__L(KVM_CAP_S390_GMAP),
177 CAP_ENTRY__L(KVM_CAP_TSC_DEADLINE_TIMER),
178 CAP_ENTRY__L(KVM_CAP_S390_UCONTROL),
179 CAP_ENTRY__L(KVM_CAP_SYNC_REGS),
180 CAP_ENTRY__L(KVM_CAP_PCI_2_3),
181 CAP_ENTRY__L(KVM_CAP_KVMCLOCK_CTRL),
182 CAP_ENTRY__L(KVM_CAP_SIGNAL_MSI),
183 CAP_ENTRY__L(KVM_CAP_PPC_GET_SMMU_INFO),
184 CAP_ENTRY__L(KVM_CAP_S390_COW),
185 CAP_ENTRY__L(KVM_CAP_PPC_ALLOC_HTAB), /* 80 */
186 CAP_ENTRY__L(KVM_CAP_READONLY_MEM),
187 CAP_ENTRY__L(KVM_CAP_IRQFD_RESAMPLE),
188 CAP_ENTRY__L(KVM_CAP_PPC_BOOKE_WATCHDOG),
189 CAP_ENTRY__L(KVM_CAP_PPC_HTAB_FD),
190 CAP_ENTRY__L(KVM_CAP_S390_CSS_SUPPORT),
191 CAP_ENTRY__L(KVM_CAP_PPC_EPR),
192#ifdef VBOX_VMM_TARGET_ARMV8
193 CAP_ENTRY_ML(KVM_CAP_ARM_PSCI),
194 CAP_ENTRY_ML(KVM_CAP_ARM_SET_DEVICE_ADDR),
195 CAP_ENTRY_ML(KVM_CAP_DEVICE_CTRL),
196#else
197 CAP_ENTRY__L(KVM_CAP_ARM_PSCI),
198 CAP_ENTRY__L(KVM_CAP_ARM_SET_DEVICE_ADDR),
199 CAP_ENTRY__L(KVM_CAP_DEVICE_CTRL),
200#endif
201 CAP_ENTRY__L(KVM_CAP_IRQ_MPIC), /* 90 */
202 CAP_ENTRY__L(KVM_CAP_PPC_RTAS),
203 CAP_ENTRY__L(KVM_CAP_IRQ_XICS),
204 CAP_ENTRY__L(KVM_CAP_ARM_EL1_32BIT),
205 CAP_ENTRY__L(KVM_CAP_SPAPR_MULTITCE),
206 CAP_ENTRY__L(KVM_CAP_EXT_EMUL_CPUID),
207 CAP_ENTRY__L(KVM_CAP_HYPERV_TIME),
208 CAP_ENTRY__L(KVM_CAP_IOAPIC_POLARITY_IGNORED),
209 CAP_ENTRY__L(KVM_CAP_ENABLE_CAP_VM),
210 CAP_ENTRY__L(KVM_CAP_S390_IRQCHIP),
211 CAP_ENTRY__L(KVM_CAP_IOEVENTFD_NO_LENGTH), /* 100 */
212 CAP_ENTRY__L(KVM_CAP_VM_ATTRIBUTES),
213#ifdef VBOX_VMM_TARGET_ARMV8
214 CAP_ENTRY_ML(KVM_CAP_ARM_PSCI_0_2),
215#else
216 CAP_ENTRY__L(KVM_CAP_ARM_PSCI_0_2),
217#endif
218 CAP_ENTRY__L(KVM_CAP_PPC_FIXUP_HCALL),
219 CAP_ENTRY__L(KVM_CAP_PPC_ENABLE_HCALL),
220 CAP_ENTRY__L(KVM_CAP_CHECK_EXTENSION_VM),
221 CAP_ENTRY__L(KVM_CAP_S390_USER_SIGP),
222 CAP_ENTRY__L(KVM_CAP_S390_VECTOR_REGISTERS),
223 CAP_ENTRY__L(KVM_CAP_S390_MEM_OP),
224 CAP_ENTRY__L(KVM_CAP_S390_USER_STSI),
225 CAP_ENTRY__L(KVM_CAP_S390_SKEYS), /* 110 */
226 CAP_ENTRY__L(KVM_CAP_MIPS_FPU),
227 CAP_ENTRY__L(KVM_CAP_MIPS_MSA),
228 CAP_ENTRY__L(KVM_CAP_S390_INJECT_IRQ),
229 CAP_ENTRY__L(KVM_CAP_S390_IRQ_STATE),
230 CAP_ENTRY__L(KVM_CAP_PPC_HWRNG),
231 CAP_ENTRY__L(KVM_CAP_DISABLE_QUIRKS),
232 CAP_ENTRY__L(KVM_CAP_X86_SMM),
233 CAP_ENTRY__L(KVM_CAP_MULTI_ADDRESS_SPACE),
234 CAP_ENTRY__L(KVM_CAP_GUEST_DEBUG_HW_BPS),
235 CAP_ENTRY__L(KVM_CAP_GUEST_DEBUG_HW_WPS), /* 120 */
236 CAP_ENTRY__L(KVM_CAP_SPLIT_IRQCHIP),
237 CAP_ENTRY__L(KVM_CAP_IOEVENTFD_ANY_LENGTH),
238 CAP_ENTRY__L(KVM_CAP_HYPERV_SYNIC),
239 CAP_ENTRY__L(KVM_CAP_S390_RI),
240 CAP_ENTRY__L(KVM_CAP_SPAPR_TCE_64),
241 CAP_ENTRY__L(KVM_CAP_ARM_PMU_V3),
242 CAP_ENTRY__L(KVM_CAP_VCPU_ATTRIBUTES),
243 CAP_ENTRY__L(KVM_CAP_MAX_VCPU_ID),
244 CAP_ENTRY__L(KVM_CAP_X2APIC_API),
245 CAP_ENTRY__L(KVM_CAP_S390_USER_INSTR0), /* 130 */
246 CAP_ENTRY__L(KVM_CAP_MSI_DEVID),
247 CAP_ENTRY__L(KVM_CAP_PPC_HTM),
248 CAP_ENTRY__L(KVM_CAP_SPAPR_RESIZE_HPT),
249 CAP_ENTRY__L(KVM_CAP_PPC_MMU_RADIX),
250 CAP_ENTRY__L(KVM_CAP_PPC_MMU_HASH_V3),
251 CAP_ENTRY__L(KVM_CAP_IMMEDIATE_EXIT),
252 CAP_ENTRY__L(KVM_CAP_MIPS_VZ),
253 CAP_ENTRY__L(KVM_CAP_MIPS_TE),
254 CAP_ENTRY__L(KVM_CAP_MIPS_64BIT),
255 CAP_ENTRY__L(KVM_CAP_S390_GS), /* 140 */
256 CAP_ENTRY__L(KVM_CAP_S390_AIS),
257 CAP_ENTRY__L(KVM_CAP_SPAPR_TCE_VFIO),
258 CAP_ENTRY__L(KVM_CAP_X86_DISABLE_EXITS),
259 CAP_ENTRY__L(KVM_CAP_ARM_USER_IRQ),
260 CAP_ENTRY__L(KVM_CAP_S390_CMMA_MIGRATION),
261 CAP_ENTRY__L(KVM_CAP_PPC_FWNMI),
262 CAP_ENTRY__L(KVM_CAP_PPC_SMT_POSSIBLE),
263 CAP_ENTRY__L(KVM_CAP_HYPERV_SYNIC2),
264 CAP_ENTRY__L(KVM_CAP_HYPERV_VP_INDEX),
265 CAP_ENTRY__L(KVM_CAP_S390_AIS_MIGRATION), /* 150 */
266 CAP_ENTRY__L(KVM_CAP_PPC_GET_CPU_CHAR),
267 CAP_ENTRY__L(KVM_CAP_S390_BPB),
268 CAP_ENTRY__L(KVM_CAP_GET_MSR_FEATURES),
269 CAP_ENTRY__L(KVM_CAP_HYPERV_EVENTFD),
270 CAP_ENTRY__L(KVM_CAP_HYPERV_TLBFLUSH),
271 CAP_ENTRY__L(KVM_CAP_S390_HPAGE_1M),
272 CAP_ENTRY__L(KVM_CAP_NESTED_STATE),
273 CAP_ENTRY__L(KVM_CAP_ARM_INJECT_SERROR_ESR),
274 CAP_ENTRY__L(KVM_CAP_MSR_PLATFORM_INFO),
275 CAP_ENTRY__L(KVM_CAP_PPC_NESTED_HV), /* 160 */
276 CAP_ENTRY__L(KVM_CAP_HYPERV_SEND_IPI),
277 CAP_ENTRY__L(KVM_CAP_COALESCED_PIO),
278 CAP_ENTRY__L(KVM_CAP_HYPERV_ENLIGHTENED_VMCS),
279 CAP_ENTRY__L(KVM_CAP_EXCEPTION_PAYLOAD),
280#ifdef VBOX_VMM_TARGET_ARMV8
281 CAP_ENTRY_MS(KVM_CAP_ARM_VM_IPA_SIZE, cIpaBits),
282#else
283 CAP_ENTRY__L(KVM_CAP_ARM_VM_IPA_SIZE),
284#endif
285 CAP_ENTRY__L(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT),
286 CAP_ENTRY__L(KVM_CAP_HYPERV_CPUID),
287 CAP_ENTRY__L(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2),
288 CAP_ENTRY__L(KVM_CAP_PPC_IRQ_XIVE),
289 CAP_ENTRY__L(KVM_CAP_ARM_SVE), /* 170 */
290 CAP_ENTRY__L(KVM_CAP_ARM_PTRAUTH_ADDRESS),
291 CAP_ENTRY__L(KVM_CAP_ARM_PTRAUTH_GENERIC),
292 CAP_ENTRY__L(KVM_CAP_PMU_EVENT_FILTER),
293 CAP_ENTRY__L(KVM_CAP_ARM_IRQ_LINE_LAYOUT_2),
294 CAP_ENTRY__L(KVM_CAP_HYPERV_DIRECT_TLBFLUSH),
295 CAP_ENTRY__L(KVM_CAP_PPC_GUEST_DEBUG_SSTEP),
296 CAP_ENTRY__L(KVM_CAP_ARM_NISV_TO_USER),
297 CAP_ENTRY__L(KVM_CAP_ARM_INJECT_EXT_DABT),
298 CAP_ENTRY__L(KVM_CAP_S390_VCPU_RESETS),
299 CAP_ENTRY__L(KVM_CAP_S390_PROTECTED), /* 180 */
300 CAP_ENTRY__L(KVM_CAP_PPC_SECURE_GUEST),
301 CAP_ENTRY__L(KVM_CAP_HALT_POLL),
302 CAP_ENTRY__L(KVM_CAP_ASYNC_PF_INT),
303 CAP_ENTRY__L(KVM_CAP_LAST_CPU),
304 CAP_ENTRY__L(KVM_CAP_SMALLER_MAXPHYADDR),
305 CAP_ENTRY__L(KVM_CAP_S390_DIAG318),
306 CAP_ENTRY__L(KVM_CAP_STEAL_TIME),
307#ifdef VBOX_VMM_TARGET_X86
308 CAP_ENTRY_ML(KVM_CAP_X86_USER_SPACE_MSR), /* (since 5.10) */
309 CAP_ENTRY_ML(KVM_CAP_X86_MSR_FILTER),
310#else
311 CAP_ENTRY__L(KVM_CAP_X86_USER_SPACE_MSR), /* (since 5.10) */
312 CAP_ENTRY__L(KVM_CAP_X86_MSR_FILTER),
313#endif
314 CAP_ENTRY__L(KVM_CAP_ENFORCE_PV_FEATURE_CPUID), /* 190 */
315#ifndef RT_ARCH_ARM64 /* Buildroot is too old. */
316 CAP_ENTRY__L(KVM_CAP_SYS_HYPERV_CPUID),
317 CAP_ENTRY__L(KVM_CAP_DIRTY_LOG_RING),
318 CAP_ENTRY__L(KVM_CAP_X86_BUS_LOCK_EXIT),
319 CAP_ENTRY__L(KVM_CAP_PPC_DAWR1),
320 CAP_ENTRY__L(KVM_CAP_SET_GUEST_DEBUG2),
321 CAP_ENTRY__L(KVM_CAP_SGX_ATTRIBUTE),
322 CAP_ENTRY__L(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM),
323 CAP_ENTRY__L(KVM_CAP_PTP_KVM),
324#else
325 CAP_ENTRY__U(191),
326 CAP_ENTRY__U(192),
327 CAP_ENTRY__U(193),
328 CAP_ENTRY__U(194),
329 CAP_ENTRY__U(195),
330 CAP_ENTRY__U(196),
331 CAP_ENTRY__U(197),
332 CAP_ENTRY__U(198),
333#endif
334 CAP_ENTRY__U(199),
335 CAP_ENTRY__U(200),
336 CAP_ENTRY__U(201),
337 CAP_ENTRY__U(202),
338 CAP_ENTRY__U(203),
339 CAP_ENTRY__U(204),
340 CAP_ENTRY__U(205),
341 CAP_ENTRY__U(206),
342 CAP_ENTRY__U(207),
343 CAP_ENTRY__U(208),
344 CAP_ENTRY__U(209),
345 CAP_ENTRY__U(210),
346 CAP_ENTRY__U(211),
347 CAP_ENTRY__U(212),
348 CAP_ENTRY__U(213),
349 CAP_ENTRY__U(214),
350 CAP_ENTRY__U(215),
351 CAP_ENTRY__U(216),
352 };
353
354 LogRel(("NEM: KVM capabilities (system):\n"));
355 int rcRet = VINF_SUCCESS;
356 for (unsigned i = 0; i < RT_ELEMENTS(s_aCaps); i++)
357 {
358 int rc = ioctl(pVM->nem.s.fdKvm, KVM_CHECK_EXTENSION, s_aCaps[i].iCap);
359 if (rc >= 10)
360 LogRel(("NEM: %36s: %#x (%d)\n", s_aCaps[i].pszName, rc, rc));
361 else if (rc >= 0)
362 LogRel(("NEM: %36s: %d\n", s_aCaps[i].pszName, rc));
363 else
364 LogRel(("NEM: %s failed: %d/%d\n", s_aCaps[i].pszName, rc, errno));
365 switch (s_aCaps[i].cbNem)
366 {
367 case 0:
368 break;
369 case 1:
370 {
371 uint8_t *puValue = (uint8_t *)&pVM->nem.padding[s_aCaps[i].offNem];
372 AssertReturn(s_aCaps[i].offNem <= sizeof(NEM) - sizeof(*puValue), VERR_NEM_IPE_0);
373 *puValue = (uint8_t)rc;
374 AssertLogRelMsg((int)*puValue == rc, ("%s: %#x\n", s_aCaps[i].pszName, rc));
375 break;
376 }
377 case 2:
378 {
379 uint16_t *puValue = (uint16_t *)&pVM->nem.padding[s_aCaps[i].offNem];
380 AssertReturn(s_aCaps[i].offNem <= sizeof(NEM) - sizeof(*puValue), VERR_NEM_IPE_0);
381 *puValue = (uint16_t)rc;
382 AssertLogRelMsg((int)*puValue == rc, ("%s: %#x\n", s_aCaps[i].pszName, rc));
383 break;
384 }
385 case 4:
386 {
387 uint32_t *puValue = (uint32_t *)&pVM->nem.padding[s_aCaps[i].offNem];
388 AssertReturn(s_aCaps[i].offNem <= sizeof(NEM) - sizeof(*puValue), VERR_NEM_IPE_0);
389 *puValue = (uint32_t)rc;
390 AssertLogRelMsg((int)*puValue == rc, ("%s: %#x\n", s_aCaps[i].pszName, rc));
391 break;
392 }
393 default:
394 rcRet = RTErrInfoSetF(pErrInfo, VERR_NEM_IPE_0, "s_aCaps[%u] is bad: cbNem=%#x - %s",
395 i, s_aCaps[i].pszName, s_aCaps[i].cbNem);
396 AssertFailedReturn(rcRet);
397 }
398
399 /*
400 * Is a require non-zero entry zero or failing?
401 */
402 if (s_aCaps[i].fReqNonZero && rc <= 0)
403 rcRet = RTERRINFO_LOG_REL_ADD_F(pErrInfo, VERR_NEM_MISSING_FEATURE,
404 "Required capability '%s' is missing!", s_aCaps[i].pszName);
405 }
406
407 /*
408 * Get per VCpu KVM_RUN MMAP area size.
409 */
410 int rc = ioctl(pVM->nem.s.fdKvm, KVM_GET_VCPU_MMAP_SIZE, 0UL);
411 if ((unsigned)rc < _64M)
412 {
413 pVM->nem.s.cbVCpuMmap = (uint32_t)rc;
414 LogRel(("NEM: %36s: %#x (%d)\n", "KVM_GET_VCPU_MMAP_SIZE", rc, rc));
415 }
416 else if (rc < 0)
417 rcRet = RTERRINFO_LOG_REL_ADD_F(pErrInfo, VERR_NEM_MISSING_FEATURE, "KVM_GET_VCPU_MMAP_SIZE failed: %d", errno);
418 else
419 rcRet = RTERRINFO_LOG_REL_ADD_F(pErrInfo, VERR_NEM_INIT_FAILED, "Odd KVM_GET_VCPU_MMAP_SIZE value: %#x (%d)", rc, rc);
420
421 /*
422 * Init the slot ID bitmap.
423 */
424 ASMBitSet(&pVM->nem.s.bmSlotIds[0], 0); /* don't use slot 0 */
425 if (pVM->nem.s.cMaxMemSlots < _32K)
426 ASMBitSetRange(&pVM->nem.s.bmSlotIds[0], pVM->nem.s.cMaxMemSlots, _32K);
427 ASMBitSet(&pVM->nem.s.bmSlotIds[0], _32K - 1); /* don't use the last slot */
428
429 return rcRet;
430}
431
432
433/** @callback_method_impl{FNVMMEMTRENDEZVOUS} */
434static DECLCALLBACK(VBOXSTRICTRC) nemR3LnxFixThreadPoke(PVM pVM, PVMCPU pVCpu, void *pvUser)
435{
436 RT_NOREF(pVM, pvUser);
437 int rc = RTThreadControlPokeSignal(pVCpu->hThread, true /*fEnable*/);
438 AssertLogRelRC(rc);
439 return VINF_SUCCESS;
440}
441
442
443/**
444 * Try initialize the native API.
445 *
446 * This may only do part of the job, more can be done in
447 * nemR3NativeInitAfterCPUM() and nemR3NativeInitCompleted().
448 *
449 * @returns VBox status code.
450 * @param pVM The cross context VM structure.
451 * @param fFallback Whether we're in fallback mode or use-NEM mode. In
452 * the latter we'll fail if we cannot initialize.
453 * @param fForced Whether the HMForced flag is set and we should
454 * fail if we cannot initialize.
455 */
456int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced)
457{
458 RT_NOREF(pVM, fFallback, fForced);
459 /*
460 * Some state init.
461 */
462 pVM->nem.s.fdKvm = -1;
463 pVM->nem.s.fdVm = -1;
464 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
465 {
466 PNEMCPU pNemCpu = &pVM->apCpusR3[idCpu]->nem.s;
467 pNemCpu->fdVCpu = -1;
468 }
469
470 /*
471 * Error state.
472 * The error message will be non-empty on failure and 'rc' will be set too.
473 */
474 RTERRINFOSTATIC ErrInfo;
475 PRTERRINFO pErrInfo = RTErrInfoInitStatic(&ErrInfo);
476
477 /*
478 * Open kvm subsystem so we can issue system ioctls.
479 */
480 int rc;
481 int fdKvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
482 if (fdKvm >= 0)
483 {
484 pVM->nem.s.fdKvm = fdKvm;
485
486 /*
487 * Check capabilities.
488 */
489 rc = nemR3LnxInitCheckCapabilities(pVM, pErrInfo);
490 if (RT_SUCCESS(rc))
491 {
492 /*
493 * Create an empty VM since it is recommended we check capabilities on
494 * the VM rather than the system descriptor.
495 */
496#ifdef VBOX_VMM_TARGET_ARMV8
497 int fdVm = ioctl(fdKvm, KVM_CREATE_VM, pVM->nem.s.cIpaBits);
498#else
499 int fdVm = ioctl(fdKvm, KVM_CREATE_VM, 0UL /* Type must be zero on x86 */);
500#endif
501 if (fdVm >= 0)
502 {
503 pVM->nem.s.fdVm = fdVm;
504
505 /*
506 * Set up the VM (more on this later).
507 */
508 rc = nemR3LnxInitSetupVm(pVM, pErrInfo);
509 if (RT_SUCCESS(rc))
510 {
511 /*
512 * Set ourselves as the execution engine and make config adjustments.
513 */
514 VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);
515 Log(("NEM: Marked active!\n"));
516 PGMR3EnableNemMode(pVM);
517
518 /*
519 * Register release statistics
520 */
521 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
522 {
523 PNEMCPU pNemCpu = &pVM->apCpusR3[idCpu]->nem.s;
524 STAMR3RegisterF(pVM, &pNemCpu->StatImportOnDemand, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of on-demand state imports", "/NEM/CPU%u/ImportOnDemand", idCpu);
525 STAMR3RegisterF(pVM, &pNemCpu->StatImportOnReturn, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of state imports on loop return", "/NEM/CPU%u/ImportOnReturn", idCpu);
526 STAMR3RegisterF(pVM, &pNemCpu->StatImportOnReturnSkipped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of skipped state imports on loop return", "/NEM/CPU%u/ImportOnReturnSkipped", idCpu);
527 STAMR3RegisterF(pVM, &pNemCpu->StatImportPendingInterrupt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of times an interrupt was pending when importing from KVM", "/NEM/CPU%u/ImportPendingInterrupt", idCpu);
528 STAMR3RegisterF(pVM, &pNemCpu->StatExportPendingInterrupt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of times an interrupt was pending when exporting to KVM", "/NEM/CPU%u/ExportPendingInterrupt", idCpu);
529 STAMR3RegisterF(pVM, &pNemCpu->StatFlushExitOnReturn, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of times a KVM_EXIT_IO or KVM_EXIT_MMIO was flushed before returning to EM", "/NEM/CPU%u/FlushExitOnReturn", idCpu);
530 STAMR3RegisterF(pVM, &pNemCpu->StatFlushExitOnReturn1Loop, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of times a KVM_EXIT_IO or KVM_EXIT_MMIO was flushed before returning to EM", "/NEM/CPU%u/FlushExitOnReturn-01-loop", idCpu);
531 STAMR3RegisterF(pVM, &pNemCpu->StatFlushExitOnReturn2Loops, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of times a KVM_EXIT_IO or KVM_EXIT_MMIO was flushed before returning to EM", "/NEM/CPU%u/FlushExitOnReturn-02-loops", idCpu);
532 STAMR3RegisterF(pVM, &pNemCpu->StatFlushExitOnReturn3Loops, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of times a KVM_EXIT_IO or KVM_EXIT_MMIO was flushed before returning to EM", "/NEM/CPU%u/FlushExitOnReturn-03-loops", idCpu);
533 STAMR3RegisterF(pVM, &pNemCpu->StatFlushExitOnReturn4PlusLoops, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of times a KVM_EXIT_IO or KVM_EXIT_MMIO was flushed before returning to EM", "/NEM/CPU%u/FlushExitOnReturn-04-to-7-loops", idCpu);
534 STAMR3RegisterF(pVM, &pNemCpu->StatQueryCpuTick, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TSC queries", "/NEM/CPU%u/QueryCpuTick", idCpu);
535 STAMR3RegisterF(pVM, &pNemCpu->StatExitTotal, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "All exits", "/NEM/CPU%u/Exit", idCpu);
536 STAMR3RegisterF(pVM, &pNemCpu->StatExitIo, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_IO", "/NEM/CPU%u/Exit/Io", idCpu);
537 STAMR3RegisterF(pVM, &pNemCpu->StatExitMmio, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_MMIO", "/NEM/CPU%u/Exit/Mmio", idCpu);
538 STAMR3RegisterF(pVM, &pNemCpu->StatExitSetTpr, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_SET_TRP", "/NEM/CPU%u/Exit/SetTpr", idCpu);
539 STAMR3RegisterF(pVM, &pNemCpu->StatExitTprAccess, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_TPR_ACCESS", "/NEM/CPU%u/Exit/TprAccess", idCpu);
540 STAMR3RegisterF(pVM, &pNemCpu->StatExitRdMsr, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_RDMSR", "/NEM/CPU%u/Exit/RdMsr", idCpu);
541 STAMR3RegisterF(pVM, &pNemCpu->StatExitWrMsr, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_WRMSR", "/NEM/CPU%u/Exit/WrMsr", idCpu);
542 STAMR3RegisterF(pVM, &pNemCpu->StatExitIrqWindowOpen, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_IRQ_WINDOWS_OPEN", "/NEM/CPU%u/Exit/IrqWindowOpen", idCpu);
543 STAMR3RegisterF(pVM, &pNemCpu->StatExitHalt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_HLT", "/NEM/CPU%u/Exit/Hlt", idCpu);
544 STAMR3RegisterF(pVM, &pNemCpu->StatExitIntr, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_INTR", "/NEM/CPU%u/Exit/Intr", idCpu);
545 STAMR3RegisterF(pVM, &pNemCpu->StatExitHypercall, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_HYPERCALL", "/NEM/CPU%u/Exit/Hypercall", idCpu);
546 STAMR3RegisterF(pVM, &pNemCpu->StatExitDebug, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_DEBUG", "/NEM/CPU%u/Exit/Debug", idCpu);
547 STAMR3RegisterF(pVM, &pNemCpu->StatExitBusLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_BUS_LOCK", "/NEM/CPU%u/Exit/BusLock", idCpu);
548 STAMR3RegisterF(pVM, &pNemCpu->StatExitInternalErrorEmulation, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_INTERNAL_ERROR/EMULATION", "/NEM/CPU%u/Exit/InternalErrorEmulation", idCpu);
549 STAMR3RegisterF(pVM, &pNemCpu->StatExitInternalErrorFatal, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "KVM_EXIT_INTERNAL_ERROR/*", "/NEM/CPU%u/Exit/InternalErrorFatal", idCpu);
550 }
551
552 /*
553 * Success.
554 */
555 return VINF_SUCCESS;
556 }
557 close(fdVm);
558 pVM->nem.s.fdVm = -1;
559
560 /*
561 * Bail out.
562 */
563 }
564 else
565 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, "KVM_CREATE_VM failed: %u", errno);
566 }
567 close(fdKvm);
568 pVM->nem.s.fdKvm = -1;
569 }
570 else if (errno == EACCES)
571 rc = RTErrInfoSet(pErrInfo, VERR_ACCESS_DENIED, "Do not have access to open /dev/kvm for reading & writing.");
572 else if (errno == ENOENT)
573 rc = RTErrInfoSet(pErrInfo, VERR_NOT_SUPPORTED, "KVM is not availble (/dev/kvm does not exist)");
574 else
575 rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromErrno(errno), "Failed to open '/dev/kvm': %u", errno);
576
577 /*
578 * We only fail if in forced mode, otherwise just log the complaint and return.
579 */
580 Assert(RTErrInfoIsSet(pErrInfo));
581 if ( (fForced || !fFallback)
582 && pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NATIVE_API)
583 return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s", pErrInfo->pszMsg);
584 LogRel(("NEM: Not available: %s\n", pErrInfo->pszMsg));
585 return VINF_SUCCESS;
586}
587
588
589/**
590 * This is called after CPUMR3Init is done.
591 *
592 * @returns VBox status code.
593 * @param pVM The VM handle..
594 */
595int nemR3NativeInitAfterCPUM(PVM pVM)
596{
597 /*
598 * Validate sanity.
599 */
600 AssertReturn(pVM->nem.s.fdKvm >= 0, VERR_WRONG_ORDER);
601 AssertReturn(pVM->nem.s.fdVm >= 0, VERR_WRONG_ORDER);
602 AssertReturn(pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API, VERR_WRONG_ORDER);
603
604 /** @todo */
605
606 return VINF_SUCCESS;
607}
608
609
610int nemR3NativeTerm(PVM pVM)
611{
612 /*
613 * Per-cpu data
614 */
615 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
616 {
617 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
618
619 if (pVCpu->nem.s.fdVCpu != -1)
620 {
621 close(pVCpu->nem.s.fdVCpu);
622 pVCpu->nem.s.fdVCpu = -1;
623 }
624 if (pVCpu->nem.s.pRun)
625 {
626 munmap(pVCpu->nem.s.pRun, pVM->nem.s.cbVCpuMmap);
627 pVCpu->nem.s.pRun = NULL;
628 }
629 }
630
631 /*
632 * Global data.
633 */
634 if (pVM->nem.s.fdVm != -1)
635 {
636 close(pVM->nem.s.fdVm);
637 pVM->nem.s.fdVm = -1;
638 }
639
640 if (pVM->nem.s.fdKvm != -1)
641 {
642 close(pVM->nem.s.fdKvm);
643 pVM->nem.s.fdKvm = -1;
644 }
645 return VINF_SUCCESS;
646}
647
648
649/**
650 * VM reset notification.
651 *
652 * @param pVM The cross context VM structure.
653 */
654void nemR3NativeReset(PVM pVM)
655{
656 RT_NOREF(pVM);
657}
658
659
660/**
661 * Reset CPU due to INIT IPI or hot (un)plugging.
662 *
663 * @param pVCpu The cross context virtual CPU structure of the CPU being
664 * reset.
665 * @param fInitIpi Whether this is the INIT IPI or hot (un)plugging case.
666 */
667void nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi)
668{
669 RT_NOREF(pVCpu, fInitIpi);
670}
671
672
673/*********************************************************************************************************************************
674* Memory management *
675*********************************************************************************************************************************/
676
677
678/**
679 * Allocates a memory slot ID.
680 *
681 * @returns Slot ID on success, UINT16_MAX on failure.
682 */
683static uint16_t nemR3LnxMemSlotIdAlloc(PVM pVM)
684{
685 /* Use the hint first. */
686 uint16_t idHint = pVM->nem.s.idPrevSlot;
687 if (idHint < _32K - 1)
688 {
689 int32_t idx = ASMBitNextClear(&pVM->nem.s.bmSlotIds, _32K, idHint);
690 Assert(idx < _32K);
691 if (idx > 0 && !ASMAtomicBitTestAndSet(&pVM->nem.s.bmSlotIds, idx))
692 return pVM->nem.s.idPrevSlot = (uint16_t)idx;
693 }
694
695 /*
696 * Search the whole map from the start.
697 */
698 int32_t idx = ASMBitFirstClear(&pVM->nem.s.bmSlotIds, _32K);
699 Assert(idx < _32K);
700 if (idx > 0 && !ASMAtomicBitTestAndSet(&pVM->nem.s.bmSlotIds, idx))
701 return pVM->nem.s.idPrevSlot = (uint16_t)idx;
702
703 Assert(idx < 0 /*shouldn't trigger unless there is a race */);
704 return UINT16_MAX; /* caller is expected to assert. */
705}
706
707
708/**
709 * Frees a memory slot ID
710 */
711static void nemR3LnxMemSlotIdFree(PVM pVM, uint16_t idSlot)
712{
713 if (RT_LIKELY(idSlot < _32K && ASMAtomicBitTestAndClear(&pVM->nem.s.bmSlotIds, idSlot)))
714 { /*likely*/ }
715 else
716 AssertMsgFailed(("idSlot=%u (%#x)\n", idSlot, idSlot));
717}
718
719
720
721VMMR3_INT_DECL(int) NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvR3,
722 uint8_t *pu2State, uint32_t *puNemRange)
723{
724 uint16_t idSlot = nemR3LnxMemSlotIdAlloc(pVM);
725 AssertLogRelReturn(idSlot < _32K, VERR_NEM_MAP_PAGES_FAILED);
726
727 Log5(("NEMR3NotifyPhysRamRegister: %RGp LB %RGp, pvR3=%p pu2State=%p (%d) puNemRange=%p (%d) - idSlot=%#x\n",
728 GCPhys, cb, pvR3, pu2State, pu2State, puNemRange, *puNemRange, idSlot));
729
730 struct kvm_userspace_memory_region Region;
731 Region.slot = idSlot;
732 Region.flags = 0;
733 Region.guest_phys_addr = GCPhys;
734 Region.memory_size = cb;
735 Region.userspace_addr = (uintptr_t)pvR3;
736
737 int rc = ioctl(pVM->nem.s.fdVm, KVM_SET_USER_MEMORY_REGION, &Region);
738 if (rc == 0)
739 {
740 *pu2State = 0;
741 *puNemRange = idSlot;
742 return VINF_SUCCESS;
743 }
744
745 LogRel(("NEMR3NotifyPhysRamRegister: %RGp LB %RGp, pvR3=%p, idSlot=%#x failed: %u/%u\n", GCPhys, cb, pvR3, idSlot, rc, errno));
746 nemR3LnxMemSlotIdFree(pVM, idSlot);
747 return VERR_NEM_MAP_PAGES_FAILED;
748}
749
750
751VMMR3_INT_DECL(bool) NEMR3IsMmio2DirtyPageTrackingSupported(PVM pVM)
752{
753 RT_NOREF(pVM);
754 return true;
755}
756
757
758VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags,
759 void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange)
760{
761 Log5(("NEMR3NotifyPhysMmioExMapEarly: %RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p pu2State=%p (%d) puNemRange=%p (%#x)\n",
762 GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State, *pu2State, puNemRange, puNemRange ? *puNemRange : UINT32_MAX));
763 RT_NOREF(pvRam);
764
765 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE)
766 {
767 /** @todo implement splitting and whatnot of ranges if we want to be 100%
768 * conforming (just modify RAM registrations in MM.cpp to test). */
769 AssertLogRelMsgFailedReturn(("%RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p\n", GCPhys, cb, fFlags, pvRam, pvMmio2),
770 VERR_NEM_MAP_PAGES_FAILED);
771 }
772
773 /*
774 * Register MMIO2.
775 */
776 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2)
777 {
778 AssertReturn(pvMmio2, VERR_NEM_MAP_PAGES_FAILED);
779 AssertReturn(puNemRange, VERR_NEM_MAP_PAGES_FAILED);
780
781 uint16_t idSlot = nemR3LnxMemSlotIdAlloc(pVM);
782 AssertLogRelReturn(idSlot < _32K, VERR_NEM_MAP_PAGES_FAILED);
783
784 struct kvm_userspace_memory_region Region;
785 Region.slot = idSlot;
786 Region.flags = fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES ? KVM_MEM_LOG_DIRTY_PAGES : 0;
787 Region.guest_phys_addr = GCPhys;
788 Region.memory_size = cb;
789 Region.userspace_addr = (uintptr_t)pvMmio2;
790
791 int rc = ioctl(pVM->nem.s.fdVm, KVM_SET_USER_MEMORY_REGION, &Region);
792 if (rc == 0)
793 {
794 *pu2State = 0;
795 *puNemRange = idSlot;
796 Log5(("NEMR3NotifyPhysMmioExMapEarly: %RGp LB %RGp fFlags=%#x pvMmio2=%p - idSlot=%#x\n",
797 GCPhys, cb, fFlags, pvMmio2, idSlot));
798 return VINF_SUCCESS;
799 }
800
801 nemR3LnxMemSlotIdFree(pVM, idSlot);
802 AssertLogRelMsgFailedReturn(("%RGp LB %RGp fFlags=%#x, pvMmio2=%p, idSlot=%#x failed: %u/%u\n",
803 GCPhys, cb, fFlags, pvMmio2, idSlot, errno, rc),
804 VERR_NEM_MAP_PAGES_FAILED);
805 }
806
807 /* MMIO, don't care. */
808 *pu2State = 0;
809 *puNemRange = UINT32_MAX;
810 return VINF_SUCCESS;
811}
812
813
814VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags,
815 void *pvRam, void *pvMmio2, uint32_t *puNemRange)
816{
817 RT_NOREF(pVM, GCPhys, cb, fFlags, pvRam, pvMmio2, puNemRange);
818 return VINF_SUCCESS;
819}
820
821
822VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, void *pvRam,
823 void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange)
824{
825 Log5(("NEMR3NotifyPhysMmioExUnmap: %RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p pu2State=%p puNemRange=%p (%#x)\n",
826 GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State, puNemRange, *puNemRange));
827 RT_NOREF(pVM, GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State);
828
829 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE)
830 {
831 /** @todo implement splitting and whatnot of ranges if we want to be 100%
832 * conforming (just modify RAM registrations in MM.cpp to test). */
833 AssertLogRelMsgFailedReturn(("%RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p\n", GCPhys, cb, fFlags, pvRam, pvMmio2),
834 VERR_NEM_UNMAP_PAGES_FAILED);
835 }
836
837 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2)
838 {
839 uint32_t const idSlot = *puNemRange;
840 AssertReturn(idSlot > 0 && idSlot < _32K, VERR_NEM_IPE_4);
841 AssertReturn(ASMBitTest(pVM->nem.s.bmSlotIds, idSlot), VERR_NEM_IPE_4);
842
843 struct kvm_userspace_memory_region Region;
844 Region.slot = idSlot;
845 Region.flags = 0;
846 Region.guest_phys_addr = GCPhys;
847 Region.memory_size = 0; /* this deregisters it. */
848 Region.userspace_addr = (uintptr_t)pvMmio2;
849
850 int rc = ioctl(pVM->nem.s.fdVm, KVM_SET_USER_MEMORY_REGION, &Region);
851 if (rc == 0)
852 {
853 if (pu2State)
854 *pu2State = 0;
855 *puNemRange = UINT32_MAX;
856 nemR3LnxMemSlotIdFree(pVM, idSlot);
857 return VINF_SUCCESS;
858 }
859
860 AssertLogRelMsgFailedReturn(("%RGp LB %RGp fFlags=%#x, pvMmio2=%p, idSlot=%#x failed: %u/%u\n",
861 GCPhys, cb, fFlags, pvMmio2, idSlot, errno, rc),
862 VERR_NEM_UNMAP_PAGES_FAILED);
863 }
864
865 if (pu2State)
866 *pu2State = UINT8_MAX;
867 return VINF_SUCCESS;
868}
869
870
871VMMR3_INT_DECL(int) NEMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t uNemRange,
872 void *pvBitmap, size_t cbBitmap)
873{
874 AssertReturn(uNemRange > 0 && uNemRange < _32K, VERR_NEM_IPE_4);
875 AssertReturn(ASMBitTest(pVM->nem.s.bmSlotIds, uNemRange), VERR_NEM_IPE_4);
876
877 RT_NOREF(GCPhys, cbBitmap);
878
879 struct kvm_dirty_log DirtyLog;
880 DirtyLog.slot = uNemRange;
881 DirtyLog.padding1 = 0;
882 DirtyLog.dirty_bitmap = pvBitmap;
883
884 int rc = ioctl(pVM->nem.s.fdVm, KVM_GET_DIRTY_LOG, &DirtyLog);
885 AssertLogRelMsgReturn(rc == 0, ("%RGp LB %RGp idSlot=%#x failed: %u/%u\n", GCPhys, cb, uNemRange, errno, rc),
886 VERR_NEM_QUERY_DIRTY_BITMAP_FAILED);
887
888 return VINF_SUCCESS;
889}
890
891
892VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, uint32_t fFlags,
893 uint8_t *pu2State, uint32_t *puNemRange)
894{
895 Log5(("NEMR3NotifyPhysRomRegisterEarly: %RGp LB %RGp pvPages=%p fFlags=%#x\n", GCPhys, cb, pvPages, fFlags));
896 *pu2State = UINT8_MAX;
897
898 /* Don't support puttint ROM where there is already RAM. For
899 now just shuffle the registrations till it works... */
900 AssertLogRelMsgReturn(!(fFlags & NEM_NOTIFY_PHYS_ROM_F_REPLACE), ("%RGp LB %RGp fFlags=%#x\n", GCPhys, cb, fFlags),
901 VERR_NEM_MAP_PAGES_FAILED);
902
903 /** @todo figure out how to do shadow ROMs. */
904
905 /*
906 * We only allocate a slot number here in case we need to use it to
907 * fend of physical handler fun.
908 */
909 uint16_t idSlot = nemR3LnxMemSlotIdAlloc(pVM);
910 AssertLogRelReturn(idSlot < _32K, VERR_NEM_MAP_PAGES_FAILED);
911
912 *pu2State = 0;
913 *puNemRange = idSlot;
914 Log5(("NEMR3NotifyPhysRomRegisterEarly: %RGp LB %RGp fFlags=%#x pvPages=%p - idSlot=%#x\n",
915 GCPhys, cb, fFlags, pvPages, idSlot));
916 RT_NOREF(GCPhys, cb, fFlags, pvPages);
917 return VINF_SUCCESS;
918}
919
920
921VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages,
922 uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange)
923{
924 Log5(("NEMR3NotifyPhysRomRegisterLate: %RGp LB %RGp pvPages=%p fFlags=%#x pu2State=%p (%d) puNemRange=%p (%#x)\n",
925 GCPhys, cb, pvPages, fFlags, pu2State, *pu2State, puNemRange, *puNemRange));
926
927 AssertPtrReturn(pvPages, VERR_NEM_IPE_5);
928
929 uint32_t const idSlot = *puNemRange;
930 AssertReturn(idSlot > 0 && idSlot < _32K, VERR_NEM_IPE_4);
931 AssertReturn(ASMBitTest(pVM->nem.s.bmSlotIds, idSlot), VERR_NEM_IPE_4);
932
933 *pu2State = UINT8_MAX;
934
935 /*
936 * Do the actual setting of the user pages here now that we've
937 * got a valid pvPages (typically isn't available during the early
938 * notification, unless we're replacing RAM).
939 */
940 /** @todo r=bird: if it's overlapping RAM, we shouldn't need an additional
941 * registration, should we? */
942 struct kvm_userspace_memory_region Region;
943 Region.slot = idSlot;
944 Region.flags = 0;
945 Region.guest_phys_addr = GCPhys;
946 Region.memory_size = cb;
947 Region.userspace_addr = (uintptr_t)pvPages;
948
949 int rc = ioctl(pVM->nem.s.fdVm, KVM_SET_USER_MEMORY_REGION, &Region);
950 if (rc == 0)
951 {
952 *pu2State = 0;
953 Log5(("NEMR3NotifyPhysRomRegisterEarly: %RGp LB %RGp fFlags=%#x pvPages=%p - idSlot=%#x\n",
954 GCPhys, cb, fFlags, pvPages, idSlot));
955 return VINF_SUCCESS;
956 }
957 AssertLogRelMsgFailedReturn(("%RGp LB %RGp fFlags=%#x, pvPages=%p, idSlot=%#x failed: %u/%u\n",
958 GCPhys, cb, fFlags, pvPages, idSlot, errno, rc),
959 VERR_NEM_MAP_PAGES_FAILED);
960}
961
962
963VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled)
964{
965 Log(("nemR3NativeNotifySetA20: fEnabled=%RTbool\n", fEnabled));
966 Assert(VM_IS_NEM_ENABLED(pVCpu->CTX_SUFF(pVM)));
967 RT_NOREF(pVCpu, fEnabled);
968}
969
970
971VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb,
972 RTR3PTR pvMemR3, uint8_t *pu2State)
973{
974 Log5(("NEMHCNotifyHandlerPhysicalDeregister: %RGp LB %RGp enmKind=%d pvMemR3=%p pu2State=%p (%d)\n",
975 GCPhys, cb, enmKind, pvMemR3, pu2State, *pu2State));
976
977 *pu2State = UINT8_MAX;
978 RT_NOREF(pVM, enmKind, GCPhys, cb, pvMemR3);
979}
980
981
982void nemHCNativeNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb)
983{
984 Log5(("nemHCNativeNotifyHandlerPhysicalRegister: %RGp LB %RGp enmKind=%d\n", GCPhys, cb, enmKind));
985 RT_NOREF(pVM, enmKind, GCPhys, cb);
986}
987
988
989void nemHCNativeNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
990 RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM)
991{
992 Log5(("nemHCNativeNotifyHandlerPhysicalModify: %RGp LB %RGp -> %RGp enmKind=%d fRestoreAsRAM=%d\n",
993 GCPhysOld, cb, GCPhysNew, enmKind, fRestoreAsRAM));
994 RT_NOREF(pVM, enmKind, GCPhysOld, GCPhysNew, cb, fRestoreAsRAM);
995}
996
997
998int nemHCNativeNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
999 PGMPAGETYPE enmType, uint8_t *pu2State)
1000{
1001 Log5(("nemHCNativeNotifyPhysPageAllocated: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
1002 GCPhys, HCPhys, fPageProt, enmType, *pu2State));
1003 RT_NOREF(pVM, GCPhys, HCPhys, fPageProt, enmType, pu2State);
1004 return VINF_SUCCESS;
1005}
1006
1007
1008VMM_INT_DECL(void) NEMHCNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, RTR3PTR pvR3, uint32_t fPageProt,
1009 PGMPAGETYPE enmType, uint8_t *pu2State)
1010{
1011 Log5(("NEMHCNotifyPhysPageProtChanged: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
1012 GCPhys, HCPhys, fPageProt, enmType, *pu2State));
1013 Assert(VM_IS_NEM_ENABLED(pVM));
1014 RT_NOREF(pVM, GCPhys, HCPhys, pvR3, fPageProt, enmType, pu2State);
1015
1016}
1017
1018
1019VMM_INT_DECL(void) NEMHCNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew,
1020 RTR3PTR pvNewR3, uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State)
1021{
1022 Log5(("nemHCNativeNotifyPhysPageChanged: %RGp HCPhys=%RHp->%RHp pvNewR3=%p fPageProt=%#x enmType=%d *pu2State=%d\n",
1023 GCPhys, HCPhysPrev, HCPhysNew, pvNewR3, fPageProt, enmType, *pu2State));
1024 Assert(VM_IS_NEM_ENABLED(pVM));
1025 RT_NOREF(pVM, GCPhys, HCPhysPrev, HCPhysNew, pvNewR3, fPageProt, enmType, pu2State);
1026}
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