VirtualBox

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

Last change on this file since 106579 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.0 KB
Line 
1/* $Id: VBoxBFE.cpp 106061 2024-09-16 14:03:52Z 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-2024 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#ifdef RT_OS_DARWIN
36# include <Carbon/Carbon.h>
37# undef PVM
38#endif
39
40#include <VBox/log.h>
41#include <VBox/version.h>
42#include <VBox/vmm/vmmr3vtable.h>
43#include <VBox/vmm/vmapi.h>
44#include <VBox/vmm/pdm.h>
45#include <iprt/buildconfig.h>
46#include <iprt/ctype.h>
47#include <iprt/initterm.h>
48#include <iprt/message.h>
49#include <iprt/semaphore.h>
50#include <iprt/file.h>
51#include <iprt/path.h>
52#include <iprt/stream.h>
53#include <iprt/ldr.h>
54#include <iprt/mem.h>
55#include <iprt/getopt.h>
56#include <iprt/env.h>
57#include <iprt/errcore.h>
58#include <iprt/thread.h>
59#include <iprt/uuid.h>
60
61#include <SDL.h>
62
63#include "Display.h"
64#include "Framebuffer.h"
65#include "Keyboard.h"
66
67
68/*********************************************************************************************************************************
69* Defined Constants And Macros *
70*********************************************************************************************************************************/
71
72#define LogError(m,rc) \
73 do { \
74 Log(("VBoxBFE: ERROR: " m " [rc=0x%08X]\n", rc)); \
75 RTPrintf("%s\n", m); \
76 } while (0)
77
78#define DTB_ADDR 0x40000000
79
80
81/*********************************************************************************************************************************
82* Structures and Typedefs *
83*********************************************************************************************************************************/
84
85enum TitlebarMode
86{
87 TITLEBAR_NORMAL = 1,
88 TITLEBAR_STARTUP = 2,
89 TITLEBAR_SAVE = 3,
90 TITLEBAR_SNAPSHOT = 4
91};
92
93
94/*********************************************************************************************************************************
95* Global Variables *
96*********************************************************************************************************************************/
97static int gHostKeyMod = KMOD_RCTRL;
98static int gHostKeySym1 = SDLK_RCTRL;
99static int gHostKeySym2 = SDLK_UNKNOWN;
100static bool gfGrabbed = FALSE;
101static bool gfGrabOnMouseClick = TRUE;
102static bool gfFullscreenResize = FALSE;
103static bool gfAllowFullscreenToggle = TRUE;
104static bool gfAbsoluteMouseHost = FALSE;
105static bool gfAbsoluteMouseGuest = FALSE;
106static bool gfRelativeMouseGuest = TRUE;
107static bool gfGuestNeedsHostCursor = FALSE;
108static bool gfOffCursorActive = FALSE;
109static bool gfGuestNumLockPressed = FALSE;
110static bool gfGuestCapsLockPressed = FALSE;
111static bool gfGuestScrollLockPressed = FALSE;
112
113/** modifier keypress status (scancode as index) */
114static uint8_t gaModifiersState[256];
115
116/** flag whether frontend should terminate */
117static volatile bool g_fTerminateFE = false;
118static RTLDRMOD g_hModVMM = NIL_RTLDRMOD;
119static PCVMMR3VTABLE g_pVMM = NULL;
120static PVM g_pVM = NULL;
121static PUVM g_pUVM = NULL;
122static uint32_t g_u32MemorySizeMB = 512;
123static VMSTATE g_enmVmState = VMSTATE_CREATING;
124static const char *g_pszLoadMem = NULL;
125static const char *g_pszLoadFlash = NULL;
126static const char *g_pszLoadDtb = NULL;
127static const char *g_pszSerialLog = NULL;
128static const char *g_pszLoadKernel = NULL;
129static const char *g_pszLoadInitrd = NULL;
130static const char *g_pszCmdLine = NULL;
131static VMM2USERMETHODS g_Vmm2UserMethods;
132static Display *g_pDisplay = NULL;
133static Framebuffer *g_pFramebuffer = NULL;
134static Keyboard *g_pKeyboard = NULL;
135static bool gfIgnoreNextResize = false;
136static uint32_t gcMonitors = 1;
137static SDL_TimerID gSdlResizeTimer = 0;
138
139/** @todo currently this is only set but never read. */
140static char szError[512];
141
142extern DECL_HIDDEN_DATA(RTSEMEVENT) g_EventSemSDLEvents;
143extern DECL_HIDDEN_DATA(volatile int32_t) g_cNotifyUpdateEventsPending;
144
145
146/* The damned GOTOs forces this to be up here - totally out of place. */
147/*
148 * Host key handling.
149 *
150 * The golden rule is that host-key combinations should not be seen
151 * by the guest. For instance a CAD should not have any extra RCtrl down
152 * and RCtrl up around itself. Nor should a resume be followed by a Ctrl-P
153 * that could encourage applications to start printing.
154 *
155 * We must not confuse the hostkey processing into any release sequences
156 * either, the host key is supposed to be explicitly pressing one key.
157 *
158 * Quick state diagram:
159 *
160 * host key down alone
161 * (Normal) ---------------
162 * ^ ^ |
163 * | | v host combination key down
164 * | | (Host key down) ----------------
165 * | | host key up v | |
166 * | |-------------- | other key down v host combination key down
167 * | | (host key used) -------------
168 * | | | ^ |
169 * | (not host key)-- | |---------------
170 * | | | | |
171 * | | ---- other |
172 * | modifiers = 0 v v
173 * -----------------------------------------------
174 */
175enum HKEYSTATE
176{
177 /** The initial and most common state, pass keystrokes to the guest.
178 * Next state: HKEYSTATE_DOWN
179 * Prev state: Any */
180 HKEYSTATE_NORMAL = 1,
181 /** The first host key was pressed down
182 */
183 HKEYSTATE_DOWN_1ST,
184 /** The second host key was pressed down (if gHostKeySym2 != SDLK_UNKNOWN)
185 */
186 HKEYSTATE_DOWN_2ND,
187 /** The host key has been pressed down.
188 * Prev state: HKEYSTATE_NORMAL
189 * Next state: HKEYSTATE_NORMAL - host key up, capture toggle.
190 * Next state: HKEYSTATE_USED - host key combination down.
191 * Next state: HKEYSTATE_NOT_IT - non-host key combination down.
192 */
193 HKEYSTATE_DOWN,
194 /** A host key combination was pressed.
195 * Prev state: HKEYSTATE_DOWN
196 * Next state: HKEYSTATE_NORMAL - when modifiers are all 0
197 */
198 HKEYSTATE_USED,
199 /** A non-host key combination was attempted. Send hostkey down to the
200 * guest and continue until all modifiers have been released.
201 * Prev state: HKEYSTATE_DOWN
202 * Next state: HKEYSTATE_NORMAL - when modifiers are all 0
203 */
204 HKEYSTATE_NOT_IT
205} enmHKeyState = HKEYSTATE_NORMAL;
206
207
208/*********************************************************************************************************************************
209* Internal Functions *
210*********************************************************************************************************************************/
211
212/**
213 * Build the titlebar string
214 */
215static void UpdateTitlebar(TitlebarMode mode, uint32_t u32User = 0)
216{
217 static char szTitle[1024] = {0};
218
219 /* back up current title */
220 char szPrevTitle[1024];
221 strcpy(szPrevTitle, szTitle);
222
223 RTStrPrintf(szTitle, sizeof(szTitle), "%s - " VBOX_PRODUCT,
224 "<noname>");
225
226 /* which mode are we in? */
227 switch (mode)
228 {
229 case TITLEBAR_NORMAL:
230 {
231 if (gfGrabbed)
232 RTStrPrintf(szTitle + strlen(szTitle), sizeof(szTitle) - strlen(szTitle), " - [Input captured]");
233 break;
234 }
235
236 case TITLEBAR_STARTUP:
237 {
238 RTStrPrintf(szTitle + strlen(szTitle), sizeof(szTitle) - strlen(szTitle),
239 " - Starting...");
240 /* ignore other states, we could already be in running or aborted state */
241 break;
242 }
243
244 case TITLEBAR_SAVE:
245 {
246 AssertMsg(u32User <= 100, ("%d\n", u32User));
247 RTStrPrintf(szTitle + strlen(szTitle), sizeof(szTitle) - strlen(szTitle),
248 " - Saving %d%%...", u32User);
249 break;
250 }
251
252 case TITLEBAR_SNAPSHOT:
253 {
254 AssertMsg(u32User <= 100, ("%d\n", u32User));
255 RTStrPrintf(szTitle + strlen(szTitle), sizeof(szTitle) - strlen(szTitle),
256 " - Taking snapshot %d%%...", u32User);
257 break;
258 }
259
260 default:
261 RTPrintf("Error: Invalid title bar mode %d!\n", mode);
262 return;
263 }
264
265 /*
266 * Don't update if it didn't change.
267 */
268 if (!strcmp(szTitle, szPrevTitle))
269 return;
270
271 /*
272 * Set the new title
273 */
274 g_pFramebuffer->setWindowTitle(szTitle);
275}
276
277
278#ifdef RT_OS_DARWIN
279RT_C_DECLS_BEGIN
280/* Private interface in 10.3 and later. */
281typedef int CGSConnection;
282typedef enum
283{
284 kCGSGlobalHotKeyEnable = 0,
285 kCGSGlobalHotKeyDisable,
286 kCGSGlobalHotKeyInvalid = -1 /* bird */
287} CGSGlobalHotKeyOperatingMode;
288extern CGSConnection _CGSDefaultConnection(void);
289extern CGError CGSGetGlobalHotKeyOperatingMode(CGSConnection Connection, CGSGlobalHotKeyOperatingMode *enmMode);
290extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection Connection, CGSGlobalHotKeyOperatingMode enmMode);
291RT_C_DECLS_END
292
293/** Keeping track of whether we disabled the hotkeys or not. */
294static bool g_fHotKeysDisabled = false;
295/** Whether we've connected or not. */
296static bool g_fConnectedToCGS = false;
297/** Cached connection. */
298static CGSConnection g_CGSConnection;
299
300/**
301 * Disables or enabled global hot keys.
302 */
303static void DisableGlobalHotKeys(bool fDisable)
304{
305 if (!g_fConnectedToCGS)
306 {
307 g_CGSConnection = _CGSDefaultConnection();
308 g_fConnectedToCGS = true;
309 }
310
311 /* get current mode. */
312 CGSGlobalHotKeyOperatingMode enmMode = kCGSGlobalHotKeyInvalid;
313 CGSGetGlobalHotKeyOperatingMode(g_CGSConnection, &enmMode);
314
315 /* calc new mode. */
316 if (fDisable)
317 {
318 if (enmMode != kCGSGlobalHotKeyEnable)
319 return;
320 enmMode = kCGSGlobalHotKeyDisable;
321 }
322 else
323 {
324 if ( enmMode != kCGSGlobalHotKeyDisable
325 /*|| !g_fHotKeysDisabled*/)
326 return;
327 enmMode = kCGSGlobalHotKeyEnable;
328 }
329
330 /* try set it and check the actual result. */
331 CGSSetGlobalHotKeyOperatingMode(g_CGSConnection, enmMode);
332 CGSGlobalHotKeyOperatingMode enmNewMode = kCGSGlobalHotKeyInvalid;
333 CGSGetGlobalHotKeyOperatingMode(g_CGSConnection, &enmNewMode);
334 if (enmNewMode == enmMode)
335 g_fHotKeysDisabled = enmMode == kCGSGlobalHotKeyDisable;
336}
337#endif /* RT_OS_DARWIN */
338
339
340/**
341 * Start grabbing the mouse.
342 */
343static void InputGrabStart(void)
344{
345#ifdef RT_OS_DARWIN
346 DisableGlobalHotKeys(true);
347#endif
348 if (!gfGuestNeedsHostCursor && gfRelativeMouseGuest)
349 SDL_ShowCursor(SDL_DISABLE);
350 SDL_SetRelativeMouseMode(SDL_TRUE);
351 gfGrabbed = TRUE;
352 UpdateTitlebar(TITLEBAR_NORMAL);
353}
354
355/**
356 * End mouse grabbing.
357 */
358static void InputGrabEnd(void)
359{
360 SDL_SetRelativeMouseMode(SDL_FALSE);
361 if (!gfGuestNeedsHostCursor && gfRelativeMouseGuest)
362 SDL_ShowCursor(SDL_ENABLE);
363#ifdef RT_OS_DARWIN
364 DisableGlobalHotKeys(false);
365#endif
366 gfGrabbed = FALSE;
367 UpdateTitlebar(TITLEBAR_NORMAL);
368}
369
370
371
372/**
373 * Handles a host key down event
374 */
375static int HandleHostKey(const SDL_KeyboardEvent *pEv)
376{
377 /*
378 * Revalidate the host key modifier
379 */
380 if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) != gHostKeyMod)
381 return VERR_NOT_SUPPORTED;
382
383 /*
384 * What was pressed?
385 */
386 switch (pEv->keysym.sym)
387 {
388#if 0
389 /* Control-Alt-Delete */
390 case SDLK_DELETE:
391 {
392 //g_pKeyboard->PutCAD();
393 break;
394 }
395
396 /*
397 * Fullscreen / Windowed toggle.
398 */
399 case SDLK_f:
400 {
401 if ( strchr(gHostKeyDisabledCombinations, 'f')
402 || !gfAllowFullscreenToggle)
403 return VERR_NOT_SUPPORTED;
404
405 /*
406 * We have to pause/resume the machine during this
407 * process because there might be a short moment
408 * without a valid framebuffer
409 */
410 /** @todo */
411 //SetFullscreen(!g_pFramebuffer->getFullscreen());
412
413 /*
414 * We have switched from/to fullscreen, so request a full
415 * screen repaint, just to be sure.
416 */
417 gpDisplay->InvalidateAndUpdate();
418 break;
419 }
420
421 /*
422 * Pause / Resume toggle.
423 */
424 case SDLK_p:
425 {
426 if (strchr(gHostKeyDisabledCombinations, 'p'))
427 return VERR_NOT_SUPPORTED;
428
429 /** @todo */
430 UpdateTitlebar(TITLEBAR_NORMAL);
431 break;
432 }
433
434 /*
435 * Reset the VM
436 */
437 case SDLK_r:
438 {
439 if (strchr(gHostKeyDisabledCombinations, 'r'))
440 return VERR_NOT_SUPPORTED;
441
442 ResetVM();
443 break;
444 }
445
446 /*
447 * Terminate the VM
448 */
449 case SDLK_q:
450 {
451 if (strchr(gHostKeyDisabledCombinations, 'q'))
452 return VERR_NOT_SUPPORTED;
453
454 return VINF_EM_TERMINATE;
455 }
456
457 /*
458 * Save the machine's state and exit
459 */
460 case SDLK_s:
461 {
462 if (strchr(gHostKeyDisabledCombinations, 's'))
463 return VERR_NOT_SUPPORTED;
464
465 SaveState();
466 return VINF_EM_TERMINATE;
467 }
468
469 case SDLK_h:
470 {
471 if (strchr(gHostKeyDisabledCombinations, 'h'))
472 return VERR_NOT_SUPPORTED;
473
474 if (gpConsole)
475 gpConsole->PowerButton();
476 break;
477 }
478#endif
479
480 case SDLK_F1: case SDLK_F2: case SDLK_F3:
481 case SDLK_F4: case SDLK_F5: case SDLK_F6:
482 case SDLK_F7: case SDLK_F8: case SDLK_F9:
483 case SDLK_F10: case SDLK_F11: case SDLK_F12:
484 {
485 /* send Ctrl-Alt-Fx to guest */
486 g_pKeyboard->PutUsageCode(0xE0 /*left ctrl*/, 0x07 /*usage code page id*/, FALSE);
487 g_pKeyboard->PutUsageCode(0xE2 /*left alt*/, 0x07 /*usage code page id*/, FALSE);
488 g_pKeyboard->PutUsageCode(pEv->keysym.sym, 0x07 /*usage code page id*/, FALSE);
489 g_pKeyboard->PutUsageCode(pEv->keysym.sym, 0x07 /*usage code page id*/, TRUE);
490 g_pKeyboard->PutUsageCode(0xE0 /*left ctrl*/, 0x07 /*usage code page id*/, TRUE);
491 g_pKeyboard->PutUsageCode(0xE2 /*left alt*/, 0x07 /*usage code page id*/, TRUE);
492 return VINF_SUCCESS;
493 }
494
495 /*
496 * Not a host key combination.
497 * Indicate this by returning false.
498 */
499 default:
500 return VERR_NOT_SUPPORTED;
501 }
502
503 return VINF_SUCCESS;
504}
505
506
507/**
508 * Releases any modifier keys that are currently in pressed state.
509 */
510static void ResetKeys(void)
511{
512 int i;
513
514 if (!g_pKeyboard)
515 return;
516
517 for(i = 0; i < 256; i++)
518 {
519 if (gaModifiersState[i])
520 {
521 if (i & 0x80)
522 g_pKeyboard->PutScancode(0xe0);
523 g_pKeyboard->PutScancode(i | 0x80);
524 gaModifiersState[i] = 0;
525 }
526 }
527}
528
529/**
530 * Keyboard event handler.
531 *
532 * @param ev SDL keyboard event.
533 */
534static void ProcessKey(SDL_KeyboardEvent *ev)
535{
536 /* According to SDL2/SDL_scancodes.h ev->keysym.sym stores scancodes which are
537 * based on USB usage page standard. This is what we can directly pass to
538 * IKeyboard::putUsageCode. */
539 g_pKeyboard->PutUsageCode(SDL_GetScancodeFromKey(ev->keysym.sym), 0x07 /*usage code page id*/, ev->type == SDL_KEYUP ? TRUE : FALSE);
540}
541
542
543/**
544 * Wait for the next SDL event. Don't use SDL_WaitEvent since this function
545 * calls SDL_Delay(10) if the event queue is empty.
546 */
547static int WaitSDLEvent(SDL_Event *event)
548{
549 for (;;)
550 {
551 int rc = SDL_PollEvent(event);
552 if (rc == 1)
553 return 1;
554 /* Immediately wake up if new SDL events are available. This does not
555 * work for internal SDL events. Don't wait more than 10ms. */
556 RTSemEventWait(g_EventSemSDLEvents, 10);
557 }
558}
559
560
561/**
562 * Timer callback function to check if resizing is finished
563 */
564static Uint32 ResizeTimer(Uint32 interval, void *param) RT_NOTHROW_DEF
565{
566 RT_NOREF(interval, param);
567
568 /* post message so the window is actually resized */
569 SDL_Event event = {0};
570 event.type = SDL_USEREVENT;
571 event.user.type = SDL_USER_EVENT_WINDOW_RESIZE_DONE;
572 PushSDLEventForSure(&event);
573 /* one-shot */
574 return 0;
575}
576
577
578/**
579 * VM state callback function. Called by the VMM
580 * using its state machine states.
581 *
582 * Primarily used to handle VM initiated power off, suspend and state saving,
583 * but also for doing termination completed work (VMSTATE_TERMINATE).
584 *
585 * In general this function is called in the context of the EMT.
586 *
587 * @todo g_enmVmState is set to VMSTATE_RUNNING before all devices have received power on events
588 * this can prematurely allow the main thread to enter the event loop
589 *
590 * @param pVM The VM handle.
591 * @param enmState The new state.
592 * @param enmOldState The old state.
593 * @param pvUser The user argument.
594 */
595static DECLCALLBACK(void) vboxbfeVmStateChangeCallback(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)
596{
597 RT_NOREF(pUVM, pVMM, enmOldState, pvUser);
598 LogFlow(("vmstateChangeCallback: changing state from %d to %d\n", enmOldState, enmState));
599 g_enmVmState = enmState;
600
601 switch (enmState)
602 {
603 /*
604 * The VM has terminated
605 */
606 case VMSTATE_OFF:
607 {
608 break;
609 }
610
611 /*
612 * The VM has been completely destroyed.
613 *
614 * Note: This state change can happen at two points:
615 * 1) At the end of VMR3Destroy() if it was not called from EMT.
616 * 2) At the end of vmR3EmulationThread if VMR3Destroy() was called by EMT.
617 */
618 case VMSTATE_TERMINATED:
619 {
620 break;
621 }
622
623 default: /* shut up gcc */
624 break;
625 }
626}
627
628
629/**
630 * VM error callback function. Called by the various VM components.
631 *
632 * @param pVM The VM handle.
633 * @param pvUser The user argument.
634 * @param vrc VBox status code.
635 * @param pszFormat Error message format string.
636 * @param args Error message arguments.
637 * @thread EMT.
638 */
639DECLCALLBACK(void) vboxbfeSetVMErrorCallback(PUVM pUVM, void *pvUser, int vrc, RT_SRC_POS_DECL, const char *pszFormat, va_list args)
640{
641 RT_NOREF(pUVM, pvUser, pszFile, iLine, pszFunction);
642
643 /** @todo accessing shared resource without any kind of synchronization */
644 if (RT_SUCCESS(vrc))
645 szError[0] = '\0';
646 else
647 {
648 va_list va2;
649 va_copy(va2, args); /* Have to make a copy here or GCC will break. */
650 RTStrPrintf(szError, sizeof(szError),
651 "%N!\nVBox status code: %d (%Rrc)", pszFormat, &va2, vrc, vrc);
652 RTPrintf("%s\n", szError);
653 va_end(va2);
654 }
655}
656
657
658/**
659 * VM Runtime error callback function. Called by the various VM components.
660 *
661 * @param pVM The VM handle.
662 * @param pvUser The user argument.
663 * @param fFlags The action flags. See VMSETRTERR_FLAGS_*.
664 * @param pszErrorId Error ID string.
665 * @param pszFormat Error message format string.
666 * @param va Error message arguments.
667 * @thread EMT.
668 */
669DECLCALLBACK(void) vboxbfeSetVMRuntimeErrorCallback(PUVM pUVM, void *pvUser, uint32_t fFlags,
670 const char *pszErrorId, const char *pszFormat, va_list va)
671{
672 RT_NOREF(pUVM, pvUser);
673
674 va_list va2;
675 va_copy(va2, va); /* Have to make a copy here or GCC/AMD64 will break. */
676 RTPrintf("%s: %s!\n%N!\n",
677 fFlags & VMSETRTERR_FLAGS_FATAL ? "Error" : "Warning",
678 pszErrorId, pszFormat, &va2);
679 RTStrmFlush(g_pStdErr);
680 va_end(va2);
681}
682
683
684/**
685 * Register the main drivers.
686 *
687 * @returns VBox status code.
688 * @param pCallbacks Pointer to the callback table.
689 * @param u32Version VBox version number.
690 */
691DECLCALLBACK(int) VBoxDriversRegister(PCPDMDRVREGCB pCallbacks, uint32_t u32Version)
692{
693 LogFlow(("VBoxDriversRegister: u32Version=%#x\n", u32Version));
694 AssertReleaseMsg(u32Version == VBOX_VERSION, ("u32Version=%#x VBOX_VERSION=%#x\n", u32Version, VBOX_VERSION));
695
696 int vrc = pCallbacks->pfnRegister(pCallbacks, &Display::DrvReg);
697 if (RT_FAILURE(vrc))
698 return vrc;
699
700 vrc = pCallbacks->pfnRegister(pCallbacks, &Keyboard::DrvReg);
701 if (RT_FAILURE(vrc))
702 return vrc;
703
704 return VINF_SUCCESS;
705}
706
707
708/**
709 * Constructs the VMM configuration tree.
710 *
711 * @returns VBox status code.
712 * @param pVM VM handle.
713 */
714static DECLCALLBACK(int) vboxbfeConfigConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvConsole)
715{
716 int rcAll = VINF_SUCCESS;
717 int rc;
718
719 RT_NOREF(pvConsole);
720 g_pUVM = pUVM;
721
722#define UPDATE_RC() do { if (RT_FAILURE(rc) && RT_SUCCESS(rcAll)) rcAll = rc; } while (0)
723
724 /*
725 * Root values.
726 */
727 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRoot(pVM);
728 rc = pVMM->pfnCFGMR3InsertString(pRoot, "Name", "Default VM"); UPDATE_RC();
729 rc = pVMM->pfnCFGMR3InsertInteger(pRoot, "TimerMillies", 1000); UPDATE_RC();
730
731 /*
732 * Memory setup.
733 */
734 PCFGMNODE pMem = NULL;
735 rc = pVMM->pfnCFGMR3InsertNode(pRoot, "MM", &pMem); UPDATE_RC();
736 rc = pVMM->pfnCFGMR3InsertNode(pMem, "MemRegions", &pMem); UPDATE_RC();
737
738 PCFGMNODE pMemRegion = NULL;
739 rc = pVMM->pfnCFGMR3InsertNode(pMem, "Flash", &pMemRegion); UPDATE_RC();
740 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "GCPhysStart", 0); UPDATE_RC();
741 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "Size", 64 * _1M); UPDATE_RC();
742 if (g_pszLoadMem)
743 {
744 rc = pVMM->pfnCFGMR3InsertString(pMemRegion, "PrepopulateFromFile", g_pszLoadMem); UPDATE_RC();
745 }
746
747 rc = pVMM->pfnCFGMR3InsertNode(pMem, "Conventional", &pMemRegion); UPDATE_RC();
748 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "GCPhysStart", DTB_ADDR); UPDATE_RC();
749 rc = pVMM->pfnCFGMR3InsertInteger(pMemRegion, "Size", (uint64_t)g_u32MemorySizeMB * _1M); UPDATE_RC();
750 if (g_pszLoadDtb)
751 {
752 rc = pVMM->pfnCFGMR3InsertString(pMemRegion, "PrepopulateFromFile", g_pszLoadDtb); UPDATE_RC();
753
754 }
755
756 /*
757 * PDM.
758 */
759 rc = pVMM->pfnPDMR3DrvStaticRegistration(pVM, VBoxDriversRegister); UPDATE_RC();
760
761 /*
762 * Devices
763 */
764 PCFGMNODE pDevices = NULL;
765 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
766 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
767 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
768 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
769 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
770 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
771
772 rc = pVMM->pfnCFGMR3InsertNode(pRoot, "Devices", &pDevices); UPDATE_RC();
773
774 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "gic", &pDev); UPDATE_RC();
775 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
776 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "Trusted", 1); UPDATE_RC();
777 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
778
779 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "DistributorMmioBase", 0x08000000); UPDATE_RC();
780 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "RedistributorMmioBase", 0x080a0000); UPDATE_RC();
781
782
783 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "qemu-fw-cfg", &pDev); UPDATE_RC();
784 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
785 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
786 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioSize", 4096); UPDATE_RC();
787 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioBase", 0x09020000); UPDATE_RC();
788 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "DmaEnabled", 1); UPDATE_RC();
789 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "QemuRamfbSupport", 1); UPDATE_RC();
790 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
791 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "MainDisplay"); UPDATE_RC();
792 if (g_pszLoadKernel)
793 {
794 rc = pVMM->pfnCFGMR3InsertString(pCfg, "KernelImage", g_pszLoadKernel); UPDATE_RC();
795 }
796 if (g_pszLoadInitrd)
797 {
798 rc = pVMM->pfnCFGMR3InsertString(pCfg, "InitrdImage", g_pszLoadInitrd); UPDATE_RC();
799 }
800 if (g_pszCmdLine)
801 {
802 rc = pVMM->pfnCFGMR3InsertString(pCfg, "CmdLine", g_pszCmdLine); UPDATE_RC();
803 }
804
805
806 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "flash-cfi", &pDev); UPDATE_RC();
807 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
808 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
809 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "BaseAddress", 64 * _1M); UPDATE_RC();
810 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "Size", 64 * _1M); UPDATE_RC();
811 if (g_pszLoadFlash)
812 {
813 rc = pVMM->pfnCFGMR3InsertString(pCfg, "FlashFile", g_pszLoadFlash); UPDATE_RC();
814 }
815
816 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "arm-pl011", &pDev); UPDATE_RC();
817 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
818 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
819 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "Irq", 1); UPDATE_RC();
820 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioBase", 0x09000000); UPDATE_RC();
821
822 if (g_pszSerialLog)
823 {
824 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
825 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "Char"); UPDATE_RC();
826 rc = pVMM->pfnCFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); UPDATE_RC();
827 rc = pVMM->pfnCFGMR3InsertString(pLunL1, "Driver", "RawFile"); UPDATE_RC();
828 rc = pVMM->pfnCFGMR3InsertNode(pLunL1, "Config", &pLunL1Cfg); UPDATE_RC();
829 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "Location", g_pszSerialLog); UPDATE_RC();
830 }
831
832 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "arm-pl031-rtc", &pDev); UPDATE_RC();
833 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
834 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
835 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "Irq", 2); UPDATE_RC();
836 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioBase", 0x09010000); UPDATE_RC();
837
838 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "arm-pl061-gpio",&pDev); UPDATE_RC();
839 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
840 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
841 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "Irq", 7); UPDATE_RC();
842 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioBase", 0x09030000); UPDATE_RC();
843
844 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "pci-generic-ecam", &pDev); UPDATE_RC();
845 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
846 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
847 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioEcamBase", 0x3f000000); UPDATE_RC();
848 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioEcamLength", 0x01000000); UPDATE_RC();
849 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioPioBase", 0x3eff0000); UPDATE_RC();
850 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "MmioPioSize", 0x0000ffff); UPDATE_RC();
851 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "IntPinA", 3); UPDATE_RC();
852 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "IntPinB", 4); UPDATE_RC();
853 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "IntPinC", 5); UPDATE_RC();
854 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "IntPinD", 6); UPDATE_RC();
855
856 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "usb-xhci", &pDev); UPDATE_RC();
857 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
858 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "Trusted", 1); UPDATE_RC();
859 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "PCIBusNo", 0); UPDATE_RC();
860 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "PCIDeviceNo", 2); UPDATE_RC();
861 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); UPDATE_RC();
862 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
863 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
864 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver","VUSBRootHub"); UPDATE_RC();
865 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#1", &pLunL0); UPDATE_RC();
866 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver","VUSBRootHub"); UPDATE_RC();
867
868 rc = pVMM->pfnCFGMR3InsertNode(pDevices, "e1000", &pDev); UPDATE_RC();
869 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
870 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "Trusted", 1); UPDATE_RC();
871 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "PCIBusNo", 0); UPDATE_RC();
872 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "PCIDeviceNo", 1); UPDATE_RC();
873 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); UPDATE_RC();
874 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
875 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "CableConnected", 1); UPDATE_RC();
876 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "LineSpeed", 0); UPDATE_RC();
877 rc = pVMM->pfnCFGMR3InsertInteger(pCfg, "AdapterType", 0); UPDATE_RC();
878
879 const char *pszMac = "080027ede92c";
880 Assert(strlen(pszMac) == 12);
881 RTMAC Mac;
882 RT_ZERO(Mac);
883 char *pMac = (char*)&Mac;
884 for (uint32_t i = 0; i < 6; ++i)
885 {
886 int c1 = *pszMac++ - '0';
887 if (c1 > 9)
888 c1 -= 7;
889 int c2 = *pszMac++ - '0';
890 if (c2 > 9)
891 c2 -= 7;
892 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
893 }
894 rc = pVMM->pfnCFGMR3InsertBytes(pCfg, "MAC", &Mac, sizeof(Mac)); UPDATE_RC();
895 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
896 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "NAT"); UPDATE_RC();
897 rc = pVMM->pfnCFGMR3InsertNode(pLunL0, "Config", &pLunL1Cfg); UPDATE_RC();
898 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "Network", "10.0.2.0/24"); UPDATE_RC();
899 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "TFTPPrefix", "/Users/vbox/Library/VirtualBox/TFTP"); UPDATE_RC();
900 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "BootFile", "default.pxe"); UPDATE_RC();
901 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "AliasMode", 0); UPDATE_RC();
902 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "DNSProxy", 0); UPDATE_RC();
903 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "LocalhostReachable", 1); UPDATE_RC();
904 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "PassDomain", 1); UPDATE_RC();
905 rc = pVMM->pfnCFGMR3InsertInteger(pLunL1Cfg, "UseHostResolver", 0); UPDATE_RC();
906
907 PCFGMNODE pUsb = NULL;
908 rc = pVMM->pfnCFGMR3InsertNode(pRoot, "USB", &pUsb); UPDATE_RC();
909 rc = pVMM->pfnCFGMR3InsertNode(pUsb, "Msd", &pDev); UPDATE_RC();
910 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
911 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "Trusted", 1); UPDATE_RC();
912 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
913 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
914 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "SCSI"); UPDATE_RC();
915 rc = pVMM->pfnCFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); UPDATE_RC();
916 rc = pVMM->pfnCFGMR3InsertString(pLunL1, "Driver", "VD"); UPDATE_RC();
917 rc = pVMM->pfnCFGMR3InsertNode(pLunL1, "Config", &pLunL1Cfg); UPDATE_RC();
918 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "Path", "/Users/vbox/rootfs.img"); UPDATE_RC();
919 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "Type", "HardDisk"); UPDATE_RC();
920 rc = pVMM->pfnCFGMR3InsertString(pLunL1Cfg, "Format", "Raw"); UPDATE_RC();
921
922 rc = pVMM->pfnCFGMR3InsertNode(pUsb, "HidKeyboard", &pDev); UPDATE_RC();
923 rc = pVMM->pfnCFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
924 rc = pVMM->pfnCFGMR3InsertInteger(pInst, "Trusted", 1); UPDATE_RC();
925 rc = pVMM->pfnCFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
926 rc = pVMM->pfnCFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
927 rc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue"); UPDATE_RC();
928 rc = pVMM->pfnCFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); UPDATE_RC();
929 rc = pVMM->pfnCFGMR3InsertString(pLunL1, "Driver", "MainKeyboard"); UPDATE_RC();
930
931#undef UPDATE_RC
932#undef UPDATE_RC
933
934 pVMM->pfnVMR3AtRuntimeErrorRegister (pUVM, vboxbfeSetVMRuntimeErrorCallback, NULL);
935
936 return rc;
937}
938
939
940/**
941 * Loads the VMM if needed.
942 *
943 * @returns VBox status code.
944 * @param pszVmmMod The VMM module to load.
945 */
946int vboxbfeLoadVMM(const char *pszVmmMod)
947{
948 Assert(!g_pVMM);
949
950 RTERRINFOSTATIC ErrInfo;
951 RTLDRMOD hModVMM = NIL_RTLDRMOD;
952 int vrc = SUPR3HardenedLdrLoadAppPriv(pszVmmMod, &hModVMM, RTLDRLOAD_FLAGS_LOCAL, RTErrInfoInitStatic(&ErrInfo));
953 if (RT_SUCCESS(vrc))
954 {
955 PFNVMMGETVTABLE pfnGetVTable = NULL;
956 vrc = RTLdrGetSymbol(hModVMM, VMMR3VTABLE_GETTER_NAME, (void **)&pfnGetVTable);
957 if (pfnGetVTable)
958 {
959 PCVMMR3VTABLE pVMM = pfnGetVTable();
960 if (pVMM)
961 {
962 if (VMMR3VTABLE_IS_COMPATIBLE(pVMM->uMagicVersion))
963 {
964 if (pVMM->uMagicVersion == pVMM->uMagicVersionEnd)
965 {
966 g_hModVMM = hModVMM;
967 g_pVMM = pVMM;
968 LogFunc(("mhLdrVMM=%p phVMM=%p uMagicVersion=%#RX64\n", hModVMM, pVMM, pVMM->uMagicVersion));
969 return VINF_SUCCESS;
970 }
971
972 LogRel(("Bogus VMM vtable: uMagicVersion=%#RX64 uMagicVersionEnd=%#RX64",
973 pVMM->uMagicVersion, pVMM->uMagicVersionEnd));
974 }
975 else
976 LogRel(("Incompatible of bogus VMM version magic: %#RX64", pVMM->uMagicVersion));
977 }
978 else
979 LogRel(("pfnGetVTable return NULL!"));
980 }
981 else
982 LogRel(("Failed to locate symbol '%s' in VBoxVMM: %Rrc", VMMR3VTABLE_GETTER_NAME, vrc));
983 RTLdrClose(hModVMM);
984 }
985 else
986 LogRel(("Failed to load VBoxVMM: %#RTeic", &ErrInfo.Core));
987
988 return vrc;
989}
990
991
992/**
993 * @interface_method_impl{VMM2USERMETHODS,pfnQueryGenericObject}
994 */
995static DECLCALLBACK(void *) vboxbfeVmm2User_QueryGenericObject(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)
996{
997 RT_NOREF(pThis, pUVM);
998
999 if (!RTUuidCompareStr(pUuid, DISPLAY_OID))
1000 return g_pDisplay;
1001
1002 if (!RTUuidCompareStr(pUuid, KEYBOARD_OID))
1003 return g_pKeyboard;
1004
1005 return NULL;
1006}
1007
1008
1009/** VM asynchronous operations thread */
1010DECLCALLBACK(int) vboxbfeVMPowerUpThread(RTTHREAD hThread, void *pvUser)
1011{
1012 RT_NOREF(hThread, pvUser);
1013
1014 int rc = VINF_SUCCESS;
1015 int rc2;
1016
1017#if 0
1018 /*
1019 * Setup the release log instance in current directory.
1020 */
1021 if (g_fReleaseLog)
1022 {
1023 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
1024 static char s_szError[RTPATH_MAX + 128] = "";
1025 PRTLOGGER pLogger;
1026 rc2 = RTLogCreateEx(&pLogger, RTLOGFLAGS_PREFIX_TIME_PROG, "all",
1027 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_FILE,
1028 NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
1029 s_szError, sizeof(s_szError), "./VBoxBFE.log");
1030 if (RT_SUCCESS(rc2))
1031 {
1032 /* some introductory information */
1033 RTTIMESPEC TimeSpec;
1034 char szNowUct[64];
1035 RTTimeSpecToString(RTTimeNow(&TimeSpec), szNowUct, sizeof(szNowUct));
1036 RTLogRelLogger(pLogger, 0, ~0U,
1037 "VBoxBFE %s (%s %s) release log\n"
1038 "Log opened %s\n",
1039 VBOX_VERSION_STRING, __DATE__, __TIME__,
1040 szNowUct);
1041
1042 /* register this logger as the release logger */
1043 RTLogRelSetDefaultInstance(pLogger);
1044 }
1045 else
1046 RTPrintf("Could not open release log (%s)\n", s_szError);
1047 }
1048#endif
1049
1050 /*
1051 * Start VM (also from saved state) and track progress
1052 */
1053 LogFlow(("VMPowerUp\n"));
1054
1055 g_Vmm2UserMethods.u32Magic = VMM2USERMETHODS_MAGIC;
1056 g_Vmm2UserMethods.u32Version = VMM2USERMETHODS_VERSION;
1057 g_Vmm2UserMethods.pfnSaveState = NULL;
1058 g_Vmm2UserMethods.pfnNotifyEmtInit = NULL;
1059 g_Vmm2UserMethods.pfnNotifyEmtTerm = NULL;
1060 g_Vmm2UserMethods.pfnNotifyPdmtInit = NULL;
1061 g_Vmm2UserMethods.pfnNotifyPdmtTerm = NULL;
1062 g_Vmm2UserMethods.pfnNotifyResetTurnedIntoPowerOff = NULL;
1063 g_Vmm2UserMethods.pfnQueryGenericObject = vboxbfeVmm2User_QueryGenericObject;
1064 g_Vmm2UserMethods.u32EndMagic = VMM2USERMETHODS_MAGIC;
1065
1066 /*
1067 * Create empty VM.
1068 */
1069 rc = g_pVMM->pfnVMR3Create(1, &g_Vmm2UserMethods, 0 /*fFlags*/, vboxbfeSetVMErrorCallback, NULL, vboxbfeConfigConstructor, NULL, &g_pVM, NULL);
1070 if (RT_FAILURE(rc))
1071 {
1072 RTPrintf("Error: VM creation failed with %Rrc.\n", rc);
1073 goto failure;
1074 }
1075
1076
1077 /*
1078 * Register VM state change handler
1079 */
1080 rc = g_pVMM->pfnVMR3AtStateRegister(g_pUVM, vboxbfeVmStateChangeCallback, NULL);
1081 if (RT_FAILURE(rc))
1082 {
1083 RTPrintf("Error: VMR3AtStateRegister failed with %Rrc.\n", rc);
1084 goto failure;
1085 }
1086
1087 /*
1088 * Power on the VM (i.e. start executing).
1089 */
1090 if (RT_SUCCESS(rc))
1091 {
1092#if 0
1093 if ( g_fRestoreState
1094 && g_pszStateFile
1095 && *g_pszStateFile
1096 && RTPathExists(g_pszStateFile))
1097 {
1098 startProgressInfo("Restoring");
1099 rc = VMR3LoadFromFile(gpVM, g_pszStateFile, callProgressInfo, (uintptr_t)NULL);
1100 endProgressInfo();
1101 if (RT_SUCCESS(rc))
1102 {
1103 rc = VMR3Resume(gpVM);
1104 AssertRC(rc);
1105 }
1106 else
1107 AssertMsgFailed(("VMR3LoadFromFile failed, rc=%Rrc\n", rc));
1108 }
1109 else
1110#endif
1111 {
1112 rc = g_pVMM->pfnVMR3PowerOn(g_pUVM);
1113 if (RT_FAILURE(rc))
1114 AssertMsgFailed(("VMR3PowerOn failed, rc=%Rrc\n", rc));
1115 }
1116 }
1117
1118 /*
1119 * On failure destroy the VM.
1120 */
1121 if (RT_FAILURE(rc))
1122 goto failure;
1123
1124 return VINF_SUCCESS;
1125
1126failure:
1127 if (g_pVM)
1128 {
1129 rc2 = g_pVMM->pfnVMR3Destroy(g_pUVM);
1130 AssertRC(rc2);
1131 g_pVM = NULL;
1132 }
1133 g_enmVmState = VMSTATE_TERMINATED;
1134
1135 return VINF_SUCCESS;
1136}
1137
1138
1139static void show_usage()
1140{
1141 RTPrintf("Usage:\n"
1142 " --start-paused Start the VM in paused state\n"
1143 "\n");
1144}
1145
1146/**
1147 * Entry point.
1148 */
1149extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
1150{
1151 RT_NOREF(envp);
1152 unsigned fPaused = 0;
1153
1154 LogFlow(("VBoxBFE STARTED.\n"));
1155 RTPrintf(VBOX_PRODUCT " Basic Interface " VBOX_VERSION_STRING "\n"
1156 "Copyright (C) 2023-" VBOX_C_YEAR " " VBOX_VENDOR "\n\n");
1157
1158 static const RTGETOPTDEF s_aOptions[] =
1159 {
1160 { "--start-paused", 'p', 0 },
1161 { "--memory-size-mib", 'm', RTGETOPT_REQ_UINT32 },
1162 { "--load-file-into-ram", 'l', RTGETOPT_REQ_STRING },
1163 { "--load-flash", 'f', RTGETOPT_REQ_STRING },
1164 { "--load-dtb", 'd', RTGETOPT_REQ_STRING },
1165 { "--load-vmm", 'v', RTGETOPT_REQ_STRING },
1166 { "--load-kernel", 'k', RTGETOPT_REQ_STRING },
1167 { "--load-initrd", 'i', RTGETOPT_REQ_STRING },
1168 { "--cmd-line", 'c', RTGETOPT_REQ_STRING },
1169 { "--serial-log", 's', RTGETOPT_REQ_STRING },
1170 };
1171
1172 const char *pszVmmMod = "VBoxVMM";
1173
1174 /* Parse the config. */
1175 int ch;
1176 RTGETOPTUNION ValueUnion;
1177 RTGETOPTSTATE GetState;
1178 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /* fFlags */);
1179 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1180 {
1181 switch(ch)
1182 {
1183 case 'p':
1184 fPaused = true;
1185 break;
1186 case 'm':
1187 g_u32MemorySizeMB = ValueUnion.u32;
1188 break;
1189 case 'l':
1190 g_pszLoadMem = ValueUnion.psz;
1191 break;
1192 case 'f':
1193 g_pszLoadFlash = ValueUnion.psz;
1194 break;
1195 case 'd':
1196 g_pszLoadDtb = ValueUnion.psz;
1197 break;
1198 case 'v':
1199 pszVmmMod = ValueUnion.psz;
1200 break;
1201 case 'k':
1202 g_pszLoadKernel = ValueUnion.psz;
1203 break;
1204 case 'i':
1205 g_pszLoadInitrd = ValueUnion.psz;
1206 break;
1207 case 'c':
1208 g_pszCmdLine = ValueUnion.psz;
1209 break;
1210 case 's':
1211 g_pszSerialLog = ValueUnion.psz;
1212 break;
1213 case 'h':
1214 show_usage();
1215 return 0;
1216 case 'V':
1217 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
1218 return 0;
1219 default:
1220 ch = RTGetOptPrintError(ch, &ValueUnion);
1221 show_usage();
1222 return ch;
1223 }
1224 }
1225
1226 /* static initialization of the SDL stuff */
1227 if (!Framebuffer::init(true /*fShowSDLConfig*/))
1228 return RTEXITCODE_FAILURE;
1229
1230 g_pKeyboard = new Keyboard();
1231 g_pDisplay = new Display();
1232 g_pFramebuffer = new Framebuffer(g_pDisplay, 0, false /*fFullscreen*/, false /*fResizable*/, true /*fShowSDLConfig*/, false,
1233 ~0, ~0, ~0, false /*fSeparate*/);
1234 g_pDisplay->SetFramebuffer(0, g_pFramebuffer);
1235
1236 int vrc = vboxbfeLoadVMM(pszVmmMod);
1237 if (RT_FAILURE(vrc))
1238 return RTEXITCODE_FAILURE;
1239
1240 /*
1241 * Start the VM execution thread. This has to be done
1242 * asynchronously as powering up can take some time
1243 * (accessing devices such as the host DVD drive). In
1244 * the meantime, we have to service the SDL event loop.
1245 */
1246
1247 RTTHREAD thread;
1248 vrc = RTThreadCreate(&thread, vboxbfeVMPowerUpThread, 0, 0, RTTHREADTYPE_MAIN_WORKER, 0, "PowerUp");
1249 if (RT_FAILURE(vrc))
1250 {
1251 RTPrintf("Error: Thread creation failed with %d\n", vrc);
1252 return RTEXITCODE_FAILURE;
1253 }
1254
1255
1256 /* loop until the powerup processing is done */
1257 do
1258 {
1259 RTThreadSleep(1000);
1260 }
1261 while ( g_enmVmState == VMSTATE_CREATING
1262 || g_enmVmState == VMSTATE_LOADING);
1263
1264 LogFlow(("VBoxSDL: Entering big event loop\n"));
1265 SDL_Event event;
1266 /** The host key down event which we have been hiding from the guest.
1267 * Used when going from HKEYSTATE_DOWN to HKEYSTATE_NOT_IT. */
1268 SDL_Event EvHKeyDown1;
1269 SDL_Event EvHKeyDown2;
1270
1271 uint32_t uResizeWidth = ~(uint32_t)0;
1272 uint32_t uResizeHeight = ~(uint32_t)0;
1273
1274 while (WaitSDLEvent(&event))
1275 {
1276 switch (event.type)
1277 {
1278 /*
1279 * The screen needs to be repainted.
1280 */
1281 case SDL_WINDOWEVENT:
1282 {
1283 switch (event.window.event)
1284 {
1285 case SDL_WINDOWEVENT_EXPOSED:
1286 {
1287 g_pFramebuffer->repaint();
1288 break;
1289 }
1290 case SDL_WINDOWEVENT_FOCUS_GAINED:
1291 {
1292 break;
1293 }
1294 case SDL_WINDOWEVENT_FOCUS_LOST:
1295 {
1296 break;
1297 }
1298 case SDL_WINDOWEVENT_RESIZED:
1299 {
1300 if (g_pDisplay)
1301 {
1302 if (gfIgnoreNextResize)
1303 {
1304 gfIgnoreNextResize = FALSE;
1305 break;
1306 }
1307 uResizeWidth = event.window.data1;
1308 uResizeHeight = event.window.data2;
1309 if (gSdlResizeTimer)
1310 SDL_RemoveTimer(gSdlResizeTimer);
1311 gSdlResizeTimer = SDL_AddTimer(300, ResizeTimer, NULL);
1312 }
1313 break;
1314 }
1315 default:
1316 break;
1317 }
1318 break;
1319 }
1320
1321 /*
1322 * Keyboard events.
1323 */
1324 case SDL_KEYDOWN:
1325 case SDL_KEYUP:
1326 {
1327 SDL_Keycode ksym = event.key.keysym.sym;
1328 switch (enmHKeyState)
1329 {
1330 case HKEYSTATE_NORMAL:
1331 {
1332 if ( event.type == SDL_KEYDOWN
1333 && ksym != SDLK_UNKNOWN
1334 && (ksym == gHostKeySym1 || ksym == gHostKeySym2))
1335 {
1336 EvHKeyDown1 = event;
1337 enmHKeyState = ksym == gHostKeySym1 ? HKEYSTATE_DOWN_1ST
1338 : HKEYSTATE_DOWN_2ND;
1339 break;
1340 }
1341 ProcessKey(&event.key);
1342 break;
1343 }
1344
1345 case HKEYSTATE_DOWN_1ST:
1346 case HKEYSTATE_DOWN_2ND:
1347 {
1348 if (gHostKeySym2 != SDLK_UNKNOWN)
1349 {
1350 if ( event.type == SDL_KEYDOWN
1351 && ksym != SDLK_UNKNOWN
1352 && ( (enmHKeyState == HKEYSTATE_DOWN_1ST && ksym == gHostKeySym2)
1353 || (enmHKeyState == HKEYSTATE_DOWN_2ND && ksym == gHostKeySym1)))
1354 {
1355 EvHKeyDown2 = event;
1356 enmHKeyState = HKEYSTATE_DOWN;
1357 break;
1358 }
1359 enmHKeyState = event.type == SDL_KEYUP ? HKEYSTATE_NORMAL
1360 : HKEYSTATE_NOT_IT;
1361 ProcessKey(&EvHKeyDown1.key);
1362 /* ugly hack: Some guests (e.g. mstsc.exe on Windows XP)
1363 * expect a small delay between two key events. 5ms work
1364 * reliable here so use 10ms to be on the safe side. A
1365 * better but more complicated fix would be to introduce
1366 * a new state and don't wait here. */
1367 RTThreadSleep(10);
1368 ProcessKey(&event.key);
1369 break;
1370 }
1371 }
1372 RT_FALL_THRU();
1373
1374 case HKEYSTATE_DOWN:
1375 {
1376 if (event.type == SDL_KEYDOWN)
1377 {
1378 /* potential host key combination, try execute it */
1379 int irc = HandleHostKey(&event.key);
1380 if (irc == VINF_SUCCESS)
1381 {
1382 enmHKeyState = HKEYSTATE_USED;
1383 break;
1384 }
1385 if (RT_SUCCESS(irc))
1386 goto leave;
1387 }
1388 else /* SDL_KEYUP */
1389 {
1390 if ( ksym != SDLK_UNKNOWN
1391 && (ksym == gHostKeySym1 || ksym == gHostKeySym2))
1392 {
1393 /* toggle grabbing state */
1394 if (!gfGrabbed)
1395 InputGrabStart();
1396 else
1397 InputGrabEnd();
1398
1399 /* SDL doesn't always reset the keystates, correct it */
1400 ResetKeys();
1401 enmHKeyState = HKEYSTATE_NORMAL;
1402 break;
1403 }
1404 }
1405
1406 /* not host key */
1407 enmHKeyState = HKEYSTATE_NOT_IT;
1408 ProcessKey(&EvHKeyDown1.key);
1409 /* see the comment for the 2-key case above */
1410 RTThreadSleep(10);
1411 if (gHostKeySym2 != SDLK_UNKNOWN)
1412 {
1413 ProcessKey(&EvHKeyDown2.key);
1414 /* see the comment for the 2-key case above */
1415 RTThreadSleep(10);
1416 }
1417 ProcessKey(&event.key);
1418 break;
1419 }
1420
1421 case HKEYSTATE_USED:
1422 {
1423 if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) == 0)
1424 enmHKeyState = HKEYSTATE_NORMAL;
1425 if (event.type == SDL_KEYDOWN)
1426 {
1427 int irc = HandleHostKey(&event.key);
1428 if (RT_SUCCESS(irc) && irc != VINF_SUCCESS)
1429 goto leave;
1430 }
1431 break;
1432 }
1433
1434 default:
1435 AssertMsgFailed(("enmHKeyState=%d\n", enmHKeyState));
1436 RT_FALL_THRU();
1437 case HKEYSTATE_NOT_IT:
1438 {
1439 if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) == 0)
1440 enmHKeyState = HKEYSTATE_NORMAL;
1441 ProcessKey(&event.key);
1442 break;
1443 }
1444 } /* state switch */
1445 break;
1446 }
1447
1448 /*
1449 * The window was closed.
1450 */
1451 case SDL_QUIT:
1452 {
1453 /** @todo */
1454 break;
1455 }
1456
1457 /*
1458 * User specific update event.
1459 */
1460 /** @todo use a common user event handler so that SDL_PeepEvents() won't
1461 * possibly remove other events in the queue!
1462 */
1463 case SDL_USER_EVENT_UPDATERECT:
1464 {
1465 /*
1466 * Decode event parameters.
1467 */
1468 ASMAtomicDecS32(&g_cNotifyUpdateEventsPending);
1469
1470 SDL_Rect *pUpdateRect = (SDL_Rect *)event.user.data1;
1471 AssertPtrBreak(pUpdateRect);
1472
1473 int const x = pUpdateRect->x;
1474 int const y = pUpdateRect->y;
1475 int const w = pUpdateRect->w;
1476 int const h = pUpdateRect->h;
1477
1478 RTMemFree(event.user.data1);
1479
1480 Log3Func(("SDL_USER_EVENT_UPDATERECT: x=%d y=%d, w=%d, h=%d\n", x, y, w, h));
1481
1482 Assert(g_pFramebuffer);
1483 g_pFramebuffer->update(x, y, w, h, true /* fGuestRelative */);
1484 break;
1485 }
1486
1487 /*
1488 * User event: Window resize done
1489 */
1490 case SDL_USER_EVENT_WINDOW_RESIZE_DONE:
1491 {
1492 /* communicate the resize event to the guest */
1493 //g_pDisplay->SetVideoModeHint(0 /*=display*/, true /*=enabled*/, false /*=changeOrigin*/,
1494 // 0 /*=originX*/, 0 /*=originY*/,
1495 // uResizeWidth, uResizeHeight, 0 /*=don't change bpp*/, true /*=notify*/);
1496 break;
1497
1498 }
1499
1500 /*
1501 * User specific framebuffer change event.
1502 */
1503 case SDL_USER_EVENT_NOTIFYCHANGE:
1504 {
1505 LogFlow(("SDL_USER_EVENT_NOTIFYCHANGE\n"));
1506 g_pFramebuffer->notifyChange(event.user.code);
1507 break;
1508 }
1509
1510 /*
1511 * User specific termination event
1512 */
1513 case SDL_USER_EVENT_TERMINATE:
1514 {
1515 if (event.user.code != VBOXSDL_TERM_NORMAL)
1516 RTPrintf("Error: VM terminated abnormally!\n");
1517 break;
1518 }
1519
1520 default:
1521 {
1522 Log8(("unknown SDL event %d\n", event.type));
1523 break;
1524 }
1525 }
1526 }
1527
1528leave:
1529 LogRel(("VBoxBFE: exiting\n"));
1530 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1531}
1532
1533
1534#ifndef VBOX_WITH_HARDENING
1535/**
1536 * Main entry point.
1537 */
1538int main(int argc, char **argv, char **envp)
1539{
1540 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_TRY_SUPLIB);
1541 if (RT_SUCCESS(rc))
1542 return TrustedMain(argc, argv, envp);
1543 RTPrintf("VBoxBFE: Runtime initialization failed: %Rrc - %Rrf\n", rc, rc);
1544 return RTEXITCODE_FAILURE;
1545}
1546#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