diff --git a/common/spl/spl.c b/common/spl/spl.c index 32b9f1e95c..9bcbd09ff3 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -513,6 +513,9 @@ ulong spl_relocate_stack_gd(void) ptr = CONFIG_SPL_STACK_R_ADDR - roundup(sizeof(gd_t),16); new_gd = (gd_t *)ptr; memcpy(new_gd, (void *)gd, sizeof(gd_t)); +#if CONFIG_IS_ENABLED(DM) + dm_fixup_for_gd_move(new_gd); +#endif #if !defined(CONFIG_ARM) gd = new_gd; #endif diff --git a/drivers/core/root.c b/drivers/core/root.c index 33dc9c0b2d..9edfc1efb6 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -41,6 +41,13 @@ struct udevice *dm_root(void) return gd->dm_root; } +void dm_fixup_for_gd_move(struct global_data *new_gd) +{ + /* The sentinel node has moved, so update things that point to it */ + new_gd->uclass_root.next->prev = &new_gd->uclass_root; + new_gd->uclass_root.prev->next = &new_gd->uclass_root; +} + fdt_addr_t dm_get_translation_offset(void) { struct udevice *root = dm_root(); diff --git a/include/dm/root.h b/include/dm/root.h index c7f0c1d5ca..3cf730dcee 100644 --- a/include/dm/root.h +++ b/include/dm/root.h @@ -21,6 +21,16 @@ struct udevice; */ struct udevice *dm_root(void); +struct global_data; +/** + * dm_fixup_for_gd_move() - Handle global_data moving to a new place + * + * The uclass list is part of global_data. Due to the way lists work, moving + * the list will cause it to become invalid. This function fixes that up so + * that the uclass list will work correctly. + */ +void dm_fixup_for_gd_move(struct global_data *new_gd); + /** * dm_scan_platdata() - Scan all platform data and bind drivers *