From d0a5023a356ff1ca98b800af61f338691234fbf6 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Fri, 25 May 2018 20:22:23 +0300 Subject: ARC: Cache: Don't compare I$ and D$ line lengths We don't care much about I$ line length really as there're no per-line ops on I$ instead we only do full invalidation of it on occasion of relocation and right before jumping to the OS. Also as compared to Linux kernel where we don't support different lengths of I$ and D$ lines in U-Boot we have to deal with such an exotic configs if the target board is not supposed to run Linux kernel. Signed-off-by: Alexey Brodkin --- arch/arc/lib/cache.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'arch/arc/lib') diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index 6f52877643..8c1cb6e800 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -432,9 +432,16 @@ void read_decode_cache_bcr(void) int dc_line_sz = 0, ic_line_sz = 0; union bcr_di_cache ibcr, dbcr; + /* + * We don't care much about I$ line length really as there're + * no per-line ops on I$ instead we only do full invalidation of it + * on occasion of relocation and right before jumping to the OS. + * Still we check insane config with zero-encoded line length in + * presense of version field in I$ BCR. Just in case. + */ ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); if (ibcr.fields.ver) { - gd->arch.l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; + ic_line_sz = 8 << ibcr.fields.line_len; if (!ic_line_sz) panic("Instruction exists but line length is 0\n"); } @@ -445,9 +452,6 @@ void read_decode_cache_bcr(void) if (!dc_line_sz) panic("Data cache exists but line length is 0\n"); } - - if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz)) - panic("Instruction and data cache line lengths differ\n"); } void cache_init(void) -- cgit From ce3071287e9837b897d49d1be03e00e52050a33e Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Tue, 29 May 2018 18:09:55 +0300 Subject: ARC: Improve relocation fix-ups We used to have the one and only linker script for all ARC boards and so we relied on a particular order of symbols there. Because of that we used __ivt_end as the marker of the end of all the code which won't be true any longer if we move .ivt section to any other place. That said we'd better check for each section separately. A couple of other improvements: 1. There's no point to include the marker of section end in interested range because its address is beyond the section, i.e. we should compare with "<" but not "<=". 2. .ivt section for ARCv2 cores is just an array of 32-bit ints and they are not swapped even on little-endia cores while in case of ARCompact cores .ivt contains valid code so swapping is required. 3. Just in case add check for ARC600 which is also ARCompact and its .ivt is normal code. Signed-off-by: Alexey Brodkin --- arch/arc/lib/relocate.c | 76 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 22 deletions(-) (limited to 'arch/arc/lib') diff --git a/arch/arc/lib/relocate.c b/arch/arc/lib/relocate.c index a3b7428d85..4ffba84eeb 100644 --- a/arch/arc/lib/relocate.c +++ b/arch/arc/lib/relocate.c @@ -8,7 +8,9 @@ #include extern ulong __image_copy_start; +extern ulong __ivt_start; extern ulong __ivt_end; +extern ulong __text_end; DECLARE_GLOBAL_DATA_PTR; @@ -48,7 +50,7 @@ int do_elf_reloc_fixups(void) debug("Section .rela.dyn is located at %08x-%08x\n", (unsigned int)re_src, (unsigned int)re_end); - Elf32_Addr *offset_ptr_rom, *last_offset = NULL; + Elf32_Addr *offset_ptr_rom; Elf32_Addr *offset_ptr_ram; do { @@ -57,15 +59,28 @@ int do_elf_reloc_fixups(void) /* Check that the location of the relocation is in .text */ if (offset_ptr_rom >= (Elf32_Addr *)&__image_copy_start && - offset_ptr_rom > last_offset) { - unsigned int val; + offset_ptr_rom < (Elf32_Addr *)&__image_copy_end) { + unsigned int val, do_swap = 0; /* Switch to the in-RAM version */ offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + gd->reloc_off); - debug("Patching value @ %08x (relocated to %08x)\n", +#ifdef __LITTLE_ENDIAN__ + /* If location in ".text" section swap value */ + if (((u32)offset_ptr_rom >= (u32)&__text_start && + (u32)offset_ptr_rom <= (u32)&__text_end) +#if defined(__ARC700__) || defined(__ARC600__) + || ((u32)offset_ptr_rom >= (u32)&__ivt_start && + (u32)offset_ptr_rom <= (u32)&__ivt_end) +#endif + ) + do_swap = 1; +#endif + + debug("Patching value @ %08x (relocated to %08x)%s\n", (unsigned int)offset_ptr_rom, - (unsigned int)offset_ptr_ram); + (unsigned int)offset_ptr_ram, + do_swap ? ", middle-endian encoded" : ""); /* * Use "memcpy" because target location might be @@ -75,28 +90,45 @@ int do_elf_reloc_fixups(void) */ memcpy(&val, offset_ptr_ram, sizeof(int)); -#ifdef __LITTLE_ENDIAN__ - /* If location in ".text" section swap value */ - if ((unsigned int)offset_ptr_rom < - (unsigned int)&__ivt_end) + if (do_swap) val = (val << 16) | (val >> 16); -#endif /* Check that the target points into executable */ - if (val >= (unsigned int)&__image_copy_start && val <= - (unsigned int)&__image_copy_end) { - val += gd->reloc_off; -#ifdef __LITTLE_ENDIAN__ - /* If location in ".text" section swap value */ - if ((unsigned int)offset_ptr_rom < - (unsigned int)&__ivt_end) - val = (val << 16) | (val >> 16); -#endif - memcpy(offset_ptr_ram, &val, sizeof(int)); + if (val < (unsigned int)&__image_copy_start || + val > (unsigned int)&__image_copy_end) { + /* TODO: Use panic() instead of debug() + * + * For some reason GCC might generate + * fake relocation even for LD/SC of constant + * inderectly. See an example below: + * ----------------------->8-------------------- + * static int setup_mon_len(void) + * { + * gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE; + * return 0; + * } + * ----------------------->8-------------------- + * + * And that's what we get in the binary: + * ----------------------->8-------------------- + * 10005cb4 : + * 10005cb4: 193c 3f80 0003 2f80 st 0x32f80,[r25,60] + * 10005cb8: R_ARC_RELATIVE *ABS*-0x10000000 + * 10005cbc: 7fe0 j_s.d [blink] + * 10005cbe: 700c mov_s r0,0 + * ----------------------->8-------------------- + */ + debug("Relocation target %08x points outside of image\n", + val); } - } - last_offset = offset_ptr_rom; + val += gd->reloc_off; + + if (do_swap) + val = (val << 16) | (val >> 16); + + memcpy(offset_ptr_ram, &val, sizeof(int)); + } } while (++re_src < re_end); return 0; -- cgit From 8f187142e51634d6887ef397cd6abaa7fab14b21 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 30 May 2018 11:31:07 +0300 Subject: ARC: Reset: Use __builtin_arc_brk() instead of open-coded ASM For quite some time we have a GCC's built-in which inserts BRK instruction so let's use it instead of simple insertion of in-line assembly. Signed-off-by: Alexey Brodkin --- arch/arc/lib/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arc/lib') diff --git a/arch/arc/lib/reset.c b/arch/arc/lib/reset.c index 40fb0f1fbd..fe38c51bff 100644 --- a/arch/arc/lib/reset.c +++ b/arch/arc/lib/reset.c @@ -12,7 +12,7 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) #ifdef DEBUG /* Stop debug session here */ - __asm__("brk"); + __builtin_arc_brk(); #endif return 0; } -- cgit From eb5c853938cb784bbf83ab87847e94764c3cd00a Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 30 May 2018 12:19:54 +0300 Subject: ARC: Reset: Implement weak reset_cpu() This will allow for board-specific implementation of reset. Default version will just stop execution with help of BRK instruction. Signed-off-by: Alexey Brodkin --- arch/arc/lib/reset.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'arch/arc/lib') diff --git a/arch/arc/lib/reset.c b/arch/arc/lib/reset.c index fe38c51bff..02e08df48d 100644 --- a/arch/arc/lib/reset.c +++ b/arch/arc/lib/reset.c @@ -6,13 +6,17 @@ #include #include -int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +__weak void reset_cpu(ulong addr) { - printf("Put your restart handler here\n"); - -#ifdef DEBUG /* Stop debug session here */ __builtin_arc_brk(); -#endif +} + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + printf("Resetting the board...\n"); + + reset_cpu(0); + return 0; } -- cgit