summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2022-03-27 23:26:20 +0300
committerTom Rini <trini@konsulko.com>2022-04-19 00:53:56 +0300
commitcdd73e7215b838095984f02554fc1bc4186124af (patch)
tree3a1b5cdaf53927f248bace6f6face7155788687f /drivers
parent092d5c2a83b730844aeaa5ac300ddc7f13a75f49 (diff)
downloadu-boot-cdd73e7215b838095984f02554fc1bc4186124af.tar.xz
dm: core: Deal with a wrinkle with linker lists
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/device.c3
-rw-r--r--drivers/core/root.c8
2 files changed, 9 insertions, 2 deletions
diff --git a/drivers/core/device.c b/drivers/core/device.c
index b7ce854414..3ab2583df3 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -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;
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 86b3884fc6..e09c12f4d6 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -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);