VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/VBoxBFE.cpp@ 99855

Last change on this file since 99855 was 99751, checked in by vboxsync, 2 years ago

FE/VBoxBFE: Configure PCIe bus, bugref:10445

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.0 KB
Line 
1/* $Id: VBoxBFE.cpp 99751 2023-05-11 13:42:56Z vboxsync $ */
2/** @file
3 * VBoxBFE - The basic VirtualBox frontend for running VMs without using Main/COM/XPCOM.
4 * Mainly serves as a playground for the ARMv8 VMM bringup for now.
5 */
6
7/*
8 * Copyright (C) 2023 Oracle and/or its affiliates.
9 *
10 * This file is part of VirtualBox base platform packages, as
11 * available from https://www.virtualbox.org.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation, in version 3 of the
16 * License.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <https://www.gnu.org/licenses>.
25 *
26 * SPDX-License-Identifier: GPL-3.0-only
27 */
28
29
30/*********************************************************************************************************************************
31* Header Files *
32*********************************************************************************************************************************/
33#define LOG_GROUP LOG_GROUP_GUI
34
35#include <VBox/log.h>
36#include <VBox/version.h>
37#include <VBox/vmm/vmmr3vtable.h>
38#include <VBox/vmm/vmapi.h>
39#include <VBox/vmm/pdm.h>
40#include <iprt/buildconfig.h>
41#include <iprt/ctype.h>
42#include <iprt/initterm.h>
43#include <iprt/message.h>
44#include <iprt/semaphore.h>
45#include <iprt/file.h>
46#include <iprt/path.h>
47#include <iprt/stream.h>
48#include <iprt/ldr.h>
49#include <iprt/mem.h>
50#include <iprt/getopt.h>
51#include <iprt/env.h>
52#include <iprt/errcore.h>
53#include <iprt/thread.h>
54#include <iprt/uuid.h>
55
56#include <SDL.h>
57
58#include "Display.h"
59#include "Framebuffer.h"
60
61
62/*********************************************************************************************************************************
63* Defined Constants And Macros *
64*********************************************************************************************************************************/
65
66#define LogError(m,rc) \
67 do { \
68 Log(("VBoxBFE: ERROR: " m " [rc=0x%08X]\n", rc)); \
69 RTPrintf("%s\n", m); \
70 } while (0)
71
72#define DTB_ADDR 0x40000000
73
74
75/*********************************************************************************************************************************
76* Structures and Typedefs *
77*********************************************************************************************************************************/
78
79
80/*********************************************************************************************************************************
81* Global Variables *
82*********************************************************************************************************************************/
83/** flag whether frontend should terminate */
84static volatile bool g_fTerminateFE = false;
85static RTLDRMOD g_hModVMM = NIL_RTLDRMOD;
86static PCVMMR3VTABLE g_pVMM = NULL;
87static PVM g_pVM = NULL;
88static PUVM g_pUVM = NULL;
89static uint32_t g_u32MemorySizeMB = 512;
90static VMSTATE g_enmVmState = VMSTATE_CREATING;
91static const char *g_pszLoadMem = NULL;
92static const char *g_pszLoadFlash = NULL;
93static const char *g_pszLoadDtb = NULL;
94static const char *g_pszSerialLog = NULL;
95static const char *g_pszLoadKernel = NULL;
96static const char *g_pszLoadInitrd = NULL;
97static const char *g_pszCmdLine = NULL;
98static VMM2USERMETHODS g_Vmm2UserMethods;
99static Display *g_pDisplay = NULL;
100static Framebuffer *g_pFramebuffer = NULL;
101static bool gfIgnoreNextResize = false;
102static SDL_TimerID gSdlResizeTimer = 0;
103
104/** @todo currently this is only set but never read. */
105static char szError[512];
106
107extern DECL_HIDDEN_DATA(RTSEMEVENT) g_EventSemSDLEvents;
108extern DECL_HIDDEN_DATA(volatile int32_t) g_cNotifyUpdateEventsPending;
109
110
111/*********************************************************************************************************************************
112* Internal Functions *
113*********************************************************************************************************************************/
114
115/**
116 * Wait for the next SDL event. Don't use SDL_WaitEvent since this function
117 * calls SDL_Delay(10) if the event queue is empty.
118 */
119static int WaitSDLEvent(SDL_Event *event)
120{
121 for (;;)
122 {
123 int rc = SDL_PollEvent(event);
124 if (rc == 1)
125 return 1;
126 /* Immediately wake up if new SDL events are available. This does not
127 * work for internal SDL events. Don't wait more than 10ms. */
128 RTSemEventWait(g_EventSemSDLEvents, 10);
129 }
130}
131
132
133/**
134 * Timer callback function to check if resizing is finished
135 */
136static Uint32 ResizeTimer(Uint32 interval, void *param) RT_NOTHROW_DEF
137{
138 RT_NOREF(interval, param);
139
140 /* post message so the window is actually resized */
141 SDL_Event event = {0};
142 event.type = SDL_USEREVENT;
143 event.user.type = SDL_USER_EVENT_WINDOW_RESIZE_DONE;
144 PushSDLEventForSure(&event);
145 /* one-shot */
146 return 0;
147}
148
149
150/**
151 * VM state callback function. Called by the VMM
152 * using its state machine states.
153 *
154 * Primarily used to handle VM initiated power off, suspend and state saving,
155 * but also for doing termination completed work (VMSTATE_TERMINATE).
156 *
157 * In general this function is called in the context of the EMT.
158 *
159 * @todo g_enmVmState is set to VMSTATE_RUNNING before all devices have received power on events
160 * this can prematurely allow the main thread to enter the event loop
161 *
162 * @param pVM The VM handle.
163 * @param enmState The new state.
164 * @param enmOldState The old state.
165 * @param pvUser The user argument.
166 */
167static DECLCALLBACK(void) vboxbfeVmStateChangeCallback(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)
168{
169 RT_NOREF(pUVM, pVMM, enmOldState, pvUser);
170 LogFlow(("vmstateChangeCallback: changing state from %d to %d\n", enmOldState, enmState));
171 g_enmVmState = enmState;
172
173 switch (enmState)
174 {
175 /*
176 * The VM has terminated
177 */
178 case VMSTATE_OFF:
179 {
180 break;
181 }
182
183 /*
184 * The VM has been completely destroyed.
185 *
186 * Note: This state change can happen at two points:
187 * 1) At the end of VMR3Destroy() if it was not called from EMT.
188 * 2) At the end of vmR3EmulationThread if VMR3Destroy() was called by EMT.
189 */
190 case VMSTATE_TERMINATED:
191 {
192 break;
193 }
194
195 default: /* shut up gcc */
196 break;
197 }
198}
199
200
201/**
202 * VM error callback function. Called by the various VM components.
203 *
204 * @param pVM The VM handle.
205 * @param pvUser The user argument.
206 * @param vrc VBox status code.
207 * @param pszFormat Error message format string.
208 * @param args Error message arguments.
209 * @thread EMT.
210 */
211DECLCALLBACK(void) vboxbfeSetVMErrorCallback(PUVM pUVM, void *pvUser, int vrc, RT_SRC_POS_DECL, const char *pszFormat, va_list args)
212{
213 RT_NOREF(pUVM, pvUser, pszFile, iLine, pszFunction);
214
215 /** @todo accessing shared resource without any kind of synchronization */
216 if (RT_SUCCESS(vrc))
217 szError[0] = '\0';
218 else
219 {
220 va_list va2;
221 va_copy(va2, args); /* Have to make a copy here or GCC will break. */
222 RTStrPrintf(szError, sizeof(szError),
223 "%N!\nVBox status code: %d (%Rrc)", pszFormat, &va2, vrc, vrc);
224 RTPrintf("%s\n", szError);
225 va_end(va2);
226 }
227}
228
229
230/**
231 * VM Runtime error callback function. Called by the various VM components.
232 *
233 * @param pVM The VM handle.
234 * @param pvUser The user argument.
235 * @param fFlags The action flags. See VMSETRTERR_FLAGS_*.
236 * @param pszErrorId Error ID string.
237 * @param pszFormat Error message format string.
238 * @param va Error message arguments.
239 * @thread EMT.
240 */
241DECLCALLBACK(void) vboxbfeSetVMRuntimeErrorCallback(PUVM pUVM, void *pvUser, uint32_t fFlags,
242 const char *pszErrorId, const char *pszFormat, va_list va)
243{
244 RT_NOREF(pUVM, pvUser);
245
246 va_list va2;
247 va_copy(va2, va); /* Have to make a copy here or GCC/AMD64 will break. */
248 RTPrintf("%s: %s!\n%N!\n",
249 fFlags & VMSETRTERR_FLAGS_FATAL ? "Error" : "Warning",
250 pszErrorId, pszFormat, &va2);
251 RTStrmFlush(g_pStdErr);
252 va_end(va2);
253}
254
255
256/**
257 * Register the main drivers.
258 *
259 * @returns VBox status code.
260 * @param pCallbacks Pointer to the callback table.
261 * @param u32Version VBox version number.
262 */
263DECLCALLBACK(int) VBoxDriversRegister(PCPDMDRVREGCB pCallbacks, uint32_t u32Version)
264{
265 LogFlow(("VBoxDriversRegister: u32Version=%#x\n", u32Version));
266 AssertReleaseMsg(u32Version == VBOX_VERSION, ("u32Version=%#x VBOX_VERSION=%#x\n", u32Version, VBOX_VERSION));
267
268 int vrc = pCallbacks->pfnRegister(pCallbacks, &Display::DrvReg);
269 if (RT_FAILURE(vrc))
270 return vrc;
271
272 return VINF_SUCCESS;
273}
274
275
276/**
277 * Constructs the VMM configuration tree.
278 *
279 * @returns VBox status code.
280 * @param pVM VM handle.
281 */
282static DECLCALLBACK(int) vboxbfeConfigConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvConsole)
283{
284 int rcAll = VINF_SUCCESS;
285 int rc;
286
287 RT_NOREF(pvConsole);
288 g_pUVM = pUVM;
289
290#define UPDATE_RC() do { if (RT_FAILURE(rc) && RT_SUCCESS(rcAll)) rcAll = rc; } while (0)
291
292 /*
293 * Root values.
294 */
295 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRoot(pVM);
296 rc = pVMM->pfnCFGMR3InsertString(pRoot, "Name", "Default VM"); UPDATE_RC();
297 rc = pVMM->pfnCFGMR3InsertInteger(pRoot, "TimerMillies", 1000); UPDATE_RC();
298
299 /*
300 * Memory setup.
301 */
302 PCFGMNODE pMem = NULL;
303 rc = pVMM->pfnCFGMR3InsertNode(pRoot, "MM", &pMem); UPDATE_RC();
304 rc = pVMM->pfnCFGMR3InsertNode(pMem, "MemRegions", &pMem); UPDATE_RC();
305
306 PCFGMNODE pMemRegion = NULL;
307 rc = pVMM->pfnCFGMR3InsertNode(pMem, "Flash", &pMemRegion); UPDATE_RC();
308 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "GCPhysStart", 0); UPDATE_RC();
309 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "Size", 64 * _1M); UPDATE_RC();
310
311 rc = pVMM->pfnCFGMR3InsertNode(pMem, "Conventional", &pMemRegion); UPDATE_RC();
312 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "GCPhysStart", DTB_ADDR); UPDATE_RC();
313 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "Size", (uint64_t)g_u32MemorySizeMB * _1M); UPDATE_RC();
314
315
316 /*
317 * PDM.
318 */
319#ifdef DEBUG_aeichner
320 PCFGMNODE pPdm = NULL;
321 PCFGMNODE pPdmDevices = NULL;
322 PCFGMNODE pPdmDevicesNvme = NULL;
323 rc = pVMM->pfnCFGMR3InsertNode(pRoot, "PDM", &pPdm); UPDATE_RC();
324 rc = pVMM->pfnCFGMR3InsertNode(pPdm, "Devices", &pPdmDevices); UPDATE_RC();
325 rc = pVMM->pfnCFGMR3InsertNode(pPdmDevices, "VBoxNvme", &pPdmDevicesNvme); UPDATE_RC();
326 rc = pVMM->pfnCFGMR3InsertString(pPdmDevicesNvme, "Path", "/Users/vbox/vbox-intern/out/darwin.arm64/debug/dist/VirtualBox.app/Contents/MacOS/ExtensionPacks/Oracle_VM_VirtualBox_Extension_Pack/darwin.arm64/VBoxNvmeR3.dylib"); UPDATE_RC();
327#endif
328
329 rc = pVMM->pfnPDMR3DrvStaticRegistration(pVM, VBoxDriversRegister); UPDATE_RC();
330
331 /*
332 * Devices
333 */
334 PCFGMNODE pDevices = NULL;
335 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
336 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
337 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
338 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
339 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
340 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
341
342 rc = pVMM->pfnCFGMR3InsertNode(pRoot, "Devices", &pDevices); UPDATE_RC();
343
344 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "gic", &pDev); UPDATE_RC();
345 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
346 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "Trusted", 1); UPDATE_RC();
347 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
348
349 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "DistributorMmioBase", 0x08000000); UPDATE_RC();
350 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "RedistributorMmioBase", 0x080a0000); UPDATE_RC();
351
352
353 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "qemu-fw-cfg", &pDev); UPDATE_RC();
354 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
355 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
356 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioSize", 4096); UPDATE_RC();
357 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioBase", 0x09020000); UPDATE_RC();
358 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "DmaEnabled", 1); UPDATE_RC();
359 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "QemuRamfbSupport", 1); UPDATE_RC();
360 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
361 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "MainDisplay"); UPDATE_RC();
362 if (g_pszLoadKernel)
363 {
364 rc = pVMM->pfnCFGMR3InsertString(pCfg, "KernelImage", g_pszLoadKernel); UPDATE_RC();
365 }
366 if (g_pszLoadInitrd)
367 {
368 rc = pVMM->pfnCFGMR3InsertString(pCfg, "InitrdImage", g_pszLoadInitrd); UPDATE_RC();
369 }
370 if (g_pszCmdLine)
371 {
372 rc = pVMM->pfnCFGMR3InsertString(pCfg, "CmdLine", g_pszCmdLine); UPDATE_RC();
373 }
374
375
376 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "flash-cfi", &pDev); UPDATE_RC();
377 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
378 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
379 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "BaseAddress", 64 * _1M); UPDATE_RC();
380 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "Size", 64 * _1M); UPDATE_RC();
381 if (g_pszLoadFlash)
382 {
383 rc = pVMM->pfnCFGMR3InsertString(pCfg, "FlashFile", g_pszLoadFlash); UPDATE_RC();
384 }
385
386 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "arm-pl011", &pDev); UPDATE_RC();
387 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
388 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
389 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "Irq", 1); UPDATE_RC();
390 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioBase", 0x09000000); UPDATE_RC();
391
392 if (g_pszSerialLog)
393 {
394 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
395 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "Char"); UPDATE_RC();
396 rc = pVMM->pfnCFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); UPDATE_RC();
397 rc = pVMM->pfnCFGMR3InsertString(pLunL1, "Driver", "RawFile"); UPDATE_RC();
398 rc = pVMM->pfnCFGMR3InsertNode(pLunL1, "Config", &pLunL1Cfg); UPDATE_RC();
399 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "Location", g_pszSerialLog); UPDATE_RC();
400 }
401
402 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "arm-pl031-rtc", &pDev); UPDATE_RC();
403 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
404 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
405 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "Irq", 2); UPDATE_RC();
406 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioBase", 0x09010000); UPDATE_RC();
407
408 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "pci-generic-ecam", &pDev); UPDATE_RC();
409 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
410 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
411 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioEcamBase", 0x3f000000); UPDATE_RC();
412 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioEcamLength", 0x01000000); UPDATE_RC();
413 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioPioBase", 0x3eff0000); UPDATE_RC();
414 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioPioSize", 0x0000ffff); UPDATE_RC();
415
416 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "usb-xhci", &pDev); UPDATE_RC();
417 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
418 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "Trusted", 1); UPDATE_RC();
419 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIBusNo", 0); UPDATE_RC();
420 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIDeviceNo", 2); UPDATE_RC();
421 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIFunctionNo", 0); UPDATE_RC();
422 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
423 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
424 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver","VUSBRootHub"); UPDATE_RC();
425 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#1", &pLunL0); UPDATE_RC();
426 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver","VUSBRootHub"); UPDATE_RC();
427
428#ifdef DEBUG_aeichner
429 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "virtio-net", &pDev); UPDATE_RC();
430 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
431 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "Trusted", 1); UPDATE_RC();
432 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIBusNo", 0); UPDATE_RC();
433 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIDeviceNo", 1); UPDATE_RC();
434 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIFunctionNo", 0); UPDATE_RC();
435 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
436 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "CableConnected", 1); UPDATE_RC();
437 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "LineSpeed", 0); UPDATE_RC();
438
439 const char *pszMac = "080027ede92c";
440 Assert(strlen(pszMac) == 12);
441 RTMAC Mac;
442 RT_ZERO(Mac);
443 char *pMac = (char*)&Mac;
444 for (uint32_t i = 0; i < 6; ++i)
445 {
446 int c1 = *pszMac++ - '0';
447 if (c1 > 9)
448 c1 -= 7;
449 int c2 = *pszMac++ - '0';
450 if (c2 > 9)
451 c2 -= 7;
452 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
453 }
454 rc = pVMM->pfnCFGMR3InsertBytes(pCfg, "MAC", &Mac, sizeof(Mac)); UPDATE_RC();
455 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
456 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "NAT"); UPDATE_RC();
457 rc = pVMM->pfnCFGMR3InsertNode(pLunL0, "Config", &pLunL1Cfg); UPDATE_RC();
458 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "Network", "10.0.2.0/24"); UPDATE_RC();
459 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "TFTPPrefix", "/Users/vbox/Library/VirtualBox/TFTP"); UPDATE_RC();
460 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "BootFile", "default.pxe"); UPDATE_RC();
461 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "AliasMode", 0); UPDATE_RC();
462 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "DNSProxy", 0); UPDATE_RC();
463 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "LocalhostReachable", 1); UPDATE_RC();
464 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "PassDomain", 1); UPDATE_RC();
465 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "UseHostResolver", 0); UPDATE_RC();
466
467 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "nvme", &pDev); UPDATE_RC();
468 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
469 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "Trusted", 1); UPDATE_RC();
470 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIBusNo", 0); UPDATE_RC();
471 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIDeviceNo", 3); UPDATE_RC();
472 rc = pVMM->pfnCFGMR3InsertInteger(pDev, "PCIFunctionNo", 0); UPDATE_RC();
473 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
474 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "CtrlMemBufSize", 0); UPDATE_RC();
475 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
476 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver","RamDisk"); UPDATE_RC();
477 rc = pVMM->pfnCFGMR3InsertNode(pLunL0, "Config", &pLunL1Cfg); UPDATE_RC();
478 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "Size", 1073741824); UPDATE_RC();
479#endif
480
481#undef UPDATE_RC
482#undef UPDATE_RC
483
484 pVMM->pfnVMR3AtRuntimeErrorRegister (pUVM, vboxbfeSetVMRuntimeErrorCallback, NULL);
485
486 return rc;
487}
488
489
490/**
491 * Loads the VMM if needed.
492 *
493 * @returns VBox status code.
494 * @param pszVmmMod The VMM module to load.
495 */
496int vboxbfeLoadVMM(const char *pszVmmMod)
497{
498 Assert(!g_pVMM);
499
500 RTERRINFOSTATIC ErrInfo;
501 RTLDRMOD hModVMM = NIL_RTLDRMOD;
502 int vrc = SUPR3HardenedLdrLoadAppPriv(pszVmmMod, &hModVMM, RTLDRLOAD_FLAGS_LOCAL, RTErrInfoInitStatic(&ErrInfo));
503 if (RT_SUCCESS(vrc))
504 {
505 PFNVMMGETVTABLE pfnGetVTable = NULL;
506 vrc = RTLdrGetSymbol(hModVMM, VMMR3VTABLE_GETTER_NAME, (void **)&pfnGetVTable);
507 if (pfnGetVTable)
508 {
509 PCVMMR3VTABLE pVMM = pfnGetVTable();
510 if (pVMM)
511 {
512 if (VMMR3VTABLE_IS_COMPATIBLE(pVMM->uMagicVersion))
513 {
514 if (pVMM->uMagicVersion == pVMM->uMagicVersionEnd)
515 {
516 g_hModVMM = hModVMM;
517 g_pVMM = pVMM;
518 LogFunc(("mhLdrVMM=%p phVMM=%p uMagicVersion=%#RX64\n", hModVMM, pVMM, pVMM->uMagicVersion));
519 return VINF_SUCCESS;
520 }
521
522 LogRel(("Bogus VMM vtable: uMagicVersion=%#RX64 uMagicVersionEnd=%#RX64",
523 pVMM->uMagicVersion, pVMM->uMagicVersionEnd));
524 }
525 else
526 LogRel(("Incompatible of bogus VMM version magic: %#RX64", pVMM->uMagicVersion));
527 }
528 else
529 LogRel(("pfnGetVTable return NULL!"));
530 }
531 else
532 LogRel(("Failed to locate symbol '%s' in VBoxVMM: %Rrc", VMMR3VTABLE_GETTER_NAME, vrc));
533 RTLdrClose(hModVMM);
534 }
535 else
536 LogRel(("Failed to load VBoxVMM: %#RTeic", &ErrInfo.Core));
537
538 return vrc;
539}
540
541
542/**
543 * Loads the content of a given file into guest RAM starting at the given guest physical address.
544 *
545 * @returns VBox status code.
546 * @param pszFile The file to load.
547 * @param GCPhysStart The physical start address to load the file at.
548 */
549static int vboxbfeLoadFileAtGCPhys(const char *pszFile, RTGCPHYS GCPhysStart)
550{
551 RTFILE hFile = NIL_RTFILE;
552 int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
553 if (RT_SUCCESS(rc))
554 {
555 uint8_t abRead[GUEST_PAGE_SIZE];
556 RTGCPHYS GCPhys = GCPhysStart;
557
558 for (;;)
559 {
560 size_t cbThisRead = 0;
561 rc = RTFileRead(hFile, &abRead[0], sizeof(abRead), &cbThisRead);
562 if (RT_FAILURE(rc))
563 break;
564
565 rc = g_pVMM->pfnPGMPhysSimpleWriteGCPhys(g_pVM, GCPhys, &abRead[0], cbThisRead);
566 if (RT_FAILURE(rc))
567 break;
568
569 GCPhys += cbThisRead;
570 if (cbThisRead < sizeof(abRead))
571 break;
572 }
573
574 RTFileClose(hFile);
575 }
576 else
577 RTPrintf("Loading file %s failed -> %Rrc\n", pszFile, rc);
578
579 return rc;
580}
581
582
583/**
584 * @interface_method_impl{VMM2USERMETHODS,pfnQueryGenericObject}
585 */
586static DECLCALLBACK(void *) vboxbfeVmm2User_QueryGenericObject(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)
587{
588 RT_NOREF(pThis, pUVM);
589
590 if (!RTUuidCompareStr(pUuid, DISPLAY_OID))
591 return g_pDisplay;
592
593 return NULL;
594}
595
596
597/** VM asynchronous operations thread */
598DECLCALLBACK(int) vboxbfeVMPowerUpThread(RTTHREAD hThread, void *pvUser)
599{
600 RT_NOREF(hThread, pvUser);
601
602 int rc = VINF_SUCCESS;
603 int rc2;
604
605#if 0
606 /*
607 * Setup the release log instance in current directory.
608 */
609 if (g_fReleaseLog)
610 {
611 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
612 static char s_szError[RTPATH_MAX + 128] = "";
613 PRTLOGGER pLogger;
614 rc2 = RTLogCreateEx(&pLogger, RTLOGFLAGS_PREFIX_TIME_PROG, "all",
615 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_FILE,
616 NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
617 s_szError, sizeof(s_szError), "./VBoxBFE.log");
618 if (RT_SUCCESS(rc2))
619 {
620 /* some introductory information */
621 RTTIMESPEC TimeSpec;
622 char szNowUct[64];
623 RTTimeSpecToString(RTTimeNow(&TimeSpec), szNowUct, sizeof(szNowUct));
624 RTLogRelLogger(pLogger, 0, ~0U,
625 "VBoxBFE %s (%s %s) release log\n"
626 "Log opened %s\n",
627 VBOX_VERSION_STRING, __DATE__, __TIME__,
628 szNowUct);
629
630 /* register this logger as the release logger */
631 RTLogRelSetDefaultInstance(pLogger);
632 }
633 else
634 RTPrintf("Could not open release log (%s)\n", s_szError);
635 }
636#endif
637
638 /*
639 * Start VM (also from saved state) and track progress
640 */
641 LogFlow(("VMPowerUp\n"));
642
643 g_Vmm2UserMethods.u32Magic = VMM2USERMETHODS_MAGIC;
644 g_Vmm2UserMethods.u32Version = VMM2USERMETHODS_VERSION;
645 g_Vmm2UserMethods.pfnSaveState = NULL;
646 g_Vmm2UserMethods.pfnNotifyEmtInit = NULL;
647 g_Vmm2UserMethods.pfnNotifyEmtTerm = NULL;
648 g_Vmm2UserMethods.pfnNotifyPdmtInit = NULL;
649 g_Vmm2UserMethods.pfnNotifyPdmtTerm = NULL;
650 g_Vmm2UserMethods.pfnNotifyResetTurnedIntoPowerOff = NULL;
651 g_Vmm2UserMethods.pfnQueryGenericObject = vboxbfeVmm2User_QueryGenericObject;
652 g_Vmm2UserMethods.u32EndMagic = VMM2USERMETHODS_MAGIC;
653
654 /*
655 * Create empty VM.
656 */
657 rc = g_pVMM->pfnVMR3Create(1, &g_Vmm2UserMethods, 0 /*fFlags*/, vboxbfeSetVMErrorCallback, NULL, vboxbfeConfigConstructor, NULL, &g_pVM, NULL);
658 if (RT_FAILURE(rc))
659 {
660 RTPrintf("Error: VM creation failed with %Rrc.\n", rc);
661 goto failure;
662 }
663
664
665 /*
666 * Register VM state change handler
667 */
668 rc = g_pVMM->pfnVMR3AtStateRegister(g_pUVM, vboxbfeVmStateChangeCallback, NULL);
669 if (RT_FAILURE(rc))
670 {
671 RTPrintf("Error: VMR3AtStateRegister failed with %Rrc.\n", rc);
672 goto failure;
673 }
674
675 /*
676 * Prepopulate the memory?
677 */
678 if (g_pszLoadMem)
679 {
680 rc = vboxbfeLoadFileAtGCPhys(g_pszLoadMem, 0 /*GCPhysStart*/);
681 if (RT_FAILURE(rc))
682 goto failure;
683 }
684
685 if (g_pszLoadDtb)
686 {
687 rc = vboxbfeLoadFileAtGCPhys(g_pszLoadDtb, DTB_ADDR);
688 if (RT_FAILURE(rc))
689 goto failure;
690 }
691
692 /*
693 * Power on the VM (i.e. start executing).
694 */
695 if (RT_SUCCESS(rc))
696 {
697#if 0
698 if ( g_fRestoreState
699 && g_pszStateFile
700 && *g_pszStateFile
701 && RTPathExists(g_pszStateFile))
702 {
703 startProgressInfo("Restoring");
704 rc = VMR3LoadFromFile(gpVM, g_pszStateFile, callProgressInfo, (uintptr_t)NULL);
705 endProgressInfo();
706 if (RT_SUCCESS(rc))
707 {
708 rc = VMR3Resume(gpVM);
709 AssertRC(rc);
710 }
711 else
712 AssertMsgFailed(("VMR3LoadFromFile failed, rc=%Rrc\n", rc));
713 }
714 else
715#endif
716 {
717 rc = g_pVMM->pfnVMR3PowerOn(g_pUVM);
718 if (RT_FAILURE(rc))
719 AssertMsgFailed(("VMR3PowerOn failed, rc=%Rrc\n", rc));
720 }
721 }
722
723 /*
724 * On failure destroy the VM.
725 */
726 if (RT_FAILURE(rc))
727 goto failure;
728
729 return VINF_SUCCESS;
730
731failure:
732 if (g_pVM)
733 {
734 rc2 = g_pVMM->pfnVMR3Destroy(g_pUVM);
735 AssertRC(rc2);
736 g_pVM = NULL;
737 }
738 g_enmVmState = VMSTATE_TERMINATED;
739
740 return VINF_SUCCESS;
741}
742
743
744static void show_usage()
745{
746 RTPrintf("Usage:\n"
747 " --start-paused Start the VM in paused state\n"
748 "\n");
749}
750
751/**
752 * Entry point.
753 */
754extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
755{
756 RT_NOREF(envp);
757 unsigned fPaused = 0;
758
759 LogFlow(("VBoxBFE STARTED.\n"));
760 RTPrintf(VBOX_PRODUCT " Basic Interface " VBOX_VERSION_STRING "\n"
761 "Copyright (C) 2023-" VBOX_C_YEAR " " VBOX_VENDOR "\n\n");
762
763 static const RTGETOPTDEF s_aOptions[] =
764 {
765 { "--start-paused", 'p', 0 },
766 { "--memory-size-mib", 'm', RTGETOPT_REQ_UINT32 },
767 { "--load-file-into-ram", 'l', RTGETOPT_REQ_STRING },
768 { "--load-flash", 'f', RTGETOPT_REQ_STRING },
769 { "--load-dtb", 'd', RTGETOPT_REQ_STRING },
770 { "--load-vmm", 'v', RTGETOPT_REQ_STRING },
771 { "--load-kernel", 'k', RTGETOPT_REQ_STRING },
772 { "--load-initrd", 'i', RTGETOPT_REQ_STRING },
773 { "--cmd-line", 'c', RTGETOPT_REQ_STRING },
774 { "--serial-log", 's', RTGETOPT_REQ_STRING },
775 };
776
777 const char *pszVmmMod = "VBoxVMM";
778
779 /* Parse the config. */
780 int ch;
781 RTGETOPTUNION ValueUnion;
782 RTGETOPTSTATE GetState;
783 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /* fFlags */);
784 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
785 {
786 switch(ch)
787 {
788 case 'p':
789 fPaused = true;
790 break;
791 case 'm':
792 g_u32MemorySizeMB = ValueUnion.u32;
793 break;
794 case 'l':
795 g_pszLoadMem = ValueUnion.psz;
796 break;
797 case 'f':
798 g_pszLoadFlash = ValueUnion.psz;
799 break;
800 case 'd':
801 g_pszLoadDtb = ValueUnion.psz;
802 break;
803 case 'v':
804 pszVmmMod = ValueUnion.psz;
805 break;
806 case 'k':
807 g_pszLoadKernel = ValueUnion.psz;
808 break;
809 case 'i':
810 g_pszLoadInitrd = ValueUnion.psz;
811 break;
812 case 'c':
813 g_pszCmdLine = ValueUnion.psz;
814 break;
815 case 's':
816 g_pszSerialLog = ValueUnion.psz;
817 break;
818 case 'h':
819 show_usage();
820 return 0;
821 case 'V':
822 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
823 return 0;
824 default:
825 ch = RTGetOptPrintError(ch, &ValueUnion);
826 show_usage();
827 return ch;
828 }
829 }
830
831 /* static initialization of the SDL stuff */
832 if (!Framebuffer::init(true /*fShowSDLConfig*/))
833 return RTEXITCODE_FAILURE;
834
835 g_pDisplay = new Display();
836 g_pFramebuffer = new Framebuffer(g_pDisplay, 0, false /*fFullscreen*/, false /*fResizable*/, true /*fShowSDLConfig*/, false,
837 ~0, ~0, ~0, false /*fSeparate*/);
838 g_pDisplay->SetFramebuffer(0, g_pFramebuffer);
839
840 int vrc = vboxbfeLoadVMM(pszVmmMod);
841 if (RT_FAILURE(vrc))
842 return RTEXITCODE_FAILURE;
843
844 /*
845 * Start the VM execution thread. This has to be done
846 * asynchronously as powering up can take some time
847 * (accessing devices such as the host DVD drive). In
848 * the meantime, we have to service the SDL event loop.
849 */
850
851 RTTHREAD thread;
852 vrc = RTThreadCreate(&thread, vboxbfeVMPowerUpThread, 0, 0, RTTHREADTYPE_MAIN_WORKER, 0, "PowerUp");
853 if (RT_FAILURE(vrc))
854 {
855 RTPrintf("Error: Thread creation failed with %d\n", vrc);
856 return RTEXITCODE_FAILURE;
857 }
858
859
860 /* loop until the powerup processing is done */
861 do
862 {
863 RTThreadSleep(1000);
864 }
865 while ( g_enmVmState == VMSTATE_CREATING
866 || g_enmVmState == VMSTATE_LOADING);
867
868 LogFlow(("VBoxSDL: Entering big event loop\n"));
869 SDL_Event event;
870 uint32_t uResizeWidth = ~(uint32_t)0;
871 uint32_t uResizeHeight = ~(uint32_t)0;
872
873 while (WaitSDLEvent(&event))
874 {
875 switch (event.type)
876 {
877 /*
878 * The screen needs to be repainted.
879 */
880 case SDL_WINDOWEVENT:
881 {
882 switch (event.window.event)
883 {
884 case SDL_WINDOWEVENT_EXPOSED:
885 {
886 g_pFramebuffer->repaint();
887 break;
888 }
889 case SDL_WINDOWEVENT_FOCUS_GAINED:
890 {
891 break;
892 }
893 case SDL_WINDOWEVENT_FOCUS_LOST:
894 {
895 break;
896 }
897 case SDL_WINDOWEVENT_RESIZED:
898 {
899 if (g_pDisplay)
900 {
901 if (gfIgnoreNextResize)
902 {
903 gfIgnoreNextResize = FALSE;
904 break;
905 }
906 uResizeWidth = event.window.data1;
907 uResizeHeight = event.window.data2;
908 if (gSdlResizeTimer)
909 SDL_RemoveTimer(gSdlResizeTimer);
910 gSdlResizeTimer = SDL_AddTimer(300, ResizeTimer, NULL);
911 }
912 break;
913 }
914 default:
915 break;
916 }
917 break;
918 }
919
920 /*
921 * The window was closed.
922 */
923 case SDL_QUIT:
924 {
925 /** @todo */
926 break;
927 }
928
929 /*
930 * User specific update event.
931 */
932 /** @todo use a common user event handler so that SDL_PeepEvents() won't
933 * possibly remove other events in the queue!
934 */
935 case SDL_USER_EVENT_UPDATERECT:
936 {
937 /*
938 * Decode event parameters.
939 */
940 ASMAtomicDecS32(&g_cNotifyUpdateEventsPending);
941
942 SDL_Rect *pUpdateRect = (SDL_Rect *)event.user.data1;
943 AssertPtrBreak(pUpdateRect);
944
945 int const x = pUpdateRect->x;
946 int const y = pUpdateRect->y;
947 int const w = pUpdateRect->w;
948 int const h = pUpdateRect->h;
949
950 RTMemFree(event.user.data1);
951
952 Log3Func(("SDL_USER_EVENT_UPDATERECT: x=%d y=%d, w=%d, h=%d\n", x, y, w, h));
953
954 Assert(g_pFramebuffer);
955 g_pFramebuffer->update(x, y, w, h, true /* fGuestRelative */);
956 break;
957 }
958
959 /*
960 * User event: Window resize done
961 */
962 case SDL_USER_EVENT_WINDOW_RESIZE_DONE:
963 {
964 /* communicate the resize event to the guest */
965 //g_pDisplay->SetVideoModeHint(0 /*=display*/, true /*=enabled*/, false /*=changeOrigin*/,
966 // 0 /*=originX*/, 0 /*=originY*/,
967 // uResizeWidth, uResizeHeight, 0 /*=don't change bpp*/, true /*=notify*/);
968 break;
969
970 }
971
972 /*
973 * User specific framebuffer change event.
974 */
975 case SDL_USER_EVENT_NOTIFYCHANGE:
976 {
977 LogFlow(("SDL_USER_EVENT_NOTIFYCHANGE\n"));
978 g_pFramebuffer->notifyChange(event.user.code);
979 break;
980 }
981
982 /*
983 * User specific termination event
984 */
985 case SDL_USER_EVENT_TERMINATE:
986 {
987 if (event.user.code != VBOXSDL_TERM_NORMAL)
988 RTPrintf("Error: VM terminated abnormally!\n");
989 break;
990 }
991
992 default:
993 {
994 Log8(("unknown SDL event %d\n", event.type));
995 break;
996 }
997 }
998 }
999
1000 LogRel(("VBoxBFE: exiting\n"));
1001 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1002}
1003
1004
1005#ifndef VBOX_WITH_HARDENING
1006/**
1007 * Main entry point.
1008 */
1009int main(int argc, char **argv, char **envp)
1010{
1011 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_TRY_SUPLIB);
1012 if (RT_SUCCESS(rc))
1013 return TrustedMain(argc, argv, envp);
1014 RTPrintf("VBoxBFE: Runtime initialization failed: %Rrc - %Rrf\n", rc, rc);
1015 return RTEXITCODE_FAILURE;
1016}
1017#endif /* !VBOX_WITH_HARDENING */
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