diff options
Diffstat (limited to 'qemu/roms/SLOF/rtas/reloc.S')
-rw-r--r-- | qemu/roms/SLOF/rtas/reloc.S | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/rtas/reloc.S b/qemu/roms/SLOF/rtas/reloc.S new file mode 100644 index 000000000..e24d293d4 --- /dev/null +++ b/qemu/roms/SLOF/rtas/reloc.S @@ -0,0 +1,183 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <rtas.h> + +/* +Function: + Input: + r3: Destination to copy rtas code to + r4: Configuration + Output: + r3: Entry point for rtas calls +Decription: Called by OpenFirmware to instantiate rtas, needs to copy + itself to destination, also do a relocations. + +*/ + +.extern rtas_entry +.extern .stack +.extern _got +.extern _got_end +.extern __bss_start +.extern __bss_end +.extern rtas_config + + + .section ".rtasstart","ax"; + .align 3 + .globl _rtas_start +_rtas_start: + mflr r10 # save link register + bcl 20,31,.over # branch (always) to .over + +.base: + .align 3 + +/* Our Open Firmware needs to know the size of the RTAS binary and the + * size & address of the RTAS function jump table. SLOF always looks for this + * information in the following three quads here at the very beginning of the + * RTAS binary at offset 8. So DO NOT DELETE/MOVE them! */ + +._rtas_size: .quad _rtas_end-_rtas_start +._ptr_to_func_tab: .quad rtas_func_tab-_rtas_start +._ptr_to_func_tab_size: .quad rtas_func_tab_size-_rtas_start + +/* The other variables are not accessed by SLOF anymore: */ + +._rel_offset: .quad _reloc_table_start-_rtas_start +._rel_end_offset: .quad _reloc_table_end-_rtas_start +._bss_offset: .quad __bss_start-_rtas_start +._bss_end_offset: .quad __bss_end-_rtas_start +._rtas_entry_offset: .quad rtas_entry-_rtas_start +._rtas_config_offset: .quad rtas_config-_rtas_start +._rtas_stack: .quad .stack-_rtas_start+RTAS_STACKSIZE-0x60 +._rtas_toc: .quad _got-_rtas_start+0x8000 + +.over: + mflr r8 # gpr 8 is the base + addi r8,r8,_rtas_start-.base # points to _rtas_start + mr r11,r4 # Save config value + +# Copy rtas code + + ld r5,._rtas_size-_rtas_start(r8) + mr r4,r8 # Start of rtas + addi r6,r3,-8 # Destination + addi r4,r4,-8 # Source + srdi r5,r5,3 # Count in quads + mtctr r5 +0: + ldu r0,8(r4) + stdu r0,8(r6) + bdnz 0b + +# Clear bss + + ld r4,._bss_offset-_rtas_start(r8) + ld r5,._bss_end_offset-_rtas_start(r8) + li r0,0 + add r6,r3,r4 # Address bss in copied code + addi r6,r6,-8 + sub r5,r5,r4 # Calculate bss size + srdi r5,r5,3 # Count in quads + mtctr r5 +0: + stdu r0,8(r6) + bdnz 0b + +# Relocate got + + ld r4, ._rel_offset-_rtas_start(r8) + ld r5, ._rel_end_offset-_rtas_start(r8) + sub r5, r5,r4 # Calculate reloc table size + cmpdi r5, 0 # No reloc table ? + beq 1f + + add r4, r4, r3 # Calculate reloc table address + addi r4, r4, -4 + srdi r5, r5, 2 # Count in words + mtctr r5 +0: + lwzu r6, 4(r4) # Load offset out of reloc table + ldx r0, r6, r3 # Load value + add r0, r0, r3 # Add relocation offset = load address + stdx r0, r6, r3 + bdnz 0b +1: + +# Save config data + + ld r5,._rtas_config_offset-_rtas_start(r8) + add r5,r5,r3 + std r11,0(r5) + +# Flush to memory + + mr r4,r3 # Destination address + ld r5,._rtas_size-_rtas_start(r8) + + add r5,r5,r4 + addi r5,r5,127 + rlwinm r4,r4,0,0,24 + rlwinm r5,r5,0,0,24 + sub r5,r5,r4 + srwi r5,r5,7 + mtctr r5 +0: + dcbst 0,r4 + sync + icbi 0,r4 + sync + isync + addi r4,r4,128 + bdnz 0b + +# Call init function + mfmsr r11 # Switch to 64 bit mode + mr r7,r11 + rotldi r11,r11,1 + ori r11,r11,1 + rotldi r11,r11,63 + mtmsrd r11 + isync + mr r9,r1 # save old stack pointer + ld r1,._rtas_stack-_rtas_start(r8) # load new stack pointer + add r1,r1,r3 + std r9,0(r1) # save stack pointer + std r2,64(r1) # save toc + std r7,72(r1) # save old msr value + + ld r2,._rtas_toc-_rtas_start(r8) # load got pointer + add r2,r2,r3 + + bl save_regs_r3_r12 + bl .rtas_init + bl restore_regs_r3_r12 + + ld r11,72(r1) # restore msr value + ld r2,64(r1) # restore toc + ld r1,0(r1) # get old stack + + mtmsrd r11 # restore msr + isync + + +# Return rtas entry + + ld r4,._rtas_entry_offset-_rtas_start(r8) + add r3,r3,r4 + mtlr r10 + blr + + + |