/*
* Kernel execution entry point code.
*
* Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
* Initial PowerPC version.
* Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
* Rewritten for PReP
* Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
* Low-level exception handers, MMU support, and rewrite.
* Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
* PowerPC 8xx modifications.
* Copyright (c) 1998-1999 TiVo, Inc.
* PowerPC 403GCX modifications.
* Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
* PowerPC 403GCX/405GP modifications.
* Copyright 2000 MontaVista Software Inc.
* PPC405 modifications
* PowerPC 403GCX/405GP modifications.
* Author: MontaVista Software, Inc.
* frank_rowand@mvista.com or source@mvista.com
* debbie_chu@mvista.com
* Copyright 2002-2005 MontaVista Software, Inc.
* PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
*
* 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.
*/
#include <linux/init.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
#include <asm/cputable.h>
#include <asm/thread_info.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/ptrace.h>
#include <asm/synch.h>
#include "head_booke.h"
/* As with the other PowerPC ports, it is expected that when code
* execution begins here, the following registers contain valid, yet
* optional, information:
*
* r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
* r4 - Starting address of the init RAM disk
* r5 - Ending address of the init RAM disk
* r6 - Start of kernel command line string (e.g. "mem=128")
* r7 - End of kernel command line string
*
*/
__HEAD
_ENTRY(_stext);
_ENTRY(_start);
/*
* Reserve a word at a fixed location to store the address
* of abatron_pteptrs
*/
nop
mr r31,r3 /* save device tree ptr */
li r24,0 /* CPU number */
#ifdef CONFIG_RELOCATABLE
/*
* Relocate ourselves to the current runtime address.
* This is called only by the Boot CPU.
* "relocate" is called with our current runtime virutal
* address.
* r21 will be loaded with the physical runtime address of _stext
*/
bl 0f /* Get our runtime address */
0: mflr r21 /* Make it accessible */
addis r21,r21,(_stext - 0b)@ha
addi r21,r21,(_stext - 0b)@l /* Get our current runtime base */
/*
* We have the runtime (virutal) address of our base.
* We calculate our shift of offset from a 256M page.
* We could map the 256M page we belong to at PAGE_OFFSET and
* get going from there.
*/
lis r4,KERNELBASE@h
ori r4,r4,KERNELBASE@l
rlwinm r6,r21,0,4,31 /* r6 = PHYS_START % 256M */
rlwinm r5,r4,0,4,31 /* r5 = KERNELBASE % 256M */
subf r3,r5,r6 /* r3 = r6 - r5 */
add r3,r4,r3 /* Required Virutal Address */
bl relocate
#endif
bl init_cpu_state
/*
* This is where the main kernel code starts.
*/
/* ptr to current */
lis r2,init_task@h
ori r2,r2,init_task@l
/* ptr to current thread */
addi r4,r2,THREAD /* init task's THREAD */
mtspr SPRN_SPRG_THREAD,r4
/* stack */
lis r1,init_thread_union@h
ori r1,r1,init_thread_union@l
li r0,0
stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
bl early_init
#ifdef CONFIG_RELOCATABLE
/*
* Relocatable kernel support based on processing of dynamic
* relocation entries.
*
* r25 will contain RPN/ERPN for the start address of memory
* r21 will contain the current offset of _stext
*/
lis r3,kernstart_addr@ha
la r3,kernstart_addr@l(r3)
/*
* Compute the kernstart_addr.
* kernstart_addr => (r6,r8)
* kernstart_addr & ~0xfffffff => (r6,r7)
*/
rlwinm r6,r25,0,28,31 /* ERPN. Bits 32-35 of Address */
rlwinm r7,r25,0,0,3 /* RPN - assuming 256 MB page size */
rlwinm r8,r21,0,4,31 /* r8 = (_stext & 0xfffffff) */
or r8,r7,r8 /* Compute the lower 32bit of kernstart_addr */
/* Store kernstart_addr */
stw r6,0(r3) /* higher 32bit */
stw r8,4(r3) /* lower 32bit */
/*
* Compute the virt_phys_offset :
* virt_phys_offset = stext.run - kernstart_addr
*
* stext.run = (KERNELBASE & ~0xfffffff) + (kernstart_addr & 0xfffffff)
* When we relocate, we have :
*
* (kernstart_addr & 0xfffffff) = (stext.run & 0xfffffff)
*
* hence:
* virt_phys_offset = (KERNELBASE & ~0xfffffff) - (kernstart_addr & ~0xfffffff)
*
*/
/* KERNELBASE&~0xfffffff => (r4,r5) */
li r4, 0 /* higer 32bit */
lis r5,KERNELBASE@h
rlwinm r5,r5,0,0,3 /* Align to 256M, lower 32bit */
/*
* 64bit subtraction.
*/
subfc r5,r7,r5
subfe r4,r6,r4
/* Store virt_phys_offset */
lis r3,virt_phys_offset@ha
la r3,virt_phys_offset@l(r3)
stw r4,0(r3)
stw r5,4(r3)
#elif defined(CONFIG_DYNAMIC_MEMSTART)
/*
* Mapping based, page aligned dynamic kernel loading.
*
* r25 will contain RPN/ERPN for the start address of memory
*
* Add the difference between KERNELBASE and PAGE_OFFSET to the
* start of physical memory to get kernstart_addr.
*/
lis r3,kernstart_addr@ha
la r3,kernstart_addr@l(r3)
lis r4,KERNELBASE@h
ori r4,r4,KERNELBASE@l
lis r5,PAGE_OFFSET@h
ori r5,r5,PAGE_OFFSET@l
|