Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/777939/?format=api
{ "id": 777939, "url": "http://patchwork.ozlabs.org/api/patches/777939/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20170619185347.13959-1-paul.burton@imgtec.com/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170619185347.13959-1-paul.burton@imgtec.com>", "list_archive_url": null, "date": "2017-06-19T18:53:47", "name": "[U-Boot,v3,2/2] MIPS: Stop building position independent code", "commit_ref": "703ec9ddf965063cd79910df281657b056879368", "pull_url": null, "state": "accepted", "archived": false, "hash": "9d52e191a236f6b2f52208ef43d0d7da550c9874", "submitter": { "id": 33698, "url": "http://patchwork.ozlabs.org/api/people/33698/?format=api", "name": "Paul Burton", "email": "paul.burton@imgtec.com" }, "delegate": { "id": 4307, "url": "http://patchwork.ozlabs.org/api/users/4307/?format=api", "username": "danielschwierzeck", "first_name": "Daniel", "last_name": "Schwierzeck", "email": "daniel.schwierzeck@googlemail.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20170619185347.13959-1-paul.burton@imgtec.com/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/777939/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/777939/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Received": [ "from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 3ws0Wb1ymjz9s0Z\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 20 Jun 2017 04:54:19 +1000 (AEST)", "by lists.denx.de (Postfix, from userid 105)\n\tid 07188C21C82; Mon, 19 Jun 2017 18:54:17 +0000 (UTC)", "from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id BD3A4C21C5B;\n\tMon, 19 Jun 2017 18:54:11 +0000 (UTC)", "by lists.denx.de (Postfix, from userid 105)\n\tid 6CF08C21C5B; Mon, 19 Jun 2017 18:54:10 +0000 (UTC)", "from mailapp01.imgtec.com (mailapp01.imgtec.com [195.59.15.196])\n\tby lists.denx.de (Postfix) with ESMTP id C1DD1C21C2A\n\tfor <u-boot@lists.denx.de>; Mon, 19 Jun 2017 18:54:09 +0000 (UTC)", "from HHMAIL01.hh.imgtec.org (unknown [10.100.10.19])\n\tby Forcepoint Email with ESMTPS id 009C64CBE82F7;\n\tMon, 19 Jun 2017 19:54:03 +0100 (IST)", "from localhost (10.20.1.33) by HHMAIL01.hh.imgtec.org\n\t(10.100.10.21) with Microsoft SMTP Server (TLS) id 14.3.294.0;\n\tMon, 19 Jun 2017 19:54:06 +0100" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_NONE\n\tautolearn=unavailable autolearn_force=no version=3.4.0", "From": "Paul Burton <paul.burton@imgtec.com>", "To": "<u-boot@lists.denx.de>", "Date": "Mon, 19 Jun 2017 11:53:47 -0700", "Message-ID": "<20170619185347.13959-1-paul.burton@imgtec.com>", "X-Mailer": "git-send-email 2.13.1", "In-Reply-To": "<1610496.73fHGmXFmX@np-p-burton>", "References": "<1610496.73fHGmXFmX@np-p-burton>", "MIME-Version": "1.0", "X-Originating-IP": "[10.20.1.33]", "Subject": "[U-Boot] [PATCH v3 2/2] MIPS: Stop building position independent\n\tcode", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.18", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<http://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "base64", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>" }, "content": "U-Boot has up until now built with -fpic for the MIPS architecture,\nproducing position independent code which uses indirection through a\nglobal offset table, making relocation fairly straightforward as it\nsimply involves patching up GOT entries.\n\nUsing -fpic does however have some downsides. The biggest of these is\nthat generated code is bloated in various ways. For example, function\ncalls are indirected through the GOT & the t9 register:\n\n 8f998064 lw t9,-32668(gp)\n 0320f809 jalr t9\n\nWithout -fpic the call is simply:\n\n 0f803f01 jal be00fc04 <puts>\n\nThis is more compact & faster (due to the lack of the load & the\ndependency the jump has on its result). It is also easier to read &\ndebug because the disassembly shows what function is being called,\nrather than just an offset from gp which would then have to be looked up\nin the ELF to discover the target function.\n\nAnother disadvantage of -fpic is that each function begins with a\nsequence to calculate the value of the gp register, for example:\n\n 3c1c0004 lui gp,0x4\n 279c3384 addiu gp,gp,13188\n 0399e021 addu gp,gp,t9\n\nWithout using -fpic this sequence no longer appears at the start of each\nfunction, reducing code size considerably.\n\nThis patch switches U-Boot from building with -fpic to building with\n-fno-pic, in order to gain the benefits described above. The cost of\nthis is an extra step during the build process to extract relocation\ndata from the ELF & write it into a new .rel section in a compact\nformat, plus the added complexity of dealing with multiple types of\nrelocation rather than the single type that applied to the GOT. The\nbenefit is smaller, cleaner, more debuggable code. The relocate_code()\nfunction is reimplemented in C to handle the new relocation scheme,\nwhich also makes it easier to read & debug.\n\nTaking maltael_defconfig as an example the size of u-boot.bin built\nusing the Codescape MIPS 2016.05-06 toolchain (gcc 4.9.2, binutils\n2.24.90) shrinks from 254KiB to 224KiB.\n\nSigned-off-by: Paul Burton <paul.burton@imgtec.com>\nCc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>\nCc: u-boot@lists.denx.de\n\n---\n\nChanges in v3:\n- Fix R_MIPS_26 case that was breaking qemu_mips_defconfig.\n\nChanges in v2:\n- Drop unused .$@.relocs from Makefile.postlink.\n- Remove PF_OBJCOPY & assign to OBJCOPYFLAGS directly in config.mk.\n- Move declaration of __rel_start to asm/sections.h.\n\n arch/mips/Makefile.postlink | 23 +++\n arch/mips/config.mk | 21 +-\n arch/mips/cpu/start.S | 130 ------------\n arch/mips/cpu/u-boot.lds | 41 +---\n arch/mips/include/asm/relocs.h | 24 +++\n arch/mips/include/asm/sections.h | 7 +\n arch/mips/lib/Makefile | 1 +\n arch/mips/lib/reloc.c | 164 +++++++++++++++\n common/board_f.c | 2 +-\n tools/.gitignore | 1 +\n tools/Makefile | 2 +\n tools/mips-relocs.c | 426 +++++++++++++++++++++++++++++++++++++++\n 12 files changed, 663 insertions(+), 179 deletions(-)\n create mode 100644 arch/mips/Makefile.postlink\n create mode 100644 arch/mips/include/asm/relocs.h\n create mode 100644 arch/mips/lib/reloc.c\n create mode 100644 tools/mips-relocs.c", "diff": "diff --git a/arch/mips/Makefile.postlink b/arch/mips/Makefile.postlink\nnew file mode 100644\nindex 0000000000..7da3acdf52\n--- /dev/null\n+++ b/arch/mips/Makefile.postlink\n@@ -0,0 +1,23 @@\n+#\n+# Copyright (c) 2017 Imagination Technologies Ltd.\n+#\n+# SPDX-License-Identifier:\tGPL-2.0+\n+#\n+\n+PHONY := __archpost\n+__archpost:\n+\n+-include include/config/auto.conf\n+include scripts/Kbuild.include\n+\n+CMD_RELOCS = tools/mips-relocs\n+quiet_cmd_relocs = RELOCS $@\n+ cmd_relocs = $(CMD_RELOCS) $@\n+\n+u-boot: FORCE\n+\t@true\n+\t$(call if_changed,relocs)\n+\n+.PHONY: FORCE\n+\n+FORCE:\ndiff --git a/arch/mips/config.mk b/arch/mips/config.mk\nindex 2c72c1553d..cefdbe65e1 100644\n--- a/arch/mips/config.mk\n+++ b/arch/mips/config.mk\n@@ -56,25 +56,14 @@ PLATFORM_ELFFLAGS += -B mips $(OBJCOPYFLAGS)\n # LDFLAGS_vmlinux\t\t+= -G 0 -static -n -nostdlib\n # MODFLAGS\t\t\t+= -mlong-calls\n #\n-# On the other hand, we want PIC in the U-Boot code to relocate it from ROM\n-# to RAM. $28 is always used as gp.\n-#\n-ifdef CONFIG_SPL_BUILD\n-PF_ABICALLS\t\t\t:= -mno-abicalls\n-PF_PIC\t\t\t\t:= -fno-pic\n-PF_PIE\t\t\t\t:=\n-else\n-PF_ABICALLS\t\t\t:= -mabicalls\n-PF_PIC\t\t\t\t:= -fpic\n-PF_PIE\t\t\t\t:= -pie\n-PF_OBJCOPY\t\t\t:= -j .got -j .rel.dyn -j .padding\n-PF_OBJCOPY\t\t\t+= -j .dtb.init.rodata\n+ifndef CONFIG_SPL_BUILD\n+OBJCOPYFLAGS\t\t\t+= -j .got -j .rel -j .padding -j .dtb.init.rodata\n+LDFLAGS_FINAL\t\t\t+= --emit-relocs\n endif\n \n-PLATFORM_CPPFLAGS\t\t+= -G 0 $(PF_ABICALLS) $(PF_PIC)\n+PLATFORM_CPPFLAGS\t\t+= -G 0 -mno-abicalls -fno-pic\n PLATFORM_CPPFLAGS\t\t+= -msoft-float\n PLATFORM_LDFLAGS\t\t+= -G 0 -static -n -nostdlib\n PLATFORM_RELFLAGS\t\t+= -ffunction-sections -fdata-sections\n-LDFLAGS_FINAL\t\t\t+= --gc-sections $(PF_PIE)\n+LDFLAGS_FINAL\t\t\t+= --gc-sections\n OBJCOPYFLAGS\t\t\t+= -j .text -j .rodata -j .data -j .u_boot_list\n-OBJCOPYFLAGS\t\t\t+= $(PF_OBJCOPY)\ndiff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S\nindex d01ee9f9bd..952c57afd7 100644\n--- a/arch/mips/cpu/start.S\n+++ b/arch/mips/cpu/start.S\n@@ -221,18 +221,6 @@ wr_done:\n \tehb\n #endif\n \n-\t/*\n-\t * Initialize $gp, force pointer sized alignment of bal instruction to\n-\t * forbid the compiler to put nop's between bal and _gp. This is\n-\t * required to keep _gp and ra aligned to 8 byte.\n-\t */\n-\t.align\tPTRLOG\n-\tbal\t1f\n-\t nop\n-\tPTR\t_gp\n-1:\n-\tPTR_L\tgp, 0(ra)\n-\n #ifdef CONFIG_MIPS_CM\n \tPTR_LA\tt9, mips_cm_map\n \tjalr\tt9\n@@ -291,121 +279,3 @@ wr_done:\n \t move\tra, zero\n \n \tEND(_start)\n-\n-/*\n- * void relocate_code (addr_sp, gd, addr_moni)\n- *\n- * This \"function\" does not return, instead it continues in RAM\n- * after relocating the monitor code.\n- *\n- * a0 = addr_sp\n- * a1 = gd\n- * a2 = destination address\n- */\n-ENTRY(relocate_code)\n-\tmove\tsp, a0\t\t\t# set new stack pointer\n-\tmove\tfp, sp\n-\n-\tmove\ts0, a1\t\t\t# save gd in s0\n-\tmove\ts2, a2\t\t\t# save destination address in s2\n-\n-\tPTR_LI\tt0, CONFIG_SYS_MONITOR_BASE\n-\tPTR_SUB\ts1, s2, t0\t\t# s1 <-- relocation offset\n-\n-\tPTR_LA\tt2, __image_copy_end\n-\tmove\tt1, a2\n-\n-\t/*\n-\t * t0 = source address\n-\t * t1 = target address\n-\t * t2 = source end address\n-\t */\n-1:\n-\tPTR_L\tt3, 0(t0)\n-\tPTR_S\tt3, 0(t1)\n-\tPTR_ADDU t0, PTRSIZE\n-\tblt\tt0, t2, 1b\n-\t PTR_ADDU t1, PTRSIZE\n-\n-\t/*\n-\t * Now we want to update GOT.\n-\t *\n-\t * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object\n-\t * generated by GNU ld. Skip these reserved entries from relocation.\n-\t */\n-\tPTR_LA\tt3, num_got_entries\n-\tPTR_LA\tt8, _GLOBAL_OFFSET_TABLE_\n-\tPTR_ADD\tt8, s1\t\t\t# t8 now holds relocated _G_O_T_\n-\tPTR_ADDIU t8, t8, 2 * PTRSIZE\t# skipping first two entries\n-\tPTR_LI\tt2, 2\n-1:\n-\tPTR_L\tt1, 0(t8)\n-\tbeqz\tt1, 2f\n-\t PTR_ADD t1, s1\n-\tPTR_S\tt1, 0(t8)\n-2:\n-\tPTR_ADDIU t2, 1\n-\tblt\tt2, t3, 1b\n-\t PTR_ADDIU t8, PTRSIZE\n-\n-\t/* Update dynamic relocations */\n-\tPTR_LA\tt1, __rel_dyn_start\n-\tPTR_LA\tt2, __rel_dyn_end\n-\n-\tb\t2f\t\t\t# skip first reserved entry\n-\t PTR_ADDIU t1, 2 * PTRSIZE\n-\n-1:\n-\tlw\tt8, -4(t1)\t\t# t8 <-- relocation info\n-\n-\tPTR_LI\tt3, MIPS_RELOC\n-\tbne\tt8, t3, 2f\t\t# skip non-MIPS_RELOC entries\n-\t nop\n-\n-\tPTR_L\tt3, -(2 * PTRSIZE)(t1)\t# t3 <-- location to fix up in FLASH\n-\n-\tPTR_L\tt8, 0(t3)\t\t# t8 <-- original pointer\n-\tPTR_ADD\tt8, s1\t\t\t# t8 <-- adjusted pointer\n-\n-\tPTR_ADD\tt3, s1\t\t\t# t3 <-- location to fix up in RAM\n-\tPTR_S\tt8, 0(t3)\n-\n-2:\n-\tblt\tt1, t2, 1b\n-\t PTR_ADDIU t1, 2 * PTRSIZE\t# each rel.dyn entry is 2*PTRSIZE bytes\n-\n-\t/*\n-\t * Flush caches to ensure our newly modified instructions are visible\n-\t * to the instruction cache. We're still running with the old GOT, so\n-\t * apply the reloc offset to the start address.\n-\t */\n-\tPTR_LA\ta0, __text_start\n-\tPTR_LA\ta1, __text_end\n-\tPTR_SUB\ta1, a1, a0\n-\tPTR_LA\tt9, flush_cache\n-\tjalr\tt9\n-\t PTR_ADD\ta0, s1\n-\n-\tPTR_ADD\tgp, s1\t\t\t# adjust gp\n-\n-\t/*\n-\t * Clear BSS\n-\t *\n-\t * GOT is now relocated. Thus __bss_start and __bss_end can be\n-\t * accessed directly via $gp.\n-\t */\n-\tPTR_LA\tt1, __bss_start\t\t# t1 <-- __bss_start\n-\tPTR_LA\tt2, __bss_end\t\t# t2 <-- __bss_end\n-\n-1:\n-\tPTR_S\tzero, 0(t1)\n-\tblt\tt1, t2, 1b\n-\t PTR_ADDIU t1, PTRSIZE\n-\n-\tmove\ta0, s0\t\t\t# a0 <-- gd\n-\tmove\ta1, s2\n-\tPTR_LA\tt9, board_init_r\n-\tjr\tt9\n-\t move\tra, zero\n-\n-\tEND(relocate_code)\ndiff --git a/arch/mips/cpu/u-boot.lds b/arch/mips/cpu/u-boot.lds\nindex 0129c99611..bd5536f013 100644\n--- a/arch/mips/cpu/u-boot.lds\n+++ b/arch/mips/cpu/u-boot.lds\n@@ -34,15 +34,6 @@ SECTIONS\n \t\t*(.data*)\n \t}\n \n-\t. = .;\n-\t_gp = ALIGN(16) + 0x7ff0;\n-\n-\t.got : {\n-\t\t*(.got)\n-\t}\n-\n-\tnum_got_entries = SIZEOF(.got) >> PTR_COUNT_SHIFT;\n-\n \t. = ALIGN(4);\n \t.sdata : {\n \t\t*(.sdata*)\n@@ -57,33 +48,19 @@ SECTIONS\n \t__image_copy_end = .;\n \t__init_end = .;\n \n-\t.rel.dyn : {\n-\t\t__rel_dyn_start = .;\n-\t\t*(.rel.dyn)\n-\t\t__rel_dyn_end = .;\n-\t}\n-\n-\t.padding : {\n-\t\t/*\n-\t\t * Workaround for a binutils feature (or bug?).\n-\t\t *\n-\t\t * The GNU ld from binutils puts the dynamic relocation\n-\t\t * entries into the .rel.dyn section. Sometimes it\n-\t\t * allocates more dynamic relocation entries than it needs\n-\t\t * and the unused slots are set to R_MIPS_NONE entries.\n-\t\t *\n-\t\t * However the size of the .rel.dyn section in the ELF\n-\t\t * section header does not cover the unused entries, so\n-\t\t * objcopy removes those during stripping.\n-\t\t *\n-\t\t * Create a small section here to avoid that.\n-\t\t */\n-\t\tLONG(0xFFFFFFFF)\n+\t/*\n+\t * .rel must come last so that the mips-relocs tool can shrink\n+\t * the section size & the PT_LOAD program header filesz.\n+\t */\n+\t.rel : {\n+\t\t__rel_start = .;\n+\t\tBYTE(0x0)\n+\t\t. += (32 * 1024) - 1;\n \t}\n \n \t_end = .;\n \n-\t.bss __rel_dyn_start (OVERLAY) : {\n+\t.bss __rel_start (OVERLAY) : {\n \t\t__bss_start = .;\n \t\t*(.sbss.*)\n \t\t*(.bss.*)\ndiff --git a/arch/mips/include/asm/relocs.h b/arch/mips/include/asm/relocs.h\nnew file mode 100644\nindex 0000000000..92e9d04f7c\n--- /dev/null\n+++ b/arch/mips/include/asm/relocs.h\n@@ -0,0 +1,24 @@\n+/*\n+ * MIPS Relocations\n+ *\n+ * Copyright (c) 2017 Imagination Technologies Ltd.\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#ifndef __ASM_MIPS_RELOCS_H__\n+#define __ASM_MIPS_RELOCS_H__\n+\n+#define R_MIPS_NONE\t\t0\n+#define R_MIPS_32\t\t2\n+#define R_MIPS_26\t\t4\n+#define R_MIPS_HI16\t\t5\n+#define R_MIPS_LO16\t\t6\n+#define R_MIPS_PC16\t\t10\n+#define R_MIPS_64\t\t18\n+#define R_MIPS_HIGHER\t\t28\n+#define R_MIPS_HIGHEST\t\t29\n+#define R_MIPS_PC21_S2\t\t60\n+#define R_MIPS_PC26_S2\t\t61\n+\n+#endif /* __ASM_MIPS_RELOCS_H__ */\ndiff --git a/arch/mips/include/asm/sections.h b/arch/mips/include/asm/sections.h\nindex fc4640a392..b9d217999e 100644\n--- a/arch/mips/include/asm/sections.h\n+++ b/arch/mips/include/asm/sections.h\n@@ -8,4 +8,11 @@\n \n #include <asm-generic/sections.h>\n \n+/**\n+ * __rel_start: Relocation data generated by the mips-relocs tool\n+ *\n+ * See arch/mips/lib/reloc.c for details on the format & use of this data.\n+ */\n+extern uint8_t __rel_start[];\n+\n #endif\ndiff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile\nindex 659c6ad187..ef557c6932 100644\n--- a/arch/mips/lib/Makefile\n+++ b/arch/mips/lib/Makefile\n@@ -8,6 +8,7 @@\n obj-y\t+= cache.o\n obj-y\t+= cache_init.o\n obj-y\t+= genex.o\n+obj-y\t+= reloc.o\n obj-y\t+= stack.o\n obj-y\t+= traps.o\n \ndiff --git a/arch/mips/lib/reloc.c b/arch/mips/lib/reloc.c\nnew file mode 100644\nindex 0000000000..d0c52c9674\n--- /dev/null\n+++ b/arch/mips/lib/reloc.c\n@@ -0,0 +1,164 @@\n+/*\n+ * MIPS Relocation\n+ *\n+ * Copyright (c) 2017 Imagination Technologies Ltd.\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ *\n+ * Relocation data, found in the .rel section, is generated by the mips-relocs\n+ * tool & contains a record of all locations in the U-Boot binary that need to\n+ * be fixed up during relocation.\n+ *\n+ * The data is a sequence of unsigned integers, which are of somewhat arbitrary\n+ * size. This is achieved by encoding integers as a sequence of bytes, each of\n+ * which contains 7 bits of data with the most significant bit indicating\n+ * whether any further bytes need to be read. The least significant bits of the\n+ * integer are found in the first byte - ie. it somewhat resembles little\n+ * endian.\n+ *\n+ * Each pair of two integers represents a relocation that must be applied. The\n+ * first integer represents the type of relocation as a standard ELF relocation\n+ * type (ie. R_MIPS_*). The second integer represents the offset at which to\n+ * apply the relocation, relative to the previous relocation or for the first\n+ * relocation the start of the relocated .text section.\n+ *\n+ * The end of the relocation data is indicated when type R_MIPS_NONE (0) is\n+ * read, at which point no further integers should be read. That is, the\n+ * terminating R_MIPS_NONE reloc includes no offset.\n+ */\n+\n+#include <common.h>\n+#include <asm/relocs.h>\n+#include <asm/sections.h>\n+\n+/**\n+ * read_uint() - Read an unsigned integer from the buffer\n+ * @buf: pointer to a pointer to the reloc buffer\n+ *\n+ * Read one whole unsigned integer from the relocation data pointed to by @buf,\n+ * advancing @buf past the bytes encoding the integer.\n+ *\n+ * Returns: the integer read from @buf\n+ */\n+static unsigned long read_uint(uint8_t **buf)\n+{\n+\tunsigned long val = 0;\n+\tunsigned int shift = 0;\n+\tuint8_t new;\n+\n+\tdo {\n+\t\tnew = *(*buf)++;\n+\t\tval |= (new & 0x7f) << shift;\n+\t\tshift += 7;\n+\t} while (new & 0x80);\n+\n+\treturn val;\n+}\n+\n+/**\n+ * apply_reloc() - Apply a single relocation\n+ * @type: the type of reloc (R_MIPS_*)\n+ * @addr: the address that the reloc should be applied to\n+ * @off: the relocation offset, ie. number of bytes we're moving U-Boot by\n+ *\n+ * Apply a single relocation of type @type at @addr. This function is\n+ * intentionally simple, and does the bare minimum needed to fixup the\n+ * relocated U-Boot - in particular, it does not check for overflows.\n+ */\n+static void apply_reloc(unsigned int type, void *addr, long off)\n+{\n+\tuint32_t u32;\n+\n+\tswitch (type) {\n+\tcase R_MIPS_26:\n+\t\tu32 = *(uint32_t *)addr;\n+\t\tu32 = (u32 & GENMASK(31, 26)) |\n+\t\t ((u32 + (off >> 2)) & GENMASK(25, 0));\n+\t\t*(uint32_t *)addr = u32;\n+\t\tbreak;\n+\n+\tcase R_MIPS_32:\n+\t\t*(uint32_t *)addr += off;\n+\t\tbreak;\n+\n+\tcase R_MIPS_64:\n+\t\t*(uint64_t *)addr += off;\n+\t\tbreak;\n+\n+\tcase R_MIPS_HI16:\n+\t\t*(uint32_t *)addr += off >> 16;\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tpanic(\"Unhandled reloc type %u\\n\", type);\n+\t}\n+}\n+\n+/**\n+ * relocate_code() - Relocate U-Boot, generally from flash to DDR\n+ * @start_addr_sp: new stack pointer\n+ * @new_gd: pointer to relocated global data\n+ * @relocaddr: the address to relocate to\n+ *\n+ * Relocate U-Boot from its current location (generally in flash) to a new one\n+ * (generally in DDR). This function will copy the U-Boot binary & apply\n+ * relocations as necessary, then jump to board_init_r in the new build of\n+ * U-Boot. As such, this function does not return.\n+ */\n+void relocate_code(ulong start_addr_sp, gd_t *new_gd, ulong relocaddr)\n+{\n+\tunsigned long addr, length, bss_len;\n+\tuint8_t *buf, *bss_start;\n+\tunsigned int type;\n+\tlong off;\n+\n+\t/*\n+\t * Ensure that we're relocating by an offset which is a multiple of\n+\t * 64KiB, ie. doesn't change the least significant 16 bits of any\n+\t * addresses. This allows us to discard R_MIPS_LO16 relocs, saving\n+\t * space in the U-Boot binary & complexity in handling them.\n+\t */\n+\toff = relocaddr - (unsigned long)__text_start;\n+\tif (off & 0xffff)\n+\t\tpanic(\"Mis-aligned relocation\\n\");\n+\n+\t/* Copy U-Boot to RAM */\n+\tlength = __image_copy_end - __text_start;\n+\tmemcpy((void *)relocaddr, __text_start, length);\n+\n+\t/* Now apply relocations to the copy in RAM */\n+\tbuf = __rel_start;\n+\taddr = relocaddr;\n+\twhile (true) {\n+\t\ttype = read_uint(&buf);\n+\t\tif (type == R_MIPS_NONE)\n+\t\t\tbreak;\n+\n+\t\taddr += read_uint(&buf) << 2;\n+\t\tapply_reloc(type, (void *)addr, off);\n+\t}\n+\n+\t/* Ensure the icache is coherent */\n+\tflush_cache(relocaddr, length);\n+\n+\t/* Clear the .bss section */\n+\tbss_start = (uint8_t *)((unsigned long)__bss_start + off);\n+\tbss_len = (unsigned long)&__bss_end - (unsigned long)__bss_start;\n+\tmemset(bss_start, 0, bss_len);\n+\n+\t/* Jump to the relocated U-Boot */\n+\tasm volatile(\n+\t\t \"move\t$29, %0\\n\"\n+\t\t\"\tmove\t$4, %1\\n\"\n+\t\t\"\tmove\t$5, %2\\n\"\n+\t\t\"\tmove\t$31, $0\\n\"\n+\t\t\"\tjr\t%3\"\n+\t\t: /* no outputs */\n+\t\t: \"r\"(start_addr_sp),\n+\t\t \"r\"(new_gd),\n+\t\t \"r\"(relocaddr),\n+\t\t \"r\"((unsigned long)board_init_r + off));\n+\n+\t/* Since we jumped to the new U-Boot above, we won't get here */\n+\tunreachable();\n+}\ndiff --git a/common/board_f.c b/common/board_f.c\nindex 46e52849fb..5983bf62e7 100644\n--- a/common/board_f.c\n+++ b/common/board_f.c\n@@ -418,7 +418,7 @@ static int reserve_uboot(void)\n \t */\n \tgd->relocaddr -= gd->mon_len;\n \tgd->relocaddr &= ~(4096 - 1);\n-#ifdef CONFIG_E500\n+#if defined(CONFIG_E500) || defined(CONFIG_MIPS)\n \t/* round down to next 64 kB limit so that IVPR stays aligned */\n \tgd->relocaddr &= ~(65536 - 1);\n #endif\ndiff --git a/tools/.gitignore b/tools/.gitignore\nindex 6ec71f5c7f..ac0c979319 100644\n--- a/tools/.gitignore\n+++ b/tools/.gitignore\n@@ -11,6 +11,7 @@\n /img2srec\n /kwboot\n /dumpimage\n+/mips-relocs\n /mkenvimage\n /mkimage\n /mkexynosspl\ndiff --git a/tools/Makefile b/tools/Makefile\nindex cb1683e153..56098e6943 100644\n--- a/tools/Makefile\n+++ b/tools/Makefile\n@@ -209,6 +209,8 @@ hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela\n hostprogs-y += fdtgrep\n fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o\n \n+hostprogs-$(CONFIG_MIPS) += mips-relocs\n+\n # We build some files with extra pedantic flags to try to minimize things\n # that won't build on some weird host compiler -- though there are lots of\n # exceptions for files that aren't complaint.\ndiff --git a/tools/mips-relocs.c b/tools/mips-relocs.c\nnew file mode 100644\nindex 0000000000..b690fa53c4\n--- /dev/null\n+++ b/tools/mips-relocs.c\n@@ -0,0 +1,426 @@\n+/*\n+ * MIPS Relocation Data Generator\n+ *\n+ * Copyright (c) 2017 Imagination Technologies Ltd.\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include <elf.h>\n+#include <errno.h>\n+#include <fcntl.h>\n+#include <limits.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <sys/mman.h>\n+#include <sys/stat.h>\n+#include <unistd.h>\n+\n+#include <asm/relocs.h>\n+\n+#define hdr_field(pfx, idx, field) ({\t\t\t\t\\\n+\tuint64_t _val;\t\t\t\t\t\t\\\n+\tunsigned int _size;\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\\\n+\tif (is_64) {\t\t\t\t\t\t\\\n+\t\t_val = pfx##hdr64[idx].field;\t\t\t\\\n+\t\t_size = sizeof(pfx##hdr64[0].field);\t\t\\\n+\t} else {\t\t\t\t\t\t\\\n+\t\t_val = pfx##hdr32[idx].field;\t\t\t\\\n+\t\t_size = sizeof(pfx##hdr32[0].field);\t\t\\\n+\t}\t\t\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\\\n+\tswitch (_size) {\t\t\t\t\t\\\n+\tcase 1:\t\t\t\t\t\t\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\tcase 2:\t\t\t\t\t\t\t\\\n+\t\t_val = is_be ? be16toh(_val) : le16toh(_val);\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\tcase 4:\t\t\t\t\t\t\t\\\n+\t\t_val = is_be ? be32toh(_val) : le32toh(_val);\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\tcase 8:\t\t\t\t\t\t\t\\\n+\t\t_val = is_be ? be64toh(_val) : le64toh(_val);\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\t}\t\t\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\\\n+\t_val;\t\t\t\t\t\t\t\\\n+})\n+\n+#define set_hdr_field(pfx, idx, field, val) ({\t\t\t\\\n+\tuint64_t _val;\t\t\t\t\t\t\\\n+\tunsigned int _size;\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\\\n+\tif (is_64)\t\t\t\t\t\t\\\n+\t\t_size = sizeof(pfx##hdr64[0].field);\t\t\\\n+\telse\t\t\t\t\t\t\t\\\n+\t\t_size = sizeof(pfx##hdr32[0].field);\t\t\\\n+\t\t\t\t\t\t\t\t\\\n+\tswitch (_size) {\t\t\t\t\t\\\n+\tcase 1:\t\t\t\t\t\t\t\\\n+\t\t_val = val;\t\t\t\t\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\tcase 2:\t\t\t\t\t\t\t\\\n+\t\t_val = is_be ? htobe16(val) : htole16(val);\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\tcase 4:\t\t\t\t\t\t\t\\\n+\t\t_val = is_be ? htobe32(val) : htole32(val);\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\tcase 8:\t\t\t\t\t\t\t\\\n+\t\t_val = is_be ? htobe64(val) : htole64(val);\t\\\n+\t\tbreak;\t\t\t\t\t\t\\\n+\t}\t\t\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\\\n+\tif (is_64)\t\t\t\t\t\t\\\n+\t\tpfx##hdr64[idx].field = _val;\t\t\t\\\n+\telse\t\t\t\t\t\t\t\\\n+\t\tpfx##hdr32[idx].field = _val;\t\t\t\\\n+})\n+\n+#define ehdr_field(field) \\\n+\thdr_field(e, 0, field)\n+#define phdr_field(idx, field) \\\n+\thdr_field(p, idx, field)\n+#define shdr_field(idx, field) \\\n+\thdr_field(s, idx, field)\n+\n+#define set_phdr_field(idx, field, val) \\\n+\tset_hdr_field(p, idx, field, val)\n+#define set_shdr_field(idx, field, val) \\\n+\tset_hdr_field(s, idx, field, val)\n+\n+#define shstr(idx) (&shstrtab[idx])\n+\n+bool is_64, is_be;\n+uint64_t text_base;\n+\n+struct mips_reloc {\n+\tuint8_t type;\n+\tuint64_t offset;\n+} *relocs;\n+size_t relocs_sz, relocs_idx;\n+\n+static int add_reloc(unsigned int type, uint64_t off)\n+{\n+\tstruct mips_reloc *new;\n+\tsize_t new_sz;\n+\n+\tswitch (type) {\n+\tcase R_MIPS_NONE:\n+\tcase R_MIPS_LO16:\n+\tcase R_MIPS_PC16:\n+\tcase R_MIPS_HIGHER:\n+\tcase R_MIPS_HIGHEST:\n+\tcase R_MIPS_PC21_S2:\n+\tcase R_MIPS_PC26_S2:\n+\t\t/* Skip these relocs */\n+\t\treturn 0;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tif (relocs_idx == relocs_sz) {\n+\t\tnew_sz = relocs_sz ? relocs_sz * 2 : 128;\n+\t\tnew = realloc(relocs, new_sz * sizeof(*relocs));\n+\t\tif (!new) {\n+\t\t\tfprintf(stderr, \"Out of memory\\n\");\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\n+\t\trelocs = new;\n+\t\trelocs_sz = new_sz;\n+\t}\n+\n+\trelocs[relocs_idx++] = (struct mips_reloc){\n+\t\t.type = type,\n+\t\t.offset = off,\n+\t};\n+\n+\treturn 0;\n+}\n+\n+static int parse_mips32_rel(const void *_rel)\n+{\n+\tconst Elf32_Rel *rel = _rel;\n+\tuint32_t off, type;\n+\n+\toff = is_be ? be32toh(rel->r_offset) : le32toh(rel->r_offset);\n+\toff -= text_base;\n+\n+\ttype = is_be ? be32toh(rel->r_info) : le32toh(rel->r_info);\n+\ttype = ELF32_R_TYPE(type);\n+\n+\treturn add_reloc(type, off);\n+}\n+\n+static int parse_mips64_rela(const void *_rel)\n+{\n+\tconst Elf64_Rela *rel = _rel;\n+\tuint64_t off, type;\n+\n+\toff = is_be ? be64toh(rel->r_offset) : le64toh(rel->r_offset);\n+\toff -= text_base;\n+\n+\ttype = rel->r_info >> (64 - 8);\n+\n+\treturn add_reloc(type, off);\n+}\n+\n+static void output_uint(uint8_t **buf, uint64_t val)\n+{\n+\tuint64_t tmp;\n+\n+\tdo {\n+\t\ttmp = val & 0x7f;\n+\t\tval >>= 7;\n+\t\ttmp |= !!val << 7;\n+\t\t*(*buf)++ = tmp;\n+\t} while (val);\n+}\n+\n+static int compare_relocs(const void *a, const void *b)\n+{\n+\tconst struct mips_reloc *ra = a, *rb = b;\n+\n+\treturn ra->offset - rb->offset;\n+}\n+\n+int main(int argc, char *argv[])\n+{\n+\tunsigned int i, j, i_rel_shdr, sh_type, sh_entsize, sh_entries;\n+\tsize_t rel_size, rel_actual_size, load_sz;\n+\tconst char *shstrtab, *sh_name, *rel_pfx;\n+\tint (*parse_fn)(const void *rel);\n+\tuint8_t *buf_start, *buf;\n+\tconst Elf32_Ehdr *ehdr32;\n+\tconst Elf64_Ehdr *ehdr64;\n+\tuintptr_t sh_offset;\n+\tElf32_Phdr *phdr32;\n+\tElf64_Phdr *phdr64;\n+\tElf32_Shdr *shdr32;\n+\tElf64_Shdr *shdr64;\n+\tstruct stat st;\n+\tint err, fd;\n+\tvoid *elf;\n+\tbool skip;\n+\n+\tfd = open(argv[1], O_RDWR);\n+\tif (fd == -1) {\n+\t\tfprintf(stderr, \"Unable to open input file %s\\n\", argv[1]);\n+\t\terr = errno;\n+\t\tgoto out_ret;\n+\t}\n+\n+\terr = fstat(fd, &st);\n+\tif (err) {\n+\t\tfprintf(stderr, \"Unable to fstat() input file\\n\");\n+\t\tgoto out_close_fd;\n+\t}\n+\n+\telf = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);\n+\tif (elf == MAP_FAILED) {\n+\t\tfprintf(stderr, \"Unable to mmap() input file\\n\");\n+\t\terr = errno;\n+\t\tgoto out_close_fd;\n+\t}\n+\n+\tehdr32 = elf;\n+\tehdr64 = elf;\n+\n+\tif (memcmp(&ehdr32->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {\n+\t\tfprintf(stderr, \"Input file is not an ELF\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+\tif (ehdr32->e_ident[EI_VERSION] != EV_CURRENT) {\n+\t\tfprintf(stderr, \"Unrecognised ELF version\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+\tswitch (ehdr32->e_ident[EI_CLASS]) {\n+\tcase ELFCLASS32:\n+\t\tis_64 = false;\n+\t\tbreak;\n+\tcase ELFCLASS64:\n+\t\tis_64 = true;\n+\t\tbreak;\n+\tdefault:\n+\t\tfprintf(stderr, \"Unrecognised ELF class\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+\tswitch (ehdr32->e_ident[EI_DATA]) {\n+\tcase ELFDATA2LSB:\n+\t\tis_be = false;\n+\t\tbreak;\n+\tcase ELFDATA2MSB:\n+\t\tis_be = true;\n+\t\tbreak;\n+\tdefault:\n+\t\tfprintf(stderr, \"Unrecognised ELF data encoding\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+\tif (ehdr_field(e_type) != ET_EXEC) {\n+\t\tfprintf(stderr, \"Input ELF is not an executable\\n\");\n+\t\tprintf(\"type 0x%lx\\n\", ehdr_field(e_type));\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+\tif (ehdr_field(e_machine) != EM_MIPS) {\n+\t\tfprintf(stderr, \"Input ELF does not target MIPS\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+\tphdr32 = elf + ehdr_field(e_phoff);\n+\tphdr64 = elf + ehdr_field(e_phoff);\n+\tshdr32 = elf + ehdr_field(e_shoff);\n+\tshdr64 = elf + ehdr_field(e_shoff);\n+\tshstrtab = elf + shdr_field(ehdr_field(e_shstrndx), sh_offset);\n+\n+\ti_rel_shdr = UINT_MAX;\n+\tfor (i = 0; i < ehdr_field(e_shnum); i++) {\n+\t\tsh_name = shstr(shdr_field(i, sh_name));\n+\n+\t\tif (!strcmp(sh_name, \".rel\")) {\n+\t\t\ti_rel_shdr = i;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!strcmp(sh_name, \".text\")) {\n+\t\t\ttext_base = shdr_field(i, sh_addr);\n+\t\t\tcontinue;\n+\t\t}\n+\t}\n+\tif (i_rel_shdr == UINT_MAX) {\n+\t\tfprintf(stderr, \"Unable to find .rel section\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\tif (!text_base) {\n+\t\tfprintf(stderr, \"Unable to find .text base address\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+\trel_pfx = is_64 ? \".rela.\" : \".rel.\";\n+\n+\tfor (i = 0; i < ehdr_field(e_shnum); i++) {\n+\t\tsh_type = shdr_field(i, sh_type);\n+\t\tif ((sh_type != SHT_REL) && (sh_type != SHT_RELA))\n+\t\t\tcontinue;\n+\n+\t\tsh_name = shstr(shdr_field(i, sh_name));\n+\t\tif (strncmp(sh_name, rel_pfx, strlen(rel_pfx))) {\n+\t\t\tif (strcmp(sh_name, \".rel\") && strcmp(sh_name, \".rel.dyn\"))\n+\t\t\t\tfprintf(stderr, \"WARNING: Unexpected reloc section name '%s'\\n\", sh_name);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/*\n+\t\t * Skip reloc sections which either don't correspond to another\n+\t\t * section in the ELF, or whose corresponding section isn't\n+\t\t * loaded as part of the U-Boot binary (ie. doesn't have the\n+\t\t * alloc flags set).\n+\t\t */\n+\t\tskip = true;\n+\t\tfor (j = 0; j < ehdr_field(e_shnum); j++) {\n+\t\t\tif (strcmp(&sh_name[strlen(rel_pfx) - 1], shstr(shdr_field(j, sh_name))))\n+\t\t\t\tcontinue;\n+\n+\t\t\tskip = !(shdr_field(j, sh_flags) & SHF_ALLOC);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (skip)\n+\t\t\tcontinue;\n+\n+\t\tsh_offset = shdr_field(i, sh_offset);\n+\t\tsh_entsize = shdr_field(i, sh_entsize);\n+\t\tsh_entries = shdr_field(i, sh_size) / sh_entsize;\n+\n+\t\tif (sh_type == SHT_REL) {\n+\t\t\tif (is_64) {\n+\t\t\t\tfprintf(stderr, \"REL-style reloc in MIPS64 ELF?\\n\");\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto out_free_relocs;\n+\t\t\t} else {\n+\t\t\t\tparse_fn = parse_mips32_rel;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tif (is_64) {\n+\t\t\t\tparse_fn = parse_mips64_rela;\n+\t\t\t} else {\n+\t\t\t\tfprintf(stderr, \"RELA-style reloc in MIPS32 ELF?\\n\");\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto out_free_relocs;\n+\t\t\t}\n+\t\t}\n+\n+\t\tfor (j = 0; j < sh_entries; j++) {\n+\t\t\terr = parse_fn(elf + sh_offset + (j * sh_entsize));\n+\t\t\tif (err)\n+\t\t\t\tgoto out_free_relocs;\n+\t\t}\n+\t}\n+\n+\t/* Sort relocs in ascending order of offset */\n+\tqsort(relocs, relocs_idx, sizeof(*relocs), compare_relocs);\n+\n+\t/* Make reloc offsets relative to their predecessor */\n+\tfor (i = relocs_idx - 1; i > 0; i--)\n+\t\trelocs[i].offset -= relocs[i - 1].offset;\n+\n+\t/* Write the relocations to the .rel section */\n+\tbuf = buf_start = elf + shdr_field(i_rel_shdr, sh_offset);\n+\tfor (i = 0; i < relocs_idx; i++) {\n+\t\toutput_uint(&buf, relocs[i].type);\n+\t\toutput_uint(&buf, relocs[i].offset >> 2);\n+\t}\n+\n+\t/* Write a terminating R_MIPS_NONE (0) */\n+\toutput_uint(&buf, R_MIPS_NONE);\n+\n+\t/* Ensure the relocs didn't overflow the .rel section */\n+\trel_size = shdr_field(i_rel_shdr, sh_size);\n+\trel_actual_size = buf - buf_start;\n+\tif (rel_actual_size > rel_size) {\n+\t\tfprintf(stderr, \"Relocs overflowed .rel section\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\t/* Update the .rel section's size */\n+\tset_shdr_field(i_rel_shdr, sh_size, rel_actual_size);\n+\n+\t/* Shrink the PT_LOAD program header filesz (ie. shrink u-boot.bin) */\n+\tfor (i = 0; i < ehdr_field(e_phnum); i++) {\n+\t\tif (phdr_field(i, p_type) != PT_LOAD)\n+\t\t\tcontinue;\n+\n+\t\tload_sz = phdr_field(i, p_filesz);\n+\t\tload_sz -= rel_size - rel_actual_size;\n+\t\tset_phdr_field(i, p_filesz, load_sz);\n+\t\tbreak;\n+\t}\n+\n+\t/* Make sure data is written back to the file */\n+\terr = msync(elf, st.st_size, MS_SYNC);\n+\tif (err) {\n+\t\tfprintf(stderr, \"Failed to msync: %d\\n\", errno);\n+\t\tgoto out_free_relocs;\n+\t}\n+\n+out_free_relocs:\n+\tfree(relocs);\n+\tmunmap(elf, st.st_size);\n+out_close_fd:\n+\tclose(fd);\n+out_ret:\n+\treturn err;\n+}\n", "prefixes": [ "U-Boot", "v3", "2/2" ] }