[U-Boot] [PATCH 0/2] RFC: make U-boot fully PIC

U-boot must be linked to the correct startup address in flash so that global data acceses work before relocation to RAM.
This patch demonstrates the changes needed in common code needed to run from any link address. With these changes and a few asm insn in start.S I can link my u-boot to address 0 and still boot linux.
I am posting this for comment only and what I want to know if this change to common code is accepable or not. if so, I will send a formal patch for 83xx
The size cost is about 500 text bytes: text data bss dec hex filename 229544 14876 27608 272028 4269c u-boot 230008 14872 27608 272488 42868 u-boot.link_off
link_off looks like this currently: .globl link_off /* const void * link_off(const void * ptr) */ link_off: /* Adds GOT offset to ptr, might be useful for true PIC too */ /* Would be great if this could be inline C __asm__ instead */ /* Hand coded as we cannot clobber r14 when called from C */ mflr r4 bl 1f .text 2 0: .long .LCTOC1-1f .text 1: mflr r6 lwz r0,0b-1b(r6) add r6,r0,r6 mtlr r4 la r4,.L__GOT2_TABLE_(r6) /* addi r4,r6,.L__GOT2_TABLE_ */ lwz r5,.L__GOT2_TABLE_(r6) sub r4,r5,r4 /* r4 - r5 */ sub r3,r3,r4 /* r4 - r3 */ blr
WD, what do you think?
Joakim Tjernlund (2): Use LINK_OFF to access global data Use LINK_OFF in enviroment too
common/cmd_nvedit.c | 2 + common/console.c | 12 ++++++-- common/env_common.c | 2 +- common/env_flash.c | 65 ++++++++++++++++++++++++---------------- cpu/mpc83xx/cpu.c | 10 +++--- cpu/mpc83xx/cpu_init.c | 26 +++++++++------- cpu/mpc83xx/speed.c | 28 +++++++----------- drivers/serial/serial.c | 21 +++++++------ include/common.h | 1 - include/linux/ctype.h | 6 ++-- lib_generic/crc32.c | 7 ++++- lib_generic/ctype.c | 2 +- lib_generic/display_options.c | 5 ++- lib_generic/vsprintf.c | 9 ++++-- lib_ppc/board.c | 5 ++- tools/updater/ctype.c | 2 +- 16 files changed, 115 insertions(+), 88 deletions(-)

