aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Kurtz <djkurtz@chromium.org>2018-04-06 19:21:53 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-23 04:06:59 -0400
commitdd709e72cb934eefd44de8d9969097173fbf45dc (patch)
tree3933ff4050296ee7c63f984cd114c6deae36a7bf
parentef9604b622ce3b77e0ec6b566a016ddd64c5deb0 (diff)
earlycon: Use a pointer table to fix __earlycon_table stride
Commit 99492c39f39f ("earlycon: Fix __earlycon_table stride") tried to fix __earlycon_table stride by forcing the earlycon_id struct alignment to 32 and asking the linker to 32-byte align the __earlycon_table symbol. This fix was based on commit 07fca0e57fca92 ("tracing: Properly align linker defined symbols") which tried a similar fix for the tracing subsystem. However, this fix doesn't quite work because there is no guarantee that gcc will place structures packed into an array format. In fact, gcc 4.9 chooses to 64-byte align these structs by inserting additional padding between the entries because it has no clue that they are supposed to be in an array. If we are unlucky, the linker will assign symbol "__earlycon_table" to a 32-byte aligned address which does not correspond to the 64-byte aligned contents of section "__earlycon_table". To address this same problem, the fix to the tracing system was subsequently re-implemented using a more robust table of pointers approach by commits: 3d56e331b653 ("tracing: Replace syscall_meta_data struct array with pointer array") 654986462939 ("tracepoints: Fix section alignment using pointer array") e4a9ea5ee7c8 ("tracing: Replace trace_event struct array with pointer array") Let's use this same "array of pointers to structs" approach for EARLYCON_TABLE. Fixes: 99492c39f39f ("earlycon: Fix __earlycon_table stride") Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> Suggested-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Rob Herring <robh@kernel.org> Tested-by: Guenter Roeck <groeck@chromium.org> Reviewed-by: Guenter Roeck <groeck@chromium.org> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/of/fdt.c7
-rw-r--r--drivers/tty/serial/earlycon.c6
-rw-r--r--include/asm-generic/vmlinux.lds.h2
-rw-r--r--include/linux/serial_core.h21
4 files changed, 24 insertions, 12 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 84aa9d676375..6da20b9688f7 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -942,7 +942,7 @@ int __init early_init_dt_scan_chosen_stdout(void)
942 int offset; 942 int offset;
943 const char *p, *q, *options = NULL; 943 const char *p, *q, *options = NULL;
944 int l; 944 int l;
945 const struct earlycon_id *match; 945 const struct earlycon_id **p_match;
946 const void *fdt = initial_boot_params; 946 const void *fdt = initial_boot_params;
947 947
948 offset = fdt_path_offset(fdt, "/chosen"); 948 offset = fdt_path_offset(fdt, "/chosen");
@@ -969,7 +969,10 @@ int __init early_init_dt_scan_chosen_stdout(void)
969 return 0; 969 return 0;
970 } 970 }
971 971
972 for (match = __earlycon_table; match < __earlycon_table_end; match++) { 972 for (p_match = __earlycon_table; p_match < __earlycon_table_end;
973 p_match++) {
974 const struct earlycon_id *match = *p_match;
975
973 if (!match->compatible[0]) 976 if (!match->compatible[0])
974 continue; 977 continue;
975 978
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index a24278380fec..22683393a0f2 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -169,7 +169,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
169 */ 169 */
170int __init setup_earlycon(char *buf) 170int __init setup_earlycon(char *buf)
171{ 171{
172 const struct earlycon_id *match; 172 const struct earlycon_id **p_match;
173 173
174 if (!buf || !buf[0]) 174 if (!buf || !buf[0])
175 return -EINVAL; 175 return -EINVAL;
@@ -177,7 +177,9 @@ int __init setup_earlycon(char *buf)
177 if (early_con.flags & CON_ENABLED) 177 if (early_con.flags & CON_ENABLED)
178 return -EALREADY; 178 return -EALREADY;
179 179
180 for (match = __earlycon_table; match < __earlycon_table_end; match++) { 180 for (p_match = __earlycon_table; p_match < __earlycon_table_end;
181 p_match++) {
182 const struct earlycon_id *match = *p_match;
181 size_t len = strlen(match->name); 183 size_t len = strlen(match->name);
182 184
183 if (strncmp(buf, match->name, len)) 185 if (strncmp(buf, match->name, len))
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 278841c75b97..af240573e482 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -188,7 +188,7 @@
188#endif 188#endif
189 189
190#ifdef CONFIG_SERIAL_EARLYCON 190#ifdef CONFIG_SERIAL_EARLYCON
191#define EARLYCON_TABLE() STRUCT_ALIGN(); \ 191#define EARLYCON_TABLE() . = ALIGN(8); \
192 VMLINUX_SYMBOL(__earlycon_table) = .; \ 192 VMLINUX_SYMBOL(__earlycon_table) = .; \
193 KEEP(*(__earlycon_table)) \ 193 KEEP(*(__earlycon_table)) \
194 VMLINUX_SYMBOL(__earlycon_table_end) = .; 194 VMLINUX_SYMBOL(__earlycon_table_end) = .;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 1d356105f25a..b4c9fda9d833 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -351,10 +351,10 @@ struct earlycon_id {
351 char name[16]; 351 char name[16];
352 char compatible[128]; 352 char compatible[128];
353 int (*setup)(struct earlycon_device *, const char *options); 353 int (*setup)(struct earlycon_device *, const char *options);
354} __aligned(32); 354};
355 355
356extern const struct earlycon_id __earlycon_table[]; 356extern const struct earlycon_id *__earlycon_table[];
357extern const struct earlycon_id __earlycon_table_end[]; 357extern const struct earlycon_id *__earlycon_table_end[];
358 358
359#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) 359#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
360#define EARLYCON_USED_OR_UNUSED __used 360#define EARLYCON_USED_OR_UNUSED __used
@@ -362,12 +362,19 @@ extern const struct earlycon_id __earlycon_table_end[];
362#define EARLYCON_USED_OR_UNUSED __maybe_unused 362#define EARLYCON_USED_OR_UNUSED __maybe_unused
363#endif 363#endif
364 364
365#define OF_EARLYCON_DECLARE(_name, compat, fn) \ 365#define _OF_EARLYCON_DECLARE(_name, compat, fn, unique_id) \
366 static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ 366 static const struct earlycon_id unique_id \
367 EARLYCON_USED_OR_UNUSED __section(__earlycon_table) \ 367 EARLYCON_USED_OR_UNUSED __initconst \
368 = { .name = __stringify(_name), \ 368 = { .name = __stringify(_name), \
369 .compatible = compat, \ 369 .compatible = compat, \
370 .setup = fn } 370 .setup = fn }; \
371 static const struct earlycon_id EARLYCON_USED_OR_UNUSED \
372 __section(__earlycon_table) \
373 * const __PASTE(__p, unique_id) = &unique_id
374
375#define OF_EARLYCON_DECLARE(_name, compat, fn) \
376 _OF_EARLYCON_DECLARE(_name, compat, fn, \
377 __UNIQUE_ID(__earlycon_##_name))
371 378
372#define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) 379#define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn)
373 380