Skip to content

Commit cdd73e7

Browse files
sjg20trini
authored andcommitted
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: 0b2fa98 linker_lists: Fix alignment issue Signed-off-by: Simon Glass <[email protected]>
1 parent 092d5c2 commit cdd73e7

File tree

3 files changed

+17
-2
lines changed

3 files changed

+17
-2
lines changed

drivers/core/device.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,8 @@ int dev_enable_by_path(const char *path)
11861186
static struct udevice_rt *dev_get_rt(const struct udevice *dev)
11871187
{
11881188
struct udevice *base = ll_entry_start(struct udevice, udevice);
1189-
int idx = dev - base;
1189+
uint each_size = dm_udevice_size();
1190+
int idx = ((void *)dev - (void *)base) / each_size;
11901191

11911192
struct udevice_rt *urt = gd_dm_udevice_rt() + idx;
11921193

drivers/core/root.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,18 @@ static int dm_setup_inst(void)
136136

137137
if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) {
138138
struct udevice_rt *urt;
139+
void *start, *end;
140+
int each_size;
139141
void *base;
140142
int n_ents;
141143
uint size;
142144

143145
/* Allocate the udevice_rt table */
144-
n_ents = ll_entry_count(struct udevice, udevice);
146+
each_size = dm_udevice_size();
147+
start = ll_entry_start(struct udevice, udevice);
148+
end = ll_entry_end(struct udevice, udevice);
149+
size = end - start;
150+
n_ents = size / each_size;
145151
urt = calloc(n_ents, sizeof(struct udevice_rt));
146152
if (!urt)
147153
return log_msg_ret("urt", -ENOMEM);

include/dm/device.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,14 @@ struct udevice {
192192
#endif
193193
};
194194

195+
static inline int dm_udevice_size(void)
196+
{
197+
if (CONFIG_IS_ENABLED(OF_PLATDATA_RT))
198+
return ALIGN(sizeof(struct udevice), CONFIG_LINKER_LIST_ALIGN);
199+
200+
return sizeof(struct udevice);
201+
}
202+
195203
/**
196204
* struct udevice_rt - runtime information set up by U-Boot
197205
*

0 commit comments

Comments
 (0)