Accessing global data before relocation needs special handling if link address != load address. Use LINK_OFF to calculate the difference. --- common/cmd_nvedit.c | 2 ++ common/console.c | 12 +++++++++--- common/env_common.c | 2 +- cpu/mpc83xx/cpu.c | 10 +++++----- cpu/mpc83xx/cpu_init.c | 26 ++++++++++++++------------ cpu/mpc83xx/speed.c | 28 +++++++++++----------------- drivers/serial/serial.c | 21 +++++++++++---------- include/common.h | 1 - include/linux/ctype.h | 6 +++--- lib_generic/crc32.c | 7 ++++++- lib_generic/ctype.c | 2 +- lib_generic/display_options.c | 5 +++-- lib_generic/vsprintf.c | 9 ++++++--- lib_ppc/board.c | 5 +++-- tools/updater/ctype.c | 2 +- 15 files changed, 76 insertions(+), 62 deletions(-)
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 9f8d531..182c6fe 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -512,6 +512,7 @@ char *getenv (char *name) { int i, nxt;
+ name = LINK_OFF(name); WATCHDOG_RESET();
for (i=0; env_get_char(i) != '\0'; i=nxt+1) { @@ -534,6 +535,7 @@ int getenv_r (char *name, char *buf, unsigned len) { int i, nxt;
+ name = LINK_OFF(name); for (i=0; env_get_char(i) != '\0'; i=nxt+1) { int val, n;
diff --git a/common/console.c b/common/console.c index dc0d13b..afda83a 100644 --- a/common/console.c +++ b/common/console.c @@ -346,7 +346,7 @@ void putc(const char c) } }
-void puts(const char *s) +static void printf_puts(const char *s) { #ifdef CONFIG_SILENT_CONSOLE if (gd->flags & GD_FLG_SILENT) @@ -367,12 +367,18 @@ void puts(const char *s) } }
+void puts(const char *s) +{ + printf_puts(LINK_OFF(s)); +} + void printf(const char *fmt, ...) { va_list args; uint i; char printbuffer[CONFIG_SYS_PBSIZE];
+ fmt = LINK_OFF(fmt); va_start(args, fmt);
/* For this to work, printbuffer must be larger than @@ -382,7 +388,7 @@ void printf(const char *fmt, ...) va_end(args);
/* Print the string */ - puts(printbuffer); + printf_puts(printbuffer); }
void vprintf(const char *fmt, va_list args) @@ -396,7 +402,7 @@ void vprintf(const char *fmt, va_list args) i = vsprintf(printbuffer, fmt, args);
/* Print the string */ - puts(printbuffer); + printf_puts(printbuffer); }
/* test if ctrl-c was pressed */ diff --git a/common/env_common.c b/common/env_common.c index 439a4a9..107e711 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -153,7 +153,7 @@ static uchar env_get_char_init (int index) { c = env_get_char_spec(index); } else { - c = default_environment[index]; + c = LINK_OFF(default_environment)[index]; }
return (c); diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index e38a372..12a2a84 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -51,8 +51,8 @@ int checkcpu(void) char buf[32]; int i;
- const struct cpu_type { - char name[15]; + static const struct cpu_type { + char *name; u32 partid; } cpu_type_list [] = { CPU_TYPE_ENTRY(8311), @@ -72,6 +72,7 @@ int checkcpu(void) CPU_TYPE_ENTRY(8378), CPU_TYPE_ENTRY(8379), }; + const struct cpu_type *cpu_ptr = LINK_OFF(cpu_type_list);
immr = (immap_t *)CONFIG_SYS_IMMR;
@@ -99,11 +100,10 @@ int checkcpu(void) }
spridr = immr->sysconf.spridr; - for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++) - if (cpu_type_list[i].partid == PARTID_NO_E(spridr)) { + if (cpu_ptr[i].partid == PARTID_NO_E(spridr)) { puts("MPC"); - puts(cpu_type_list[i].name); + puts(cpu_ptr[i].name); if (IS_E_PROCESSOR(spridr)) puts("E"); if (REVID_MAJOR(spridr) >= 2) diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c index 031e8d5..2912dec 100644 --- a/cpu/mpc83xx/cpu_init.c +++ b/cpu/mpc83xx/cpu_init.c @@ -42,13 +42,14 @@ static void config_qe_ioports(void) u8 port, pin; int dir, open_drain, assign; int i; - - for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) { - port = qe_iop_conf_tab[i].port; - pin = qe_iop_conf_tab[i].pin; - dir = qe_iop_conf_tab[i].dir; - open_drain = qe_iop_conf_tab[i].open_drain; - assign = qe_iop_conf_tab[i].assign; + qe_iop_conf_t *qe_ptr = LINK_OFF(qe_iop_conf_tab); + + for (i = 0; qe_ptr[i].assign != QE_IOP_TAB_END; i++) { + port = qe_ptr[i].port; + pin = qe_ptr[i].pin; + dir = qe_ptr[i].dir; + open_drain = qe_ptr[i].open_drain; + assign = qe_ptr[i].assign; qe_config_iopin(port, pin, dir, open_drain, assign); } } @@ -501,7 +502,7 @@ static int print_83xx_arb_event(int force) */ int prt_83xx_rsr(void) { - static struct { + static const struct reset_type { ulong mask; char *desc; } bits[] = { @@ -515,7 +516,7 @@ int prt_83xx_rsr(void) RSR_SRS, "External/Internal Soft"}, { RSR_HRS, "External/Internal Hard"} }; - static int n = sizeof bits / sizeof bits[0]; + const struct reset_type *bp = LINK_OFF(bits); ulong rsr = gd->reset_status; int i; char *sep; @@ -523,9 +524,10 @@ int prt_83xx_rsr(void) puts("Reset Status:");
sep = " "; - for (i = 0; i < n; i++) - if (rsr & bits[i].mask) { - printf("%s%s", sep, bits[i].desc); + for (i = 0; i < ARRAY_SIZE(bits); i++) + if (rsr & bp[i].mask) { + puts(sep); + puts(bp[i].desc); sep = ", "; } puts("\n"); diff --git a/cpu/mpc83xx/speed.c b/cpu/mpc83xx/speed.c index bde7e92..001387a 100644 --- a/cpu/mpc83xx/speed.c +++ b/cpu/mpc83xx/speed.c @@ -98,7 +98,8 @@ int get_clocks(void) u32 corecnf_tab_index; u8 corepll; u32 lcrr; - + corecnf_t *cnf_tab; + int csb_r; u32 csb_clk; #if defined(CONFIG_MPC834x) || defined(CONFIG_MPC831x) || defined(CONFIG_MPC837x) u32 tsec1_clk; @@ -413,28 +414,21 @@ int get_clocks(void) /* corecnf_tab_index is too high, possibly worng value */ return -11; } - switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) { - case _byp: - case _x1: - case _1x: + cnf_tab = LINK_OFF(corecnf_tab); + csb_r = cnf_tab[corecnf_tab_index].core_csb_ratio; + /* Cannot use a switch stmt here, it uses linked address */ + if (csb_r == _byp || csb_r == _x1 || csb_r == _1x) core_clk = csb_clk; - break; - case _1_5x: + else if (csb_r == _1_5x) core_clk = (3 * csb_clk) / 2; - break; - case _2x: + else if (csb_r == _2x) core_clk = 2 * csb_clk; - break; - case _2_5x: + else if (csb_r == _2_5x) core_clk = (5 * csb_clk) / 2; - break; - case _3x: + else if (csb_r == _3x) core_clk = 3 * csb_clk; - break; - default: - /* unkown core to csb ratio */ + else /* unkown core to csb ratio */ return -13; - }
#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832x) qepmf = (im->reset.rcwl & HRCWL_CEPMF) >> HRCWL_CEPMF_SHIFT; diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index dd5f332..4ccfb56 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -85,9 +85,9 @@ static NS16550_t serial_ports[4] = { #endif };
-#define PORT serial_ports[port-1] +#define PORT (LINK_OFF(serial_ports)[port-1]) #if defined(CONFIG_CONS_INDEX) -#define CONSOLE (serial_ports[CONFIG_CONS_INDEX-1]) +#define CONSOLE (LINK_OFF(serial_ports)[CONFIG_CONS_INDEX-1]) #endif
#if defined(CONFIG_SERIAL_MULTI) @@ -159,26 +159,27 @@ static int calc_divisor (NS16550_t port) int serial_init (void) { int clock_divisor; + NS16550_t * sp = LINK_OFF(serial_ports);
#ifdef CONFIG_NS87308 initialise_ns87308(); #endif
#ifdef CONFIG_SYS_NS16550_COM1 - clock_divisor = calc_divisor(serial_ports[0]); - NS16550_init(serial_ports[0], clock_divisor); + clock_divisor = calc_divisor(sp[0]); + NS16550_init(sp[0], clock_divisor); #endif #ifdef CONFIG_SYS_NS16550_COM2 - clock_divisor = calc_divisor(serial_ports[1]); - NS16550_init(serial_ports[1], clock_divisor); + clock_divisor = calc_divisor(sp[1]); + NS16550_init(sp[1], clock_divisor); #endif #ifdef CONFIG_SYS_NS16550_COM3 - clock_divisor = calc_divisor(serial_ports[2]); - NS16550_init(serial_ports[2], clock_divisor); + clock_divisor = calc_divisor(sp[2]); + NS16550_init(sp[2], clock_divisor); #endif #ifdef CONFIG_SYS_NS16550_COM4 - clock_divisor = calc_divisor(serial_ports[3]); - NS16550_init(serial_ports[3], clock_divisor); + clock_divisor = calc_divisor(sp[3]); + NS16550_init(sp[3], clock_divisor); #endif
return (0); diff --git a/include/common.h b/include/common.h index 90c9a13..67add2d 100644 --- a/include/common.h +++ b/include/common.h @@ -99,7 +99,6 @@ const void * link_off(const void *); #define link_off(x) ((const void *)(x)) #endif #define LINK_OFF(x) ((__typeof__(&(x)[0]))link_off(x)) -#define GOT_OFF(x) LINK_OFF(x) #ifdef CONFIG_4xx #include <ppc4xx.h> #endif diff --git a/include/linux/ctype.h b/include/linux/ctype.h index afa3639..5873c55 100644 --- a/include/linux/ctype.h +++ b/include/linux/ctype.h @@ -1,6 +1,6 @@ #ifndef _LINUX_CTYPE_H #define _LINUX_CTYPE_H - +#include <common.h> /* * NOTE! This ctype does not handle EOF like the standard C * library is required to. @@ -15,9 +15,9 @@ #define _X 0x40 /* hex digit */ #define _SP 0x80 /* hard space (0x20) */
-extern unsigned char _ctype[]; +extern const unsigned char _ctype[];
-#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) +#define __ismask(x) (LINK_OFF(_ctype)[(int)(unsigned char)(x)])
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) diff --git a/lib_generic/crc32.c b/lib_generic/crc32.c index b27048c..2e11548 100644 --- a/lib_generic/crc32.c +++ b/lib_generic/crc32.c @@ -148,7 +148,7 @@ const uint32_t * ZEXPORT get_crc_table() #endif
/* ========================================================================= */ -#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO1(buf) crc = crc_tab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define DO2(buf) DO1(buf); DO1(buf); #define DO4(buf) DO2(buf); DO2(buf); #define DO8(buf) DO4(buf); DO4(buf); @@ -156,6 +156,11 @@ const uint32_t * ZEXPORT get_crc_table() /* ========================================================================= */ uint32_t ZEXPORT crc32 (uint32_t crc, const Bytef *buf, uInt len) { +#ifdef LINK_OFF + const uint32_t *crc_tab = LINK_OFF(crc_table); +#else + const uint32_t *crc_tab = crc_table; +#endif #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); diff --git a/lib_generic/ctype.c b/lib_generic/ctype.c index 6ed0468..dffe563 100644 --- a/lib_generic/ctype.c +++ b/lib_generic/ctype.c @@ -29,7 +29,7 @@
#include <linux/ctype.h>
-unsigned char _ctype[] = { +const unsigned char _ctype[] = { _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ diff --git a/lib_generic/display_options.c b/lib_generic/display_options.c index 2dc2567..6b9fba2 100644 --- a/lib_generic/display_options.c +++ b/lib_generic/display_options.c @@ -31,9 +31,9 @@ int display_options (void) extern char version_string[];
#if defined(BUILD_TAG) - printf ("\n\n%s, Build: %s\n\n", version_string, BUILD_TAG); + printf ("\n\n%s, Build: %s\n\n", LINK_OFF(version_string), LINK_OFF(BUILD_TAG)); #else - printf ("\n\n%s\n\n", version_string); + printf ("\n\n%s\n\n", LINK_OFF(version_string)); #endif return 0; } @@ -49,6 +49,7 @@ void print_size (phys_size_t size, const char *s) phys_size_t d = 1 << 30; /* 1 GB */ char c = 'G';
+ s = LINK_OFF(s); if (size < d) { /* try MB */ c = 'M'; d = 1 << 20; diff --git a/lib_generic/vsprintf.c b/lib_generic/vsprintf.c index 3d95728..b779f56 100644 --- a/lib_generic/vsprintf.c +++ b/lib_generic/vsprintf.c @@ -37,8 +37,8 @@ extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
const char hex_asc[] = "0123456789abcdef"; -#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] -#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] +#define hex_asc_lo(x) LINK_OFF(hex_asc)[((x) & 0x0f)] +#define hex_asc_hi(x) LINK_OFF(hex_asc)[((x) & 0xf0) >> 4]
static inline char *pack_hex_byte(char *buf, u8 byte) { @@ -303,7 +303,7 @@ static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int pr int shift = 3; if (base == 16) shift = 4; do { - tmp[i++] = (digits[((unsigned char)num) & mask] | locase); + tmp[i++] = (LINK_OFF(digits)[((unsigned char)num) & mask] | locase); num >>= shift; } while (num); } else { /* base 10 */ @@ -675,6 +675,7 @@ int sprintf(char * buf, const char *fmt, ...) va_list args; int i;
+ fmt = LINK_OFF(fmt); va_start(args, fmt); i=vsprintf(buf,fmt,args); va_end(args); @@ -684,6 +685,8 @@ int sprintf(char * buf, const char *fmt, ...) void panic(const char *fmt, ...) { va_list args; + + fmt = LINK_OFF(fmt); va_start(args, fmt); vprintf(fmt, args); putc('\n'); diff --git a/lib_ppc/board.c b/lib_ppc/board.c index 765f97a..f9a7d30 100644 --- a/lib_ppc/board.c +++ b/lib_ppc/board.c @@ -384,8 +384,9 @@ void board_init_f (ulong bootflag) memset ((void *) gd, 0, sizeof (gd_t)); #endif
- for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { - if ((*init_fnc_ptr) () != 0) { + for (init_fnc_ptr = LINK_OFF(init_sequence); *init_fnc_ptr; + ++init_fnc_ptr) { + if (((init_fnc_t *)link_off(*init_fnc_ptr)) () != 0) { hang (); } } diff --git a/tools/updater/ctype.c b/tools/updater/ctype.c index 6ed0468..dffe563 100644 --- a/tools/updater/ctype.c +++ b/tools/updater/ctype.c @@ -29,7 +29,7 @@
#include <linux/ctype.h>
-unsigned char _ctype[] = { +const unsigned char _ctype[] = { _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */

This is the most complex change. Keep this one as a separate commit for now. --- common/env_flash.c | 65 +++++++++++++++++++++++++++++++-------------------- 1 files changed, 39 insertions(+), 26 deletions(-)
diff --git a/common/env_flash.c b/common/env_flash.c index b860c48..64882d2 100644 --- a/common/env_flash.c +++ b/common/env_flash.c @@ -52,27 +52,28 @@ DECLARE_GLOBAL_DATA_PTR;
char * env_name_spec = "Flash";
+static int flash_env_swapped; + #ifdef ENV_IS_EMBEDDED
extern uchar environment[]; env_t *env_ptr = (env_t *)(&environment[0]);
#ifdef CMD_SAVEENV -/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/ -static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR; +#define flash_addr f_flash_addr() #endif
#else /* ! ENV_IS_EMBEDDED */
env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR; #ifdef CMD_SAVEENV -static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR; +#define flash_addr f_flash_addr() #endif
#endif /* ENV_IS_EMBEDDED */
#ifdef CONFIG_ENV_ADDR_REDUND -static env_t *flash_addr_new = (env_t *)CONFIG_ENV_ADDR_REDUND; +#define flash_addr_new f_flash_addr_new()
/* CONFIG_ENV_ADDR is supposed to be on sector boundary */ static ulong end_addr = CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1; @@ -80,10 +81,35 @@ static ulong end_addr_new = CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1;
#define ACTIVE_FLAG 1 #define OBSOLETE_FLAG 0 + +static void flash_env_swap(void) +{ + ulong ltmp = end_addr; + + flash_env_swapped = !flash_env_swapped; + + end_addr = end_addr_new; + end_addr_new = ltmp; +} + +static env_t * f_flash_addr_new(void) +{ + if (!*(LINK_OFF(&flash_env_swapped))) + return (env_t *)CONFIG_ENV_ADDR_REDUND; + else + return (env_t *)CONFIG_ENV_ADDR; +} #endif /* CONFIG_ENV_ADDR_REDUND */
extern uchar default_environment[];
+static env_t * f_flash_addr(void) +{ + if (!(*LINK_OFF(&flash_env_swapped))) + return (env_t *)CONFIG_ENV_ADDR; + else + return (env_t *)CONFIG_ENV_ADDR_REDUND; +}
uchar env_get_char_spec (int index) { @@ -99,7 +125,7 @@ int env_init(void) uchar flag1 = flash_addr->flags; uchar flag2 = flash_addr_new->flags;
- ulong addr_default = (ulong)&default_environment[0]; + ulong addr_default = (ulong)LINK_OFF(default_environment); ulong addr1 = (ulong)&(flash_addr->data); ulong addr2 = (ulong)&(flash_addr_new->data);
@@ -218,14 +244,7 @@ int saveenv(void) } #endif { - env_t * etmp = flash_addr; - ulong ltmp = end_addr; - - flash_addr = flash_addr_new; - flash_addr_new = etmp; - - end_addr = end_addr_new; - end_addr_new = ltmp; + flash_env_swap(); }
rc = 0; @@ -245,13 +264,15 @@ Done:
int env_init(void) { - if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { - gd->env_addr = (ulong)&(env_ptr->data); + env_t *ep = *LINK_OFF(&env_ptr); + + if (crc32(0, ep->data, ENV_SIZE) == ep->crc) { + gd->env_addr = (ulong)&(ep->data); gd->env_valid = 1; return(0); }
- gd->env_addr = (ulong)&default_environment[0]; + gd->env_addr = (ulong)LINK_OFF(default_environment); gd->env_valid = 0; return (0); } @@ -334,16 +355,8 @@ void env_relocate_spec (void) { #if !defined(ENV_IS_EMBEDDED) || defined(CONFIG_ENV_ADDR_REDUND) #ifdef CONFIG_ENV_ADDR_REDUND - if (gd->env_addr != (ulong)&(flash_addr->data)) { - env_t * etmp = flash_addr; - ulong ltmp = end_addr; - - flash_addr = flash_addr_new; - flash_addr_new = etmp; - - end_addr = end_addr_new; - end_addr_new = ltmp; - } + if (gd->env_addr != (ulong)&(flash_addr->data)) + flash_env_swap();
if (flash_addr_new->flags != OBSOLETE_FLAG && crc32(0, flash_addr_new->data, ENV_SIZE) ==
participants (1)
-
Joakim Tjernlund