[U-Boot] [PATCH 04/20] dm: core: Handle global_data moving in SPL

Simon Glass sjg at chromium.org
Mon Oct 31 21:39:20 CET 2016


When CONFIG_SPL_STACK_R is enabled, and spl_init() is called before
board_init_r(), spl_relocate_stack_gd() will move global_data to a new
place in memory. This affects driver model since it uses a list for the
uclasses. Unless this is updated the list will become invalid. When
looking for a non-existent uclass, such as when adding a new one, the loop
in uclass_find() may continue forever, thus causing a hang.

Add a function to correct this rather obscure bug.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 common/spl/spl.c    |  3 +++
 drivers/core/root.c |  7 +++++++
 include/dm/root.h   | 10 ++++++++++
 3 files changed, 20 insertions(+)

diff --git a/common/spl/spl.c b/common/spl/spl.c
index bdb165a..9dc9e22 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -511,6 +511,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(CONFIG_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 33dc9c0..9edfc1e 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 c7f0c1d..3cf730d 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
  *
-- 
2.8.0.rc3.226.g39d4020



More information about the U-Boot mailing list