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 * This is an Object which implements Resettable simply to call the 48 * callback function in the hold phase. 49 */ 50 #define TYPE_LEGACY_RESET "legacy-reset" 51 OBJECT_DECLARE_SIMPLE_TYPE(LegacyReset, LEGACY_RESET) 52 53 struct LegacyReset { 54 Object parent; 55 ResettableState reset_state; 56 QEMUResetHandler *func; 57 void *opaque; 58 bool skip_on_snapshot_load; 59 }; 60 61 OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(LegacyReset, legacy_reset, LEGACY_RESET, OBJECT, { TYPE_RESETTABLE_INTERFACE }, { }) 62 63 static ResettableState *legacy_reset_get_state(Object *obj) 64 { 65 LegacyReset *lr = LEGACY_RESET(obj); 66 return &lr->reset_state; 67 } 68 69 static void legacy_reset_hold(Object *obj, ResetType type) 70 { 71 LegacyReset *lr = LEGACY_RESET(obj); 72 73 if (type == RESET_TYPE_SNAPSHOT_LOAD && lr->skip_on_snapshot_load) { 74 return; 75 } 76 lr->func(lr->opaque); 77 } 78 79 static void legacy_reset_init(Object *obj) 80 { 81 } 82 83 static void legacy_reset_finalize(Object *obj) 84 { 85 } 86 87 static void legacy_reset_class_init(ObjectClass *klass, void *data) 88 { 89 ResettableClass *rc = RESETTABLE_CLASS(klass); 90 91 rc->get_state = legacy_reset_get_state; 92 rc->phases.hold = legacy_reset_hold; 93 } 94 95 void qemu_register_reset(QEMUResetHandler *func, void *opaque) 96 { 97 Object *obj = object_new(TYPE_LEGACY_RESET); 98 LegacyReset *lr = LEGACY_RESET(obj); 99 100 lr->func = func; 101 lr->opaque = opaque; 102 qemu_register_resettable(obj); 103 } 104 105 void qemu_register_reset_nosnapshotload(QEMUResetHandler *func, void *opaque) 106 { 107 Object *obj = object_new(TYPE_LEGACY_RESET); 108 LegacyReset *lr = LEGACY_RESET(obj); 109 110 lr->func = func; 111 lr->opaque = opaque; 112 lr->skip_on_snapshot_load = true; 113 qemu_register_resettable(obj); 114 } 115 116 typedef struct FindLegacyInfo { 117 QEMUResetHandler *func; 118 void *opaque; 119 LegacyReset *lr; 120 } FindLegacyInfo; 121 122 static void find_legacy_reset_cb(Object *obj, void *opaque, ResetType type) 123 { 124 LegacyReset *lr; 125 FindLegacyInfo *fli = opaque; 126 127 /* Not everything in the ResettableContainer will be a LegacyReset */ 128 lr = LEGACY_RESET(object_dynamic_cast(obj, TYPE_LEGACY_RESET)); 129 if (lr && lr->func == fli->func && lr->opaque == fli->opaque) { 130 fli->lr = lr; 131 } 132 } 133 134 static LegacyReset *find_legacy_reset(QEMUResetHandler *func, void *opaque) 135 { 136 /* 137 * Find the LegacyReset with the specified func and opaque, 138 * by getting the ResettableContainer to call our callback for 139 * every item in it. 140 */ 141 ResettableContainer *rootcon = get_root_reset_container(); 142 ResettableClass *rc = RESETTABLE_GET_CLASS(rootcon); 143 FindLegacyInfo fli; 144 145 fli.func = func; 146 fli.opaque = opaque; 147 fli.lr = NULL; 148 rc->child_foreach(OBJECT(rootcon), find_legacy_reset_cb, 149 &fli, RESET_TYPE_COLD); 150 return fli.lr; 151 } 152 153 void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) 154 { 155 Object *obj = OBJECT(find_legacy_reset(func, opaque)); 156 157 if (obj) { 158 qemu_unregister_resettable(obj); 159 object_unref(obj); 160 } 161 } 162 163 void qemu_register_resettable(Object *obj) 164 { 165 resettable_container_add(get_root_reset_container(), obj); 166 } 167 168 void qemu_unregister_resettable(Object *obj) 169 { 170 resettable_container_remove(get_root_reset_container(), obj); 171 } 172 173 void qemu_devices_reset(ShutdownCause reason) 174 { 175 ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ? 176 RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD; 177 178 /* Reset the simulation */ 179 resettable_reset(OBJECT(get_root_reset_container()), type); 180 } 181