summaryrefslogtreecommitdiffstats
path: root/arch/ppc/boot/head.S
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /arch/ppc/boot/head.S
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'arch/ppc/boot/head.S')
-rw-r--r--arch/ppc/boot/head.S237
1 files changed, 237 insertions, 0 deletions
diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S
new file mode 100644
index 000000000..35dacd514
--- /dev/null
+++ b/arch/ppc/boot/head.S
@@ -0,0 +1,237 @@
+#include "../kernel/ppc_defs.h"
+#include "../kernel/ppc_asm.tmpl"
+
+ .text
+
+/*
+ * This code is loaded by the ROM loader at some arbitrary location.
+ * Move it to high memory so that it can load the kernel at 0x0000.
+ */
+
+ .globl start
+start:
+ bl start_
+start_:
+/* TEMP - No residual data on BeBox (yet) */
+#if 0
+#define IS_BE_BOX 0x42654278 /* 'BeBx' */
+ lis r2,IS_BE_BOX>>16
+ ori r2,r2,IS_BE_BOX&0xFFFF
+ cmp 0,r30,r2
+ bne notBeBox
+ li r3,0
+#endif
+notBeBox:
+/* TEMP */
+ mr r11,r3 /* Save pointer to residual data */
+ mfmsr r3 /* Turn off interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r3,r3,r4
+ mtmsr r3
+/* Copy relocation code down to location 0x0100 (where we hope it's safe!) */
+ mflr r3
+ addi r5,r3,start_ldr-start_
+ addi r3,r3,relocate-start_
+ li r4,0x0100
+ mtctr r4
+ subi r3,r3,4
+ subi r4,r4,4
+00: lwzu r6,4(r3)
+ stwu r6,4(r4)
+ cmp 0,r3,r5
+ bne 00b
+ mflr r21
+ mfctr r22
+ bl flush_instruction_cache
+ mtlr r21
+ mtctr r22
+ bctr /* Jump to code */
+/* Relocate code to final resting spot */
+relocate:
+ mflr r3 /* Compute code bias */
+ subi r3,r3,4
+ mr r8,r3
+ lis r4,start@h
+ ori r4,r4,start@l
+ lis r5,edata@h
+ ori r5,r5,edata@l
+ addi r5,r5,3 /* Round up - just in case */
+ sub r5,r5,r4 /* Compute # longwords to move */
+ srwi r5,r5,2
+ mtctr r5
+ mr r7,r5
+ li r6,0
+ subi r3,r3,4 /* Set up for loop */
+ subi r4,r4,4
+00: lwzu r5,4(r3)
+ stwu r5,4(r4)
+ xor r6,r6,r5
+ bdnz 00b
+ lis r3,start_ldr@h
+ ori r3,r3,start_ldr@l
+ mtlr r3 /* Easiest way to do an absolute jump */
+ blr
+start_ldr:
+/* Clear all of BSS */
+ lis r3,edata@h
+ ori r3,r3,edata@l
+ lis r4,end@h
+ ori r4,r4,end@l
+ subi r3,r3,4
+ subi r4,r4,4
+ li r0,0
+50: stwu r0,4(r3)
+ cmp 0,r3,r4
+ bne 50b
+90: mr r9,r1 /* Save old stack pointer (in case it matters) */
+ lis r1,.stack@h
+ ori r1,r1,.stack@l
+ addi r1,r1,4096*2
+ subi r1,r1,256
+ li r2,0x000F /* Mask pointer to 16-byte boundary */
+ andc r1,r1,r2
+/* Run loader */
+ mr r3,r8 /* Load point */
+ mr r4,r7 /* Program length */
+ mr r5,r6 /* Checksum */
+ mr r6,r11 /* Residual data */
+ bl decompress_kernel
+ /*mr r29,r3*/ /* R3 = TotalMemory */
+ /*lis r28,hold_residual@h
+ ori r28,r28,hold_residual@l*/
+ /* changed to use r3 (as firmware does) for kernel
+ as ptr to residual -- Cort*/
+ li r5,0x100 /* Kernel code starts here */
+ mtlr r5
+ blr
+hang:
+ b hang
+
+ .globl _get_SP
+_get_SP:
+ mr r3,r1
+ blr
+
+ .globl _get_PVR
+_get_PVR:
+ mfspr r3,PVR
+ blr
+
+ .globl _get_MSR
+_get_MSR:
+ mfmsr r3
+ blr
+
+ .globl _put_MSR
+_put_MSR:
+ sync
+ mtmsr r3
+ blr
+
+ .globl _get_HID0
+_get_HID0:
+ mfspr r3,HID0
+ blr
+
+ .globl _put_HID0
+_put_HID0:
+ sync
+ mtspr HID0,r3
+ blr
+
+/*
+ * This space [buffer] is used to forceably flush the data cache when
+ * running in copyback mode. This is necessary IFF the data cache could
+ * contain instructions for which the instruction cache has stale data.
+ * Since the instruction cache NEVER snoops the data cache, memory must
+ * be made coherent with the data cache to insure that the instruction
+ * cache gets a valid instruction stream. Note that this flushing is
+ * only performed when switching from system to user mode since this is
+ * the only juncture [as far as the OS goes] where the data cache may
+ * contain instructions, e.g. after a disk read.
+ */
+#define NUM_CACHE_LINES 128*8
+#define CACHE_LINE_SIZE 32
+#if 0
+cache_flush_buffer:
+ .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
+#else
+#define cache_flush_buffer 0x1000
+#endif
+
+
+/*
+ * Flush instruction cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_instruction_cache)
+ mflr r5
+ bl flush_data_cache
+ mfspr r3,HID0 /* Caches are controlled by this register */
+ li r4,0
+ ori r4,r4,(HID0_ICE|HID0_ICFI)
+ or r3,r3,r4 /* Need to enable+invalidate to clear */
+ mtspr HID0,r3
+ andc r3,r3,r4
+ ori r3,r3,HID0_ICE /* Enable cache */
+ mtspr HID0,r3
+ mtlr r5
+ blr
+
+/*
+ * Flush data cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_data_cache)
+ lis r3,cache_flush_buffer@h
+ ori r3,r3,cache_flush_buffer@l
+ li r4,NUM_CACHE_LINES
+ mtctr r4
+#if 0
+00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
+#else
+00: lwz r4,0(r3)
+#endif
+ addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
+ bdnz 00b
+10: blr
+
+/*
+ * Flush a particular page from the DATA cache
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * void flush_page(void *page)
+ */
+_GLOBAL(flush_page)
+ li r4,0x0FFF
+ andc r3,r3,r4 /* Get page base address */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+00: dcbf 0,r3 /* Clear line */
+ icbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 00b
+ blr
+
+/*
+ * Execute a [foreign] function
+ *
+ * run(p1, p2, cp, ep, entry)
+ *
+ */
+ .globl run
+run:
+ mtctr r7 /* Entry point */
+#define IS_PreP 0x50726550 /* 'PreP' */
+ lis r30,IS_PreP>>16
+ ori r30,r30,IS_PreP&0xFFFF
+ mr 11,r5
+ mr 12,r6
+ mr r28,r5
+ mr r29,r6
+ mr 11,r5
+ mr 12,r6
+ bctr
+
+ .comm .stack,4096*2,4