VirtualBox

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

Last change on this file since 99548 was 99546, checked in by vboxsync, 22 months ago

FE/VBoxBFE: Some very simple SDL based display output and add more devices, bugref:10397

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

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