From 484fdf5ba058b07be5ca82763aa2b72063540ef3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 2 Feb 2015 16:31:59 +0100 Subject: [PATCH] dm: Add support for all targets which requires MANUAL_RELOC Targets with CONFIG_NEEDS_MANUAL_RELOC do not use REL/RELA relocation (mostly only GOT) where functions aray are not updated. This patch is fixing function pointers for DM core and serial-uclass to ensure that relocated functions are called. Signed-off-by: Michal Simek Acked-by: Simon Glass --- drivers/core/root.c | 64 ++++++++++++++++++++++++++++++++++ drivers/serial/serial-uclass.c | 16 +++++++++ 2 files changed, 80 insertions(+) diff --git a/drivers/core/root.c b/drivers/core/root.c index 73e3c7228e..9b5c6bb10c 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -37,6 +37,65 @@ struct udevice *dm_root(void) return gd->dm_root; } +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +void fix_drivers(void) +{ + struct driver *drv = + ll_entry_start(struct driver, driver); + const int n_ents = ll_entry_count(struct driver, driver); + struct driver *entry; + + for (entry = drv; entry != drv + n_ents; entry++) { + if (entry->of_match) + entry->of_match = (const struct udevice_id *) + ((u32)entry->of_match + gd->reloc_off); + if (entry->bind) + entry->bind += gd->reloc_off; + if (entry->probe) + entry->probe += gd->reloc_off; + if (entry->remove) + entry->remove += gd->reloc_off; + if (entry->unbind) + entry->unbind += gd->reloc_off; + if (entry->ofdata_to_platdata) + entry->ofdata_to_platdata += gd->reloc_off; + if (entry->child_pre_probe) + entry->child_pre_probe += gd->reloc_off; + if (entry->child_post_remove) + entry->child_post_remove += gd->reloc_off; + /* OPS are fixed in every uclass post_probe function */ + if (entry->ops) + entry->ops += gd->reloc_off; + } +} + +void fix_uclass(void) +{ + struct uclass_driver *uclass = + ll_entry_start(struct uclass_driver, uclass); + const int n_ents = ll_entry_count(struct uclass_driver, uclass); + struct uclass_driver *entry; + + for (entry = uclass; entry != uclass + n_ents; entry++) { + if (entry->post_bind) + entry->post_bind += gd->reloc_off; + if (entry->pre_unbind) + entry->pre_unbind += gd->reloc_off; + if (entry->post_probe) + entry->post_probe += gd->reloc_off; + if (entry->pre_remove) + entry->pre_remove += gd->reloc_off; + if (entry->init) + entry->init += gd->reloc_off; + if (entry->destroy) + entry->destroy += gd->reloc_off; + /* FIXME maybe also need to fix these ops */ + if (entry->ops) + entry->ops += gd->reloc_off; + } +} +#endif + int dm_init(void) { int ret; @@ -47,6 +106,11 @@ int dm_init(void) } INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST); +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + fix_drivers(); + fix_uclass(); +#endif + ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); if (ret) return ret; diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 9131a8f93d..3fc7104359 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -258,6 +258,22 @@ static int serial_post_probe(struct udevice *dev) #endif int ret; +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + if (ops->setbrg) + ops->setbrg += gd->reloc_off; + if (ops->getc) + ops->getc += gd->reloc_off; + if (ops->putc) + ops->putc += gd->reloc_off; + if (ops->pending) + ops->pending += gd->reloc_off; + if (ops->clear) + ops->clear += gd->reloc_off; +#if CONFIG_POST & CONFIG_SYS_POST_UART + if (ops->loop) + ops->loop += gd->reloc_off +#endif +#endif /* Set the baud rate */ if (ops->setbrg) { ret = ops->setbrg(dev, gd->baudrate); -- 2.30.2