]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
dm: core: Deal with a wrinkle with linker lists
authorSimon Glass <sjg@chromium.org>
Sun, 27 Mar 2022 20:26:20 +0000 (14:26 -0600)
committerTom Rini <trini@konsulko.com>
Mon, 18 Apr 2022 21:53:56 +0000 (17:53 -0400)
When every member of a linker list is aligned by the compiler, we can no
longer rely on the sizeof of the struct to determine the number of
entries.

For example, if the struct size is 0x90 but every entry is aligned to 0xa0
by the compiler, the linker list entries takes more space in memory and
the calculation of the number of entries is incorrect. For example, we may
see 0x12 entries when there are only 0x11.

This is a real problem. There may be a general solution, although I cannot
currently think of one. So far it only bites with OF_PLATDATA_RT which
creates a pointer to each entry of the 'struct udevice' linker_list. This
does not happen without that option, so it only affects SPL.

Work around it by manually calculating the aligned size of struct udevice,
then using that for the n_ent calculation.

Note: the alignment fix to linker list was here:

   0b2fa98aa5e linker_lists: Fix alignment issue

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/core/device.c
drivers/core/root.c
include/dm/device.h

index b7ce8544140024ed73b92bdea52775c7df530ad8..3ab2583df3885cf99a9c2255037339a774491852 100644 (file)
@@ -1186,7 +1186,8 @@ int dev_enable_by_path(const char *path)
 static struct udevice_rt *dev_get_rt(const struct udevice *dev)
 {
        struct udevice *base = ll_entry_start(struct udevice, udevice);
-       int idx = dev - base;
+       uint each_size = dm_udevice_size();
+       int idx = ((void *)dev - (void *)base) / each_size;
 
        struct udevice_rt *urt = gd_dm_udevice_rt() + idx;
 
index 86b3884fc674c8bc5de64419cf0ca097406d9f22..e09c12f4d6eadd9df51246d615ffc94a126bd432 100644 (file)
@@ -136,12 +136,18 @@ static int dm_setup_inst(void)
 
        if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) {
                struct udevice_rt *urt;
+               void *start, *end;
+               int each_size;
                void *base;
                int n_ents;
                uint size;
 
                /* Allocate the udevice_rt table */
-               n_ents = ll_entry_count(struct udevice, udevice);
+               each_size = dm_udevice_size();
+               start = ll_entry_start(struct udevice, udevice);
+               end = ll_entry_end(struct udevice, udevice);
+               size = end - start;
+               n_ents = size / each_size;
                urt = calloc(n_ents, sizeof(struct udevice_rt));
                if (!urt)
                        return log_msg_ret("urt", -ENOMEM);
index 3d8961f9ac65f385af95071af03e174aaf9d7521..e0f86f5df9f2681ad099f3f17ee59e9f3ed003a5 100644 (file)
@@ -192,6 +192,14 @@ struct udevice {
 #endif
 };
 
+static inline int dm_udevice_size(void)
+{
+       if (CONFIG_IS_ENABLED(OF_PLATDATA_RT))
+               return ALIGN(sizeof(struct udevice), CONFIG_LINKER_LIST_ALIGN);
+
+       return sizeof(struct udevice);
+}
+
 /**
  * struct udevice_rt - runtime information set up by U-Boot
  *