| /* |
| * Copyright (C) Paul Mackerras 1997. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version |
| * 2 of the License, or (at your option) any later version. |
| * |
| * NOTE: this code runs in 32 bit mode, is position-independent, |
| * and is packaged as ELF32. |
| */ |
| |
| #include "ppc_asm.h" |
| |
| .text |
| /* A procedure descriptor used when booting this as a COFF file. |
| * When making COFF, this comes first in the link and we're |
| * linked at 0x500000. |
| */ |
| .globl _zimage_start_opd |
| _zimage_start_opd: |
| .long 0x500000, 0, 0, 0 |
| |
| p_start: .long _start |
| p_etext: .long _etext |
| p_bss_start: .long __bss_start |
| p_end: .long _end |
| |
| .weak _platform_stack_top |
| p_pstack: .long _platform_stack_top |
| |
| .weak _zimage_start |
| .globl _zimage_start |
| _zimage_start: |
| .globl _zimage_start_lib |
| _zimage_start_lib: |
| /* Work out the offset between the address we were linked at |
| and the address where we're running. */ |
| bl .+4 |
| p_base: mflr r10 /* r10 now points to runtime addr of p_base */ |
| /* grab the link address of the dynamic section in r11 */ |
| addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha |
| lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) |
| cmpwi r11,0 |
| beq 3f /* if not linked -pie */ |
| /* get the runtime address of the dynamic section in r12 */ |
| .weak __dynamic_start |
| addis r12,r10,(__dynamic_start-p_base)@ha |
| addi r12,r12,(__dynamic_start-p_base)@l |
| subf r11,r11,r12 /* runtime - linktime offset */ |
| |
| /* The dynamic section contains a series of tagged entries. |
| * We need the RELA and RELACOUNT entries. */ |
| RELA = 7 |
| RELACOUNT = 0x6ffffff9 |
| li r9,0 |
| li r0,0 |
| 9: lwz r8,0(r12) /* get tag */ |
| cmpwi r8,0 |
| beq 10f /* end of list */ |
| cmpwi r8,RELA |
| bne 11f |
| lwz r9,4(r12) /* get RELA pointer in r9 */ |
| b 12f |
| 11: addis r8,r8,(-RELACOUNT)@ha |
| cmpwi r8,RELACOUNT@l |
| bne 12f |
| lwz r0,4(r12) /* get RELACOUNT value in r0 */ |
| 12: addi r12,r12,8 |
| b 9b |
| |
| /* The relocation section contains a list of relocations. |
| * We now do the R_PPC_RELATIVE ones, which point to words |
| * which need to be initialized with addend + offset. |
| * The R_PPC_RELATIVE ones come first and there are RELACOUNT |
| * of them. */ |
| 10: /* skip relocation if we don't have both */ |
| cmpwi r0,0 |
| beq 3f |
| cmpwi r9,0 |
| beq 3f |
| |
| add r9,r9,r11 /* Relocate RELA pointer */ |
| mtctr r0 |
| 2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ |
| cmpwi r0,22 /* R_PPC_RELATIVE */ |
| bne 3f |
| lwz r12,0(r9) /* reloc->r_offset */ |
| lwz r0,8(r9) /* reloc->r_addend */ |
| add r0,r0,r11 |
| stwx r0,r11,r12 |
| addi r9,r9,12 |
| bdnz 2b |
| |
| /* Do a cache flush for our text, in case the loader didn't */ |
| 3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ |
| lwz r8,p_etext-p_base(r10) |
| 4: dcbf r0,r9 |
| icbi r0,r9 |
| addi r9,r9,0x20 |
| cmplw cr0,r9,r8 |
| blt 4b |
| sync |
| isync |
| |
| /* Clear the BSS */ |
| lwz r9,p_bss_start-p_base(r10) |
| lwz r8,p_end-p_base(r10) |
| li r0,0 |
| 5: stw r0,0(r9) |
| addi r9,r9,4 |
| cmplw cr0,r9,r8 |
| blt 5b |
| |
| /* Possibly set up a custom stack */ |
| lwz r8,p_pstack-p_base(r10) |
| cmpwi r8,0 |
| beq 6f |
| lwz r1,0(r8) |
| li r0,0 |
| stwu r0,-16(r1) /* establish a stack frame */ |
| 6: |
| |
| /* Call platform_init() */ |
| bl platform_init |
| |
| /* Call start */ |
| b start |