diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index a6d20b0719..4c29dedd97 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -325,4 +325,10 @@ typedef struct MainLoopPoll {
 void main_loop_poll_add_notifier(Notifier *notify);
 void main_loop_poll_remove_notifier(Notifier *notify);
 
+#ifdef XBOX
+void qemu_init_main_loop_lock(void);
+void qemu_mutex_lock_main_loop(void);
+void qemu_mutex_unlock_main_loop(void);
+#endif
+
 #endif
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 0d1eb7d5e0..63da28ebd4 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -2993,6 +2993,10 @@ void qemu_init(int argc, char **argv, char **envp)
     qemu_init_cpu_list();
     qemu_init_cpu_loop();
 
+#ifdef XBOX
+    qemu_init_main_loop_lock();
+    qemu_mutex_lock_main_loop();
+#endif
     qemu_mutex_lock_iothread();
 
     atexit(qemu_run_exit_notifiers);
diff --git a/ui/xemu.c b/ui/xemu.c
index 709a7e04d1..73a0ead944 100644
--- a/ui/xemu.c
+++ b/ui/xemu.c
@@ -1085,9 +1085,11 @@ static void xemu_sdl2_gl_render_surface(struct sdl2_console *scon)
     glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, NULL);
 
     // FIXME: Finer locking
+    qemu_mutex_lock_main_loop();
     qemu_mutex_lock_iothread();
     xemu_hud_render();
     qemu_mutex_unlock_iothread();
+    qemu_mutex_unlock_main_loop();
 
     // xb_surface_gl_render_texture(scon->surface);
     pre_swap();
@@ -1172,6 +1174,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
 
     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
 
+    qemu_mutex_lock_main_loop();
     qemu_mutex_lock_iothread();
     graphic_hw_update(dcl->con);
 
@@ -1180,6 +1183,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
     }
     sdl2_poll_events(scon);
     qemu_mutex_unlock_iothread();
+    qemu_mutex_unlock_main_loop();
     xemu_sdl2_gl_render_surface(scon);
 }
 
diff --git a/util/main-loop.c b/util/main-loop.c
index 9d7ad8dd4c..bf5e590bd3 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -48,6 +48,12 @@
  */
 GMainContext *qemu_main_context = NULL;
 GMainLoop *qemu_main_loop_obj = NULL;
+
+/* *Another* main loop lock. Used for ensuring the main loop does not get a
+ * chance to continue when some action is being handled on the UI interaction
+ * thread that gives up the BQL but expects the main loop to not be running.
+ */
+QemuMutex qemu_main_loop_lock;
 #endif
 
 #ifndef _WIN32
@@ -160,6 +166,23 @@ void qemu_notify_event(void)
 
 static GArray *gpollfds;
 
+#ifdef XBOX
+void qemu_init_main_loop_lock(void)
+{
+    qemu_mutex_init(&qemu_main_loop_lock);
+}
+
+void qemu_mutex_lock_main_loop(void)
+{
+    qemu_mutex_lock(&qemu_main_loop_lock);
+}
+
+void qemu_mutex_unlock_main_loop(void)
+{
+    qemu_mutex_unlock(&qemu_main_loop_lock);
+}
+#endif
+
 int qemu_init_main_loop(Error **errp)
 {
     int ret;
@@ -277,7 +300,13 @@ static int os_host_main_loop_wait(int64_t timeout)
     qemu_mutex_unlock_iothread();
     replay_mutex_unlock();
 
+#ifdef XBOX
+    qemu_mutex_unlock_main_loop();
+#endif
     ret = qemu_poll_ns((GPollFD *)gpollfds->data, gpollfds->len, timeout);
+#ifdef XBOX
+    qemu_mutex_lock_main_loop();
+#endif
 
     replay_mutex_lock();
     qemu_mutex_lock_iothread();
@@ -494,7 +523,13 @@ static int os_host_main_loop_wait(int64_t timeout)
 
     replay_mutex_unlock();
 
+#ifdef XBOX
+    qemu_mutex_unlock_main_loop();
+#endif
     g_poll_ret = qemu_poll_ns(poll_fds, n_poll_fds + w->num, poll_timeout_ns);
+#ifdef XBOX
+    qemu_mutex_lock_main_loop();
+#endif
 
     replay_mutex_lock();