diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-generic/memory_layout.h | 7 | ||||
-rw-r--r-- | include/asm-generic/reloc.h | 69 | ||||
-rw-r--r-- | include/linux/reset.h | 6 | ||||
-rw-r--r-- | include/restart.h | 15 | ||||
-rw-r--r-- | include/soc/fsl/fsl_udc.h | 3 | ||||
-rw-r--r-- | include/soc/stm32/reboot.h | 6 |
6 files changed, 101 insertions, 5 deletions
diff --git a/include/asm-generic/memory_layout.h b/include/asm-generic/memory_layout.h index 5cfd2a43a0..7593e18da1 100644 --- a/include/asm-generic/memory_layout.h +++ b/include/asm-generic/memory_layout.h @@ -23,4 +23,11 @@ #define MALLOC_SIZE CONFIG_MALLOC_SIZE #define STACK_SIZE CONFIG_STACK_SIZE +/* + * This generates a useless load from the specified symbol + * to ensure linker garbage collection doesn't delete it + */ +#define __keep_symbolref(sym) \ + __asm__ __volatile__("": :"r"(&sym) :) + #endif /* __ASM_GENERIC_MEMORY_LAYOUT_H */ diff --git a/include/asm-generic/reloc.h b/include/asm-generic/reloc.h index 90459371eb..06fccbd6f3 100644 --- a/include/asm-generic/reloc.h +++ b/include/asm-generic/reloc.h @@ -3,8 +3,77 @@ #ifndef _ASM_GENERIC_RELOC_H_ #define _ASM_GENERIC_RELOC_H_ +#include <linux/build_bug.h> +#include <linux/compiler.h> + #ifndef global_variable_offset #define global_variable_offset() get_runtime_offset() #endif +/* + * Using sizeof() on incomplete types always fails, so we use GCC's + * __builtin_object_size() instead. This is the mechanism underlying + * FORTIFY_SOURCE. &symbol should always be something GCC can compute + * a size for, even without annotations, unless it's incomplete. + * The second argument ensures we get 0 for failure. + */ +#define __has_type_complete(sym) __builtin_object_size(&(sym), 2) + +#define __has_type_byte_array(sym) (sizeof(*sym) == 1 + __must_be_array(sym)) + +/* + * runtime_address() defined below is supposed to be used exclusively + * with linker defined symbols, e.g. unsigned char input_end[]. + * + * We can't completely ensure that, but this gets us close enough + * to avoid most abuse of runtime_address(). + */ +#define __is_incomplete_byte_array(sym) \ + (!__has_type_complete(sym) && __has_type_byte_array(sym)) + +/* + * While accessing global variables before C environment is setup is + * questionable, we can't avoid it when we decide to write our + * relocation routines in C. This invites a tricky problem with + * this naive code: + * + * var = &variable + global_variable_offset(); relocate_to_current_adr(); + * + * Compiler is within rights to rematerialize &variable after + * relocate_to_current_adr(), which is unfortunate because we + * then end up adding a relocated &variable with the relocation + * offset once more. We avoid this here by hiding address with + * RELOC_HIDE. This is required as a simple compiler barrier() + * with "memory" clobber is not immune to compiler proving that + * &sym fits in a register and as such is unaffected by the memory + * clobber. barrier_data(&sym) would work too, but that comes with + * aforementioned compiler "memory" barrier, that we don't care for. + * + * We don't necessarily need the volatile variable assignment when + * using the compiler-gcc.h RELOC_HIDE implementation as __asm__ + * __volatile__ takes care of it, but the generic RELOC_HIDE + * implementation has GCC misscompile runtime_address() when not passing + * in a volatile object. Volatile casts instead of variable assignments + * also led to miscompilations with GCC v11.1.1 for THUMB2. + */ + +#define runtime_address(sym) ({ \ + void *volatile __addrof_sym = (sym); \ + if (!__is_incomplete_byte_array(sym)) \ + __unsafe_runtime_address(); \ + RELOC_HIDE(__addrof_sym, global_variable_offset()); \ +}) + +/* + * Above will fail for "near" objects, e.g. data in the same + * translation unit or with LTO, as the compiler can be smart + * enough to omit relocation entry and just generate PC relative + * accesses leading to base address being added twice. We try to + * catch most of these here by triggering an error when runtime_address() + * is used with anything that is not a byte array of unknown size. + */ +extern void *__compiletime_error( + "runtime_address() may only be called on linker defined symbols." +) __unsafe_runtime_address(void); + #endif diff --git a/include/linux/reset.h b/include/linux/reset.h index c1282a84c7..2d788547f4 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -49,6 +49,12 @@ static inline int reset_control_deassert(struct reset_control *rstc) } static inline struct reset_control * +of_reset_control_get(struct device_node *node, const char *id) +{ + return NULL; +} + +static inline struct reset_control * reset_control_get(struct device_d *dev, const char *id) { return NULL; diff --git a/include/restart.h b/include/restart.h index 2d15c7598a..15f30bb7ad 100644 --- a/include/restart.h +++ b/include/restart.h @@ -2,13 +2,24 @@ #ifndef __INCLUDE_RESTART_H #define __INCLUDE_RESTART_H +#include <linux/compiler.h> +#include <linux/types.h> +#include <linux/bitops.h> + +struct device_node; + void restart_handlers_print(void); void __noreturn restart_machine(void); -struct restart_handler *restart_handler_get_by_name(const char *name); +struct restart_handler *restart_handler_get_by_name(const char *name, int flags); + +struct device_node; struct restart_handler { void (*restart)(struct restart_handler *); int priority; +#define RESTART_FLAG_WARM_BOOTROM BIT(0) + int flags; + struct device_node *of_node; const char *name; struct list_head list; }; @@ -19,6 +30,4 @@ int restart_handler_register_fn(const char *name, #define RESTART_DEFAULT_PRIORITY 100 -unsigned int of_get_restart_priority(struct device_node *node); - #endif /* __INCLUDE_RESTART_H */ diff --git a/include/soc/fsl/fsl_udc.h b/include/soc/fsl/fsl_udc.h index aa1db2fb38..c1abe222ba 100644 --- a/include/soc/fsl/fsl_udc.h +++ b/include/soc/fsl/fsl_udc.h @@ -385,6 +385,9 @@ int imx_barebox_start_usb(void __iomem *dr, void *dest); int imx6_barebox_load_usb(void *dest); int imx6_barebox_start_usb(void *dest); +int imx7_barebox_load_usb(void *dest); +int imx7_barebox_start_usb(void *dest); + int imx8mm_barebox_load_usb(void *dest); int imx8mm_barebox_start_usb(void *dest); diff --git a/include/soc/stm32/reboot.h b/include/soc/stm32/reboot.h index d6c731f59f..cf0d0286e7 100644 --- a/include/soc/stm32/reboot.h +++ b/include/soc/stm32/reboot.h @@ -5,10 +5,12 @@ #include <linux/compiler.h> +struct device_d; + #ifdef CONFIG_RESET_STM32 -void stm32mp_system_restart_init(void __iomem *rcc); +void stm32mp_system_restart_init(struct device_d *rcc); #else -static inline void stm32mp_system_restart_init(void __iomem *rcc) +static inline void stm32mp_system_restart_init(struct device_d *rcc) { } #endif |