From 802de64433c11a299d469f9a400959db113f5af5 Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Sun, 6 Oct 2024 20:24:38 +0700 Subject: [PATCH] Adds an option to start VMM immediately (#1019) --- .vscode/launch.json | 1 + .vscode/tasks.json | 32 +++++++ gui/main.cpp | 22 ++++- gui/main_window.cpp | 208 ++++++++++++++++++++++++-------------------- gui/main_window.hpp | 16 +++- 5 files changed, 177 insertions(+), 102 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 7c55527c..037c4ced 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -23,6 +23,7 @@ "name": "Kernel", "type": "lldb", "request": "custom", + "preLaunchTask": "Launch VMM (Debug)", "initCommands": [ "platform select remote-gdb-server", "platform connect connect://localhost:1234" diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..9dfa1048 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,32 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Launch VMM (Debug)", + "detail": "Launch the GUI then start the VMM in debug mode", + "type": "process", + "isBackground": true, + "runOptions": { + "instanceLimit": 1 + }, + "linux": { + "command": "${workspaceFolder}/build/gui/obliteration" + }, + "osx": { + "command": "${workspaceFolder}/build/gui/obliteration.app/Contents/MacOS/obliteration" + }, + "windows": { + "command": "${workspaceFolder}/build/gui/Obliteration.exe", + "options": { + "env": { + "Path": "${env:Path};${env:CMAKE_PREFIX_PATH}\\bin" + } + } + }, + "args": [ + "--debug", + "127.0.0.1:1234" + ] + } + ] +} diff --git a/gui/main.cpp b/gui/main.cpp index 4d36edd7..0346745e 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -7,6 +7,7 @@ #endif #include +#include #include #include #include @@ -57,6 +58,14 @@ int main(int argc, char *argv[]) QGuiApplication::setWindowIcon(QIcon(":/resources/obliteration-icon.png")); + // Parse arguments. + QCommandLineParser args; + + args.setApplicationDescription("Virtualization stack for Obliteration"); + args.addHelpOption(); + args.addOption(Args::debug); + args.process(app); + // Hook Rust panic. QObject panic; @@ -199,11 +208,11 @@ int main(int argc, char *argv[]) } } - // Run main window. + // Setup main window. #ifdef __APPLE__ - MainWindow win; + MainWindow win(args); #else - MainWindow win(&vulkan, std::move(vkDevices)); + MainWindow win(args, &vulkan, std::move(vkDevices)); #endif if (!win.loadProfiles() || !win.loadGames()) { @@ -212,5 +221,12 @@ int main(int argc, char *argv[]) win.restoreGeometry(); + // Run main window. + auto debug = args.value(Args::debug); + + if (!debug.isEmpty()) { + win.startVmm(debug); + } + return QApplication::exec(); } diff --git a/gui/main_window.cpp b/gui/main_window.cpp index e075cdd9..c30b9af7 100644 --- a/gui/main_window.cpp +++ b/gui/main_window.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -35,11 +37,19 @@ #include +namespace Args { + const QCommandLineOption debug("debug", "Immediate launch the VMM in debug mode.", "addr", "127.0.0.1:1234"); +} + #ifdef __APPLE__ -MainWindow::MainWindow() : +MainWindow::MainWindow(const QCommandLineParser &args) : #else -MainWindow::MainWindow(QVulkanInstance *vulkan, QList &&vkDevices) : +MainWindow::MainWindow( + const QCommandLineParser &args, + QVulkanInstance *vulkan, + QList &&vkDevices) : #endif + m_args(args), m_main(nullptr), m_profiles(nullptr), m_games(nullptr), @@ -341,95 +351,6 @@ void MainWindow::saveProfile(Profile *p) } } -void MainWindow::startVmm(const QString &debugAddr) -{ - // Get full path to kernel binary. - std::string kernel; - - if (QFile::exists(".obliteration-development")) { - auto b = std::filesystem::current_path(); -#ifdef _WIN32 - auto target = L"x86_64-unknown-none"; -#elif defined(__aarch64__) - auto target = "aarch64-unknown-none-softfloat"; -#else - auto target = "x86_64-unknown-none"; -#endif - -#if defined(_WIN32) && defined(NDEBUG) - kernel = (b / L"target" / target / L"release" / L"obkrnl").u8string(); -#elif defined(_WIN32) && !defined(NDEBUG) - kernel = (b / L"target" / target / L"debug" / L"obkrnl").u8string(); -#elif defined(NDEBUG) - kernel = (b / "target" / target / "release" / "obkrnl").u8string(); -#else - kernel = (b / "target" / target / "debug" / "obkrnl").u8string(); -#endif - } else { -#ifdef _WIN32 - std::filesystem::path b(QCoreApplication::applicationDirPath().toStdString(), std::filesystem::path::native_format); - b /= L"share"; - b /= L"obkrnl"; - kernel = b.u8string(); -#else - auto b = std::filesystem::path(QCoreApplication::applicationDirPath().toStdString(), std::filesystem::path::native_format).parent_path(); -#ifdef __APPLE__ - b /= "Resources"; -#else - b /= "share"; -#endif - b /= "obkrnl"; - kernel = b.u8string(); -#endif - } - - // Swap launch settings with the screen before getting a Vulkan surface otherwise it will fail. - m_main->setCurrentIndex(1); - - // Run. - auto debug = debugAddr.toStdString(); - VmmScreen screen; - Rust error; - Rust vmm; - - memset(&screen, 0, sizeof(screen)); - -#ifdef __APPLE__ - screen.view = m_screen->winId(); -#else - screen.vk_instance = reinterpret_cast(m_screen->vulkanInstance()->vkInstance()); - screen.vk_device = reinterpret_cast(m_launch->currentDisplayDevice()->handle()); - screen.vk_surface = reinterpret_cast(QVulkanInstance::surfaceForWindow(m_screen)); - - if (!screen.vk_surface) { - m_main->setCurrentIndex(0); - QMessageBox::critical(this, "Error", "Couldn't create VkSurfaceKHR."); - return; - } -#endif - - vmm = vmm_run( - kernel.c_str(), - &screen, - m_launch->currentProfile(), - debug.empty() ? nullptr : debug.c_str(), - MainWindow::vmmHandler, - this, - &error); - - if (!vmm) { - m_main->setCurrentIndex(0); - QMessageBox::critical( - this, - "Error", - QString("Couldn't run %1: %2").arg(kernel.c_str()).arg(error_message(error))); - return; - } - - m_vmm = std::move(vmm); - m_screen->requestUpdate(); -} - void MainWindow::updateScreen() { // Do nothing if the VMM is not running. @@ -462,15 +383,21 @@ void MainWindow::vmmError(const QString &msg) QMessageBox::critical(this, "Error", msg); - m_main->setCurrentIndex(0); + if (m_args.isSet(Args::debug)) { + close(); + } else { + m_main->setCurrentIndex(0); + } } void MainWindow::waitingDebugger(const QString &addr) { - QMessageBox::information( - this, - "Debug", - QString("The VMM are waiting for a debugger at %1.").arg(addr)); + if (!m_args.isSet(Args::debug)) { + QMessageBox::information( + this, + "Debug", + QString("The VMM are waiting for a debugger at %1.").arg(addr)); + } } void MainWindow::waitKernelExit(bool success) @@ -564,6 +491,95 @@ void MainWindow::restoreGeometry() } } +void MainWindow::startVmm(const QString &debugAddr) +{ + // Get full path to kernel binary. + std::string kernel; + + if (QFile::exists(".obliteration-development")) { + auto b = std::filesystem::current_path(); +#ifdef _WIN32 + auto target = L"x86_64-unknown-none"; +#elif defined(__aarch64__) + auto target = "aarch64-unknown-none-softfloat"; +#else + auto target = "x86_64-unknown-none"; +#endif + +#if defined(_WIN32) && defined(NDEBUG) + kernel = (b / L"target" / target / L"release" / L"obkrnl").u8string(); +#elif defined(_WIN32) && !defined(NDEBUG) + kernel = (b / L"target" / target / L"debug" / L"obkrnl").u8string(); +#elif defined(NDEBUG) + kernel = (b / "target" / target / "release" / "obkrnl").u8string(); +#else + kernel = (b / "target" / target / "debug" / "obkrnl").u8string(); +#endif + } else { +#ifdef _WIN32 + std::filesystem::path b(QCoreApplication::applicationDirPath().toStdString(), std::filesystem::path::native_format); + b /= L"share"; + b /= L"obkrnl"; + kernel = b.u8string(); +#else + auto b = std::filesystem::path(QCoreApplication::applicationDirPath().toStdString(), std::filesystem::path::native_format).parent_path(); +#ifdef __APPLE__ + b /= "Resources"; +#else + b /= "share"; +#endif + b /= "obkrnl"; + kernel = b.u8string(); +#endif + } + + // Swap launch settings with the screen before getting a Vulkan surface otherwise it will fail. + m_main->setCurrentIndex(1); + + // Run. + auto debug = debugAddr.toStdString(); + VmmScreen screen; + Rust error; + Rust vmm; + + memset(&screen, 0, sizeof(screen)); + +#ifdef __APPLE__ + screen.view = m_screen->winId(); +#else + screen.vk_instance = reinterpret_cast(m_screen->vulkanInstance()->vkInstance()); + screen.vk_device = reinterpret_cast(m_launch->currentDisplayDevice()->handle()); + screen.vk_surface = reinterpret_cast(QVulkanInstance::surfaceForWindow(m_screen)); + + if (!screen.vk_surface) { + m_main->setCurrentIndex(0); + QMessageBox::critical(this, "Error", "Couldn't create VkSurfaceKHR."); + return; + } +#endif + + vmm = vmm_run( + kernel.c_str(), + &screen, + m_launch->currentProfile(), + debug.empty() ? nullptr : debug.c_str(), + MainWindow::vmmHandler, + this, + &error); + + if (!vmm) { + m_main->setCurrentIndex(0); + QMessageBox::critical( + this, + "Error", + QString("Couldn't run %1: %2").arg(kernel.c_str()).arg(error_message(error))); + return; + } + + m_vmm = std::move(vmm); + m_screen->requestUpdate(); +} + bool MainWindow::requireVmmStopped() { if (m_vmm) { diff --git a/gui/main_window.hpp b/gui/main_window.hpp index 1213e22d..ee9c5336 100644 --- a/gui/main_window.hpp +++ b/gui/main_window.hpp @@ -13,21 +13,27 @@ class GameListModel; class LaunchSettings; class LogsViewer; class ProfileList; +class QCommandLineOption; +class QCommandLineParser; class QStackedWidget; class Screen; class MainWindow final : public QMainWindow { public: #ifdef __APPLE__ - MainWindow(); + MainWindow(const QCommandLineParser &args); #else - MainWindow(QVulkanInstance *vulkan, QList &&vkDevices); + MainWindow( + const QCommandLineParser &args, + QVulkanInstance *vulkan, + QList &&vkDevices); #endif ~MainWindow() override; bool loadProfiles(); bool loadGames(); void restoreGeometry(); + void startVmm(const QString &debugAddr); protected: void closeEvent(QCloseEvent *event) override; @@ -38,7 +44,6 @@ private slots: void reportIssue(); void aboutObliteration(); void saveProfile(Profile *p); - void startVmm(const QString &debugAddr); void updateScreen(); private: void vmmError(const QString &msg); @@ -50,6 +55,7 @@ private: static void vmmHandler(const VmmEvent *ev, void *cx); + const QCommandLineParser &m_args; QStackedWidget *m_main; ProfileList *m_profiles; GameListModel *m_games; @@ -58,3 +64,7 @@ private: QPointer m_logs; Rust m_vmm; // Destroy first. }; + +namespace Args { + extern const QCommandLineOption debug; +}