summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/rtas/reloc.S
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/SLOF/rtas/reloc.S')
-rw-r--r--qemu/roms/SLOF/rtas/reloc.S183
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
+
+
+