Commit 631f46d4ea for qemu.org

commit 631f46d4ea7cb7ac0e529aacc1e7d832473f96c3
Author: Peter Maydell <peter.maydell@linaro.org>
Date:   Fri Apr 12 17:08:09 2024 +0100

    reset: Add RESET_TYPE_SNAPSHOT_LOAD

    Some devices and machines need to handle the reset before a vmsave
    snapshot is loaded differently -- the main user is the handling of
    RNG seed information, which does not want to put a new RNG seed into
    a ROM blob when we are doing a snapshot load.

    Currently this kind of reset handling is supported only for:
     * TYPE_MACHINE reset methods, which take a ShutdownCause argument
     * reset functions registered with qemu_register_reset_nosnapshotload

    To allow a three-phase-reset device to also distinguish "snapshot
    load" reset from the normal kind, add a new ResetType
    RESET_TYPE_SNAPSHOT_LOAD. All our existing reset methods ignore
    the reset type, so we don't need to update any device code.

    Add the enum type, and make qemu_devices_reset() use the
    right reset type for the ShutdownCause it is passed. This
    allows us to get rid of the device_reset_reason global we
    were using to implement qemu_register_reset_nosnapshotload().

    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
    Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
    Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
    Reviewed-by: Luc Michel <luc.michel@amd.com>
    Message-id: 20240412160809.1260625-7-peter.maydell@linaro.org

diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst
index 49baa1ea27..9746a4e8a0 100644
--- a/docs/devel/reset.rst
+++ b/docs/devel/reset.rst
@@ -27,9 +27,7 @@ instantly reset an object, without keeping it in reset state, just call
 ``resettable_reset()``. These functions take two parameters: a pointer to the
 object to reset and a reset type.

-Several types of reset will be supported. For now only cold reset is defined;
-others may be added later. The Resettable interface handles reset types with an
-enum:
+The Resettable interface handles reset types with an enum ``ResetType``:

 ``RESET_TYPE_COLD``
   Cold reset is supported by every resettable object. In QEMU, it means we reset
@@ -37,6 +35,19 @@ enum:
   from what is a real hardware cold reset. It differs from other resets (like
   warm or bus resets) which may keep certain parts untouched.

+``RESET_TYPE_SNAPSHOT_LOAD``
+  This is called for a reset which is being done to put the system into a
+  clean state prior to loading a snapshot. (This corresponds to a reset
+  with ``SHUTDOWN_CAUSE_SNAPSHOT_LOAD``.) Almost all devices should treat
+  this the same as ``RESET_TYPE_COLD``. The main exception is devices which
+  have some non-deterministic state they want to reinitialize to a different
+  value on each cold reset, such as RNG seed information, and which they
+  must not reinitialize on a snapshot-load reset.
+
+Devices which implement reset methods must treat any unknown ``ResetType``
+as equivalent to ``RESET_TYPE_COLD``; this will reduce the amount of
+existing code we need to change if we add more types in future.
+
 Calling ``resettable_reset()`` is equivalent to calling
 ``resettable_assert_reset()`` then ``resettable_release_reset()``. It is
 possible to interleave multiple calls to these three functions. There may
diff --git a/hw/core/reset.c b/hw/core/reset.c
index f9fef45e05..58dfc8db3d 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -43,13 +43,6 @@ static ResettableContainer *get_root_reset_container(void)
     return root_reset_container;
 }

-/*
- * Reason why the currently in-progress qemu_devices_reset() was called.
- * If we made at least SHUTDOWN_CAUSE_SNAPSHOT_LOAD have a corresponding
- * ResetType we could perhaps avoid the need for this global.
- */
-static ShutdownCause device_reset_reason;
-
 /*
  * This is an Object which implements Resettable simply to call the
  * callback function in the hold phase.
@@ -77,8 +70,7 @@ static void legacy_reset_hold(Object *obj, ResetType type)
 {
     LegacyReset *lr = LEGACY_RESET(obj);

-    if (device_reset_reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD &&
-        lr->skip_on_snapshot_load) {
+    if (type == RESET_TYPE_SNAPSHOT_LOAD && lr->skip_on_snapshot_load) {
         return;
     }
     lr->func(lr->opaque);
@@ -180,8 +172,9 @@ void qemu_unregister_resettable(Object *obj)

 void qemu_devices_reset(ShutdownCause reason)
 {
-    device_reset_reason = reason;
+    ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ?
+        RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD;

     /* Reset the simulation */
-    resettable_reset(OBJECT(get_root_reset_container()), RESET_TYPE_COLD);
+    resettable_reset(OBJECT(get_root_reset_container()), type);
 }
diff --git a/hw/core/resettable.c b/hw/core/resettable.c
index bebf7f10b2..6dd3e3dc48 100644
--- a/hw/core/resettable.c
+++ b/hw/core/resettable.c
@@ -48,8 +48,6 @@ void resettable_reset(Object *obj, ResetType type)

 void resettable_assert_reset(Object *obj, ResetType type)
 {
-    /* TODO: change this assert when adding support for other reset types */
-    assert(type == RESET_TYPE_COLD);
     trace_resettable_reset_assert_begin(obj, type);
     assert(!enter_phase_in_progress);

@@ -64,8 +62,6 @@ void resettable_assert_reset(Object *obj, ResetType type)

 void resettable_release_reset(Object *obj, ResetType type)
 {
-    /* TODO: change this assert when adding support for other reset types */
-    assert(type == RESET_TYPE_COLD);
     trace_resettable_reset_release_begin(obj, type);
     assert(!enter_phase_in_progress);

diff --git a/include/hw/resettable.h b/include/hw/resettable.h
index 3161e471c9..7e249deb8b 100644
--- a/include/hw/resettable.h
+++ b/include/hw/resettable.h
@@ -35,6 +35,7 @@ typedef struct ResettableState ResettableState;
  */
 typedef enum ResetType {
     RESET_TYPE_COLD,
+    RESET_TYPE_SNAPSHOT_LOAD,
 } ResetType;

 /*