diff --git a/dynamic.h b/dynamic.h
index af4a0cdd15f..f8c530a73e7 100644
--- a/dynamic.h
+++ b/dynamic.h
@@ -68,6 +68,13 @@ struct retro_core_t
enum poll_type poll_type;
uint8_t flags;
+
+ /**
+ * Arbitrary core data.
+ *
+ * @see RETRO_ENVIRONMENT_GET_CORE_DATA
+ */
+ void *core_data;
};
diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h
index 73ff390c508..b00b77d3f24 100644
--- a/libretro-common/include/libretro.h
+++ b/libretro-common/include/libretro.h
@@ -2944,6 +2944,32 @@ enum retro_mod
| RETRO_AUDIO_SPEAKER_SIDE_LEFT | RETRO_AUDIO_SPEAKER_SIDE_RIGHT)
#define RETRO_AUDIO_LAYOUT_7_1 (RETRO_AUDIO_LAYOUT_5_1 | RETRO_AUDIO_SPEAKER_SIDE_LEFT | RETRO_AUDIO_SPEAKER_SIDE_RIGHT)
+/**
+ * Sets a pointer to arbitrary data for the actively running core.
+ *
+ * Intended for use as a substitute for global state, which is a common
+ * source of bugs. Can be set in either \c retro_init() or \c retro_load_game().
+ *
+ * @param[in] data void *. Pointer to the data to set.
+ * @return \c true if the environment call is available.
+ *
+ * @see RETRO_ENVIRONMENT_GET_CORE_DATA
+ */
+#define RETRO_ENVIRONMENT_SET_CORE_DATA (95 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+
+/**
+ * Gets a pointer to arbitrary data for the actively running core.
+ *
+ * This is persistent for the lifetime of the core until \c retro_deinit() is called.
+ *
+ * @param[out] data void **. Pointer to the data that was set.
+ * May be \c NULL if the data was not set yet.
+ * @return \c true if the environment call is available.
+ *
+ * @see RETRO_ENVIRONMENT_SET_CORE_DATA
+ */
+#define RETRO_ENVIRONMENT_GET_CORE_DATA (96 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+
/**
* Result of \c RETRO_ENVIRONMENT_GET_MEMORY_STATUS.
*
diff --git a/runloop.c b/runloop.c
index c21a32682e1..c282686fc08 100644
--- a/runloop.c
+++ b/runloop.c
@@ -4119,6 +4119,18 @@ bool runloop_environment_cb(unsigned cmd, void *data)
}
}
break;
+
+ case RETRO_ENVIRONMENT_SET_CORE_DATA:
+ runloop_st->current_core.core_data = data;
+ break;
+
+ case RETRO_ENVIRONMENT_GET_CORE_DATA:
+ if (data != NULL) {
+ void **core_data = (void **)data;
+ *core_data = runloop_st->current_core.core_data;
+ }
+ break;
+
default:
RARCH_LOG("[Environ] UNSUPPORTED (#%u).\n", cmd);
return false;