1 /* 2 * Reset handlers. 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * Copyright (c) 2016 Red Hat, Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26 #include "qemu/osdep.h" 27 #include "sysemu/reset.h" 28 #include "hw/resettable.h" 29 #include "hw/core/resetcontainer.h" 30 31 /* 32 * Return a pointer to the singleton container that holds all the Resettable 33 * items that will be reset when qemu_devices_reset() is called. 34 */ 35 static ResettableContainer *get_root_reset_container(void) 36 { 37 static ResettableContainer *root_reset_container; 38 39 if (!root_reset_container) { 40 root_reset_container = 41 RESETTABLE_CONTAINER(object_new(TYPE_RESETTABLE_CONTAINER)); 42 } 43 return root_reset_container; 44 } 45 46 /* 47 * Reason why the currently in-progress qemu_devices_reset() was called. 48 * If we made at least SHUTDOWN_CAUSE_SNAPSHOT_LOAD have a corresponding 49 * ResetType we could perhaps avoid the need for this global. 50 */ 51 static ShutdownCause device_reset_reason; 52 53 /* 54 * This is an Object which implements Resettable simply to call the 55 * callback function in the hold phase. 56 */ 57 #define TYPE_LEGACY_RESET "legacy-reset" 58 OBJECT_DECLARE_SIMPLE_TYPE(LegacyReset, LEGACY_RESET) 59 60 struct LegacyReset { 61 Object parent; 62 ResettableState reset_state; 63 QEMUResetHandler *func; 64 void *opaque; 65 bool skip_on_snapshot_load; 66 }; 67 68 OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(LegacyReset, legacy_reset, LEGACY_RESET, OBJECT, { TYPE_RESETTABLE_INTERFACE }, { }) 69 70 static ResettableState *legacy_reset_get_state(Object *obj) 71 { 72 LegacyReset *lr = LEGACY_RESET(obj); 73 return &lr->reset_state; 74 } 75 76 static void legacy_reset_hold(Object *obj) 77 { 78 LegacyReset *lr = LEGACY_RESET(obj); 79 80 if (device_reset_reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD && 81 lr->skip_on_snapshot_load) { 82 return; 83 } 84 lr->func(lr->opaque); 85 } 86 87 static void legacy_reset_init(Object *obj) 88 { 89 } 90 91 static void legacy_reset_finalize(Object *obj) 92 { 93 } 94 95 static void legacy_reset_class_init(ObjectClass *klass, void *data) 96 { 97 ResettableClass *rc = RESETTABLE_CLASS(klass); 98 99 rc->get_state = legacy_reset_get_state; 100 rc->phases.hold = legacy_reset_hold; 101 } 102 103 void qemu_register_reset(QEMUResetHandler *func, void *opaque) 104 { 105 Object *obj = object_new(TYPE_LEGACY_RESET); 106 LegacyReset *lr = LEGACY_RESET(obj); 107 108 lr->func = func; 109 lr->opaque = opaque; 110 qemu_register_resettable(obj); 111 } 112 113 void qemu_register_reset_nosnapshotload(QEMUResetHandler *func, void *opaque) 114 { 115 Object *obj = object_new(TYPE_LEGACY_RESET); 116 LegacyReset *lr = LEGACY_RESET(obj); 117 118 lr->func = func; 119 lr->opaque = opaque; 120 lr->skip_on_snapshot_load = true; 121 qemu_register_resettable(obj); 122 } 123 124 typedef struct FindLegacyInfo { 125 QEMUResetHandler *func; 126 void *opaque; 127 LegacyReset *lr; 128 } FindLegacyInfo; 129 130 static void find_legacy_reset_cb(Object *obj, void *opaque, ResetType type) 131 { 132 LegacyReset *lr; 133 FindLegacyInfo *fli = opaque; 134 135 /* Not everything in the ResettableContainer will be a LegacyReset */ 136 lr = LEGACY_RESET(object_dynamic_cast(obj, TYPE_LEGACY_RESET)); 137 if (lr && lr->func == fli->func && lr->opaque == fli->opaque) { 138 fli->lr = lr; 139 } 140 } 141 142 static LegacyReset *find_legacy_reset(QEMUResetHandler *func, void *opaque) 143 { 144 /* 145 * Find the LegacyReset with the specified func and opaque, 146 * by getting the ResettableContainer to call our callback for 147 * every item in it. 148 */ 149 ResettableContainer *rootcon = get_root_reset_container(); 150 ResettableClass *rc = RESETTABLE_GET_CLASS(rootcon); 151 FindLegacyInfo fli; 152 153 fli.func = func; 154 fli.opaque = opaque; 155 fli.lr = NULL; 156 rc->child_foreach(OBJECT(rootcon), find_legacy_reset_cb, 157 &fli, RESET_TYPE_COLD); 158 return fli.lr; 159 } 160 161 void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) 162 { 163 Object *obj = OBJECT(find_legacy_reset(func, opaque)); 164 165 if (obj) { 166 qemu_unregister_resettable(obj); 167 object_unref(obj); 168 } 169 } 170 171 void qemu_register_resettable(Object *obj) 172 { 173 resettable_container_add(get_root_reset_container(), obj); 174 } 175 176 void qemu_unregister_resettable(Object *obj) 177 { 178 resettable_container_remove(get_root_reset_container(), obj); 179 } 180 181 void qemu_devices_reset(ShutdownCause reason) 182 { 183 device_reset_reason = reason; 184 185 /* Reset the simulation */ 186 resettable_reset(OBJECT(get_root_reset_container()), RESET_TYPE_COLD); 187 } 188